summaryrefslogtreecommitdiff
path: root/target/linux/xburst/patches-3.3/0006-MTD-NAND-JZ4740-Multi-bank-support-with-autodetectio.patch
diff options
context:
space:
mode:
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.patch417
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);