1 From 88aacb09dfdf4d85c507757524166433204260e8 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sat, 24 Apr 2010 12:14:46 +0200
4 Subject: [PATCH] Add jz4740 nand driver
7 drivers/mtd/nand/Kconfig | 6 +
8 drivers/mtd/nand/Makefile | 1 +
9 drivers/mtd/nand/jz4740_nand.c | 444 +++++++++++++++++++++++++++++++++++++++
10 include/linux/mtd/jz4740_nand.h | 34 +++
11 include/mtd/mtd-abi.h | 2 +-
12 5 files changed, 486 insertions(+), 1 deletions(-)
13 create mode 100644 drivers/mtd/nand/jz4740_nand.c
14 create mode 100644 include/linux/mtd/jz4740_nand.h
16 diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
17 index 42e5ea4..6f587b8 100644
18 --- a/drivers/mtd/nand/Kconfig
19 +++ b/drivers/mtd/nand/Kconfig
20 @@ -488,4 +488,10 @@ config MTD_NAND_W90P910
21 This enables the driver for the NAND Flash on evaluation board based
24 +config MTD_NAND_JZ4740
25 + tristate "Support NAND Flash device on Jz4740 board"
26 + depends on SOC_JZ4740
28 + Support NAND Flash device on Jz4740 board
31 diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
32 index 1407bd1..e56bd52 100644
33 --- a/drivers/mtd/nand/Makefile
34 +++ b/drivers/mtd/nand/Makefile
35 @@ -42,5 +42,6 @@ obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
36 obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o
37 obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
38 obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
39 +obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
41 nand-objs := nand_base.o nand_bbt.o
42 diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
44 index 0000000..7b3477d
46 +++ b/drivers/mtd/nand/jz4740_nand.c
49 + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
50 + * JZ4720/JZ4740 SoC NAND controller driver
52 + * This program is free software; you can redistribute it and/or modify it
53 + * under the terms of the GNU General Public License as published by the
54 + * Free Software Foundation; either version 2 of the License, or (at your
55 + * option) any later version.
57 + * You should have received a copy of the GNU General Public License along
58 + * with this program; if not, write to the Free Software Foundation, Inc.,
59 + * 675 Mass Ave, Cambridge, MA 02139, USA.
63 +#include <linux/ioport.h>
64 +#include <linux/kernel.h>
65 +#include <linux/module.h>
66 +#include <linux/platform_device.h>
67 +#include <linux/slab.h>
69 +#include <linux/mtd/mtd.h>
70 +#include <linux/mtd/nand.h>
71 +#include <linux/mtd/partitions.h>
73 +#include <linux/mtd/jz4740_nand.h>
74 +#include <linux/gpio.h>
76 +#define JZ_REG_NAND_CTRL 0x50
77 +#define JZ_REG_NAND_ECC_CTRL 0x100
78 +#define JZ_REG_NAND_DATA 0x104
79 +#define JZ_REG_NAND_PAR0 0x108
80 +#define JZ_REG_NAND_PAR1 0x10C
81 +#define JZ_REG_NAND_PAR2 0x110
82 +#define JZ_REG_NAND_IRQ_STAT 0x114
83 +#define JZ_REG_NAND_IRQ_CTRL 0x118
84 +#define JZ_REG_NAND_ERR(x) (0x11C + (x << 2))
86 +#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4)
87 +#define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
88 +#define JZ_NAND_ECC_CTRL_RS BIT(2)
89 +#define JZ_NAND_ECC_CTRL_RESET BIT(1)
90 +#define JZ_NAND_ECC_CTRL_ENABLE BIT(0)
92 +#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29))
93 +#define JZ_NAND_STATUS_PAD_FINISH BIT(4)
94 +#define JZ_NAND_STATUS_DEC_FINISH BIT(3)
95 +#define JZ_NAND_STATUS_ENC_FINISH BIT(2)
96 +#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1)
97 +#define JZ_NAND_STATUS_ERROR BIT(0)
99 +#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT(x << 1)
100 +#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT((x << 1) + 1)
102 +#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000)
103 +#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
104 +#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000)
107 + struct mtd_info mtd;
108 + struct nand_chip chip;
109 + void __iomem *base;
110 + struct resource *mem;
112 + struct jz_nand_platform_data *pdata;
116 +static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
118 + return container_of(mtd, struct jz_nand, mtd);
121 +static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
123 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
124 + struct nand_chip *chip = mtd->priv;
127 + if (ctrl & NAND_CTRL_CHANGE) {
128 + BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE));
129 + if (ctrl & NAND_ALE)
130 + chip->IO_ADDR_W = JZ_NAND_ADDR_ADDR;
131 + else if (ctrl & NAND_CLE)
132 + chip->IO_ADDR_W = JZ_NAND_CMD_ADDR;
134 + chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
136 + reg = readl(nand->base + JZ_REG_NAND_CTRL);
137 + if (ctrl & NAND_NCE)
138 + reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
140 + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
141 + writel(reg, nand->base + JZ_REG_NAND_CTRL);
143 + if (dat != NAND_CMD_NONE)
144 + writeb(dat, chip->IO_ADDR_W);
147 +static int jz_nand_dev_ready(struct mtd_info *mtd)
149 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
150 + return gpio_get_value_cansleep(nand->pdata->busy_gpio);
153 +static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
155 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
159 + writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
160 + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
162 + reg |= JZ_NAND_ECC_CTRL_RESET;
163 + reg |= JZ_NAND_ECC_CTRL_ENABLE;
164 + reg |= JZ_NAND_ECC_CTRL_RS;
167 + case NAND_ECC_READ:
168 + reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
169 + nand->is_reading = true;
171 + case NAND_ECC_WRITE:
172 + reg |= JZ_NAND_ECC_CTRL_ENCODING;
173 + nand->is_reading = false;
179 + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
183 +static int jz_nand_calculate_ecc_rs(struct mtd_info* mtd, const uint8_t *dat,
186 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
187 + uint32_t reg, status;
189 + static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
190 + 0x8b, 0xff, 0xb7, 0x6f};
192 + if (nand->is_reading)
196 + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
197 + } while (!(status & JZ_NAND_STATUS_ENC_FINISH));
199 + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
200 + reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
201 + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
203 + for (i = 0; i < 9; ++i)
204 + ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
206 + /* If the written data is completly 0xff, we also want to write 0xff as
207 + * ecc, otherwise we will get in trouble when doing subpage writes. */
208 + if (memcmp(ecc_code, empty_block_ecc, 9) == 0)
209 + memset(ecc_code, 0xff, 9);
214 +/*#define printkd printk*/
215 +#define printkd(...)
217 +static void correct_data(uint8_t *dat, int index, int mask)
219 + int offset = index & 0x7;
221 + printkd("correct: ");
223 + index += (index >> 3);
226 + data |= dat[index+1] << 8;
228 + printkd("0x%x -> ", data);
230 + mask ^= (data >> offset) & 0x1ff;
231 + data &= ~(0x1ff << offset);
232 + data |= (mask << offset);
234 + printkd("0x%x\n", data);
236 + dat[index] = data & 0xff;
237 + dat[index+1] = (data >> 8) & 0xff;
240 +static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
241 + uint8_t *read_ecc, uint8_t *calc_ecc)
243 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
244 + int i, error_count, index;
245 + uint32_t reg, status, error;
251 + for (i = 1; i < 9; ++i)
255 + t &= dat[nand->chip.ecc.size / 2];
256 + t &= dat[nand->chip.ecc.size - 1];
259 + for (i = 1; i < nand->chip.ecc.size - 1; ++i)
266 + for (i = 0; i < 9; ++i)
267 + writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
269 + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
270 + reg |= JZ_NAND_ECC_CTRL_PAR_READY;
271 + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
274 + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
275 + } while (!(status & JZ_NAND_STATUS_DEC_FINISH));
277 + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
278 + reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
279 + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
281 + if (status & JZ_NAND_STATUS_ERROR) {
282 + if (status & JZ_NAND_STATUS_UNCOR_ERROR) {
283 + printkd("uncorrectable ecc:");
284 + for (i = 0; i < 9; ++i)
285 + printkd(" 0x%x", read_ecc[i]);
287 + printkd("uncorrectable data:");
288 + for (i = 0; i < 32; ++i)
289 + printkd(" 0x%x", dat[i]);
294 + error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
296 + printkd("error_count: %d %x\n", error_count, status);
298 + for (i = 0; i < error_count; ++i) {
299 + error = readl(nand->base + JZ_REG_NAND_ERR(i));
300 + index = ((error >> 16) & 0x1ff) - 1;
301 + if (index >= 0 && index < 512)
302 + correct_data(dat, index, error & 0x1ff);
305 + return error_count;
313 +#ifdef CONFIG_MTD_CMDLINE_PARTS
314 +static const char *part_probes[] = {"cmdline", NULL};
317 +static int __devinit jz_nand_probe(struct platform_device *pdev)
320 + struct jz_nand *nand;
321 + struct nand_chip *chip;
322 + struct mtd_info *mtd;
323 + struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
324 +#ifdef CONFIG_MTD_PARTITIONS
325 + struct mtd_partition *partition_info;
326 + int num_partitions = 0;
329 + nand = kzalloc(sizeof(*nand), GFP_KERNEL);
331 + dev_err(&pdev->dev, "Failed to allocate device structure.\n");
335 + nand->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
337 + dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
342 + nand->mem = request_mem_region(nand->mem->start,
343 + resource_size(nand->mem), pdev->name);
346 + dev_err(&pdev->dev, "Failed to request mmio memory region\n");
351 + nand->base = ioremap(nand->mem->start, resource_size(nand->mem));
354 + dev_err(&pdev->dev, "Failed to ioremap mmio memory region\n");
356 + goto err_release_mem;
359 + if (pdata && gpio_is_valid(pdata->busy_gpio)) {
360 + ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
362 + dev_err(&pdev->dev,
363 + "Failed to request busy gpio %d: %d\n",
364 + pdata->busy_gpio, ret);
370 + chip = &nand->chip;
372 + mtd->owner = THIS_MODULE;
373 + mtd->name = "jz4740-nand";
375 + chip->ecc.hwctl = jz_nand_hwctl;
377 + chip->ecc.calculate = jz_nand_calculate_ecc_rs;
378 + chip->ecc.correct = jz_nand_correct_ecc_rs;
379 + chip->ecc.mode = NAND_ECC_HW_OOB_FIRST;
380 + chip->ecc.size = 512;
381 + chip->ecc.bytes = 9;
383 + chip->ecc.layout = pdata->ecc_layout;
385 + chip->chip_delay = 50;
386 + chip->cmd_ctrl = jz_nand_cmd_ctrl;
388 + if (pdata && gpio_is_valid(pdata->busy_gpio))
389 + chip->dev_ready = jz_nand_dev_ready;
391 + chip->IO_ADDR_R = JZ_NAND_DATA_ADDR;
392 + chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
394 + nand->pdata = pdata;
395 + platform_set_drvdata(pdev, nand);
397 + ret = nand_scan_ident(mtd, 1);
399 + dev_err(&pdev->dev, "Failed to scan nand\n");
400 + goto err_gpio_free;
403 + if (pdata && pdata->ident_callback) {
404 + pdata->ident_callback(pdev, chip, &pdata->partitions,
405 + &pdata->num_partitions);
408 + ret = nand_scan_tail(mtd);
410 + dev_err(&pdev->dev, "Failed to scan nand\n");
411 + goto err_gpio_free;
414 +#ifdef CONFIG_MTD_PARTITIONS
415 +#ifdef CONFIG_MTD_CMDLINE_PARTS
416 + num_partitions = parse_mtd_partitions(mtd, part_probes,
417 + &partition_info, 0);
419 + if (num_partitions <= 0 && pdata) {
420 + num_partitions = pdata->num_partitions;
421 + partition_info = pdata->partitions;
424 + if (num_partitions > 0)
425 + ret = add_mtd_partitions(mtd, partition_info, num_partitions);
428 + ret = add_mtd_device(mtd);
431 + dev_err(&pdev->dev, "Failed to add mtd device\n");
432 + goto err_nand_release;
435 + dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
439 + nand_release(&nand->mtd);
441 + platform_set_drvdata(pdev, NULL);
442 + gpio_free(pdata->busy_gpio);
444 + iounmap(nand->base);
446 + release_mem_region(nand->mem->start, resource_size(nand->mem));
452 +static void __devexit jz_nand_remove(struct platform_device *pdev)
454 + struct jz_nand *nand = platform_get_drvdata(pdev);
456 + nand_release(&nand->mtd);
458 + iounmap(nand->base);
460 + release_mem_region(nand->mem->start, resource_size(nand->mem));
462 + platform_set_drvdata(pdev, NULL);
466 +struct platform_driver jz_nand_driver = {
467 + .probe = jz_nand_probe,
468 + .remove = __devexit_p(jz_nand_probe),
470 + .name = "jz4740-nand",
471 + .owner = THIS_MODULE,
475 +static int __init jz_nand_init(void)
477 + return platform_driver_register(&jz_nand_driver);
479 +module_init(jz_nand_init);
481 +static void __exit jz_nand_exit(void)
483 + platform_driver_unregister(&jz_nand_driver);
485 +module_exit(jz_nand_exit);
487 +MODULE_LICENSE("GPL");
488 +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
489 +MODULE_DESCRIPTION("NAND controller driver for JZ4720/JZ4740 SoC");
490 +MODULE_ALIAS("platform:jz4740-nand");
491 +MODULE_ALIAS("platform:jz4720-nand");
492 diff --git a/include/linux/mtd/jz4740_nand.h b/include/linux/mtd/jz4740_nand.h
494 index 0000000..8254e4c
496 +++ b/include/linux/mtd/jz4740_nand.h
499 + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
500 + * JZ4720/JZ4740 SoC NAND controller driver
502 + * This program is free software; you can redistribute it and/or modify it
503 + * under the terms of the GNU General Public License as published by the
504 + * Free Software Foundation; either version 2 of the License, or (at your
505 + * option) any later version.
507 + * You should have received a copy of the GNU General Public License along
508 + * with this program; if not, write to the Free Software Foundation, Inc.,
509 + * 675 Mass Ave, Cambridge, MA 02139, USA.
513 +#ifndef __JZ_NAND_H__
514 +#define __JZ_NAND_H__
516 +#include <linux/mtd/nand.h>
517 +#include <linux/mtd/partitions.h>
519 +struct jz_nand_platform_data {
520 + int num_partitions;
521 + struct mtd_partition *partitions;
523 + struct nand_ecclayout *ecc_layout;
525 + unsigned int busy_gpio;
527 + void (*ident_callback)(struct platform_device *, struct nand_chip *,
528 + struct mtd_partition **, int *num_partitions);
532 diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
533 index be51ae2..cf90168 100644
534 --- a/include/mtd/mtd-abi.h
535 +++ b/include/mtd/mtd-abi.h
536 @@ -134,7 +134,7 @@ struct nand_oobfree {
538 struct nand_ecclayout {
543 struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];