diff options
Diffstat (limited to 'target/linux/xburst/patches-3.3/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch')
-rw-r--r-- | target/linux/xburst/patches-3.3/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch | 417 |
1 files changed, 0 insertions, 417 deletions
diff --git a/target/linux/xburst/patches-3.3/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch b/target/linux/xburst/patches-3.3/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch deleted file mode 100644 index 4110147..0000000 --- a/target/linux/xburst/patches-3.3/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch +++ /dev/null @@ -1,417 +0,0 @@ -From d5814bdb661d3dac61422f8f69e459be884c9a9d Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Tue, 2 Aug 2011 10:49:28 +0200 -Subject: [PATCH 06/21] MTD: NAND: JZ4740: Multi-bank support with - autodetection - -The platform data can now specify which external memory banks to probe -for NAND chips, and in which order. Banks that contain a NAND are used -and the other banks are freed. - -Squashed version of development done in jz-2.6.38 branch. -Original patch by Lars-Peter Clausen with some bug fixes from me. -Thanks to Paul Cercueil for the initial autodetection patch. ---- - arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 4 + - arch/mips/jz4740/platform.c | 20 ++- - drivers/mtd/nand/jz4740_nand.c | 228 +++++++++++++++++++---- - 3 files changed, 215 insertions(+), 37 deletions(-) - ---- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h -+++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h -@@ -19,6 +19,8 @@ - #include <linux/mtd/nand.h> - #include <linux/mtd/partitions.h> - -+#define JZ_NAND_NUM_BANKS 4 -+ - struct jz_nand_platform_data { - int num_partitions; - struct mtd_partition *partitions; -@@ -27,6 +29,8 @@ struct jz_nand_platform_data { - - unsigned int busy_gpio; - -+ unsigned char banks[JZ_NAND_NUM_BANKS]; -+ - void (*ident_callback)(struct platform_device *, struct nand_chip *, - struct mtd_partition **, int *num_partitions); - }; ---- a/arch/mips/jz4740/platform.c -+++ b/arch/mips/jz4740/platform.c -@@ -157,11 +157,29 @@ static struct resource jz4740_nand_resou - .flags = IORESOURCE_MEM, - }, - { -- .name = "bank", -+ .name = "bank1", - .start = 0x18000000, - .end = 0x180C0000 - 1, - .flags = IORESOURCE_MEM, - }, -+ { -+ .name = "bank2", -+ .start = 0x14000000, -+ .end = 0x140C0000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .name = "bank3", -+ .start = 0x0C000000, -+ .end = 0x0C0C0000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .name = "bank4", -+ .start = 0x08000000, -+ .end = 0x080C0000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, - }; - - struct platform_device jz4740_nand_device = { ---- a/drivers/mtd/nand/jz4740_nand.c -+++ b/drivers/mtd/nand/jz4740_nand.c -@@ -52,9 +52,10 @@ - - #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) - #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) -+#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa - --#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 - #define JZ_NAND_MEM_CMD_OFFSET 0x08000 -+#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 - - struct jz_nand { - struct mtd_info mtd; -@@ -62,8 +63,11 @@ struct jz_nand { - void __iomem *base; - struct resource *mem; - -- void __iomem *bank_base; -- struct resource *bank_mem; -+ unsigned char banks[JZ_NAND_NUM_BANKS]; -+ void __iomem *bank_base[JZ_NAND_NUM_BANKS]; -+ struct resource *bank_mem[JZ_NAND_NUM_BANKS]; -+ -+ int selected_bank; - - struct jz_nand_platform_data *pdata; - bool is_reading; -@@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_ - return container_of(mtd, struct jz_nand, mtd); - } - -+static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) -+{ -+ struct jz_nand *nand = mtd_to_jz_nand(mtd); -+ struct nand_chip *chip = mtd->priv; -+ uint32_t ctrl; -+ int banknr; -+ -+ ctrl = readl(nand->base + JZ_REG_NAND_CTRL); -+ ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; -+ -+ if (chipnr == -1) { -+ banknr = -1; -+ } else { -+ banknr = nand->banks[chipnr] - 1; -+ chip->IO_ADDR_R = nand->bank_base[banknr]; -+ chip->IO_ADDR_W = nand->bank_base[banknr]; -+ } -+ writel(ctrl, nand->base + JZ_REG_NAND_CTRL); -+ -+ nand->selected_bank = banknr; -+} -+ - static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) - { - struct jz_nand *nand = mtd_to_jz_nand(mtd); - struct nand_chip *chip = mtd->priv; - uint32_t reg; -+ void __iomem *bank_base = nand->bank_base[nand->selected_bank]; -+ -+ BUG_ON(nand->selected_bank < 0); - - if (ctrl & NAND_CTRL_CHANGE) { - BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); - if (ctrl & NAND_ALE) -- chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET; -+ bank_base += JZ_NAND_MEM_ADDR_OFFSET; - else if (ctrl & NAND_CLE) -- chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET; -- else -- chip->IO_ADDR_W = nand->bank_base; -+ bank_base += JZ_NAND_MEM_CMD_OFFSET; -+ chip->IO_ADDR_W = bank_base; - - reg = readl(nand->base + JZ_REG_NAND_CTRL); - if (ctrl & NAND_NCE) -- reg |= JZ_NAND_CTRL_ASSERT_CHIP(0); -+ reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - else -- reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0); -+ reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); - writel(reg, nand->base + JZ_REG_NAND_CTRL); - } - if (dat != NAND_CMD_NONE) -@@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct - } - - static int jz_nand_ioremap_resource(struct platform_device *pdev, -- const char *name, struct resource **res, void __iomem **base) -+ const char *name, struct resource **res, void *__iomem *base) - { - int ret; - -@@ -288,6 +316,90 @@ err: - return ret; - } - -+static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) -+{ -+ iounmap(base); -+ release_mem_region(res->start, resource_size(res)); -+} -+ -+static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { -+ int ret; -+ int gpio; -+ char gpio_name[9]; -+ char res_name[6]; -+ uint32_t ctrl; -+ struct mtd_info *mtd = &nand->mtd; -+ struct nand_chip *chip = &nand->chip; -+ -+ /* Request GPIO port. */ -+ gpio = JZ_GPIO_MEM_CS0 + bank - 1; -+ sprintf(gpio_name, "NAND CS%d", bank); -+ ret = gpio_request(gpio, gpio_name); -+ if (ret) { -+ dev_warn(&pdev->dev, -+ "Failed to request %s gpio %d: %d\n", -+ gpio_name, gpio, ret); -+ goto notfound_gpio; -+ } -+ -+ /* Request I/O resource. */ -+ sprintf(res_name, "bank%d", bank); -+ ret = jz_nand_ioremap_resource(pdev, res_name, -+ &nand->bank_mem[bank - 1], -+ &nand->bank_base[bank - 1]); -+ if (ret) -+ goto notfound_resource; -+ -+ /* Enable chip in bank. */ -+ jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0); -+ ctrl = readl(nand->base + JZ_REG_NAND_CTRL); -+ ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); -+ writel(ctrl, nand->base + JZ_REG_NAND_CTRL); -+ -+ if (chipnr == 0) { -+ /* Detect first chip. */ -+ ret = nand_scan_ident(mtd, 1, NULL); -+ if (ret) -+ goto notfound_id; -+ -+ /* Retrieve the IDs from the first chip. */ -+ chip->select_chip(mtd, 0); -+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); -+ *nand_maf_id = chip->read_byte(mtd); -+ *nand_dev_id = chip->read_byte(mtd); -+ } else { -+ /* Detect additional chip. */ -+ chip->select_chip(mtd, chipnr); -+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); -+ if (*nand_maf_id != chip->read_byte(mtd) -+ || *nand_dev_id != chip->read_byte(mtd)) { -+ ret = -ENODEV; -+ goto notfound_id; -+ } -+ -+ /* Update size of the MTD. */ -+ chip->numchips++; -+ mtd->size += chip->chipsize; -+ } -+ -+ dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank); -+ return 0; -+ -+notfound_id: -+ dev_info(&pdev->dev, "No chip found on bank %i\n", bank); -+ ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); -+ writel(ctrl, nand->base + JZ_REG_NAND_CTRL); -+ jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); -+ jz_nand_iounmap_resource(nand->bank_mem[bank - 1], -+ nand->bank_base[bank - 1]); -+notfound_resource: -+ gpio_free(gpio); -+notfound_gpio: -+ return ret; -+} -+ - static int __devinit jz_nand_probe(struct platform_device *pdev) - { - int ret; -@@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struc - struct nand_chip *chip; - struct mtd_info *mtd; - struct jz_nand_platform_data *pdata = pdev->dev.platform_data; -+ size_t chipnr, bank_idx; -+ uint8_t nand_maf_id = 0, nand_dev_id = 0; - - nand = kzalloc(sizeof(*nand), GFP_KERNEL); - if (!nand) { -@@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struc - ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); - if (ret) - goto err_free; -- ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem, -- &nand->bank_base); -- if (ret) -- goto err_iounmap_mmio; - - if (pdata && gpio_is_valid(pdata->busy_gpio)) { - ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); -@@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struc - dev_err(&pdev->dev, - "Failed to request busy gpio %d: %d\n", - pdata->busy_gpio, ret); -- goto err_iounmap_mem; -+ goto err_iounmap_mmio; - } - } - -@@ -338,22 +448,51 @@ static int __devinit jz_nand_probe(struc - - chip->chip_delay = 50; - chip->cmd_ctrl = jz_nand_cmd_ctrl; -+ chip->select_chip = jz_nand_select_chip; - - if (pdata && gpio_is_valid(pdata->busy_gpio)) - chip->dev_ready = jz_nand_dev_ready; - -- chip->IO_ADDR_R = nand->bank_base; -- chip->IO_ADDR_W = nand->bank_base; -- - nand->pdata = pdata; - platform_set_drvdata(pdev, nand); - -- writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL); -- -- ret = nand_scan_ident(mtd, 1, NULL); -- if (ret) { -- dev_err(&pdev->dev, "Failed to scan nand\n"); -- goto err_gpio_free; -+ /* We are going to autodetect NAND chips in the banks specified in the -+ * platform data. Although nand_scan_ident() can detect multiple chips, -+ * it requires those chips to be numbered consecuitively, which is not -+ * always the case for external memory banks. And a fixed chip-to-bank -+ * mapping is not practical either, since for example Dingoo units -+ * produced at different times have NAND chips in different banks. -+ */ -+ chipnr = 0; -+ for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { -+ unsigned char bank; -+ -+ /* If there is no platform data, look for NAND in bank 1, -+ * which is the most likely bank since it is the only one -+ * that can be booted from. -+ */ -+ bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; -+ if (bank == 0) -+ break; -+ if (bank > JZ_NAND_NUM_BANKS) { -+ dev_warn(&pdev->dev, -+ "Skipping non-existing bank: %d\n", bank); -+ continue; -+ } -+ /* The detection routine will directly or indirectly call -+ * jz_nand_select_chip(), so nand->banks has to contain the -+ * bank we're checking. -+ */ -+ nand->banks[chipnr] = bank; -+ if (jz_nand_detect_bank(pdev, nand, bank, chipnr, -+ &nand_maf_id, &nand_dev_id) == 0) -+ chipnr++; -+ else -+ nand->banks[chipnr] = 0; -+ } -+ if (chipnr == 0) { -+ dev_err(&pdev->dev, "No NAND chips found\n"); -+ goto err_gpio_busy; - } - - if (pdata && pdata->ident_callback) { -@@ -363,8 +502,8 @@ static int __devinit jz_nand_probe(struc - - ret = nand_scan_tail(mtd); - if (ret) { -- dev_err(&pdev->dev, "Failed to scan nand\n"); -- goto err_gpio_free; -+ dev_err(&pdev->dev, "Failed to scan NAND\n"); -+ goto err_unclaim_banks; - } - - ret = mtd_device_parse_register(mtd, NULL, 0, -@@ -381,14 +520,21 @@ static int __devinit jz_nand_probe(struc - return 0; - - err_nand_release: -- nand_release(&nand->mtd); --err_gpio_free: -+ nand_release(mtd); -+err_unclaim_banks: -+ while (chipnr--) { -+ unsigned char bank = nand->banks[chipnr]; -+ gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); -+ jz_nand_iounmap_resource(nand->bank_mem[bank - 1], -+ nand->bank_base[bank - 1]); -+ } -+ writel(0, nand->base + JZ_REG_NAND_CTRL); -+err_gpio_busy: -+ if (pdata && gpio_is_valid(pdata->busy_gpio)) -+ gpio_free(pdata->busy_gpio); - platform_set_drvdata(pdev, NULL); -- gpio_free(pdata->busy_gpio); --err_iounmap_mem: -- iounmap(nand->bank_base); - err_iounmap_mmio: -- iounmap(nand->base); -+ jz_nand_iounmap_resource(nand->mem, nand->base); - err_free: - kfree(nand); - return ret; -@@ -397,16 +543,26 @@ err_free: - static int __devexit jz_nand_remove(struct platform_device *pdev) - { - struct jz_nand *nand = platform_get_drvdata(pdev); -+ struct jz_nand_platform_data *pdata = pdev->dev.platform_data; -+ size_t i; - - nand_release(&nand->mtd); - - /* Deassert and disable all chips */ - writel(0, nand->base + JZ_REG_NAND_CTRL); - -- iounmap(nand->bank_base); -- release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem)); -- iounmap(nand->base); -- release_mem_region(nand->mem->start, resource_size(nand->mem)); -+ for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { -+ unsigned char bank = nand->banks[i]; -+ if (bank != 0) { -+ jz_nand_iounmap_resource(nand->bank_mem[bank - 1], -+ nand->bank_base[bank - 1]); -+ gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); -+ } -+ } -+ if (pdata && gpio_is_valid(pdata->busy_gpio)) -+ gpio_free(pdata->busy_gpio); -+ -+ jz_nand_iounmap_resource(nand->mem, nand->base); - - platform_set_drvdata(pdev, NULL); - kfree(nand); |