linux/ixp4xx: fix an embracing mistake on commit r23150 (thank you KanjiMonster)
[openwrt.git] / target / linux / xburst / patches-2.6.34 / 050-nand.patch
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
5
6 ---
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
15
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
22 on w90p910.
23
24 +config MTD_NAND_JZ4740
25 + tristate "Support NAND Flash device on Jz4740 board"
26 + depends on SOC_JZ4740
27 + help
28 + Support NAND Flash device on Jz4740 board
29 +
30 endif # MTD_NAND
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
40
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
43 new file mode 100644
44 index 0000000..7b3477d
45 --- /dev/null
46 +++ b/drivers/mtd/nand/jz4740_nand.c
47 @@ -0,0 +1,444 @@
48 +/*
49 + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
50 + * JZ4720/JZ4740 SoC NAND controller driver
51 + *
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.
56 + *
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.
60 + *
61 + */
62 +
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>
68 +
69 +#include <linux/mtd/mtd.h>
70 +#include <linux/mtd/nand.h>
71 +#include <linux/mtd/partitions.h>
72 +
73 +#include <linux/mtd/jz4740_nand.h>
74 +#include <linux/gpio.h>
75 +
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))
85 +
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)
91 +
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)
98 +
99 +#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT(x << 1)
100 +#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT((x << 1) + 1)
101 +
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)
105 +
106 +struct jz_nand {
107 + struct mtd_info mtd;
108 + struct nand_chip chip;
109 + void __iomem *base;
110 + struct resource *mem;
111 +
112 + struct jz_nand_platform_data *pdata;
113 + bool is_reading;
114 +};
115 +
116 +static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd)
117 +{
118 + return container_of(mtd, struct jz_nand, mtd);
119 +}
120 +
121 +static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
122 +{
123 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
124 + struct nand_chip *chip = mtd->priv;
125 + uint32_t reg;
126 +
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;
133 + else
134 + chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
135 +
136 + reg = readl(nand->base + JZ_REG_NAND_CTRL);
137 + if (ctrl & NAND_NCE)
138 + reg |= JZ_NAND_CTRL_ASSERT_CHIP(0);
139 + else
140 + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0);
141 + writel(reg, nand->base + JZ_REG_NAND_CTRL);
142 + }
143 + if (dat != NAND_CMD_NONE)
144 + writeb(dat, chip->IO_ADDR_W);
145 +}
146 +
147 +static int jz_nand_dev_ready(struct mtd_info *mtd)
148 +{
149 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
150 + return gpio_get_value_cansleep(nand->pdata->busy_gpio);
151 +}
152 +
153 +static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
154 +{
155 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
156 + uint32_t reg;
157 +
158 +
159 + writel(0, nand->base + JZ_REG_NAND_IRQ_STAT);
160 + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL);
161 +
162 + reg |= JZ_NAND_ECC_CTRL_RESET;
163 + reg |= JZ_NAND_ECC_CTRL_ENABLE;
164 + reg |= JZ_NAND_ECC_CTRL_RS;
165 +
166 + switch (mode) {
167 + case NAND_ECC_READ:
168 + reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
169 + nand->is_reading = true;
170 + break;
171 + case NAND_ECC_WRITE:
172 + reg |= JZ_NAND_ECC_CTRL_ENCODING;
173 + nand->is_reading = false;
174 + break;
175 + default:
176 + break;
177 + }
178 +
179 + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL);
180 +}
181 +
182 +
183 +static int jz_nand_calculate_ecc_rs(struct mtd_info* mtd, const uint8_t *dat,
184 + uint8_t *ecc_code)
185 +{
186 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
187 + uint32_t reg, status;
188 + int i;
189 + static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4,
190 + 0x8b, 0xff, 0xb7, 0x6f};
191 +
192 + if (nand->is_reading)
193 + return 0;
194 +
195 + do {
196 + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
197 + } while (!(status & JZ_NAND_STATUS_ENC_FINISH));
198 +
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);
202 +
203 + for (i = 0; i < 9; ++i)
204 + ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i);
205 +
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);
210 +
211 + return 0;
212 +}
213 +
214 +/*#define printkd printk*/
215 +#define printkd(...)
216 +
217 +static void correct_data(uint8_t *dat, int index, int mask)
218 +{
219 + int offset = index & 0x7;
220 + uint16_t data;
221 + printkd("correct: ");
222 +
223 + index += (index >> 3);
224 +
225 + data = dat[index];
226 + data |= dat[index+1] << 8;
227 +
228 + printkd("0x%x -> ", data);
229 +
230 + mask ^= (data >> offset) & 0x1ff;
231 + data &= ~(0x1ff << offset);
232 + data |= (mask << offset);
233 +
234 + printkd("0x%x\n", data);
235 +
236 + dat[index] = data & 0xff;
237 + dat[index+1] = (data >> 8) & 0xff;
238 +}
239 +
240 +static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
241 + uint8_t *read_ecc, uint8_t *calc_ecc)
242 +{
243 + struct jz_nand *nand = mtd_to_jz_nand(mtd);
244 + int i, error_count, index;
245 + uint32_t reg, status, error;
246 + uint32_t t;
247 +
248 + t = read_ecc[0];
249 +
250 + if (t == 0xff) {
251 + for (i = 1; i < 9; ++i)
252 + t &= read_ecc[i];
253 +
254 + t &= dat[0];
255 + t &= dat[nand->chip.ecc.size / 2];
256 + t &= dat[nand->chip.ecc.size - 1];
257 +
258 + if (t == 0xff) {
259 + for (i = 1; i < nand->chip.ecc.size - 1; ++i)
260 + t &= dat[i];
261 + if (t == 0xff)
262 + return 0;
263 + }
264 + }
265 +
266 + for (i = 0; i < 9; ++i)
267 + writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i);
268 +
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);
272 +
273 + do {
274 + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT);
275 + } while (!(status & JZ_NAND_STATUS_DEC_FINISH));
276 +
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);
280 +
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]);
286 + printkd("\n");
287 + printkd("uncorrectable data:");
288 + for (i = 0; i < 32; ++i)
289 + printkd(" 0x%x", dat[i]);
290 + printkd("\n");
291 + return -1;
292 + }
293 +
294 + error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
295 +
296 + printkd("error_count: %d %x\n", error_count, status);
297 +
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);
303 + }
304 +
305 + return error_count;
306 + }
307 +
308 + return 0;
309 +}
310 +
311 +
312 +
313 +#ifdef CONFIG_MTD_CMDLINE_PARTS
314 +static const char *part_probes[] = {"cmdline", NULL};
315 +#endif
316 +
317 +static int __devinit jz_nand_probe(struct platform_device *pdev)
318 +{
319 + int ret;
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;
327 +#endif
328 +
329 + nand = kzalloc(sizeof(*nand), GFP_KERNEL);
330 + if (!nand) {
331 + dev_err(&pdev->dev, "Failed to allocate device structure.\n");
332 + return -ENOMEM;
333 + }
334 +
335 + nand->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
336 + if (!nand->mem) {
337 + dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
338 + ret = -ENOENT;
339 + goto err_free;
340 + }
341 +
342 + nand->mem = request_mem_region(nand->mem->start,
343 + resource_size(nand->mem), pdev->name);
344 +
345 + if (!nand->mem) {
346 + dev_err(&pdev->dev, "Failed to request mmio memory region\n");
347 + ret = -EBUSY;
348 + goto err_free;
349 + }
350 +
351 + nand->base = ioremap(nand->mem->start, resource_size(nand->mem));
352 +
353 + if (!nand->base) {
354 + dev_err(&pdev->dev, "Failed to ioremap mmio memory region\n");
355 + ret = -EBUSY;
356 + goto err_release_mem;
357 + }
358 +
359 + if (pdata && gpio_is_valid(pdata->busy_gpio)) {
360 + ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
361 + if (ret) {
362 + dev_err(&pdev->dev,
363 + "Failed to request busy gpio %d: %d\n",
364 + pdata->busy_gpio, ret);
365 + goto err_iounmap;
366 + }
367 + }
368 +
369 + mtd = &nand->mtd;
370 + chip = &nand->chip;
371 + mtd->priv = chip;
372 + mtd->owner = THIS_MODULE;
373 + mtd->name = "jz4740-nand";
374 +
375 + chip->ecc.hwctl = jz_nand_hwctl;
376 +
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;
382 + if (pdata)
383 + chip->ecc.layout = pdata->ecc_layout;
384 +
385 + chip->chip_delay = 50;
386 + chip->cmd_ctrl = jz_nand_cmd_ctrl;
387 +
388 + if (pdata && gpio_is_valid(pdata->busy_gpio))
389 + chip->dev_ready = jz_nand_dev_ready;
390 +
391 + chip->IO_ADDR_R = JZ_NAND_DATA_ADDR;
392 + chip->IO_ADDR_W = JZ_NAND_DATA_ADDR;
393 +
394 + nand->pdata = pdata;
395 + platform_set_drvdata(pdev, nand);
396 +
397 + ret = nand_scan_ident(mtd, 1);
398 + if (ret) {
399 + dev_err(&pdev->dev, "Failed to scan nand\n");
400 + goto err_gpio_free;
401 + }
402 +
403 + if (pdata && pdata->ident_callback) {
404 + pdata->ident_callback(pdev, chip, &pdata->partitions,
405 + &pdata->num_partitions);
406 + }
407 +
408 + ret = nand_scan_tail(mtd);
409 + if (ret) {
410 + dev_err(&pdev->dev, "Failed to scan nand\n");
411 + goto err_gpio_free;
412 + }
413 +
414 +#ifdef CONFIG_MTD_PARTITIONS
415 +#ifdef CONFIG_MTD_CMDLINE_PARTS
416 + num_partitions = parse_mtd_partitions(mtd, part_probes,
417 + &partition_info, 0);
418 +#endif
419 + if (num_partitions <= 0 && pdata) {
420 + num_partitions = pdata->num_partitions;
421 + partition_info = pdata->partitions;
422 + }
423 +
424 + if (num_partitions > 0)
425 + ret = add_mtd_partitions(mtd, partition_info, num_partitions);
426 + else
427 +#endif
428 + ret = add_mtd_device(mtd);
429 +
430 + if (ret) {
431 + dev_err(&pdev->dev, "Failed to add mtd device\n");
432 + goto err_nand_release;
433 + }
434 +
435 + dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n");
436 +
437 + return 0;
438 +err_nand_release:
439 + nand_release(&nand->mtd);
440 +err_gpio_free:
441 + platform_set_drvdata(pdev, NULL);
442 + gpio_free(pdata->busy_gpio);
443 +err_iounmap:
444 + iounmap(nand->base);
445 +err_release_mem:
446 + release_mem_region(nand->mem->start, resource_size(nand->mem));
447 +err_free:
448 + kfree(nand);
449 + return ret;
450 +}
451 +
452 +static void __devexit jz_nand_remove(struct platform_device *pdev)
453 +{
454 + struct jz_nand *nand = platform_get_drvdata(pdev);
455 +
456 + nand_release(&nand->mtd);
457 +
458 + iounmap(nand->base);
459 +
460 + release_mem_region(nand->mem->start, resource_size(nand->mem));
461 +
462 + platform_set_drvdata(pdev, NULL);
463 + kfree(nand);
464 +}
465 +
466 +struct platform_driver jz_nand_driver = {
467 + .probe = jz_nand_probe,
468 + .remove = __devexit_p(jz_nand_probe),
469 + .driver = {
470 + .name = "jz4740-nand",
471 + .owner = THIS_MODULE,
472 + },
473 +};
474 +
475 +static int __init jz_nand_init(void)
476 +{
477 + return platform_driver_register(&jz_nand_driver);
478 +}
479 +module_init(jz_nand_init);
480 +
481 +static void __exit jz_nand_exit(void)
482 +{
483 + platform_driver_unregister(&jz_nand_driver);
484 +}
485 +module_exit(jz_nand_exit);
486 +
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
493 new file mode 100644
494 index 0000000..8254e4c
495 --- /dev/null
496 +++ b/include/linux/mtd/jz4740_nand.h
497 @@ -0,0 +1,34 @@
498 +/*
499 + * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
500 + * JZ4720/JZ4740 SoC NAND controller driver
501 + *
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.
506 + *
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.
510 + *
511 + */
512 +
513 +#ifndef __JZ_NAND_H__
514 +#define __JZ_NAND_H__
515 +
516 +#include <linux/mtd/nand.h>
517 +#include <linux/mtd/partitions.h>
518 +
519 +struct jz_nand_platform_data {
520 + int num_partitions;
521 + struct mtd_partition *partitions;
522 +
523 + struct nand_ecclayout *ecc_layout;
524 +
525 + unsigned int busy_gpio;
526 +
527 + void (*ident_callback)(struct platform_device *, struct nand_chip *,
528 + struct mtd_partition **, int *num_partitions);
529 +};
530 +
531 +#endif
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 {
537 */
538 struct nand_ecclayout {
539 __u32 eccbytes;
540 - __u32 eccpos[64];
541 + __u32 eccpos[72];
542 __u32 oobavail;
543 struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
544 };
545 --
546 1.5.6.5
547
This page took 0.090352 seconds and 5 git commands to generate.