aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-19 16:34:11 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-19 16:34:11 -0500
commit4935361766cc73949fe032cd157d314f288922ba (patch)
tree1584f81525ae05a04d515b13a4787cd8eed46029 /drivers/mtd/nand
parent2874b391bd78a5b8cb84be67297a345fbdec4ac8 (diff)
parent4f65992381112acd7d2732665a9eae492c2c9de6 (diff)
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (49 commits) [MTD] [NAND] S3C2412 fix hw ecc [MTD] [NAND] Work around false compiler warning in CAFÉ driver [JFFS2] printk warning fixes [MTD] [MAPS] ichxrom warning fix [MTD] [MAPS] amd76xrom warning fix [MTD] [MAPS] esb2rom warning fixes [MTD] [MAPS] ck804xrom warning fix [MTD] [MAPS] netsc520 warning fix [MTD] [MAPS] sc520cdp warning fix [MTD] [ONENAND] onenand_base warning fix [MTD] [NAND] eXcite nand flash driver [MTD] Improve heuristic for detecting wrong-endian RedBoot partition table [MTD] Fix RedBoot partition parsing regression harder. [MTD] [NAND] S3C2410: Hardware ECC correction code [JFFS2] Use MTD_OOB_AUTO to automatically place cleanmarker on NAND [MTD] Clarify OOB-operation interface comments [MTD] remove unused ecctype,eccsize fields from struct mtd_info [MTD] [NOR] Intel: remove ugly PROGREGION macros [MTD] [NOR] STAA: use writesize instead off eccsize to represent ECC block [MTD] OneNAND: Invalidate bufferRAM after erase ...
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/Kconfig14
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/cafe.c89
-rw-r--r--drivers/mtd/nand/cafe_ecc.c2
-rw-r--r--drivers/mtd/nand/excite_nandflash.c248
-rw-r--r--drivers/mtd/nand/nand_base.c47
-rw-r--r--drivers/mtd/nand/s3c2410.c96
7 files changed, 424 insertions, 73 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 358f55a82dbe..2d12dcdd740c 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -126,10 +126,6 @@ config MTD_NAND_S3C2410_HWECC
126 incorrect ECC generation, and if using these, the default of 126 incorrect ECC generation, and if using these, the default of
127 software ECC is preferable. 127 software ECC is preferable.
128 128
129 If you lay down a device with the hardware ECC, then you will
130 currently not be able to switch to software, as there is no
131 implementation for ECC method used by the S3C2410
132
133config MTD_NAND_NDFC 129config MTD_NAND_NDFC
134 tristate "NDFC NanD Flash Controller" 130 tristate "NDFC NanD Flash Controller"
135 depends on MTD_NAND && 44x 131 depends on MTD_NAND && 44x
@@ -221,9 +217,17 @@ config MTD_NAND_SHARPSL
221 tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" 217 tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
222 depends on MTD_NAND && ARCH_PXA 218 depends on MTD_NAND && ARCH_PXA
223 219
220config MTD_NAND_BASLER_EXCITE
221 tristate "Support for NAND Flash on Basler eXcite"
222 depends on MTD_NAND && BASLER_EXCITE
223 help
224 This enables the driver for the NAND flash device found on the
225 Basler eXcite Smart Camera. If built as a module, the driver
226 will be named "excite_nandflash.ko".
227
224config MTD_NAND_CAFE 228config MTD_NAND_CAFE
225 tristate "NAND support for OLPC CAFÉ chip" 229 tristate "NAND support for OLPC CAFÉ chip"
226 depends on PCI 230 depends on MTD_NAND && PCI
227 help 231 help
228 Use NAND flash attached to the CAFÉ chip designed for the $100 232 Use NAND flash attached to the CAFÉ chip designed for the $100
229 laptop. 233 laptop.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f7a53f0b7017..80f1dfc77949 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
24obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o 24obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
25obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o 25obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
26obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o 26obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
27obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
27 28
28nand-objs := nand_base.o nand_bbt.o 29nand-objs := nand_base.o nand_bbt.o
29cafe_nand-objs := cafe.o cafe_ecc.o 30cafe_nand-objs := cafe.o cafe_ecc.o
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c
index 08cb060dfa3d..fd6bb3ed40df 100644
--- a/drivers/mtd/nand/cafe.c
+++ b/drivers/mtd/nand/cafe.c
@@ -78,8 +78,9 @@ module_param(regdebug, int, 0644);
78static int checkecc = 1; 78static int checkecc = 1;
79module_param(checkecc, int, 0644); 79module_param(checkecc, int, 0644);
80 80
81static int slowtiming = 0; 81static int numtimings;
82module_param(slowtiming, int, 0644); 82static int timing[3];
83module_param_array(timing, int, &numtimings, 0644);
83 84
84/* Hrm. Why isn't this already conditional on something in the struct device? */ 85/* Hrm. Why isn't this already conditional on something in the struct device? */
85#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0) 86#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
@@ -264,10 +265,10 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
264 ndelay(100); 265 ndelay(100);
265 266
266 if (1) { 267 if (1) {
267 int c = 500000; 268 int c;
268 uint32_t irqs; 269 uint32_t irqs;
269 270
270 while (c--) { 271 for (c = 500000; c != 0; c--) {
271 irqs = cafe_readl(cafe, NAND_IRQ); 272 irqs = cafe_readl(cafe, NAND_IRQ);
272 if (irqs & doneint) 273 if (irqs & doneint)
273 break; 274 break;
@@ -529,6 +530,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
529{ 530{
530 struct mtd_info *mtd; 531 struct mtd_info *mtd;
531 struct cafe_priv *cafe; 532 struct cafe_priv *cafe;
533 uint32_t timing1, timing2, timing3;
532 uint32_t ctrl; 534 uint32_t ctrl;
533 int err = 0; 535 int err = 0;
534 536
@@ -580,31 +582,45 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
580 cafe->nand.block_bad = cafe_nand_block_bad; 582 cafe->nand.block_bad = cafe_nand_block_bad;
581 } 583 }
582 584
585 if (numtimings && numtimings != 3) {
586 dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
587 }
588
589 if (numtimings == 3) {
590 timing1 = timing[0];
591 timing2 = timing[1];
592 timing3 = timing[2];
593 cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
594 timing1, timing2, timing3);
595 } else {
596 timing1 = cafe_readl(cafe, NAND_TIMING1);
597 timing2 = cafe_readl(cafe, NAND_TIMING2);
598 timing3 = cafe_readl(cafe, NAND_TIMING3);
599
600 if (timing1 | timing2 | timing3) {
601 cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3);
602 } else {
603 dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
604 timing1 = timing2 = timing3 = 0xffffffff;
605 }
606 }
607
583 /* Start off by resetting the NAND controller completely */ 608 /* Start off by resetting the NAND controller completely */
584 cafe_writel(cafe, 1, NAND_RESET); 609 cafe_writel(cafe, 1, NAND_RESET);
585 cafe_writel(cafe, 0, NAND_RESET); 610 cafe_writel(cafe, 0, NAND_RESET);
586 611
587 cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); 612 cafe_writel(cafe, timing1, NAND_TIMING1);
613 cafe_writel(cafe, timing2, NAND_TIMING2);
614 cafe_writel(cafe, timing3, NAND_TIMING3);
588 615
589 /* Timings from Marvell's test code (not verified or calculated by us) */
590 if (!slowtiming) {
591 cafe_writel(cafe, 0x01010a0a, NAND_TIMING1);
592 cafe_writel(cafe, 0x24121212, NAND_TIMING2);
593 cafe_writel(cafe, 0x11000000, NAND_TIMING3);
594 } else {
595 cafe_writel(cafe, 0xffffffff, NAND_TIMING1);
596 cafe_writel(cafe, 0xffffffff, NAND_TIMING2);
597 cafe_writel(cafe, 0xffffffff, NAND_TIMING3);
598 }
599 cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); 616 cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
600 err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED, 617 err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
601 "CAFE NAND", mtd); 618 "CAFE NAND", mtd);
602 if (err) { 619 if (err) {
603 dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq); 620 dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
604
605 goto out_free_dma; 621 goto out_free_dma;
606 } 622 }
607#if 1 623
608 /* Disable master reset, enable NAND clock */ 624 /* Disable master reset, enable NAND clock */
609 ctrl = cafe_readl(cafe, GLOBAL_CTRL); 625 ctrl = cafe_readl(cafe, GLOBAL_CTRL);
610 ctrl &= 0xffffeff0; 626 ctrl &= 0xffffeff0;
@@ -631,32 +647,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
631 cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK); 647 cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
632 cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n", 648 cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
633 cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK)); 649 cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
634#endif 650
635#if 1 651 /* Scan to find existence of the device */
636 mtd->writesize=2048;
637 mtd->oobsize = 0x40;
638 memset(cafe->dmabuf, 0x5a, 2112);
639 cafe->nand.cmdfunc(mtd, NAND_CMD_READID, 0, -1);
640 cafe->nand.read_byte(mtd);
641 cafe->nand.read_byte(mtd);
642 cafe->nand.read_byte(mtd);
643 cafe->nand.read_byte(mtd);
644 cafe->nand.read_byte(mtd);
645#endif
646#if 0
647 cafe->nand.cmdfunc(mtd, NAND_CMD_READ0, 0, 0);
648 // nand_wait_ready(mtd);
649 cafe->nand.read_byte(mtd);
650 cafe->nand.read_byte(mtd);
651 cafe->nand.read_byte(mtd);
652 cafe->nand.read_byte(mtd);
653#endif
654#if 0
655 writel(0x84600070, cafe->mmio);
656 udelay(10);
657 cafe_dev_dbg(&cafe->pdev->dev, "Status %x\n", cafe_readl(cafe, NAND_NONMEM));
658#endif
659 /* Scan to find existance of the device */
660 if (nand_scan_ident(mtd, 1)) { 652 if (nand_scan_ident(mtd, 1)) {
661 err = -ENXIO; 653 err = -ENXIO;
662 goto out_irq; 654 goto out_irq;
@@ -760,13 +752,4 @@ module_exit(cafe_nand_exit);
760 752
761MODULE_LICENSE("GPL"); 753MODULE_LICENSE("GPL");
762MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 754MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
763MODULE_DESCRIPTION("NAND flash driver for OLPC CAFE chip"); 755MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
764
765/* Correct ECC for 2048 bytes of 0xff:
766 41 a0 71 65 54 27 f3 93 ec a9 be ed 0b a1 */
767
768/* dwmw2's B-test board, in case of completely screwing it:
769Bad eraseblock 2394 at 0x12b40000
770Bad eraseblock 2627 at 0x14860000
771Bad eraseblock 3349 at 0x1a2a0000
772*/
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
index 1b9fa05a4474..ea5c8491d2c5 100644
--- a/drivers/mtd/nand/cafe_ecc.c
+++ b/drivers/mtd/nand/cafe_ecc.c
@@ -1045,7 +1045,7 @@ static unsigned short err_pos_lut[4096] = {
1045 1045
1046static unsigned short err_pos(unsigned short din) 1046static unsigned short err_pos(unsigned short din)
1047{ 1047{
1048 BUG_ON(din > 4096); 1048 BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
1049 return err_pos_lut[din]; 1049 return err_pos_lut[din];
1050} 1050}
1051static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info) 1051static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c
new file mode 100644
index 000000000000..7e9afc4c7757
--- /dev/null
+++ b/drivers/mtd/nand/excite_nandflash.c
@@ -0,0 +1,248 @@
1/*
2* Copyright (C) 2005 - 2007 by Basler Vision Technologies AG
3* Author: Thomas Koeller <thomas.koeller.qbaslerweb.com>
4* Original code by Thies Moeller <thies.moeller@baslerweb.com>
5*
6* This program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2 of the License, or
9* (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program; if not, write to the Free Software
18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/string.h>
26#include <linux/ioport.h>
27#include <linux/platform_device.h>
28#include <linux/delay.h>
29#include <linux/err.h>
30#include <linux/kernel.h>
31
32#include <linux/mtd/mtd.h>
33#include <linux/mtd/nand.h>
34#include <linux/mtd/nand_ecc.h>
35#include <linux/mtd/partitions.h>
36
37#include <asm/io.h>
38#include <asm/rm9k-ocd.h>
39
40#include <excite_nandflash.h>
41
42#define EXCITE_NANDFLASH_VERSION "0.1"
43
44/* I/O register offsets */
45#define EXCITE_NANDFLASH_DATA_BYTE 0x00
46#define EXCITE_NANDFLASH_STATUS_BYTE 0x0c
47#define EXCITE_NANDFLASH_ADDR_BYTE 0x10
48#define EXCITE_NANDFLASH_CMD_BYTE 0x14
49
50/* prefix for debug output */
51static const char module_id[] = "excite_nandflash";
52
53/*
54 * partition definition
55 */
56static const struct mtd_partition partition_info[] = {
57 {
58 .name = "eXcite RootFS",
59 .offset = 0,
60 .size = MTDPART_SIZ_FULL
61 }
62};
63
64static inline const struct resource *
65excite_nand_get_resource(struct platform_device *d, unsigned long flags,
66 const char *basename)
67{
68 char buf[80];
69
70 if (snprintf(buf, sizeof buf, "%s_%u", basename, d->id) >= sizeof buf)
71 return NULL;
72 return platform_get_resource_byname(d, flags, buf);
73}
74
75static inline void __iomem *
76excite_nand_map_regs(struct platform_device *d, const char *basename)
77{
78 void *result = NULL;
79 const struct resource *const r =
80 excite_nand_get_resource(d, IORESOURCE_MEM, basename);
81
82 if (r)
83 result = ioremap_nocache(r->start, r->end + 1 - r->start);
84 return result;
85}
86
87/* controller and mtd information */
88struct excite_nand_drvdata {
89 struct mtd_info board_mtd;
90 struct nand_chip board_chip;
91 void __iomem *regs;
92 void __iomem *tgt;
93};
94
95/* Control function */
96static void excite_nand_control(struct mtd_info *mtd, int cmd,
97 unsigned int ctrl)
98{
99 struct excite_nand_drvdata * const d =
100 container_of(mtd, struct excite_nand_drvdata, board_mtd);
101
102 switch (ctrl) {
103 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
104 d->tgt = d->regs + EXCITE_NANDFLASH_CMD_BYTE;
105 break;
106 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
107 d->tgt = d->regs + EXCITE_NANDFLASH_ADDR_BYTE;
108 break;
109 case NAND_CTRL_CHANGE | NAND_NCE:
110 d->tgt = d->regs + EXCITE_NANDFLASH_DATA_BYTE;
111 break;
112 }
113
114 if (cmd != NAND_CMD_NONE)
115 __raw_writeb(cmd, d->tgt);
116}
117
118/* Return 0 if flash is busy, 1 if ready */
119static int excite_nand_devready(struct mtd_info *mtd)
120{
121 struct excite_nand_drvdata * const drvdata =
122 container_of(mtd, struct excite_nand_drvdata, board_mtd);
123
124 return __raw_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS_BYTE);
125}
126
127/*
128 * Called by device layer to remove the driver.
129 * The binding to the mtd and all allocated
130 * resources are released.
131 */
132static int __exit excite_nand_remove(struct device *dev)
133{
134 struct excite_nand_drvdata * const this = dev_get_drvdata(dev);
135
136 dev_set_drvdata(dev, NULL);
137
138 if (unlikely(!this)) {
139 printk(KERN_ERR "%s: called %s without private data!!",
140 module_id, __func__);
141 return -EINVAL;
142 }
143
144 /* first thing we need to do is release our mtd
145 * then go through freeing the resource used
146 */
147 nand_release(&this->board_mtd);
148
149 /* free the common resources */
150 iounmap(this->regs);
151 kfree(this);
152
153 DEBUG(MTD_DEBUG_LEVEL1, "%s: removed\n", module_id);
154 return 0;
155}
156
157/*
158 * Called by device layer when it finds a device matching
159 * one our driver can handle. This code checks to see if
160 * it can allocate all necessary resources then calls the
161 * nand layer to look for devices.
162*/
163static int __init excite_nand_probe(struct device *dev)
164{
165 struct platform_device * const pdev = to_platform_device(dev);
166 struct excite_nand_drvdata *drvdata; /* private driver data */
167 struct nand_chip *board_chip; /* private flash chip data */
168 struct mtd_info *board_mtd; /* mtd info for this board */
169 int scan_res;
170
171 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
172 if (unlikely(!drvdata)) {
173 printk(KERN_ERR "%s: no memory for drvdata\n",
174 module_id);
175 return -ENOMEM;
176 }
177
178 /* bind private data into driver */
179 dev_set_drvdata(dev, drvdata);
180
181 /* allocate and map the resource */
182 drvdata->regs =
183 excite_nand_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS);
184
185 if (unlikely(!drvdata->regs)) {
186 printk(KERN_ERR "%s: cannot reserve register region\n",
187 module_id);
188 kfree(drvdata);
189 return -ENXIO;
190 }
191
192 drvdata->tgt = drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
193
194 /* initialise our chip */
195 board_chip = &drvdata->board_chip;
196 board_chip->IO_ADDR_R = board_chip->IO_ADDR_W =
197 drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
198 board_chip->cmd_ctrl = excite_nand_control;
199 board_chip->dev_ready = excite_nand_devready;
200 board_chip->chip_delay = 25;
201 board_chip->ecc.mode = NAND_ECC_SOFT;
202
203 /* link chip to mtd */
204 board_mtd = &drvdata->board_mtd;
205 board_mtd->priv = board_chip;
206
207 DEBUG(MTD_DEBUG_LEVEL2, "%s: device scan\n", module_id);
208 scan_res = nand_scan(&drvdata->board_mtd, 1);
209
210 if (likely(!scan_res)) {
211 DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id);
212 add_mtd_partitions(&drvdata->board_mtd, partition_info,
213 sizeof partition_info / sizeof partition_info[0]);
214 } else {
215 iounmap(drvdata->regs);
216 kfree(drvdata);
217 printk(KERN_ERR "%s: device scan failed\n", module_id);
218 return -EIO;
219 }
220 return 0;
221}
222
223static struct device_driver excite_nand_driver = {
224 .name = "excite_nand",
225 .bus = &platform_bus_type,
226 .probe = excite_nand_probe,
227 .remove = __exit_p(excite_nand_remove)
228};
229
230static int __init excite_nand_init(void)
231{
232 pr_info("Basler eXcite nand flash driver Version "
233 EXCITE_NANDFLASH_VERSION "\n");
234 return driver_register(&excite_nand_driver);
235}
236
237static void __exit excite_nand_exit(void)
238{
239 driver_unregister(&excite_nand_driver);
240}
241
242module_init(excite_nand_init);
243module_exit(excite_nand_exit);
244
245MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
246MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver");
247MODULE_LICENSE("GPL");
248MODULE_VERSION(EXCITE_NANDFLASH_VERSION)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index dfe56e03e48b..acaf97bc80d1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1272,10 +1272,25 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1272 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", 1272 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
1273 (unsigned long long)from, readlen); 1273 (unsigned long long)from, readlen);
1274 1274
1275 if (ops->mode == MTD_OOB_RAW) 1275 if (ops->mode == MTD_OOB_AUTO)
1276 len = mtd->oobsize;
1277 else
1278 len = chip->ecc.layout->oobavail; 1276 len = chip->ecc.layout->oobavail;
1277 else
1278 len = mtd->oobsize;
1279
1280 if (unlikely(ops->ooboffs >= len)) {
1281 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1282 "Attempt to start read outside oob\n");
1283 return -EINVAL;
1284 }
1285
1286 /* Do not allow reads past end of device */
1287 if (unlikely(from >= mtd->size ||
1288 ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
1289 (from >> chip->page_shift)) * len)) {
1290 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1291 "Attempt read beyond end of device\n");
1292 return -EINVAL;
1293 }
1279 1294
1280 chipnr = (int)(from >> chip->chip_shift); 1295 chipnr = (int)(from >> chip->chip_shift);
1281 chip->select_chip(mtd, chipnr); 1296 chip->select_chip(mtd, chipnr);
@@ -1742,19 +1757,40 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1742static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, 1757static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1743 struct mtd_oob_ops *ops) 1758 struct mtd_oob_ops *ops)
1744{ 1759{
1745 int chipnr, page, status; 1760 int chipnr, page, status, len;
1746 struct nand_chip *chip = mtd->priv; 1761 struct nand_chip *chip = mtd->priv;
1747 1762
1748 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", 1763 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
1749 (unsigned int)to, (int)ops->ooblen); 1764 (unsigned int)to, (int)ops->ooblen);
1750 1765
1766 if (ops->mode == MTD_OOB_AUTO)
1767 len = chip->ecc.layout->oobavail;
1768 else
1769 len = mtd->oobsize;
1770
1751 /* Do not allow write past end of page */ 1771 /* Do not allow write past end of page */
1752 if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) { 1772 if ((ops->ooboffs + ops->ooblen) > len) {
1753 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " 1773 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1754 "Attempt to write past end of page\n"); 1774 "Attempt to write past end of page\n");
1755 return -EINVAL; 1775 return -EINVAL;
1756 } 1776 }
1757 1777
1778 if (unlikely(ops->ooboffs >= len)) {
1779 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1780 "Attempt to start write outside oob\n");
1781 return -EINVAL;
1782 }
1783
1784 /* Do not allow reads past end of device */
1785 if (unlikely(to >= mtd->size ||
1786 ops->ooboffs + ops->ooblen >
1787 ((mtd->size >> chip->page_shift) -
1788 (to >> chip->page_shift)) * len)) {
1789 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1790 "Attempt write beyond end of device\n");
1791 return -EINVAL;
1792 }
1793
1758 chipnr = (int)(to >> chip->chip_shift); 1794 chipnr = (int)(to >> chip->chip_shift);
1759 chip->select_chip(mtd, chipnr); 1795 chip->select_chip(mtd, chipnr);
1760 1796
@@ -2530,7 +2566,6 @@ int nand_scan_tail(struct mtd_info *mtd)
2530 /* Fill in remaining MTD driver data */ 2566 /* Fill in remaining MTD driver data */
2531 mtd->type = MTD_NANDFLASH; 2567 mtd->type = MTD_NANDFLASH;
2532 mtd->flags = MTD_CAP_NANDFLASH; 2568 mtd->flags = MTD_CAP_NANDFLASH;
2533 mtd->ecctype = MTD_ECC_SW;
2534 mtd->erase = nand_erase; 2569 mtd->erase = nand_erase;
2535 mtd->point = NULL; 2570 mtd->point = NULL;
2536 mtd->unpoint = NULL; 2571 mtd->unpoint = NULL;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 8b3203571eeb..0ddfd6de75c5 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -337,17 +337,69 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
337static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, 337static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
338 u_char *read_ecc, u_char *calc_ecc) 338 u_char *read_ecc, u_char *calc_ecc)
339{ 339{
340 pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc); 340 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
341 unsigned int diff0, diff1, diff2;
342 unsigned int bit, byte;
341 343
342 pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n", 344 pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
343 read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2]);
344 345
345 if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2]) 346 diff0 = read_ecc[0] ^ calc_ecc[0];
346 return 0; 347 diff1 = read_ecc[1] ^ calc_ecc[1];
348 diff2 = read_ecc[2] ^ calc_ecc[2];
349
350 pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n",
351 __func__,
352 read_ecc[0], read_ecc[1], read_ecc[2],
353 calc_ecc[0], calc_ecc[1], calc_ecc[2],
354 diff0, diff1, diff2);
355
356 if (diff0 == 0 && diff1 == 0 && diff2 == 0)
357 return 0; /* ECC is ok */
358
359 /* Can we correct this ECC (ie, one row and column change).
360 * Note, this is similar to the 256 error code on smartmedia */
361
362 if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
363 ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
364 ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
365 /* calculate the bit position of the error */
366
367 bit = (diff2 >> 2) & 1;
368 bit |= (diff2 >> 3) & 2;
369 bit |= (diff2 >> 4) & 4;
370
371 /* calculate the byte position of the error */
372
373 byte = (diff1 << 1) & 0x80;
374 byte |= (diff1 << 2) & 0x40;
375 byte |= (diff1 << 3) & 0x20;
376 byte |= (diff1 << 4) & 0x10;
377
378 byte |= (diff0 >> 3) & 0x08;
379 byte |= (diff0 >> 2) & 0x04;
380 byte |= (diff0 >> 1) & 0x02;
381 byte |= (diff0 >> 0) & 0x01;
347 382
348 /* we curently have no method for correcting the error */ 383 byte |= (diff2 << 8) & 0x100;
349 384
350 return -1; 385 dev_dbg(info->device, "correcting error bit %d, byte %d\n",
386 bit, byte);
387
388 dat[byte] ^= (1 << bit);
389 return 1;
390 }
391
392 /* if there is only one bit difference in the ECC, then
393 * one of only a row or column parity has changed, which
394 * means the error is most probably in the ECC itself */
395
396 diff0 |= (diff1 << 8);
397 diff0 |= (diff2 << 16);
398
399 if ((diff0 & ~(1<<fls(diff0))) == 0)
400 return 1;
401
402 return 0;
351} 403}
352 404
353/* ECC functions 405/* ECC functions
@@ -366,6 +418,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
366 writel(ctrl, info->regs + S3C2410_NFCONF); 418 writel(ctrl, info->regs + S3C2410_NFCONF);
367} 419}
368 420
421static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
422{
423 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
424 unsigned long ctrl;
425
426 ctrl = readl(info->regs + S3C2440_NFCONT);
427 writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT);
428}
429
369static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) 430static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
370{ 431{
371 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); 432 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -383,6 +444,21 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
383 ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1); 444 ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
384 ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2); 445 ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
385 446
447 pr_debug("%s: returning ecc %02x%02x%02x\n", __func__,
448 ecc_code[0], ecc_code[1], ecc_code[2]);
449
450 return 0;
451}
452
453static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
454{
455 struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
456 unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
457
458 ecc_code[0] = ecc;
459 ecc_code[1] = ecc >> 8;
460 ecc_code[2] = ecc >> 16;
461
386 pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); 462 pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
387 463
388 return 0; 464 return 0;
@@ -397,7 +473,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
397 ecc_code[1] = ecc >> 8; 473 ecc_code[1] = ecc >> 8;
398 ecc_code[2] = ecc >> 16; 474 ecc_code[2] = ecc >> 16;
399 475
400 pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); 476 pr_debug("%s: returning ecc %06x\n", __func__, ecc);
401 477
402 return 0; 478 return 0;
403} 479}
@@ -565,6 +641,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
565 break; 641 break;
566 642
567 case TYPE_S3C2412: 643 case TYPE_S3C2412:
644 chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
645 chip->ecc.calculate = s3c2412_nand_calculate_ecc;
646 break;
647
568 case TYPE_S3C2440: 648 case TYPE_S3C2440:
569 chip->ecc.hwctl = s3c2440_nand_enable_hwecc; 649 chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
570 chip->ecc.calculate = s3c2440_nand_calculate_ecc; 650 chip->ecc.calculate = s3c2440_nand_calculate_ecc;