diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 12:03:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 12:03:12 -0400 |
commit | 2be508d847392e431759e370d21cea9412848758 (patch) | |
tree | be5e00a4d7be4ef353ffe4d550fb80a251d321c3 /drivers/mtd/nand | |
parent | 01e8ef11bc1a74e65678ed55795f59266d4add01 (diff) | |
parent | 8a1a6272057e2ad90ab531a70330165888866e60 (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (69 commits)
Revert "[MTD] m25p80.c code cleanup"
[MTD] [NAND] GPIO driver depends on ARM... for now.
[MTD] [NAND] sh_flctl: fix compile error
[MTD] [NOR] AT49BV6416 has swapped erase regions
[MTD] [NAND] GPIO NAND flash driver
[MTD] cmdlineparts documentation change - explain where mtd-id comes from
[MTD] cfi_cmdset_0002.c: Add Macronix CFI V1.0 TopBottom detection
[MTD] [NAND] Fix compilation warnings in drivers/mtd/nand/cs553x_nand.c
[JFFS2] Write buffer offset adjustment for NOR-ECC (Sibley) flash
[MTD] mtdoops: Fix a bug where block may not be erased
[MTD] mtdoops: Add a magic number to logged kernel oops
[MTD] mtdoops: Fix an off by one error
[JFFS2] Correct parameter names of jffs2_compress() in comments
[MTD] [NAND] sh_flctl: add support for Renesas SuperH FLCTL
[MTD] [NAND] Bug on atmel_nand HW ECC : OOB info not correctly written
[MTD] [MAPS] Remove unused variable after ROM API cleanup.
[MTD] m25p80.c extended jedec support (v2)
[MTD] remove unused mtd parameter in of_mtd_parse_partitions()
[MTD] [NAND] remove dead Kconfig associated with !CONFIG_PPC_MERGE
[MTD] [NAND] driver extension to support NAND on TQM85xx modules
...
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 42 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 58 | ||||
-rw-r--r-- | drivers/mtd/nand/cs553x_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_upm.c | 68 | ||||
-rw-r--r-- | drivers/mtd/nand/gpio.c | 375 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 1077 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 16 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ecc.c | 554 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 147 | ||||
-rw-r--r-- | drivers/mtd/nand/sh_flctl.c | 878 | ||||
-rw-r--r-- | drivers/mtd/nand/toto.c | 206 |
14 files changed, 2932 insertions, 499 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 41f361c49b32..1c2e9450d663 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -56,6 +56,12 @@ config MTD_NAND_H1900 | |||
56 | help | 56 | help |
57 | This enables the driver for the iPAQ h1900 flash. | 57 | This enables the driver for the iPAQ h1900 flash. |
58 | 58 | ||
59 | config MTD_NAND_GPIO | ||
60 | tristate "GPIO NAND Flash driver" | ||
61 | depends on GENERIC_GPIO && ARM | ||
62 | help | ||
63 | This enables a GPIO based NAND flash driver. | ||
64 | |||
59 | config MTD_NAND_SPIA | 65 | config MTD_NAND_SPIA |
60 | tristate "NAND Flash device on SPIA board" | 66 | tristate "NAND Flash device on SPIA board" |
61 | depends on ARCH_P720T | 67 | depends on ARCH_P720T |
@@ -68,12 +74,6 @@ config MTD_NAND_AMS_DELTA | |||
68 | help | 74 | help |
69 | Support for NAND flash on Amstrad E3 (Delta). | 75 | Support for NAND flash on Amstrad E3 (Delta). |
70 | 76 | ||
71 | config MTD_NAND_TOTO | ||
72 | tristate "NAND Flash device on TOTO board" | ||
73 | depends on ARCH_OMAP && BROKEN | ||
74 | help | ||
75 | Support for NAND flash on Texas Instruments Toto platform. | ||
76 | |||
77 | config MTD_NAND_TS7250 | 77 | config MTD_NAND_TS7250 |
78 | tristate "NAND Flash device on TS-7250 board" | 78 | tristate "NAND Flash device on TS-7250 board" |
79 | depends on MACH_TS72XX | 79 | depends on MACH_TS72XX |
@@ -163,13 +163,6 @@ config MTD_NAND_S3C2410_HWECC | |||
163 | incorrect ECC generation, and if using these, the default of | 163 | incorrect ECC generation, and if using these, the default of |
164 | software ECC is preferable. | 164 | software ECC is preferable. |
165 | 165 | ||
166 | config MTD_NAND_NDFC | ||
167 | tristate "NDFC NanD Flash Controller" | ||
168 | depends on 4xx && !PPC_MERGE | ||
169 | select MTD_NAND_ECC_SMC | ||
170 | help | ||
171 | NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs | ||
172 | |||
173 | config MTD_NAND_S3C2410_CLKSTOP | 166 | config MTD_NAND_S3C2410_CLKSTOP |
174 | bool "S3C2410 NAND IDLE clock stop" | 167 | bool "S3C2410 NAND IDLE clock stop" |
175 | depends on MTD_NAND_S3C2410 | 168 | depends on MTD_NAND_S3C2410 |
@@ -340,6 +333,13 @@ config MTD_NAND_PXA3xx | |||
340 | This enables the driver for the NAND flash device found on | 333 | This enables the driver for the NAND flash device found on |
341 | PXA3xx processors | 334 | PXA3xx processors |
342 | 335 | ||
336 | config MTD_NAND_PXA3xx_BUILTIN | ||
337 | bool "Use builtin definitions for some NAND chips (deprecated)" | ||
338 | depends on MTD_NAND_PXA3xx | ||
339 | help | ||
340 | This enables builtin definitions for some NAND chips. This | ||
341 | is deprecated in favor of platform specific data. | ||
342 | |||
343 | config MTD_NAND_CM_X270 | 343 | config MTD_NAND_CM_X270 |
344 | tristate "Support for NAND Flash on CM-X270 modules" | 344 | tristate "Support for NAND Flash on CM-X270 modules" |
345 | depends on MTD_NAND && MACH_ARMCORE | 345 | depends on MTD_NAND && MACH_ARMCORE |
@@ -400,10 +400,24 @@ config MTD_NAND_FSL_ELBC | |||
400 | 400 | ||
401 | config MTD_NAND_FSL_UPM | 401 | config MTD_NAND_FSL_UPM |
402 | tristate "Support for NAND on Freescale UPM" | 402 | tristate "Support for NAND on Freescale UPM" |
403 | depends on MTD_NAND && OF_GPIO && (PPC_83xx || PPC_85xx) | 403 | depends on MTD_NAND && (PPC_83xx || PPC_85xx) |
404 | select FSL_LBC | 404 | select FSL_LBC |
405 | help | 405 | help |
406 | Enables support for NAND Flash chips wired onto Freescale PowerPC | 406 | Enables support for NAND Flash chips wired onto Freescale PowerPC |
407 | processor localbus with User-Programmable Machine support. | 407 | processor localbus with User-Programmable Machine support. |
408 | 408 | ||
409 | config MTD_NAND_MXC | ||
410 | tristate "MXC NAND support" | ||
411 | depends on ARCH_MX2 | ||
412 | help | ||
413 | This enables the driver for the NAND flash controller on the | ||
414 | MXC processors. | ||
415 | |||
416 | config MTD_NAND_SH_FLCTL | ||
417 | tristate "Support for NAND on Renesas SuperH FLCTL" | ||
418 | depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 | ||
419 | help | ||
420 | Several Renesas SuperH CPU has FLCTL. This option enables support | ||
421 | for NAND Flash using FLCTL. This driver support SH7723. | ||
422 | |||
409 | endif # MTD_NAND | 423 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b786c5da82da..b661586afbfc 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -8,7 +8,6 @@ obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o | |||
8 | obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o | 8 | obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o |
9 | obj-$(CONFIG_MTD_NAND_SPIA) += spia.o | 9 | obj-$(CONFIG_MTD_NAND_SPIA) += spia.o |
10 | obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o | 10 | obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o |
11 | obj-$(CONFIG_MTD_NAND_TOTO) += toto.o | ||
12 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o | 11 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o |
13 | obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o | 12 | obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o |
14 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o | 13 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o |
@@ -24,6 +23,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o | |||
24 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o | 23 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o |
25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o | 24 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o |
26 | obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o | 25 | obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o |
26 | obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o | ||
27 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o | 27 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o |
28 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o | 28 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o |
29 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o | 29 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o |
@@ -34,5 +34,7 @@ obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o | |||
34 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o | 34 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o |
35 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o | 35 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o |
36 | obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o | 36 | obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o |
37 | obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o | ||
38 | obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o | ||
37 | 39 | ||
38 | nand-objs := nand_base.o nand_bbt.o | 40 | nand-objs := nand_base.o nand_bbt.o |
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 3387e0d5076b..c98c1570a40b 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -174,48 +174,6 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) | |||
174 | } | 174 | } |
175 | 175 | ||
176 | /* | 176 | /* |
177 | * write oob for small pages | ||
178 | */ | ||
179 | static int atmel_nand_write_oob_512(struct mtd_info *mtd, | ||
180 | struct nand_chip *chip, int page) | ||
181 | { | ||
182 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | ||
183 | int eccsize = chip->ecc.size, length = mtd->oobsize; | ||
184 | int len, pos, status = 0; | ||
185 | const uint8_t *bufpoi = chip->oob_poi; | ||
186 | |||
187 | pos = eccsize + chunk; | ||
188 | |||
189 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); | ||
190 | len = min_t(int, length, chunk); | ||
191 | chip->write_buf(mtd, bufpoi, len); | ||
192 | bufpoi += len; | ||
193 | length -= len; | ||
194 | if (length > 0) | ||
195 | chip->write_buf(mtd, bufpoi, length); | ||
196 | |||
197 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
198 | status = chip->waitfunc(mtd, chip); | ||
199 | |||
200 | return status & NAND_STATUS_FAIL ? -EIO : 0; | ||
201 | |||
202 | } | ||
203 | |||
204 | /* | ||
205 | * read oob for small pages | ||
206 | */ | ||
207 | static int atmel_nand_read_oob_512(struct mtd_info *mtd, | ||
208 | struct nand_chip *chip, int page, int sndcmd) | ||
209 | { | ||
210 | if (sndcmd) { | ||
211 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
212 | sndcmd = 0; | ||
213 | } | ||
214 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
215 | return sndcmd; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Calculate HW ECC | 177 | * Calculate HW ECC |
220 | * | 178 | * |
221 | * function called after a write | 179 | * function called after a write |
@@ -235,14 +193,14 @@ static int atmel_nand_calculate(struct mtd_info *mtd, | |||
235 | /* get the first 2 ECC bytes */ | 193 | /* get the first 2 ECC bytes */ |
236 | ecc_value = ecc_readl(host->ecc, PR); | 194 | ecc_value = ecc_readl(host->ecc, PR); |
237 | 195 | ||
238 | ecc_code[eccpos[0]] = ecc_value & 0xFF; | 196 | ecc_code[0] = ecc_value & 0xFF; |
239 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; | 197 | ecc_code[1] = (ecc_value >> 8) & 0xFF; |
240 | 198 | ||
241 | /* get the last 2 ECC bytes */ | 199 | /* get the last 2 ECC bytes */ |
242 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; | 200 | ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; |
243 | 201 | ||
244 | ecc_code[eccpos[2]] = ecc_value & 0xFF; | 202 | ecc_code[2] = ecc_value & 0xFF; |
245 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; | 203 | ecc_code[3] = (ecc_value >> 8) & 0xFF; |
246 | 204 | ||
247 | return 0; | 205 | return 0; |
248 | } | 206 | } |
@@ -476,14 +434,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
476 | res = -EIO; | 434 | res = -EIO; |
477 | goto err_ecc_ioremap; | 435 | goto err_ecc_ioremap; |
478 | } | 436 | } |
479 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; | 437 | nand_chip->ecc.mode = NAND_ECC_HW; |
480 | nand_chip->ecc.calculate = atmel_nand_calculate; | 438 | nand_chip->ecc.calculate = atmel_nand_calculate; |
481 | nand_chip->ecc.correct = atmel_nand_correct; | 439 | nand_chip->ecc.correct = atmel_nand_correct; |
482 | nand_chip->ecc.hwctl = atmel_nand_hwctl; | 440 | nand_chip->ecc.hwctl = atmel_nand_hwctl; |
483 | nand_chip->ecc.read_page = atmel_nand_read_page; | 441 | nand_chip->ecc.read_page = atmel_nand_read_page; |
484 | nand_chip->ecc.bytes = 4; | 442 | nand_chip->ecc.bytes = 4; |
485 | nand_chip->ecc.prepad = 0; | ||
486 | nand_chip->ecc.postpad = 0; | ||
487 | } | 443 | } |
488 | 444 | ||
489 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 445 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
@@ -514,7 +470,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
514 | goto err_scan_ident; | 470 | goto err_scan_ident; |
515 | } | 471 | } |
516 | 472 | ||
517 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { | 473 | if (nand_chip->ecc.mode == NAND_ECC_HW) { |
518 | /* ECC is calculated for the whole page (1 step) */ | 474 | /* ECC is calculated for the whole page (1 step) */ |
519 | nand_chip->ecc.size = mtd->writesize; | 475 | nand_chip->ecc.size = mtd->writesize; |
520 | 476 | ||
@@ -522,8 +478,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
522 | switch (mtd->writesize) { | 478 | switch (mtd->writesize) { |
523 | case 512: | 479 | case 512: |
524 | nand_chip->ecc.layout = &atmel_oobinfo_small; | 480 | nand_chip->ecc.layout = &atmel_oobinfo_small; |
525 | nand_chip->ecc.read_oob = atmel_nand_read_oob_512; | ||
526 | nand_chip->ecc.write_oob = atmel_nand_write_oob_512; | ||
527 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); | 481 | ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); |
528 | break; | 482 | break; |
529 | case 1024: | 483 | case 1024: |
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 3370a800fd36..9f1b451005ca 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c | |||
@@ -289,8 +289,10 @@ static int __init cs553x_init(void) | |||
289 | int i; | 289 | int i; |
290 | uint64_t val; | 290 | uint64_t val; |
291 | 291 | ||
292 | #ifdef CONFIG_MTD_PARTITIONS | ||
292 | int mtd_parts_nb = 0; | 293 | int mtd_parts_nb = 0; |
293 | struct mtd_partition *mtd_parts = NULL; | 294 | struct mtd_partition *mtd_parts = NULL; |
295 | #endif | ||
294 | 296 | ||
295 | /* If the CPU isn't a Geode GX or LX, abort */ | 297 | /* If the CPU isn't a Geode GX or LX, abort */ |
296 | if (!is_geode()) | 298 | if (!is_geode()) |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 98ad3cefcaf4..4aa5bd6158da 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -918,8 +918,7 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | |||
918 | 918 | ||
919 | #ifdef CONFIG_MTD_OF_PARTS | 919 | #ifdef CONFIG_MTD_OF_PARTS |
920 | if (ret == 0) { | 920 | if (ret == 0) { |
921 | ret = of_mtd_parse_partitions(priv->dev, &priv->mtd, | 921 | ret = of_mtd_parse_partitions(priv->dev, node, &parts); |
922 | node, &parts); | ||
923 | if (ret < 0) | 922 | if (ret < 0) |
924 | goto err; | 923 | goto err; |
925 | } | 924 | } |
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 1ebfd87f00b4..024e3fffd4bb 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/delay.h> | ||
16 | #include <linux/mtd/nand.h> | 17 | #include <linux/mtd/nand.h> |
17 | #include <linux/mtd/nand_ecc.h> | 18 | #include <linux/mtd/nand_ecc.h> |
18 | #include <linux/mtd/partitions.h> | 19 | #include <linux/mtd/partitions.h> |
@@ -36,8 +37,6 @@ struct fsl_upm_nand { | |||
36 | uint8_t upm_cmd_offset; | 37 | uint8_t upm_cmd_offset; |
37 | void __iomem *io_base; | 38 | void __iomem *io_base; |
38 | int rnb_gpio; | 39 | int rnb_gpio; |
39 | const uint32_t *wait_pattern; | ||
40 | const uint32_t *wait_write; | ||
41 | int chip_delay; | 40 | int chip_delay; |
42 | }; | 41 | }; |
43 | 42 | ||
@@ -61,10 +60,11 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun) | |||
61 | if (fun->rnb_gpio >= 0) { | 60 | if (fun->rnb_gpio >= 0) { |
62 | while (--cnt && !fun_chip_ready(&fun->mtd)) | 61 | while (--cnt && !fun_chip_ready(&fun->mtd)) |
63 | cpu_relax(); | 62 | cpu_relax(); |
63 | if (!cnt) | ||
64 | dev_err(fun->dev, "tired waiting for RNB\n"); | ||
65 | } else { | ||
66 | ndelay(100); | ||
64 | } | 67 | } |
65 | |||
66 | if (!cnt) | ||
67 | dev_err(fun->dev, "tired waiting for RNB\n"); | ||
68 | } | 68 | } |
69 | 69 | ||
70 | static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 70 | static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
@@ -89,8 +89,7 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
89 | 89 | ||
90 | fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); | 90 | fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); |
91 | 91 | ||
92 | if (fun->wait_pattern) | 92 | fun_wait_rnb(fun); |
93 | fun_wait_rnb(fun); | ||
94 | } | 93 | } |
95 | 94 | ||
96 | static uint8_t fun_read_byte(struct mtd_info *mtd) | 95 | static uint8_t fun_read_byte(struct mtd_info *mtd) |
@@ -116,14 +115,16 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
116 | 115 | ||
117 | for (i = 0; i < len; i++) { | 116 | for (i = 0; i < len; i++) { |
118 | out_8(fun->chip.IO_ADDR_W, buf[i]); | 117 | out_8(fun->chip.IO_ADDR_W, buf[i]); |
119 | if (fun->wait_write) | 118 | fun_wait_rnb(fun); |
120 | fun_wait_rnb(fun); | ||
121 | } | 119 | } |
122 | } | 120 | } |
123 | 121 | ||
124 | static int __devinit fun_chip_init(struct fsl_upm_nand *fun) | 122 | static int __devinit fun_chip_init(struct fsl_upm_nand *fun, |
123 | const struct device_node *upm_np, | ||
124 | const struct resource *io_res) | ||
125 | { | 125 | { |
126 | int ret; | 126 | int ret; |
127 | struct device_node *flash_np; | ||
127 | #ifdef CONFIG_MTD_PARTITIONS | 128 | #ifdef CONFIG_MTD_PARTITIONS |
128 | static const char *part_types[] = { "cmdlinepart", NULL, }; | 129 | static const char *part_types[] = { "cmdlinepart", NULL, }; |
129 | #endif | 130 | #endif |
@@ -143,18 +144,37 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun) | |||
143 | fun->mtd.priv = &fun->chip; | 144 | fun->mtd.priv = &fun->chip; |
144 | fun->mtd.owner = THIS_MODULE; | 145 | fun->mtd.owner = THIS_MODULE; |
145 | 146 | ||
147 | flash_np = of_get_next_child(upm_np, NULL); | ||
148 | if (!flash_np) | ||
149 | return -ENODEV; | ||
150 | |||
151 | fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start, | ||
152 | flash_np->name); | ||
153 | if (!fun->mtd.name) { | ||
154 | ret = -ENOMEM; | ||
155 | goto err; | ||
156 | } | ||
157 | |||
146 | ret = nand_scan(&fun->mtd, 1); | 158 | ret = nand_scan(&fun->mtd, 1); |
147 | if (ret) | 159 | if (ret) |
148 | return ret; | 160 | goto err; |
149 | |||
150 | fun->mtd.name = fun->dev->bus_id; | ||
151 | 161 | ||
152 | #ifdef CONFIG_MTD_PARTITIONS | 162 | #ifdef CONFIG_MTD_PARTITIONS |
153 | ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); | 163 | ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); |
164 | |||
165 | #ifdef CONFIG_MTD_OF_PARTS | ||
166 | if (ret == 0) | ||
167 | ret = of_mtd_parse_partitions(fun->dev, &fun->mtd, | ||
168 | flash_np, &fun->parts); | ||
169 | #endif | ||
154 | if (ret > 0) | 170 | if (ret > 0) |
155 | return add_mtd_partitions(&fun->mtd, fun->parts, ret); | 171 | ret = add_mtd_partitions(&fun->mtd, fun->parts, ret); |
172 | else | ||
156 | #endif | 173 | #endif |
157 | return add_mtd_device(&fun->mtd); | 174 | ret = add_mtd_device(&fun->mtd); |
175 | err: | ||
176 | of_node_put(flash_np); | ||
177 | return ret; | ||
158 | } | 178 | } |
159 | 179 | ||
160 | static int __devinit fun_probe(struct of_device *ofdev, | 180 | static int __devinit fun_probe(struct of_device *ofdev, |
@@ -211,6 +231,12 @@ static int __devinit fun_probe(struct of_device *ofdev, | |||
211 | goto err2; | 231 | goto err2; |
212 | } | 232 | } |
213 | 233 | ||
234 | prop = of_get_property(ofdev->node, "chip-delay", NULL); | ||
235 | if (prop) | ||
236 | fun->chip_delay = *prop; | ||
237 | else | ||
238 | fun->chip_delay = 50; | ||
239 | |||
214 | fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, | 240 | fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, |
215 | io_res.end - io_res.start + 1); | 241 | io_res.end - io_res.start + 1); |
216 | if (!fun->io_base) { | 242 | if (!fun->io_base) { |
@@ -220,17 +246,8 @@ static int __devinit fun_probe(struct of_device *ofdev, | |||
220 | 246 | ||
221 | fun->dev = &ofdev->dev; | 247 | fun->dev = &ofdev->dev; |
222 | fun->last_ctrl = NAND_CLE; | 248 | fun->last_ctrl = NAND_CLE; |
223 | fun->wait_pattern = of_get_property(ofdev->node, "fsl,wait-pattern", | ||
224 | NULL); | ||
225 | fun->wait_write = of_get_property(ofdev->node, "fsl,wait-write", NULL); | ||
226 | |||
227 | prop = of_get_property(ofdev->node, "chip-delay", NULL); | ||
228 | if (prop) | ||
229 | fun->chip_delay = *prop; | ||
230 | else | ||
231 | fun->chip_delay = 50; | ||
232 | 249 | ||
233 | ret = fun_chip_init(fun); | 250 | ret = fun_chip_init(fun, ofdev->node, &io_res); |
234 | if (ret) | 251 | if (ret) |
235 | goto err2; | 252 | goto err2; |
236 | 253 | ||
@@ -251,6 +268,7 @@ static int __devexit fun_remove(struct of_device *ofdev) | |||
251 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); | 268 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); |
252 | 269 | ||
253 | nand_release(&fun->mtd); | 270 | nand_release(&fun->mtd); |
271 | kfree(fun->mtd.name); | ||
254 | 272 | ||
255 | if (fun->rnb_gpio >= 0) | 273 | if (fun->rnb_gpio >= 0) |
256 | gpio_free(fun->rnb_gpio); | 274 | gpio_free(fun->rnb_gpio); |
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c new file mode 100644 index 000000000000..8f902e75aa85 --- /dev/null +++ b/drivers/mtd/nand/gpio.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/gpio.c | ||
3 | * | ||
4 | * Updated, and converted to generic GPIO based driver by Russell King. | ||
5 | * | ||
6 | * Written by Ben Dooks <ben@simtec.co.uk> | ||
7 | * Based on 2.4 version by Mark Whittaker | ||
8 | * | ||
9 | * © 2004 Simtec Electronics | ||
10 | * | ||
11 | * Device driver for NAND connected via GPIO | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/mtd/mtd.h> | ||
27 | #include <linux/mtd/nand.h> | ||
28 | #include <linux/mtd/partitions.h> | ||
29 | #include <linux/mtd/nand-gpio.h> | ||
30 | |||
31 | struct gpiomtd { | ||
32 | void __iomem *io_sync; | ||
33 | struct mtd_info mtd_info; | ||
34 | struct nand_chip nand_chip; | ||
35 | struct gpio_nand_platdata plat; | ||
36 | }; | ||
37 | |||
38 | #define gpio_nand_getpriv(x) container_of(x, struct gpiomtd, mtd_info) | ||
39 | |||
40 | |||
41 | #ifdef CONFIG_ARM | ||
42 | /* gpio_nand_dosync() | ||
43 | * | ||
44 | * Make sure the GPIO state changes occur in-order with writes to NAND | ||
45 | * memory region. | ||
46 | * Needed on PXA due to bus-reordering within the SoC itself (see section on | ||
47 | * I/O ordering in PXA manual (section 2.3, p35) | ||
48 | */ | ||
49 | static void gpio_nand_dosync(struct gpiomtd *gpiomtd) | ||
50 | { | ||
51 | unsigned long tmp; | ||
52 | |||
53 | if (gpiomtd->io_sync) { | ||
54 | /* | ||
55 | * Linux memory barriers don't cater for what's required here. | ||
56 | * What's required is what's here - a read from a separate | ||
57 | * region with a dependency on that read. | ||
58 | */ | ||
59 | tmp = readl(gpiomtd->io_sync); | ||
60 | asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp)); | ||
61 | } | ||
62 | } | ||
63 | #else | ||
64 | static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} | ||
65 | #endif | ||
66 | |||
67 | static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
68 | { | ||
69 | struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); | ||
70 | |||
71 | gpio_nand_dosync(gpiomtd); | ||
72 | |||
73 | if (ctrl & NAND_CTRL_CHANGE) { | ||
74 | gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE)); | ||
75 | gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE)); | ||
76 | gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE)); | ||
77 | gpio_nand_dosync(gpiomtd); | ||
78 | } | ||
79 | if (cmd == NAND_CMD_NONE) | ||
80 | return; | ||
81 | |||
82 | writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W); | ||
83 | gpio_nand_dosync(gpiomtd); | ||
84 | } | ||
85 | |||
86 | static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len) | ||
87 | { | ||
88 | struct nand_chip *this = mtd->priv; | ||
89 | |||
90 | writesb(this->IO_ADDR_W, buf, len); | ||
91 | } | ||
92 | |||
93 | static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len) | ||
94 | { | ||
95 | struct nand_chip *this = mtd->priv; | ||
96 | |||
97 | readsb(this->IO_ADDR_R, buf, len); | ||
98 | } | ||
99 | |||
100 | static int gpio_nand_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) | ||
101 | { | ||
102 | struct nand_chip *this = mtd->priv; | ||
103 | unsigned char read, *p = (unsigned char *) buf; | ||
104 | int i, err = 0; | ||
105 | |||
106 | for (i = 0; i < len; i++) { | ||
107 | read = readb(this->IO_ADDR_R); | ||
108 | if (read != p[i]) { | ||
109 | pr_debug("%s: err at %d (read %04x vs %04x)\n", | ||
110 | __func__, i, read, p[i]); | ||
111 | err = -EFAULT; | ||
112 | } | ||
113 | } | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, | ||
118 | int len) | ||
119 | { | ||
120 | struct nand_chip *this = mtd->priv; | ||
121 | |||
122 | if (IS_ALIGNED((unsigned long)buf, 2)) { | ||
123 | writesw(this->IO_ADDR_W, buf, len>>1); | ||
124 | } else { | ||
125 | int i; | ||
126 | unsigned short *ptr = (unsigned short *)buf; | ||
127 | |||
128 | for (i = 0; i < len; i += 2, ptr++) | ||
129 | writew(*ptr, this->IO_ADDR_W); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) | ||
134 | { | ||
135 | struct nand_chip *this = mtd->priv; | ||
136 | |||
137 | if (IS_ALIGNED((unsigned long)buf, 2)) { | ||
138 | readsw(this->IO_ADDR_R, buf, len>>1); | ||
139 | } else { | ||
140 | int i; | ||
141 | unsigned short *ptr = (unsigned short *)buf; | ||
142 | |||
143 | for (i = 0; i < len; i += 2, ptr++) | ||
144 | *ptr = readw(this->IO_ADDR_R); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | static int gpio_nand_verifybuf16(struct mtd_info *mtd, const u_char *buf, | ||
149 | int len) | ||
150 | { | ||
151 | struct nand_chip *this = mtd->priv; | ||
152 | unsigned short read, *p = (unsigned short *) buf; | ||
153 | int i, err = 0; | ||
154 | len >>= 1; | ||
155 | |||
156 | for (i = 0; i < len; i++) { | ||
157 | read = readw(this->IO_ADDR_R); | ||
158 | if (read != p[i]) { | ||
159 | pr_debug("%s: err at %d (read %04x vs %04x)\n", | ||
160 | __func__, i, read, p[i]); | ||
161 | err = -EFAULT; | ||
162 | } | ||
163 | } | ||
164 | return err; | ||
165 | } | ||
166 | |||
167 | |||
168 | static int gpio_nand_devready(struct mtd_info *mtd) | ||
169 | { | ||
170 | struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); | ||
171 | return gpio_get_value(gpiomtd->plat.gpio_rdy); | ||
172 | } | ||
173 | |||
174 | static int __devexit gpio_nand_remove(struct platform_device *dev) | ||
175 | { | ||
176 | struct gpiomtd *gpiomtd = platform_get_drvdata(dev); | ||
177 | struct resource *res; | ||
178 | |||
179 | nand_release(&gpiomtd->mtd_info); | ||
180 | |||
181 | res = platform_get_resource(dev, IORESOURCE_MEM, 1); | ||
182 | iounmap(gpiomtd->io_sync); | ||
183 | if (res) | ||
184 | release_mem_region(res->start, res->end - res->start + 1); | ||
185 | |||
186 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
187 | iounmap(gpiomtd->nand_chip.IO_ADDR_R); | ||
188 | release_mem_region(res->start, res->end - res->start + 1); | ||
189 | |||
190 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) | ||
191 | gpio_set_value(gpiomtd->plat.gpio_nwp, 0); | ||
192 | gpio_set_value(gpiomtd->plat.gpio_nce, 1); | ||
193 | |||
194 | gpio_free(gpiomtd->plat.gpio_cle); | ||
195 | gpio_free(gpiomtd->plat.gpio_ale); | ||
196 | gpio_free(gpiomtd->plat.gpio_nce); | ||
197 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) | ||
198 | gpio_free(gpiomtd->plat.gpio_nwp); | ||
199 | gpio_free(gpiomtd->plat.gpio_rdy); | ||
200 | |||
201 | kfree(gpiomtd); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static void __iomem *request_and_remap(struct resource *res, size_t size, | ||
207 | const char *name, int *err) | ||
208 | { | ||
209 | void __iomem *ptr; | ||
210 | |||
211 | if (!request_mem_region(res->start, res->end - res->start + 1, name)) { | ||
212 | *err = -EBUSY; | ||
213 | return NULL; | ||
214 | } | ||
215 | |||
216 | ptr = ioremap(res->start, size); | ||
217 | if (!ptr) { | ||
218 | release_mem_region(res->start, res->end - res->start + 1); | ||
219 | *err = -ENOMEM; | ||
220 | } | ||
221 | return ptr; | ||
222 | } | ||
223 | |||
224 | static int __devinit gpio_nand_probe(struct platform_device *dev) | ||
225 | { | ||
226 | struct gpiomtd *gpiomtd; | ||
227 | struct nand_chip *this; | ||
228 | struct resource *res0, *res1; | ||
229 | int ret; | ||
230 | |||
231 | if (!dev->dev.platform_data) | ||
232 | return -EINVAL; | ||
233 | |||
234 | res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
235 | if (!res0) | ||
236 | return -EINVAL; | ||
237 | |||
238 | gpiomtd = kzalloc(sizeof(*gpiomtd), GFP_KERNEL); | ||
239 | if (gpiomtd == NULL) { | ||
240 | dev_err(&dev->dev, "failed to create NAND MTD\n"); | ||
241 | return -ENOMEM; | ||
242 | } | ||
243 | |||
244 | this = &gpiomtd->nand_chip; | ||
245 | this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret); | ||
246 | if (!this->IO_ADDR_R) { | ||
247 | dev_err(&dev->dev, "unable to map NAND\n"); | ||
248 | goto err_map; | ||
249 | } | ||
250 | |||
251 | res1 = platform_get_resource(dev, IORESOURCE_MEM, 1); | ||
252 | if (res1) { | ||
253 | gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); | ||
254 | if (!gpiomtd->io_sync) { | ||
255 | dev_err(&dev->dev, "unable to map sync NAND\n"); | ||
256 | goto err_sync; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat)); | ||
261 | |||
262 | ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); | ||
263 | if (ret) | ||
264 | goto err_nce; | ||
265 | gpio_direction_output(gpiomtd->plat.gpio_nce, 1); | ||
266 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { | ||
267 | ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP"); | ||
268 | if (ret) | ||
269 | goto err_nwp; | ||
270 | gpio_direction_output(gpiomtd->plat.gpio_nwp, 1); | ||
271 | } | ||
272 | ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE"); | ||
273 | if (ret) | ||
274 | goto err_ale; | ||
275 | gpio_direction_output(gpiomtd->plat.gpio_ale, 0); | ||
276 | ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE"); | ||
277 | if (ret) | ||
278 | goto err_cle; | ||
279 | gpio_direction_output(gpiomtd->plat.gpio_cle, 0); | ||
280 | ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); | ||
281 | if (ret) | ||
282 | goto err_rdy; | ||
283 | gpio_direction_input(gpiomtd->plat.gpio_rdy); | ||
284 | |||
285 | |||
286 | this->IO_ADDR_W = this->IO_ADDR_R; | ||
287 | this->ecc.mode = NAND_ECC_SOFT; | ||
288 | this->options = gpiomtd->plat.options; | ||
289 | this->chip_delay = gpiomtd->plat.chip_delay; | ||
290 | |||
291 | /* install our routines */ | ||
292 | this->cmd_ctrl = gpio_nand_cmd_ctrl; | ||
293 | this->dev_ready = gpio_nand_devready; | ||
294 | |||
295 | if (this->options & NAND_BUSWIDTH_16) { | ||
296 | this->read_buf = gpio_nand_readbuf16; | ||
297 | this->write_buf = gpio_nand_writebuf16; | ||
298 | this->verify_buf = gpio_nand_verifybuf16; | ||
299 | } else { | ||
300 | this->read_buf = gpio_nand_readbuf; | ||
301 | this->write_buf = gpio_nand_writebuf; | ||
302 | this->verify_buf = gpio_nand_verifybuf; | ||
303 | } | ||
304 | |||
305 | /* set the mtd private data for the nand driver */ | ||
306 | gpiomtd->mtd_info.priv = this; | ||
307 | gpiomtd->mtd_info.owner = THIS_MODULE; | ||
308 | |||
309 | if (nand_scan(&gpiomtd->mtd_info, 1)) { | ||
310 | dev_err(&dev->dev, "no nand chips found?\n"); | ||
311 | ret = -ENXIO; | ||
312 | goto err_wp; | ||
313 | } | ||
314 | |||
315 | if (gpiomtd->plat.adjust_parts) | ||
316 | gpiomtd->plat.adjust_parts(&gpiomtd->plat, | ||
317 | gpiomtd->mtd_info.size); | ||
318 | |||
319 | add_mtd_partitions(&gpiomtd->mtd_info, gpiomtd->plat.parts, | ||
320 | gpiomtd->plat.num_parts); | ||
321 | platform_set_drvdata(dev, gpiomtd); | ||
322 | |||
323 | return 0; | ||
324 | |||
325 | err_wp: | ||
326 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) | ||
327 | gpio_set_value(gpiomtd->plat.gpio_nwp, 0); | ||
328 | gpio_free(gpiomtd->plat.gpio_rdy); | ||
329 | err_rdy: | ||
330 | gpio_free(gpiomtd->plat.gpio_cle); | ||
331 | err_cle: | ||
332 | gpio_free(gpiomtd->plat.gpio_ale); | ||
333 | err_ale: | ||
334 | if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) | ||
335 | gpio_free(gpiomtd->plat.gpio_nwp); | ||
336 | err_nwp: | ||
337 | gpio_free(gpiomtd->plat.gpio_nce); | ||
338 | err_nce: | ||
339 | iounmap(gpiomtd->io_sync); | ||
340 | if (res1) | ||
341 | release_mem_region(res1->start, res1->end - res1->start + 1); | ||
342 | err_sync: | ||
343 | iounmap(gpiomtd->nand_chip.IO_ADDR_R); | ||
344 | release_mem_region(res0->start, res0->end - res0->start + 1); | ||
345 | err_map: | ||
346 | kfree(gpiomtd); | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | static struct platform_driver gpio_nand_driver = { | ||
351 | .probe = gpio_nand_probe, | ||
352 | .remove = gpio_nand_remove, | ||
353 | .driver = { | ||
354 | .name = "gpio-nand", | ||
355 | }, | ||
356 | }; | ||
357 | |||
358 | static int __init gpio_nand_init(void) | ||
359 | { | ||
360 | printk(KERN_INFO "GPIO NAND driver, © 2004 Simtec Electronics\n"); | ||
361 | |||
362 | return platform_driver_register(&gpio_nand_driver); | ||
363 | } | ||
364 | |||
365 | static void __exit gpio_nand_exit(void) | ||
366 | { | ||
367 | platform_driver_unregister(&gpio_nand_driver); | ||
368 | } | ||
369 | |||
370 | module_init(gpio_nand_init); | ||
371 | module_exit(gpio_nand_exit); | ||
372 | |||
373 | MODULE_LICENSE("GPL"); | ||
374 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
375 | MODULE_DESCRIPTION("GPIO NAND Driver"); | ||
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c new file mode 100644 index 000000000000..21fd4f1c4806 --- /dev/null +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -0,0 +1,1077 @@ | |||
1 | /* | ||
2 | * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | * Copyright 2008 Sascha Hauer, kernel@pengutronix.de | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
17 | * MA 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mtd/mtd.h> | ||
25 | #include <linux/mtd/nand.h> | ||
26 | #include <linux/mtd/partitions.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/err.h> | ||
32 | #include <linux/io.h> | ||
33 | |||
34 | #include <asm/mach/flash.h> | ||
35 | #include <mach/mxc_nand.h> | ||
36 | |||
37 | #define DRIVER_NAME "mxc_nand" | ||
38 | |||
39 | /* Addresses for NFC registers */ | ||
40 | #define NFC_BUF_SIZE 0xE00 | ||
41 | #define NFC_BUF_ADDR 0xE04 | ||
42 | #define NFC_FLASH_ADDR 0xE06 | ||
43 | #define NFC_FLASH_CMD 0xE08 | ||
44 | #define NFC_CONFIG 0xE0A | ||
45 | #define NFC_ECC_STATUS_RESULT 0xE0C | ||
46 | #define NFC_RSLTMAIN_AREA 0xE0E | ||
47 | #define NFC_RSLTSPARE_AREA 0xE10 | ||
48 | #define NFC_WRPROT 0xE12 | ||
49 | #define NFC_UNLOCKSTART_BLKADDR 0xE14 | ||
50 | #define NFC_UNLOCKEND_BLKADDR 0xE16 | ||
51 | #define NFC_NF_WRPRST 0xE18 | ||
52 | #define NFC_CONFIG1 0xE1A | ||
53 | #define NFC_CONFIG2 0xE1C | ||
54 | |||
55 | /* Addresses for NFC RAM BUFFER Main area 0 */ | ||
56 | #define MAIN_AREA0 0x000 | ||
57 | #define MAIN_AREA1 0x200 | ||
58 | #define MAIN_AREA2 0x400 | ||
59 | #define MAIN_AREA3 0x600 | ||
60 | |||
61 | /* Addresses for NFC SPARE BUFFER Spare area 0 */ | ||
62 | #define SPARE_AREA0 0x800 | ||
63 | #define SPARE_AREA1 0x810 | ||
64 | #define SPARE_AREA2 0x820 | ||
65 | #define SPARE_AREA3 0x830 | ||
66 | |||
67 | /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register | ||
68 | * for Command operation */ | ||
69 | #define NFC_CMD 0x1 | ||
70 | |||
71 | /* Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register | ||
72 | * for Address operation */ | ||
73 | #define NFC_ADDR 0x2 | ||
74 | |||
75 | /* Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register | ||
76 | * for Input operation */ | ||
77 | #define NFC_INPUT 0x4 | ||
78 | |||
79 | /* Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register | ||
80 | * for Data Output operation */ | ||
81 | #define NFC_OUTPUT 0x8 | ||
82 | |||
83 | /* Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register | ||
84 | * for Read ID operation */ | ||
85 | #define NFC_ID 0x10 | ||
86 | |||
87 | /* Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register | ||
88 | * for Read Status operation */ | ||
89 | #define NFC_STATUS 0x20 | ||
90 | |||
91 | /* Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read | ||
92 | * Status operation */ | ||
93 | #define NFC_INT 0x8000 | ||
94 | |||
95 | #define NFC_SP_EN (1 << 2) | ||
96 | #define NFC_ECC_EN (1 << 3) | ||
97 | #define NFC_INT_MSK (1 << 4) | ||
98 | #define NFC_BIG (1 << 5) | ||
99 | #define NFC_RST (1 << 6) | ||
100 | #define NFC_CE (1 << 7) | ||
101 | #define NFC_ONE_CYCLE (1 << 8) | ||
102 | |||
103 | struct mxc_nand_host { | ||
104 | struct mtd_info mtd; | ||
105 | struct nand_chip nand; | ||
106 | struct mtd_partition *parts; | ||
107 | struct device *dev; | ||
108 | |||
109 | void __iomem *regs; | ||
110 | int spare_only; | ||
111 | int status_request; | ||
112 | int pagesize_2k; | ||
113 | uint16_t col_addr; | ||
114 | struct clk *clk; | ||
115 | int clk_act; | ||
116 | int irq; | ||
117 | |||
118 | wait_queue_head_t irq_waitq; | ||
119 | }; | ||
120 | |||
121 | /* Define delays in microsec for NAND device operations */ | ||
122 | #define TROP_US_DELAY 2000 | ||
123 | /* Macros to get byte and bit positions of ECC */ | ||
124 | #define COLPOS(x) ((x) >> 3) | ||
125 | #define BITPOS(x) ((x) & 0xf) | ||
126 | |||
127 | /* Define single bit Error positions in Main & Spare area */ | ||
128 | #define MAIN_SINGLEBIT_ERROR 0x4 | ||
129 | #define SPARE_SINGLEBIT_ERROR 0x1 | ||
130 | |||
131 | /* OOB placement block for use with hardware ecc generation */ | ||
132 | static struct nand_ecclayout nand_hw_eccoob_8 = { | ||
133 | .eccbytes = 5, | ||
134 | .eccpos = {6, 7, 8, 9, 10}, | ||
135 | .oobfree = {{0, 5}, {11, 5}, } | ||
136 | }; | ||
137 | |||
138 | static struct nand_ecclayout nand_hw_eccoob_16 = { | ||
139 | .eccbytes = 5, | ||
140 | .eccpos = {6, 7, 8, 9, 10}, | ||
141 | .oobfree = {{0, 6}, {12, 4}, } | ||
142 | }; | ||
143 | |||
144 | #ifdef CONFIG_MTD_PARTITIONS | ||
145 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | ||
146 | #endif | ||
147 | |||
148 | static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | ||
149 | { | ||
150 | struct mxc_nand_host *host = dev_id; | ||
151 | |||
152 | uint16_t tmp; | ||
153 | |||
154 | tmp = readw(host->regs + NFC_CONFIG1); | ||
155 | tmp |= NFC_INT_MSK; /* Disable interrupt */ | ||
156 | writew(tmp, host->regs + NFC_CONFIG1); | ||
157 | |||
158 | wake_up(&host->irq_waitq); | ||
159 | |||
160 | return IRQ_HANDLED; | ||
161 | } | ||
162 | |||
163 | /* This function polls the NANDFC to wait for the basic operation to | ||
164 | * complete by checking the INT bit of config2 register. | ||
165 | */ | ||
166 | static void wait_op_done(struct mxc_nand_host *host, int max_retries, | ||
167 | uint16_t param, int useirq) | ||
168 | { | ||
169 | uint32_t tmp; | ||
170 | |||
171 | if (useirq) { | ||
172 | if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) { | ||
173 | |||
174 | tmp = readw(host->regs + NFC_CONFIG1); | ||
175 | tmp &= ~NFC_INT_MSK; /* Enable interrupt */ | ||
176 | writew(tmp, host->regs + NFC_CONFIG1); | ||
177 | |||
178 | wait_event(host->irq_waitq, | ||
179 | readw(host->regs + NFC_CONFIG2) & NFC_INT); | ||
180 | |||
181 | tmp = readw(host->regs + NFC_CONFIG2); | ||
182 | tmp &= ~NFC_INT; | ||
183 | writew(tmp, host->regs + NFC_CONFIG2); | ||
184 | } | ||
185 | } else { | ||
186 | while (max_retries-- > 0) { | ||
187 | if (readw(host->regs + NFC_CONFIG2) & NFC_INT) { | ||
188 | tmp = readw(host->regs + NFC_CONFIG2); | ||
189 | tmp &= ~NFC_INT; | ||
190 | writew(tmp, host->regs + NFC_CONFIG2); | ||
191 | break; | ||
192 | } | ||
193 | udelay(1); | ||
194 | } | ||
195 | if (max_retries <= 0) | ||
196 | DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", | ||
197 | __func__, param); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* This function issues the specified command to the NAND device and | ||
202 | * waits for completion. */ | ||
203 | static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq) | ||
204 | { | ||
205 | DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); | ||
206 | |||
207 | writew(cmd, host->regs + NFC_FLASH_CMD); | ||
208 | writew(NFC_CMD, host->regs + NFC_CONFIG2); | ||
209 | |||
210 | /* Wait for operation to complete */ | ||
211 | wait_op_done(host, TROP_US_DELAY, cmd, useirq); | ||
212 | } | ||
213 | |||
214 | /* This function sends an address (or partial address) to the | ||
215 | * NAND device. The address is used to select the source/destination for | ||
216 | * a NAND command. */ | ||
217 | static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast) | ||
218 | { | ||
219 | DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); | ||
220 | |||
221 | writew(addr, host->regs + NFC_FLASH_ADDR); | ||
222 | writew(NFC_ADDR, host->regs + NFC_CONFIG2); | ||
223 | |||
224 | /* Wait for operation to complete */ | ||
225 | wait_op_done(host, TROP_US_DELAY, addr, islast); | ||
226 | } | ||
227 | |||
228 | /* This function requests the NANDFC to initate the transfer | ||
229 | * of data currently in the NANDFC RAM buffer to the NAND device. */ | ||
230 | static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, | ||
231 | int spare_only) | ||
232 | { | ||
233 | DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only); | ||
234 | |||
235 | /* NANDFC buffer 0 is used for page read/write */ | ||
236 | writew(buf_id, host->regs + NFC_BUF_ADDR); | ||
237 | |||
238 | /* Configure spare or page+spare access */ | ||
239 | if (!host->pagesize_2k) { | ||
240 | uint16_t config1 = readw(host->regs + NFC_CONFIG1); | ||
241 | if (spare_only) | ||
242 | config1 |= NFC_SP_EN; | ||
243 | else | ||
244 | config1 &= ~(NFC_SP_EN); | ||
245 | writew(config1, host->regs + NFC_CONFIG1); | ||
246 | } | ||
247 | |||
248 | writew(NFC_INPUT, host->regs + NFC_CONFIG2); | ||
249 | |||
250 | /* Wait for operation to complete */ | ||
251 | wait_op_done(host, TROP_US_DELAY, spare_only, true); | ||
252 | } | ||
253 | |||
254 | /* Requests NANDFC to initated the transfer of data from the | ||
255 | * NAND device into in the NANDFC ram buffer. */ | ||
256 | static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, | ||
257 | int spare_only) | ||
258 | { | ||
259 | DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); | ||
260 | |||
261 | /* NANDFC buffer 0 is used for page read/write */ | ||
262 | writew(buf_id, host->regs + NFC_BUF_ADDR); | ||
263 | |||
264 | /* Configure spare or page+spare access */ | ||
265 | if (!host->pagesize_2k) { | ||
266 | uint32_t config1 = readw(host->regs + NFC_CONFIG1); | ||
267 | if (spare_only) | ||
268 | config1 |= NFC_SP_EN; | ||
269 | else | ||
270 | config1 &= ~NFC_SP_EN; | ||
271 | writew(config1, host->regs + NFC_CONFIG1); | ||
272 | } | ||
273 | |||
274 | writew(NFC_OUTPUT, host->regs + NFC_CONFIG2); | ||
275 | |||
276 | /* Wait for operation to complete */ | ||
277 | wait_op_done(host, TROP_US_DELAY, spare_only, true); | ||
278 | } | ||
279 | |||
280 | /* Request the NANDFC to perform a read of the NAND device ID. */ | ||
281 | static void send_read_id(struct mxc_nand_host *host) | ||
282 | { | ||
283 | struct nand_chip *this = &host->nand; | ||
284 | uint16_t tmp; | ||
285 | |||
286 | /* NANDFC buffer 0 is used for device ID output */ | ||
287 | writew(0x0, host->regs + NFC_BUF_ADDR); | ||
288 | |||
289 | /* Read ID into main buffer */ | ||
290 | tmp = readw(host->regs + NFC_CONFIG1); | ||
291 | tmp &= ~NFC_SP_EN; | ||
292 | writew(tmp, host->regs + NFC_CONFIG1); | ||
293 | |||
294 | writew(NFC_ID, host->regs + NFC_CONFIG2); | ||
295 | |||
296 | /* Wait for operation to complete */ | ||
297 | wait_op_done(host, TROP_US_DELAY, 0, true); | ||
298 | |||
299 | if (this->options & NAND_BUSWIDTH_16) { | ||
300 | void __iomem *main_buf = host->regs + MAIN_AREA0; | ||
301 | /* compress the ID info */ | ||
302 | writeb(readb(main_buf + 2), main_buf + 1); | ||
303 | writeb(readb(main_buf + 4), main_buf + 2); | ||
304 | writeb(readb(main_buf + 6), main_buf + 3); | ||
305 | writeb(readb(main_buf + 8), main_buf + 4); | ||
306 | writeb(readb(main_buf + 10), main_buf + 5); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | /* This function requests the NANDFC to perform a read of the | ||
311 | * NAND device status and returns the current status. */ | ||
312 | static uint16_t get_dev_status(struct mxc_nand_host *host) | ||
313 | { | ||
314 | void __iomem *main_buf = host->regs + MAIN_AREA1; | ||
315 | uint32_t store; | ||
316 | uint16_t ret, tmp; | ||
317 | /* Issue status request to NAND device */ | ||
318 | |||
319 | /* store the main area1 first word, later do recovery */ | ||
320 | store = readl(main_buf); | ||
321 | /* NANDFC buffer 1 is used for device status to prevent | ||
322 | * corruption of read/write buffer on status requests. */ | ||
323 | writew(1, host->regs + NFC_BUF_ADDR); | ||
324 | |||
325 | /* Read status into main buffer */ | ||
326 | tmp = readw(host->regs + NFC_CONFIG1); | ||
327 | tmp &= ~NFC_SP_EN; | ||
328 | writew(tmp, host->regs + NFC_CONFIG1); | ||
329 | |||
330 | writew(NFC_STATUS, host->regs + NFC_CONFIG2); | ||
331 | |||
332 | /* Wait for operation to complete */ | ||
333 | wait_op_done(host, TROP_US_DELAY, 0, true); | ||
334 | |||
335 | /* Status is placed in first word of main buffer */ | ||
336 | /* get status, then recovery area 1 data */ | ||
337 | ret = readw(main_buf); | ||
338 | writel(store, main_buf); | ||
339 | |||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | /* This functions is used by upper layer to checks if device is ready */ | ||
344 | static int mxc_nand_dev_ready(struct mtd_info *mtd) | ||
345 | { | ||
346 | /* | ||
347 | * NFC handles R/B internally. Therefore, this function | ||
348 | * always returns status as ready. | ||
349 | */ | ||
350 | return 1; | ||
351 | } | ||
352 | |||
353 | static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) | ||
354 | { | ||
355 | /* | ||
356 | * If HW ECC is enabled, we turn it on during init. There is | ||
357 | * no need to enable again here. | ||
358 | */ | ||
359 | } | ||
360 | |||
361 | static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, | ||
362 | u_char *read_ecc, u_char *calc_ecc) | ||
363 | { | ||
364 | struct nand_chip *nand_chip = mtd->priv; | ||
365 | struct mxc_nand_host *host = nand_chip->priv; | ||
366 | |||
367 | /* | ||
368 | * 1-Bit errors are automatically corrected in HW. No need for | ||
369 | * additional correction. 2-Bit errors cannot be corrected by | ||
370 | * HW ECC, so we need to return failure | ||
371 | */ | ||
372 | uint16_t ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT); | ||
373 | |||
374 | if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { | ||
375 | DEBUG(MTD_DEBUG_LEVEL0, | ||
376 | "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); | ||
377 | return -1; | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | ||
384 | u_char *ecc_code) | ||
385 | { | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static u_char mxc_nand_read_byte(struct mtd_info *mtd) | ||
390 | { | ||
391 | struct nand_chip *nand_chip = mtd->priv; | ||
392 | struct mxc_nand_host *host = nand_chip->priv; | ||
393 | uint8_t ret = 0; | ||
394 | uint16_t col, rd_word; | ||
395 | uint16_t __iomem *main_buf = host->regs + MAIN_AREA0; | ||
396 | uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0; | ||
397 | |||
398 | /* Check for status request */ | ||
399 | if (host->status_request) | ||
400 | return get_dev_status(host) & 0xFF; | ||
401 | |||
402 | /* Get column for 16-bit access */ | ||
403 | col = host->col_addr >> 1; | ||
404 | |||
405 | /* If we are accessing the spare region */ | ||
406 | if (host->spare_only) | ||
407 | rd_word = readw(&spare_buf[col]); | ||
408 | else | ||
409 | rd_word = readw(&main_buf[col]); | ||
410 | |||
411 | /* Pick upper/lower byte of word from RAM buffer */ | ||
412 | if (host->col_addr & 0x1) | ||
413 | ret = (rd_word >> 8) & 0xFF; | ||
414 | else | ||
415 | ret = rd_word & 0xFF; | ||
416 | |||
417 | /* Update saved column address */ | ||
418 | host->col_addr++; | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | static uint16_t mxc_nand_read_word(struct mtd_info *mtd) | ||
424 | { | ||
425 | struct nand_chip *nand_chip = mtd->priv; | ||
426 | struct mxc_nand_host *host = nand_chip->priv; | ||
427 | uint16_t col, rd_word, ret; | ||
428 | uint16_t __iomem *p; | ||
429 | |||
430 | DEBUG(MTD_DEBUG_LEVEL3, | ||
431 | "mxc_nand_read_word(col = %d)\n", host->col_addr); | ||
432 | |||
433 | col = host->col_addr; | ||
434 | /* Adjust saved column address */ | ||
435 | if (col < mtd->writesize && host->spare_only) | ||
436 | col += mtd->writesize; | ||
437 | |||
438 | if (col < mtd->writesize) | ||
439 | p = (host->regs + MAIN_AREA0) + (col >> 1); | ||
440 | else | ||
441 | p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1); | ||
442 | |||
443 | if (col & 1) { | ||
444 | rd_word = readw(p); | ||
445 | ret = (rd_word >> 8) & 0xff; | ||
446 | rd_word = readw(&p[1]); | ||
447 | ret |= (rd_word << 8) & 0xff00; | ||
448 | |||
449 | } else | ||
450 | ret = readw(p); | ||
451 | |||
452 | /* Update saved column address */ | ||
453 | host->col_addr = col + 2; | ||
454 | |||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | /* Write data of length len to buffer buf. The data to be | ||
459 | * written on NAND Flash is first copied to RAMbuffer. After the Data Input | ||
460 | * Operation by the NFC, the data is written to NAND Flash */ | ||
461 | static void mxc_nand_write_buf(struct mtd_info *mtd, | ||
462 | const u_char *buf, int len) | ||
463 | { | ||
464 | struct nand_chip *nand_chip = mtd->priv; | ||
465 | struct mxc_nand_host *host = nand_chip->priv; | ||
466 | int n, col, i = 0; | ||
467 | |||
468 | DEBUG(MTD_DEBUG_LEVEL3, | ||
469 | "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, | ||
470 | len); | ||
471 | |||
472 | col = host->col_addr; | ||
473 | |||
474 | /* Adjust saved column address */ | ||
475 | if (col < mtd->writesize && host->spare_only) | ||
476 | col += mtd->writesize; | ||
477 | |||
478 | n = mtd->writesize + mtd->oobsize - col; | ||
479 | n = min(len, n); | ||
480 | |||
481 | DEBUG(MTD_DEBUG_LEVEL3, | ||
482 | "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); | ||
483 | |||
484 | while (n) { | ||
485 | void __iomem *p; | ||
486 | |||
487 | if (col < mtd->writesize) | ||
488 | p = host->regs + MAIN_AREA0 + (col & ~3); | ||
489 | else | ||
490 | p = host->regs + SPARE_AREA0 - | ||
491 | mtd->writesize + (col & ~3); | ||
492 | |||
493 | DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, | ||
494 | __LINE__, p); | ||
495 | |||
496 | if (((col | (int)&buf[i]) & 3) || n < 16) { | ||
497 | uint32_t data = 0; | ||
498 | |||
499 | if (col & 3 || n < 4) | ||
500 | data = readl(p); | ||
501 | |||
502 | switch (col & 3) { | ||
503 | case 0: | ||
504 | if (n) { | ||
505 | data = (data & 0xffffff00) | | ||
506 | (buf[i++] << 0); | ||
507 | n--; | ||
508 | col++; | ||
509 | } | ||
510 | case 1: | ||
511 | if (n) { | ||
512 | data = (data & 0xffff00ff) | | ||
513 | (buf[i++] << 8); | ||
514 | n--; | ||
515 | col++; | ||
516 | } | ||
517 | case 2: | ||
518 | if (n) { | ||
519 | data = (data & 0xff00ffff) | | ||
520 | (buf[i++] << 16); | ||
521 | n--; | ||
522 | col++; | ||
523 | } | ||
524 | case 3: | ||
525 | if (n) { | ||
526 | data = (data & 0x00ffffff) | | ||
527 | (buf[i++] << 24); | ||
528 | n--; | ||
529 | col++; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | writel(data, p); | ||
534 | } else { | ||
535 | int m = mtd->writesize - col; | ||
536 | |||
537 | if (col >= mtd->writesize) | ||
538 | m += mtd->oobsize; | ||
539 | |||
540 | m = min(n, m) & ~3; | ||
541 | |||
542 | DEBUG(MTD_DEBUG_LEVEL3, | ||
543 | "%s:%d: n = %d, m = %d, i = %d, col = %d\n", | ||
544 | __func__, __LINE__, n, m, i, col); | ||
545 | |||
546 | memcpy(p, &buf[i], m); | ||
547 | col += m; | ||
548 | i += m; | ||
549 | n -= m; | ||
550 | } | ||
551 | } | ||
552 | /* Update saved column address */ | ||
553 | host->col_addr = col; | ||
554 | } | ||
555 | |||
556 | /* Read the data buffer from the NAND Flash. To read the data from NAND | ||
557 | * Flash first the data output cycle is initiated by the NFC, which copies | ||
558 | * the data to RAMbuffer. This data of length len is then copied to buffer buf. | ||
559 | */ | ||
560 | static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | ||
561 | { | ||
562 | struct nand_chip *nand_chip = mtd->priv; | ||
563 | struct mxc_nand_host *host = nand_chip->priv; | ||
564 | int n, col, i = 0; | ||
565 | |||
566 | DEBUG(MTD_DEBUG_LEVEL3, | ||
567 | "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); | ||
568 | |||
569 | col = host->col_addr; | ||
570 | |||
571 | /* Adjust saved column address */ | ||
572 | if (col < mtd->writesize && host->spare_only) | ||
573 | col += mtd->writesize; | ||
574 | |||
575 | n = mtd->writesize + mtd->oobsize - col; | ||
576 | n = min(len, n); | ||
577 | |||
578 | while (n) { | ||
579 | void __iomem *p; | ||
580 | |||
581 | if (col < mtd->writesize) | ||
582 | p = host->regs + MAIN_AREA0 + (col & ~3); | ||
583 | else | ||
584 | p = host->regs + SPARE_AREA0 - | ||
585 | mtd->writesize + (col & ~3); | ||
586 | |||
587 | if (((col | (int)&buf[i]) & 3) || n < 16) { | ||
588 | uint32_t data; | ||
589 | |||
590 | data = readl(p); | ||
591 | switch (col & 3) { | ||
592 | case 0: | ||
593 | if (n) { | ||
594 | buf[i++] = (uint8_t) (data); | ||
595 | n--; | ||
596 | col++; | ||
597 | } | ||
598 | case 1: | ||
599 | if (n) { | ||
600 | buf[i++] = (uint8_t) (data >> 8); | ||
601 | n--; | ||
602 | col++; | ||
603 | } | ||
604 | case 2: | ||
605 | if (n) { | ||
606 | buf[i++] = (uint8_t) (data >> 16); | ||
607 | n--; | ||
608 | col++; | ||
609 | } | ||
610 | case 3: | ||
611 | if (n) { | ||
612 | buf[i++] = (uint8_t) (data >> 24); | ||
613 | n--; | ||
614 | col++; | ||
615 | } | ||
616 | } | ||
617 | } else { | ||
618 | int m = mtd->writesize - col; | ||
619 | |||
620 | if (col >= mtd->writesize) | ||
621 | m += mtd->oobsize; | ||
622 | |||
623 | m = min(n, m) & ~3; | ||
624 | memcpy(&buf[i], p, m); | ||
625 | col += m; | ||
626 | i += m; | ||
627 | n -= m; | ||
628 | } | ||
629 | } | ||
630 | /* Update saved column address */ | ||
631 | host->col_addr = col; | ||
632 | |||
633 | } | ||
634 | |||
635 | /* Used by the upper layer to verify the data in NAND Flash | ||
636 | * with the data in the buf. */ | ||
637 | static int mxc_nand_verify_buf(struct mtd_info *mtd, | ||
638 | const u_char *buf, int len) | ||
639 | { | ||
640 | return -EFAULT; | ||
641 | } | ||
642 | |||
643 | /* This function is used by upper layer for select and | ||
644 | * deselect of the NAND chip */ | ||
645 | static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) | ||
646 | { | ||
647 | struct nand_chip *nand_chip = mtd->priv; | ||
648 | struct mxc_nand_host *host = nand_chip->priv; | ||
649 | |||
650 | #ifdef CONFIG_MTD_NAND_MXC_FORCE_CE | ||
651 | if (chip > 0) { | ||
652 | DEBUG(MTD_DEBUG_LEVEL0, | ||
653 | "ERROR: Illegal chip select (chip = %d)\n", chip); | ||
654 | return; | ||
655 | } | ||
656 | |||
657 | if (chip == -1) { | ||
658 | writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE, | ||
659 | host->regs + NFC_CONFIG1); | ||
660 | return; | ||
661 | } | ||
662 | |||
663 | writew(readw(host->regs + NFC_CONFIG1) | NFC_CE, | ||
664 | host->regs + NFC_CONFIG1); | ||
665 | #endif | ||
666 | |||
667 | switch (chip) { | ||
668 | case -1: | ||
669 | /* Disable the NFC clock */ | ||
670 | if (host->clk_act) { | ||
671 | clk_disable(host->clk); | ||
672 | host->clk_act = 0; | ||
673 | } | ||
674 | break; | ||
675 | case 0: | ||
676 | /* Enable the NFC clock */ | ||
677 | if (!host->clk_act) { | ||
678 | clk_enable(host->clk); | ||
679 | host->clk_act = 1; | ||
680 | } | ||
681 | break; | ||
682 | |||
683 | default: | ||
684 | break; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | /* Used by the upper layer to write command to NAND Flash for | ||
689 | * different operations to be carried out on NAND Flash */ | ||
690 | static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | ||
691 | int column, int page_addr) | ||
692 | { | ||
693 | struct nand_chip *nand_chip = mtd->priv; | ||
694 | struct mxc_nand_host *host = nand_chip->priv; | ||
695 | int useirq = true; | ||
696 | |||
697 | DEBUG(MTD_DEBUG_LEVEL3, | ||
698 | "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", | ||
699 | command, column, page_addr); | ||
700 | |||
701 | /* Reset command state information */ | ||
702 | host->status_request = false; | ||
703 | |||
704 | /* Command pre-processing step */ | ||
705 | switch (command) { | ||
706 | |||
707 | case NAND_CMD_STATUS: | ||
708 | host->col_addr = 0; | ||
709 | host->status_request = true; | ||
710 | break; | ||
711 | |||
712 | case NAND_CMD_READ0: | ||
713 | host->col_addr = column; | ||
714 | host->spare_only = false; | ||
715 | useirq = false; | ||
716 | break; | ||
717 | |||
718 | case NAND_CMD_READOOB: | ||
719 | host->col_addr = column; | ||
720 | host->spare_only = true; | ||
721 | useirq = false; | ||
722 | if (host->pagesize_2k) | ||
723 | command = NAND_CMD_READ0; /* only READ0 is valid */ | ||
724 | break; | ||
725 | |||
726 | case NAND_CMD_SEQIN: | ||
727 | if (column >= mtd->writesize) { | ||
728 | /* | ||
729 | * FIXME: before send SEQIN command for write OOB, | ||
730 | * We must read one page out. | ||
731 | * For K9F1GXX has no READ1 command to set current HW | ||
732 | * pointer to spare area, we must write the whole page | ||
733 | * including OOB together. | ||
734 | */ | ||
735 | if (host->pagesize_2k) | ||
736 | /* call ourself to read a page */ | ||
737 | mxc_nand_command(mtd, NAND_CMD_READ0, 0, | ||
738 | page_addr); | ||
739 | |||
740 | host->col_addr = column - mtd->writesize; | ||
741 | host->spare_only = true; | ||
742 | |||
743 | /* Set program pointer to spare region */ | ||
744 | if (!host->pagesize_2k) | ||
745 | send_cmd(host, NAND_CMD_READOOB, false); | ||
746 | } else { | ||
747 | host->spare_only = false; | ||
748 | host->col_addr = column; | ||
749 | |||
750 | /* Set program pointer to page start */ | ||
751 | if (!host->pagesize_2k) | ||
752 | send_cmd(host, NAND_CMD_READ0, false); | ||
753 | } | ||
754 | useirq = false; | ||
755 | break; | ||
756 | |||
757 | case NAND_CMD_PAGEPROG: | ||
758 | send_prog_page(host, 0, host->spare_only); | ||
759 | |||
760 | if (host->pagesize_2k) { | ||
761 | /* data in 4 areas datas */ | ||
762 | send_prog_page(host, 1, host->spare_only); | ||
763 | send_prog_page(host, 2, host->spare_only); | ||
764 | send_prog_page(host, 3, host->spare_only); | ||
765 | } | ||
766 | |||
767 | break; | ||
768 | |||
769 | case NAND_CMD_ERASE1: | ||
770 | useirq = false; | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | /* Write out the command to the device. */ | ||
775 | send_cmd(host, command, useirq); | ||
776 | |||
777 | /* Write out column address, if necessary */ | ||
778 | if (column != -1) { | ||
779 | /* | ||
780 | * MXC NANDFC can only perform full page+spare or | ||
781 | * spare-only read/write. When the upper layers | ||
782 | * layers perform a read/write buf operation, | ||
783 | * we will used the saved column adress to index into | ||
784 | * the full page. | ||
785 | */ | ||
786 | send_addr(host, 0, page_addr == -1); | ||
787 | if (host->pagesize_2k) | ||
788 | /* another col addr cycle for 2k page */ | ||
789 | send_addr(host, 0, false); | ||
790 | } | ||
791 | |||
792 | /* Write out page address, if necessary */ | ||
793 | if (page_addr != -1) { | ||
794 | /* paddr_0 - p_addr_7 */ | ||
795 | send_addr(host, (page_addr & 0xff), false); | ||
796 | |||
797 | if (host->pagesize_2k) { | ||
798 | send_addr(host, (page_addr >> 8) & 0xFF, false); | ||
799 | if (mtd->size >= 0x40000000) | ||
800 | send_addr(host, (page_addr >> 16) & 0xff, true); | ||
801 | } else { | ||
802 | /* One more address cycle for higher density devices */ | ||
803 | if (mtd->size >= 0x4000000) { | ||
804 | /* paddr_8 - paddr_15 */ | ||
805 | send_addr(host, (page_addr >> 8) & 0xff, false); | ||
806 | send_addr(host, (page_addr >> 16) & 0xff, true); | ||
807 | } else | ||
808 | /* paddr_8 - paddr_15 */ | ||
809 | send_addr(host, (page_addr >> 8) & 0xff, true); | ||
810 | } | ||
811 | } | ||
812 | |||
813 | /* Command post-processing step */ | ||
814 | switch (command) { | ||
815 | |||
816 | case NAND_CMD_RESET: | ||
817 | break; | ||
818 | |||
819 | case NAND_CMD_READOOB: | ||
820 | case NAND_CMD_READ0: | ||
821 | if (host->pagesize_2k) { | ||
822 | /* send read confirm command */ | ||
823 | send_cmd(host, NAND_CMD_READSTART, true); | ||
824 | /* read for each AREA */ | ||
825 | send_read_page(host, 0, host->spare_only); | ||
826 | send_read_page(host, 1, host->spare_only); | ||
827 | send_read_page(host, 2, host->spare_only); | ||
828 | send_read_page(host, 3, host->spare_only); | ||
829 | } else | ||
830 | send_read_page(host, 0, host->spare_only); | ||
831 | break; | ||
832 | |||
833 | case NAND_CMD_READID: | ||
834 | send_read_id(host); | ||
835 | break; | ||
836 | |||
837 | case NAND_CMD_PAGEPROG: | ||
838 | break; | ||
839 | |||
840 | case NAND_CMD_STATUS: | ||
841 | break; | ||
842 | |||
843 | case NAND_CMD_ERASE2: | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | static int __init mxcnd_probe(struct platform_device *pdev) | ||
849 | { | ||
850 | struct nand_chip *this; | ||
851 | struct mtd_info *mtd; | ||
852 | struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; | ||
853 | struct mxc_nand_host *host; | ||
854 | struct resource *res; | ||
855 | uint16_t tmp; | ||
856 | int err = 0, nr_parts = 0; | ||
857 | |||
858 | /* Allocate memory for MTD device structure and private data */ | ||
859 | host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL); | ||
860 | if (!host) | ||
861 | return -ENOMEM; | ||
862 | |||
863 | host->dev = &pdev->dev; | ||
864 | /* structures must be linked */ | ||
865 | this = &host->nand; | ||
866 | mtd = &host->mtd; | ||
867 | mtd->priv = this; | ||
868 | mtd->owner = THIS_MODULE; | ||
869 | |||
870 | /* 50 us command delay time */ | ||
871 | this->chip_delay = 5; | ||
872 | |||
873 | this->priv = host; | ||
874 | this->dev_ready = mxc_nand_dev_ready; | ||
875 | this->cmdfunc = mxc_nand_command; | ||
876 | this->select_chip = mxc_nand_select_chip; | ||
877 | this->read_byte = mxc_nand_read_byte; | ||
878 | this->read_word = mxc_nand_read_word; | ||
879 | this->write_buf = mxc_nand_write_buf; | ||
880 | this->read_buf = mxc_nand_read_buf; | ||
881 | this->verify_buf = mxc_nand_verify_buf; | ||
882 | |||
883 | host->clk = clk_get(&pdev->dev, "nfc_clk"); | ||
884 | if (IS_ERR(host->clk)) | ||
885 | goto eclk; | ||
886 | |||
887 | clk_enable(host->clk); | ||
888 | host->clk_act = 1; | ||
889 | |||
890 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
891 | if (!res) { | ||
892 | err = -ENODEV; | ||
893 | goto eres; | ||
894 | } | ||
895 | |||
896 | host->regs = ioremap(res->start, res->end - res->start + 1); | ||
897 | if (!host->regs) { | ||
898 | err = -EIO; | ||
899 | goto eres; | ||
900 | } | ||
901 | |||
902 | tmp = readw(host->regs + NFC_CONFIG1); | ||
903 | tmp |= NFC_INT_MSK; | ||
904 | writew(tmp, host->regs + NFC_CONFIG1); | ||
905 | |||
906 | init_waitqueue_head(&host->irq_waitq); | ||
907 | |||
908 | host->irq = platform_get_irq(pdev, 0); | ||
909 | |||
910 | err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host); | ||
911 | if (err) | ||
912 | goto eirq; | ||
913 | |||
914 | if (pdata->hw_ecc) { | ||
915 | this->ecc.calculate = mxc_nand_calculate_ecc; | ||
916 | this->ecc.hwctl = mxc_nand_enable_hwecc; | ||
917 | this->ecc.correct = mxc_nand_correct_data; | ||
918 | this->ecc.mode = NAND_ECC_HW; | ||
919 | this->ecc.size = 512; | ||
920 | this->ecc.bytes = 3; | ||
921 | this->ecc.layout = &nand_hw_eccoob_8; | ||
922 | tmp = readw(host->regs + NFC_CONFIG1); | ||
923 | tmp |= NFC_ECC_EN; | ||
924 | writew(tmp, host->regs + NFC_CONFIG1); | ||
925 | } else { | ||
926 | this->ecc.size = 512; | ||
927 | this->ecc.bytes = 3; | ||
928 | this->ecc.layout = &nand_hw_eccoob_8; | ||
929 | this->ecc.mode = NAND_ECC_SOFT; | ||
930 | tmp = readw(host->regs + NFC_CONFIG1); | ||
931 | tmp &= ~NFC_ECC_EN; | ||
932 | writew(tmp, host->regs + NFC_CONFIG1); | ||
933 | } | ||
934 | |||
935 | /* Reset NAND */ | ||
936 | this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
937 | |||
938 | /* preset operation */ | ||
939 | /* Unlock the internal RAM Buffer */ | ||
940 | writew(0x2, host->regs + NFC_CONFIG); | ||
941 | |||
942 | /* Blocks to be unlocked */ | ||
943 | writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR); | ||
944 | writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR); | ||
945 | |||
946 | /* Unlock Block Command for given address range */ | ||
947 | writew(0x4, host->regs + NFC_WRPROT); | ||
948 | |||
949 | /* NAND bus width determines access funtions used by upper layer */ | ||
950 | if (pdata->width == 2) { | ||
951 | this->options |= NAND_BUSWIDTH_16; | ||
952 | this->ecc.layout = &nand_hw_eccoob_16; | ||
953 | } | ||
954 | |||
955 | host->pagesize_2k = 0; | ||
956 | |||
957 | /* Scan to find existence of the device */ | ||
958 | if (nand_scan(mtd, 1)) { | ||
959 | DEBUG(MTD_DEBUG_LEVEL0, | ||
960 | "MXC_ND: Unable to find any NAND device.\n"); | ||
961 | err = -ENXIO; | ||
962 | goto escan; | ||
963 | } | ||
964 | |||
965 | /* Register the partitions */ | ||
966 | #ifdef CONFIG_MTD_PARTITIONS | ||
967 | nr_parts = | ||
968 | parse_mtd_partitions(mtd, part_probes, &host->parts, 0); | ||
969 | if (nr_parts > 0) | ||
970 | add_mtd_partitions(mtd, host->parts, nr_parts); | ||
971 | else | ||
972 | #endif | ||
973 | { | ||
974 | pr_info("Registering %s as whole device\n", mtd->name); | ||
975 | add_mtd_device(mtd); | ||
976 | } | ||
977 | |||
978 | platform_set_drvdata(pdev, host); | ||
979 | |||
980 | return 0; | ||
981 | |||
982 | escan: | ||
983 | free_irq(host->irq, NULL); | ||
984 | eirq: | ||
985 | iounmap(host->regs); | ||
986 | eres: | ||
987 | clk_put(host->clk); | ||
988 | eclk: | ||
989 | kfree(host); | ||
990 | |||
991 | return err; | ||
992 | } | ||
993 | |||
994 | static int __devexit mxcnd_remove(struct platform_device *pdev) | ||
995 | { | ||
996 | struct mxc_nand_host *host = platform_get_drvdata(pdev); | ||
997 | |||
998 | clk_put(host->clk); | ||
999 | |||
1000 | platform_set_drvdata(pdev, NULL); | ||
1001 | |||
1002 | nand_release(&host->mtd); | ||
1003 | free_irq(host->irq, NULL); | ||
1004 | iounmap(host->regs); | ||
1005 | kfree(host); | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | #ifdef CONFIG_PM | ||
1011 | static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state) | ||
1012 | { | ||
1013 | struct mtd_info *info = platform_get_drvdata(pdev); | ||
1014 | int ret = 0; | ||
1015 | |||
1016 | DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n"); | ||
1017 | if (info) | ||
1018 | ret = info->suspend(info); | ||
1019 | |||
1020 | /* Disable the NFC clock */ | ||
1021 | clk_disable(nfc_clk); /* FIXME */ | ||
1022 | |||
1023 | return ret; | ||
1024 | } | ||
1025 | |||
1026 | static int mxcnd_resume(struct platform_device *pdev) | ||
1027 | { | ||
1028 | struct mtd_info *info = platform_get_drvdata(pdev); | ||
1029 | int ret = 0; | ||
1030 | |||
1031 | DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n"); | ||
1032 | /* Enable the NFC clock */ | ||
1033 | clk_enable(nfc_clk); /* FIXME */ | ||
1034 | |||
1035 | if (info) | ||
1036 | info->resume(info); | ||
1037 | |||
1038 | return ret; | ||
1039 | } | ||
1040 | |||
1041 | #else | ||
1042 | # define mxcnd_suspend NULL | ||
1043 | # define mxcnd_resume NULL | ||
1044 | #endif /* CONFIG_PM */ | ||
1045 | |||
1046 | static struct platform_driver mxcnd_driver = { | ||
1047 | .driver = { | ||
1048 | .name = DRIVER_NAME, | ||
1049 | }, | ||
1050 | .remove = __exit_p(mxcnd_remove), | ||
1051 | .suspend = mxcnd_suspend, | ||
1052 | .resume = mxcnd_resume, | ||
1053 | }; | ||
1054 | |||
1055 | static int __init mxc_nd_init(void) | ||
1056 | { | ||
1057 | /* Register the device driver structure. */ | ||
1058 | pr_info("MXC MTD nand Driver\n"); | ||
1059 | if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) { | ||
1060 | printk(KERN_ERR "Driver register failed for mxcnd_driver\n"); | ||
1061 | return -ENODEV; | ||
1062 | } | ||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | static void __exit mxc_nd_cleanup(void) | ||
1067 | { | ||
1068 | /* Unregister the device structure */ | ||
1069 | platform_driver_unregister(&mxcnd_driver); | ||
1070 | } | ||
1071 | |||
1072 | module_init(mxc_nd_init); | ||
1073 | module_exit(mxc_nd_cleanup); | ||
1074 | |||
1075 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
1076 | MODULE_DESCRIPTION("MXC NAND MTD driver"); | ||
1077 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d1129bae6c27..0a9c9cd33f96 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -801,9 +801,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
801 | * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function | 801 | * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function |
802 | * @mtd: mtd info structure | 802 | * @mtd: mtd info structure |
803 | * @chip: nand chip info structure | 803 | * @chip: nand chip info structure |
804 | * @dataofs offset of requested data within the page | 804 | * @data_offs: offset of requested data within the page |
805 | * @readlen data length | 805 | * @readlen: data length |
806 | * @buf: buffer to store read data | 806 | * @bufpoi: buffer to store read data |
807 | */ | 807 | */ |
808 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) | 808 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) |
809 | { | 809 | { |
@@ -2042,7 +2042,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2042 | return -EINVAL; | 2042 | return -EINVAL; |
2043 | } | 2043 | } |
2044 | 2044 | ||
2045 | instr->fail_addr = 0xffffffff; | 2045 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
2046 | 2046 | ||
2047 | /* Grab the lock and see if the device is available */ | 2047 | /* Grab the lock and see if the device is available */ |
2048 | nand_get_device(chip, mtd, FL_ERASING); | 2048 | nand_get_device(chip, mtd, FL_ERASING); |
@@ -2318,6 +2318,12 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2318 | /* Select the device */ | 2318 | /* Select the device */ |
2319 | chip->select_chip(mtd, 0); | 2319 | chip->select_chip(mtd, 0); |
2320 | 2320 | ||
2321 | /* | ||
2322 | * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) | ||
2323 | * after power-up | ||
2324 | */ | ||
2325 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
2326 | |||
2321 | /* Send the command for reading device ID */ | 2327 | /* Send the command for reading device ID */ |
2322 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 2328 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
2323 | 2329 | ||
@@ -2488,6 +2494,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) | |||
2488 | /* Check for a chip array */ | 2494 | /* Check for a chip array */ |
2489 | for (i = 1; i < maxchips; i++) { | 2495 | for (i = 1; i < maxchips; i++) { |
2490 | chip->select_chip(mtd, i); | 2496 | chip->select_chip(mtd, i); |
2497 | /* See comment in nand_get_flash_type for reset */ | ||
2498 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); | ||
2491 | /* Send the command for reading device ID */ | 2499 | /* Send the command for reading device ID */ |
2492 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | 2500 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
2493 | /* Read manufacturer and device IDs */ | 2501 | /* Read manufacturer and device IDs */ |
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 918a806a8471..868147acce2c 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -1,13 +1,18 @@ | |||
1 | /* | 1 | /* |
2 | * This file contains an ECC algorithm from Toshiba that detects and | 2 | * This file contains an ECC algorithm that detects and corrects 1 bit |
3 | * corrects 1 bit errors in a 256 byte block of data. | 3 | * errors in a 256 byte block of data. |
4 | * | 4 | * |
5 | * drivers/mtd/nand/nand_ecc.c | 5 | * drivers/mtd/nand/nand_ecc.c |
6 | * | 6 | * |
7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright © 2008 Koninklijke Philips Electronics NV. |
8 | * Toshiba America Electronics Components, Inc. | 8 | * Author: Frans Meulenbroeks |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> | 10 | * Completely replaces the previous ECC implementation which was written by: |
11 | * Steven J. Hill (sjhill@realitydiluted.com) | ||
12 | * Thomas Gleixner (tglx@linutronix.de) | ||
13 | * | ||
14 | * Information on how this algorithm works and how it was developed | ||
15 | * can be found in Documentation/mtd/nand_ecc.txt | ||
11 | * | 16 | * |
12 | * This file is free software; you can redistribute it and/or modify it | 17 | * This file is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 18 | * under the terms of the GNU General Public License as published by the |
@@ -23,174 +28,475 @@ | |||
23 | * with this file; if not, write to the Free Software Foundation, Inc., | 28 | * with this file; if not, write to the Free Software Foundation, Inc., |
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 29 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
25 | * | 30 | * |
26 | * As a special exception, if other files instantiate templates or use | ||
27 | * macros or inline functions from these files, or you compile these | ||
28 | * files and link them with other works to produce a work based on these | ||
29 | * files, these files do not by themselves cause the resulting work to be | ||
30 | * covered by the GNU General Public License. However the source code for | ||
31 | * these files must still be made available in accordance with section (3) | ||
32 | * of the GNU General Public License. | ||
33 | * | ||
34 | * This exception does not invalidate any other reasons why a work based on | ||
35 | * this file might be covered by the GNU General Public License. | ||
36 | */ | 31 | */ |
37 | 32 | ||
33 | /* | ||
34 | * The STANDALONE macro is useful when running the code outside the kernel | ||
35 | * e.g. when running the code in a testbed or a benchmark program. | ||
36 | * When STANDALONE is used, the module related macros are commented out | ||
37 | * as well as the linux include files. | ||
38 | * Instead a private definition of mtd_info is given to satisfy the compiler | ||
39 | * (the code does not use mtd_info, so the code does not care) | ||
40 | */ | ||
41 | #ifndef STANDALONE | ||
38 | #include <linux/types.h> | 42 | #include <linux/types.h> |
39 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
40 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/mtd/mtd.h> | ||
46 | #include <linux/mtd/nand.h> | ||
41 | #include <linux/mtd/nand_ecc.h> | 47 | #include <linux/mtd/nand_ecc.h> |
48 | #include <asm/byteorder.h> | ||
49 | #else | ||
50 | #include <stdint.h> | ||
51 | struct mtd_info; | ||
52 | #define EXPORT_SYMBOL(x) /* x */ | ||
53 | |||
54 | #define MODULE_LICENSE(x) /* x */ | ||
55 | #define MODULE_AUTHOR(x) /* x */ | ||
56 | #define MODULE_DESCRIPTION(x) /* x */ | ||
57 | |||
58 | #define printk printf | ||
59 | #define KERN_ERR "" | ||
60 | #endif | ||
61 | |||
62 | /* | ||
63 | * invparity is a 256 byte table that contains the odd parity | ||
64 | * for each byte. So if the number of bits in a byte is even, | ||
65 | * the array element is 1, and when the number of bits is odd | ||
66 | * the array eleemnt is 0. | ||
67 | */ | ||
68 | static const char invparity[256] = { | ||
69 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
70 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
71 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
72 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
73 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
74 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
75 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
76 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
77 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
78 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
79 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
80 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
81 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
82 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
83 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
84 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 | ||
85 | }; | ||
86 | |||
87 | /* | ||
88 | * bitsperbyte contains the number of bits per byte | ||
89 | * this is only used for testing and repairing parity | ||
90 | * (a precalculated value slightly improves performance) | ||
91 | */ | ||
92 | static const char bitsperbyte[256] = { | ||
93 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, | ||
94 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
95 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
96 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
97 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
98 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
99 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
100 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
101 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
102 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
103 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
104 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
105 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
106 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
107 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
108 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, | ||
109 | }; | ||
42 | 110 | ||
43 | /* | 111 | /* |
44 | * Pre-calculated 256-way 1 byte column parity | 112 | * addressbits is a lookup table to filter out the bits from the xor-ed |
113 | * ecc data that identify the faulty location. | ||
114 | * this is only used for repairing parity | ||
115 | * see the comments in nand_correct_data for more details | ||
45 | */ | 116 | */ |
46 | static const u_char nand_ecc_precalc_table[] = { | 117 | static const char addressbits[256] = { |
47 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, | 118 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
48 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | 119 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
49 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | 120 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
50 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | 121 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
51 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | 122 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
52 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | 123 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
53 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | 124 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
54 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | 125 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
55 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | 126 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
56 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | 127 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
57 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | 128 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
58 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | 129 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
59 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | 130 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
60 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | 131 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
61 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | 132 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
62 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 | 133 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
134 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
135 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
136 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
137 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
138 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
139 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, | ||
140 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
141 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, | ||
142 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
143 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
144 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
145 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
146 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
147 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, | ||
148 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
149 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f | ||
63 | }; | 150 | }; |
64 | 151 | ||
65 | /** | 152 | /** |
66 | * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block | 153 | * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte |
154 | * block | ||
67 | * @mtd: MTD block structure | 155 | * @mtd: MTD block structure |
68 | * @dat: raw data | 156 | * @buf: input buffer with raw data |
69 | * @ecc_code: buffer for ECC | 157 | * @code: output buffer with ECC |
70 | */ | 158 | */ |
71 | int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | 159 | int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, |
72 | u_char *ecc_code) | 160 | unsigned char *code) |
73 | { | 161 | { |
74 | uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; | ||
75 | int i; | 162 | int i; |
163 | const uint32_t *bp = (uint32_t *)buf; | ||
164 | /* 256 or 512 bytes/ecc */ | ||
165 | const uint32_t eccsize_mult = | ||
166 | (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; | ||
167 | uint32_t cur; /* current value in buffer */ | ||
168 | /* rp0..rp15..rp17 are the various accumulated parities (per byte) */ | ||
169 | uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; | ||
170 | uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16; | ||
171 | uint32_t uninitialized_var(rp17); /* to make compiler happy */ | ||
172 | uint32_t par; /* the cumulative parity for all data */ | ||
173 | uint32_t tmppar; /* the cumulative parity for this iteration; | ||
174 | for rp12, rp14 and rp16 at the end of the | ||
175 | loop */ | ||
176 | |||
177 | par = 0; | ||
178 | rp4 = 0; | ||
179 | rp6 = 0; | ||
180 | rp8 = 0; | ||
181 | rp10 = 0; | ||
182 | rp12 = 0; | ||
183 | rp14 = 0; | ||
184 | rp16 = 0; | ||
185 | |||
186 | /* | ||
187 | * The loop is unrolled a number of times; | ||
188 | * This avoids if statements to decide on which rp value to update | ||
189 | * Also we process the data by longwords. | ||
190 | * Note: passing unaligned data might give a performance penalty. | ||
191 | * It is assumed that the buffers are aligned. | ||
192 | * tmppar is the cumulative sum of this iteration. | ||
193 | * needed for calculating rp12, rp14, rp16 and par | ||
194 | * also used as a performance improvement for rp6, rp8 and rp10 | ||
195 | */ | ||
196 | for (i = 0; i < eccsize_mult << 2; i++) { | ||
197 | cur = *bp++; | ||
198 | tmppar = cur; | ||
199 | rp4 ^= cur; | ||
200 | cur = *bp++; | ||
201 | tmppar ^= cur; | ||
202 | rp6 ^= tmppar; | ||
203 | cur = *bp++; | ||
204 | tmppar ^= cur; | ||
205 | rp4 ^= cur; | ||
206 | cur = *bp++; | ||
207 | tmppar ^= cur; | ||
208 | rp8 ^= tmppar; | ||
76 | 209 | ||
77 | /* Initialize variables */ | 210 | cur = *bp++; |
78 | reg1 = reg2 = reg3 = 0; | 211 | tmppar ^= cur; |
212 | rp4 ^= cur; | ||
213 | rp6 ^= cur; | ||
214 | cur = *bp++; | ||
215 | tmppar ^= cur; | ||
216 | rp6 ^= cur; | ||
217 | cur = *bp++; | ||
218 | tmppar ^= cur; | ||
219 | rp4 ^= cur; | ||
220 | cur = *bp++; | ||
221 | tmppar ^= cur; | ||
222 | rp10 ^= tmppar; | ||
79 | 223 | ||
80 | /* Build up column parity */ | 224 | cur = *bp++; |
81 | for(i = 0; i < 256; i++) { | 225 | tmppar ^= cur; |
82 | /* Get CP0 - CP5 from table */ | 226 | rp4 ^= cur; |
83 | idx = nand_ecc_precalc_table[*dat++]; | 227 | rp6 ^= cur; |
84 | reg1 ^= (idx & 0x3f); | 228 | rp8 ^= cur; |
229 | cur = *bp++; | ||
230 | tmppar ^= cur; | ||
231 | rp6 ^= cur; | ||
232 | rp8 ^= cur; | ||
233 | cur = *bp++; | ||
234 | tmppar ^= cur; | ||
235 | rp4 ^= cur; | ||
236 | rp8 ^= cur; | ||
237 | cur = *bp++; | ||
238 | tmppar ^= cur; | ||
239 | rp8 ^= cur; | ||
85 | 240 | ||
86 | /* All bit XOR = 1 ? */ | 241 | cur = *bp++; |
87 | if (idx & 0x40) { | 242 | tmppar ^= cur; |
88 | reg3 ^= (uint8_t) i; | 243 | rp4 ^= cur; |
89 | reg2 ^= ~((uint8_t) i); | 244 | rp6 ^= cur; |
90 | } | 245 | cur = *bp++; |
246 | tmppar ^= cur; | ||
247 | rp6 ^= cur; | ||
248 | cur = *bp++; | ||
249 | tmppar ^= cur; | ||
250 | rp4 ^= cur; | ||
251 | cur = *bp++; | ||
252 | tmppar ^= cur; | ||
253 | |||
254 | par ^= tmppar; | ||
255 | if ((i & 0x1) == 0) | ||
256 | rp12 ^= tmppar; | ||
257 | if ((i & 0x2) == 0) | ||
258 | rp14 ^= tmppar; | ||
259 | if (eccsize_mult == 2 && (i & 0x4) == 0) | ||
260 | rp16 ^= tmppar; | ||
91 | } | 261 | } |
92 | 262 | ||
93 | /* Create non-inverted ECC code from line parity */ | 263 | /* |
94 | tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ | 264 | * handle the fact that we use longword operations |
95 | tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ | 265 | * we'll bring rp4..rp14..rp16 back to single byte entities by |
96 | tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ | 266 | * shifting and xoring first fold the upper and lower 16 bits, |
97 | tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ | 267 | * then the upper and lower 8 bits. |
98 | tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ | 268 | */ |
99 | tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ | 269 | rp4 ^= (rp4 >> 16); |
100 | tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ | 270 | rp4 ^= (rp4 >> 8); |
101 | tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ | 271 | rp4 &= 0xff; |
102 | 272 | rp6 ^= (rp6 >> 16); | |
103 | tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ | 273 | rp6 ^= (rp6 >> 8); |
104 | tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ | 274 | rp6 &= 0xff; |
105 | tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ | 275 | rp8 ^= (rp8 >> 16); |
106 | tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ | 276 | rp8 ^= (rp8 >> 8); |
107 | tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ | 277 | rp8 &= 0xff; |
108 | tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ | 278 | rp10 ^= (rp10 >> 16); |
109 | tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ | 279 | rp10 ^= (rp10 >> 8); |
110 | tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ | 280 | rp10 &= 0xff; |
111 | 281 | rp12 ^= (rp12 >> 16); | |
112 | /* Calculate final ECC code */ | 282 | rp12 ^= (rp12 >> 8); |
113 | #ifdef CONFIG_MTD_NAND_ECC_SMC | 283 | rp12 &= 0xff; |
114 | ecc_code[0] = ~tmp2; | 284 | rp14 ^= (rp14 >> 16); |
115 | ecc_code[1] = ~tmp1; | 285 | rp14 ^= (rp14 >> 8); |
286 | rp14 &= 0xff; | ||
287 | if (eccsize_mult == 2) { | ||
288 | rp16 ^= (rp16 >> 16); | ||
289 | rp16 ^= (rp16 >> 8); | ||
290 | rp16 &= 0xff; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * we also need to calculate the row parity for rp0..rp3 | ||
295 | * This is present in par, because par is now | ||
296 | * rp3 rp3 rp2 rp2 in little endian and | ||
297 | * rp2 rp2 rp3 rp3 in big endian | ||
298 | * as well as | ||
299 | * rp1 rp0 rp1 rp0 in little endian and | ||
300 | * rp0 rp1 rp0 rp1 in big endian | ||
301 | * First calculate rp2 and rp3 | ||
302 | */ | ||
303 | #ifdef __BIG_ENDIAN | ||
304 | rp2 = (par >> 16); | ||
305 | rp2 ^= (rp2 >> 8); | ||
306 | rp2 &= 0xff; | ||
307 | rp3 = par & 0xffff; | ||
308 | rp3 ^= (rp3 >> 8); | ||
309 | rp3 &= 0xff; | ||
116 | #else | 310 | #else |
117 | ecc_code[0] = ~tmp1; | 311 | rp3 = (par >> 16); |
118 | ecc_code[1] = ~tmp2; | 312 | rp3 ^= (rp3 >> 8); |
313 | rp3 &= 0xff; | ||
314 | rp2 = par & 0xffff; | ||
315 | rp2 ^= (rp2 >> 8); | ||
316 | rp2 &= 0xff; | ||
119 | #endif | 317 | #endif |
120 | ecc_code[2] = ((~reg1) << 2) | 0x03; | ||
121 | 318 | ||
122 | return 0; | 319 | /* reduce par to 16 bits then calculate rp1 and rp0 */ |
123 | } | 320 | par ^= (par >> 16); |
124 | EXPORT_SYMBOL(nand_calculate_ecc); | 321 | #ifdef __BIG_ENDIAN |
322 | rp0 = (par >> 8) & 0xff; | ||
323 | rp1 = (par & 0xff); | ||
324 | #else | ||
325 | rp1 = (par >> 8) & 0xff; | ||
326 | rp0 = (par & 0xff); | ||
327 | #endif | ||
125 | 328 | ||
126 | static inline int countbits(uint32_t byte) | 329 | /* finally reduce par to 8 bits */ |
127 | { | 330 | par ^= (par >> 8); |
128 | int res = 0; | 331 | par &= 0xff; |
129 | 332 | ||
130 | for (;byte; byte >>= 1) | 333 | /* |
131 | res += byte & 0x01; | 334 | * and calculate rp5..rp15..rp17 |
132 | return res; | 335 | * note that par = rp4 ^ rp5 and due to the commutative property |
336 | * of the ^ operator we can say: | ||
337 | * rp5 = (par ^ rp4); | ||
338 | * The & 0xff seems superfluous, but benchmarking learned that | ||
339 | * leaving it out gives slightly worse results. No idea why, probably | ||
340 | * it has to do with the way the pipeline in pentium is organized. | ||
341 | */ | ||
342 | rp5 = (par ^ rp4) & 0xff; | ||
343 | rp7 = (par ^ rp6) & 0xff; | ||
344 | rp9 = (par ^ rp8) & 0xff; | ||
345 | rp11 = (par ^ rp10) & 0xff; | ||
346 | rp13 = (par ^ rp12) & 0xff; | ||
347 | rp15 = (par ^ rp14) & 0xff; | ||
348 | if (eccsize_mult == 2) | ||
349 | rp17 = (par ^ rp16) & 0xff; | ||
350 | |||
351 | /* | ||
352 | * Finally calculate the ecc bits. | ||
353 | * Again here it might seem that there are performance optimisations | ||
354 | * possible, but benchmarks showed that on the system this is developed | ||
355 | * the code below is the fastest | ||
356 | */ | ||
357 | #ifdef CONFIG_MTD_NAND_ECC_SMC | ||
358 | code[0] = | ||
359 | (invparity[rp7] << 7) | | ||
360 | (invparity[rp6] << 6) | | ||
361 | (invparity[rp5] << 5) | | ||
362 | (invparity[rp4] << 4) | | ||
363 | (invparity[rp3] << 3) | | ||
364 | (invparity[rp2] << 2) | | ||
365 | (invparity[rp1] << 1) | | ||
366 | (invparity[rp0]); | ||
367 | code[1] = | ||
368 | (invparity[rp15] << 7) | | ||
369 | (invparity[rp14] << 6) | | ||
370 | (invparity[rp13] << 5) | | ||
371 | (invparity[rp12] << 4) | | ||
372 | (invparity[rp11] << 3) | | ||
373 | (invparity[rp10] << 2) | | ||
374 | (invparity[rp9] << 1) | | ||
375 | (invparity[rp8]); | ||
376 | #else | ||
377 | code[1] = | ||
378 | (invparity[rp7] << 7) | | ||
379 | (invparity[rp6] << 6) | | ||
380 | (invparity[rp5] << 5) | | ||
381 | (invparity[rp4] << 4) | | ||
382 | (invparity[rp3] << 3) | | ||
383 | (invparity[rp2] << 2) | | ||
384 | (invparity[rp1] << 1) | | ||
385 | (invparity[rp0]); | ||
386 | code[0] = | ||
387 | (invparity[rp15] << 7) | | ||
388 | (invparity[rp14] << 6) | | ||
389 | (invparity[rp13] << 5) | | ||
390 | (invparity[rp12] << 4) | | ||
391 | (invparity[rp11] << 3) | | ||
392 | (invparity[rp10] << 2) | | ||
393 | (invparity[rp9] << 1) | | ||
394 | (invparity[rp8]); | ||
395 | #endif | ||
396 | if (eccsize_mult == 1) | ||
397 | code[2] = | ||
398 | (invparity[par & 0xf0] << 7) | | ||
399 | (invparity[par & 0x0f] << 6) | | ||
400 | (invparity[par & 0xcc] << 5) | | ||
401 | (invparity[par & 0x33] << 4) | | ||
402 | (invparity[par & 0xaa] << 3) | | ||
403 | (invparity[par & 0x55] << 2) | | ||
404 | 3; | ||
405 | else | ||
406 | code[2] = | ||
407 | (invparity[par & 0xf0] << 7) | | ||
408 | (invparity[par & 0x0f] << 6) | | ||
409 | (invparity[par & 0xcc] << 5) | | ||
410 | (invparity[par & 0x33] << 4) | | ||
411 | (invparity[par & 0xaa] << 3) | | ||
412 | (invparity[par & 0x55] << 2) | | ||
413 | (invparity[rp17] << 1) | | ||
414 | (invparity[rp16] << 0); | ||
415 | return 0; | ||
133 | } | 416 | } |
417 | EXPORT_SYMBOL(nand_calculate_ecc); | ||
134 | 418 | ||
135 | /** | 419 | /** |
136 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) | 420 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) |
137 | * @mtd: MTD block structure | 421 | * @mtd: MTD block structure |
138 | * @dat: raw data read from the chip | 422 | * @buf: raw data read from the chip |
139 | * @read_ecc: ECC from the chip | 423 | * @read_ecc: ECC from the chip |
140 | * @calc_ecc: the ECC calculated from raw data | 424 | * @calc_ecc: the ECC calculated from raw data |
141 | * | 425 | * |
142 | * Detect and correct a 1 bit error for 256 byte block | 426 | * Detect and correct a 1 bit error for 256/512 byte block |
143 | */ | 427 | */ |
144 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, | 428 | int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, |
145 | u_char *read_ecc, u_char *calc_ecc) | 429 | unsigned char *read_ecc, unsigned char *calc_ecc) |
146 | { | 430 | { |
147 | uint8_t s0, s1, s2; | 431 | unsigned char b0, b1, b2; |
432 | unsigned char byte_addr, bit_addr; | ||
433 | /* 256 or 512 bytes/ecc */ | ||
434 | const uint32_t eccsize_mult = | ||
435 | (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; | ||
148 | 436 | ||
437 | /* | ||
438 | * b0 to b2 indicate which bit is faulty (if any) | ||
439 | * we might need the xor result more than once, | ||
440 | * so keep them in a local var | ||
441 | */ | ||
149 | #ifdef CONFIG_MTD_NAND_ECC_SMC | 442 | #ifdef CONFIG_MTD_NAND_ECC_SMC |
150 | s0 = calc_ecc[0] ^ read_ecc[0]; | 443 | b0 = read_ecc[0] ^ calc_ecc[0]; |
151 | s1 = calc_ecc[1] ^ read_ecc[1]; | 444 | b1 = read_ecc[1] ^ calc_ecc[1]; |
152 | s2 = calc_ecc[2] ^ read_ecc[2]; | ||
153 | #else | 445 | #else |
154 | s1 = calc_ecc[0] ^ read_ecc[0]; | 446 | b0 = read_ecc[1] ^ calc_ecc[1]; |
155 | s0 = calc_ecc[1] ^ read_ecc[1]; | 447 | b1 = read_ecc[0] ^ calc_ecc[0]; |
156 | s2 = calc_ecc[2] ^ read_ecc[2]; | ||
157 | #endif | 448 | #endif |
158 | if ((s0 | s1 | s2) == 0) | 449 | b2 = read_ecc[2] ^ calc_ecc[2]; |
159 | return 0; | ||
160 | |||
161 | /* Check for a single bit error */ | ||
162 | if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && | ||
163 | ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && | ||
164 | ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { | ||
165 | 450 | ||
166 | uint32_t byteoffs, bitnum; | 451 | /* check if there are any bitfaults */ |
167 | 452 | ||
168 | byteoffs = (s1 << 0) & 0x80; | 453 | /* repeated if statements are slightly more efficient than switch ... */ |
169 | byteoffs |= (s1 << 1) & 0x40; | 454 | /* ordered in order of likelihood */ |
170 | byteoffs |= (s1 << 2) & 0x20; | ||
171 | byteoffs |= (s1 << 3) & 0x10; | ||
172 | 455 | ||
173 | byteoffs |= (s0 >> 4) & 0x08; | 456 | if ((b0 | b1 | b2) == 0) |
174 | byteoffs |= (s0 >> 3) & 0x04; | 457 | return 0; /* no error */ |
175 | byteoffs |= (s0 >> 2) & 0x02; | ||
176 | byteoffs |= (s0 >> 1) & 0x01; | ||
177 | |||
178 | bitnum = (s2 >> 5) & 0x04; | ||
179 | bitnum |= (s2 >> 4) & 0x02; | ||
180 | bitnum |= (s2 >> 3) & 0x01; | ||
181 | |||
182 | dat[byteoffs] ^= (1 << bitnum); | ||
183 | 458 | ||
459 | if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) && | ||
460 | (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) && | ||
461 | ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) || | ||
462 | (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) { | ||
463 | /* single bit error */ | ||
464 | /* | ||
465 | * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty | ||
466 | * byte, cp 5/3/1 indicate the faulty bit. | ||
467 | * A lookup table (called addressbits) is used to filter | ||
468 | * the bits from the byte they are in. | ||
469 | * A marginal optimisation is possible by having three | ||
470 | * different lookup tables. | ||
471 | * One as we have now (for b0), one for b2 | ||
472 | * (that would avoid the >> 1), and one for b1 (with all values | ||
473 | * << 4). However it was felt that introducing two more tables | ||
474 | * hardly justify the gain. | ||
475 | * | ||
476 | * The b2 shift is there to get rid of the lowest two bits. | ||
477 | * We could also do addressbits[b2] >> 1 but for the | ||
478 | * performace it does not make any difference | ||
479 | */ | ||
480 | if (eccsize_mult == 1) | ||
481 | byte_addr = (addressbits[b1] << 4) + addressbits[b0]; | ||
482 | else | ||
483 | byte_addr = (addressbits[b2 & 0x3] << 8) + | ||
484 | (addressbits[b1] << 4) + addressbits[b0]; | ||
485 | bit_addr = addressbits[b2 >> 2]; | ||
486 | /* flip the bit */ | ||
487 | buf[byte_addr] ^= (1 << bit_addr); | ||
184 | return 1; | 488 | return 1; |
185 | } | ||
186 | 489 | ||
187 | if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) | 490 | } |
188 | return 1; | 491 | /* count nr of bits; use table lookup, faster than calculating it */ |
492 | if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) | ||
493 | return 1; /* error in ecc data; no action needed */ | ||
189 | 494 | ||
190 | return -EBADMSG; | 495 | printk(KERN_ERR "uncorrectable error : "); |
496 | return -1; | ||
191 | } | 497 | } |
192 | EXPORT_SYMBOL(nand_correct_data); | 498 | EXPORT_SYMBOL(nand_correct_data); |
193 | 499 | ||
194 | MODULE_LICENSE("GPL"); | 500 | MODULE_LICENSE("GPL"); |
195 | MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); | 501 | MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>"); |
196 | MODULE_DESCRIPTION("Generic NAND ECC support"); | 502 | MODULE_DESCRIPTION("Generic NAND ECC support"); |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 556e8131ecdc..ae7c57781a68 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/list.h> | 39 | #include <linux/list.h> |
40 | #include <linux/random.h> | 40 | #include <linux/random.h> |
41 | #include <asm/div64.h> | ||
42 | 41 | ||
43 | /* Default simulator parameters values */ | 42 | /* Default simulator parameters values */ |
44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a64ad15b8fdd..c0fa9c9edf08 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -115,55 +115,11 @@ enum { | |||
115 | STATE_PIO_WRITING, | 115 | STATE_PIO_WRITING, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | struct pxa3xx_nand_timing { | ||
119 | unsigned int tCH; /* Enable signal hold time */ | ||
120 | unsigned int tCS; /* Enable signal setup time */ | ||
121 | unsigned int tWH; /* ND_nWE high duration */ | ||
122 | unsigned int tWP; /* ND_nWE pulse time */ | ||
123 | unsigned int tRH; /* ND_nRE high duration */ | ||
124 | unsigned int tRP; /* ND_nRE pulse width */ | ||
125 | unsigned int tR; /* ND_nWE high to ND_nRE low for read */ | ||
126 | unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ | ||
127 | unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ | ||
128 | }; | ||
129 | |||
130 | struct pxa3xx_nand_cmdset { | ||
131 | uint16_t read1; | ||
132 | uint16_t read2; | ||
133 | uint16_t program; | ||
134 | uint16_t read_status; | ||
135 | uint16_t read_id; | ||
136 | uint16_t erase; | ||
137 | uint16_t reset; | ||
138 | uint16_t lock; | ||
139 | uint16_t unlock; | ||
140 | uint16_t lock_status; | ||
141 | }; | ||
142 | |||
143 | struct pxa3xx_nand_flash { | ||
144 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ | ||
145 | struct pxa3xx_nand_cmdset *cmdset; | ||
146 | |||
147 | uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */ | ||
148 | uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ | ||
149 | uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ | ||
150 | uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */ | ||
151 | uint32_t num_blocks; /* Number of physical blocks in Flash */ | ||
152 | uint32_t chip_id; | ||
153 | |||
154 | /* NOTE: these are automatically calculated, do not define */ | ||
155 | size_t oob_size; | ||
156 | size_t read_id_bytes; | ||
157 | |||
158 | unsigned int col_addr_cycles; | ||
159 | unsigned int row_addr_cycles; | ||
160 | }; | ||
161 | |||
162 | struct pxa3xx_nand_info { | 118 | struct pxa3xx_nand_info { |
163 | struct nand_chip nand_chip; | 119 | struct nand_chip nand_chip; |
164 | 120 | ||
165 | struct platform_device *pdev; | 121 | struct platform_device *pdev; |
166 | struct pxa3xx_nand_flash *flash_info; | 122 | const struct pxa3xx_nand_flash *flash_info; |
167 | 123 | ||
168 | struct clk *clk; | 124 | struct clk *clk; |
169 | void __iomem *mmio_base; | 125 | void __iomem *mmio_base; |
@@ -202,12 +158,20 @@ struct pxa3xx_nand_info { | |||
202 | uint32_t ndcb0; | 158 | uint32_t ndcb0; |
203 | uint32_t ndcb1; | 159 | uint32_t ndcb1; |
204 | uint32_t ndcb2; | 160 | uint32_t ndcb2; |
161 | |||
162 | /* calculated from pxa3xx_nand_flash data */ | ||
163 | size_t oob_size; | ||
164 | size_t read_id_bytes; | ||
165 | |||
166 | unsigned int col_addr_cycles; | ||
167 | unsigned int row_addr_cycles; | ||
205 | }; | 168 | }; |
206 | 169 | ||
207 | static int use_dma = 1; | 170 | static int use_dma = 1; |
208 | module_param(use_dma, bool, 0444); | 171 | module_param(use_dma, bool, 0444); |
209 | MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); | 172 | MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); |
210 | 173 | ||
174 | #ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN | ||
211 | static struct pxa3xx_nand_cmdset smallpage_cmdset = { | 175 | static struct pxa3xx_nand_cmdset smallpage_cmdset = { |
212 | .read1 = 0x0000, | 176 | .read1 = 0x0000, |
213 | .read2 = 0x0050, | 177 | .read2 = 0x0050, |
@@ -291,11 +255,35 @@ static struct pxa3xx_nand_flash micron1GbX16 = { | |||
291 | .chip_id = 0xb12c, | 255 | .chip_id = 0xb12c, |
292 | }; | 256 | }; |
293 | 257 | ||
258 | static struct pxa3xx_nand_timing stm2GbX16_timing = { | ||
259 | .tCH = 10, | ||
260 | .tCS = 35, | ||
261 | .tWH = 15, | ||
262 | .tWP = 25, | ||
263 | .tRH = 15, | ||
264 | .tRP = 25, | ||
265 | .tR = 25000, | ||
266 | .tWHR = 60, | ||
267 | .tAR = 10, | ||
268 | }; | ||
269 | |||
270 | static struct pxa3xx_nand_flash stm2GbX16 = { | ||
271 | .timing = &stm2GbX16_timing, | ||
272 | .page_per_block = 64, | ||
273 | .page_size = 2048, | ||
274 | .flash_width = 16, | ||
275 | .dfc_width = 16, | ||
276 | .num_blocks = 2048, | ||
277 | .chip_id = 0xba20, | ||
278 | }; | ||
279 | |||
294 | static struct pxa3xx_nand_flash *builtin_flash_types[] = { | 280 | static struct pxa3xx_nand_flash *builtin_flash_types[] = { |
295 | &samsung512MbX16, | 281 | &samsung512MbX16, |
296 | µn1GbX8, | 282 | µn1GbX8, |
297 | µn1GbX16, | 283 | µn1GbX16, |
284 | &stm2GbX16, | ||
298 | }; | 285 | }; |
286 | #endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */ | ||
299 | 287 | ||
300 | #define NDTR0_tCH(c) (min((c), 7) << 19) | 288 | #define NDTR0_tCH(c) (min((c), 7) << 19) |
301 | #define NDTR0_tCS(c) (min((c), 7) << 16) | 289 | #define NDTR0_tCS(c) (min((c), 7) << 16) |
@@ -312,7 +300,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { | |||
312 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) | 300 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) |
313 | 301 | ||
314 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | 302 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, |
315 | struct pxa3xx_nand_timing *t) | 303 | const struct pxa3xx_nand_timing *t) |
316 | { | 304 | { |
317 | unsigned long nand_clk = clk_get_rate(info->clk); | 305 | unsigned long nand_clk = clk_get_rate(info->clk); |
318 | uint32_t ndtr0, ndtr1; | 306 | uint32_t ndtr0, ndtr1; |
@@ -354,8 +342,8 @@ static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) | |||
354 | static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | 342 | static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, |
355 | uint16_t cmd, int column, int page_addr) | 343 | uint16_t cmd, int column, int page_addr) |
356 | { | 344 | { |
357 | struct pxa3xx_nand_flash *f = info->flash_info; | 345 | const struct pxa3xx_nand_flash *f = info->flash_info; |
358 | struct pxa3xx_nand_cmdset *cmdset = f->cmdset; | 346 | const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; |
359 | 347 | ||
360 | /* calculate data size */ | 348 | /* calculate data size */ |
361 | switch (f->page_size) { | 349 | switch (f->page_size) { |
@@ -373,14 +361,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | |||
373 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | 361 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); |
374 | info->ndcb1 = 0; | 362 | info->ndcb1 = 0; |
375 | info->ndcb2 = 0; | 363 | info->ndcb2 = 0; |
376 | info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles); | 364 | info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles); |
377 | 365 | ||
378 | if (f->col_addr_cycles == 2) { | 366 | if (info->col_addr_cycles == 2) { |
379 | /* large block, 2 cycles for column address | 367 | /* large block, 2 cycles for column address |
380 | * row address starts from 3rd cycle | 368 | * row address starts from 3rd cycle |
381 | */ | 369 | */ |
382 | info->ndcb1 |= (page_addr << 16) | (column & 0xffff); | 370 | info->ndcb1 |= (page_addr << 16) | (column & 0xffff); |
383 | if (f->row_addr_cycles == 3) | 371 | if (info->row_addr_cycles == 3) |
384 | info->ndcb2 = (page_addr >> 16) & 0xff; | 372 | info->ndcb2 = (page_addr >> 16) & 0xff; |
385 | } else | 373 | } else |
386 | /* small block, 1 cycles for column address | 374 | /* small block, 1 cycles for column address |
@@ -406,7 +394,7 @@ static int prepare_erase_cmd(struct pxa3xx_nand_info *info, | |||
406 | 394 | ||
407 | static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) | 395 | static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) |
408 | { | 396 | { |
409 | struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; | 397 | const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; |
410 | 398 | ||
411 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | 399 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); |
412 | info->ndcb1 = 0; | 400 | info->ndcb1 = 0; |
@@ -641,8 +629,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
641 | int column, int page_addr) | 629 | int column, int page_addr) |
642 | { | 630 | { |
643 | struct pxa3xx_nand_info *info = mtd->priv; | 631 | struct pxa3xx_nand_info *info = mtd->priv; |
644 | struct pxa3xx_nand_flash *flash_info = info->flash_info; | 632 | const struct pxa3xx_nand_flash *flash_info = info->flash_info; |
645 | struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; | 633 | const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; |
646 | int ret; | 634 | int ret; |
647 | 635 | ||
648 | info->use_dma = (use_dma) ? 1 : 0; | 636 | info->use_dma = (use_dma) ? 1 : 0; |
@@ -720,7 +708,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
720 | info->use_dma = 0; /* force PIO read */ | 708 | info->use_dma = 0; /* force PIO read */ |
721 | info->buf_start = 0; | 709 | info->buf_start = 0; |
722 | info->buf_count = (command == NAND_CMD_READID) ? | 710 | info->buf_count = (command == NAND_CMD_READID) ? |
723 | flash_info->read_id_bytes : 1; | 711 | info->read_id_bytes : 1; |
724 | 712 | ||
725 | if (prepare_other_cmd(info, (command == NAND_CMD_READID) ? | 713 | if (prepare_other_cmd(info, (command == NAND_CMD_READID) ? |
726 | cmdset->read_id : cmdset->read_status)) | 714 | cmdset->read_id : cmdset->read_status)) |
@@ -861,8 +849,8 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, | |||
861 | 849 | ||
862 | static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) | 850 | static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) |
863 | { | 851 | { |
864 | struct pxa3xx_nand_flash *f = info->flash_info; | 852 | const struct pxa3xx_nand_flash *f = info->flash_info; |
865 | struct pxa3xx_nand_cmdset *cmdset = f->cmdset; | 853 | const struct pxa3xx_nand_cmdset *cmdset = f->cmdset; |
866 | uint32_t ndcr; | 854 | uint32_t ndcr; |
867 | uint8_t id_buff[8]; | 855 | uint8_t id_buff[8]; |
868 | 856 | ||
@@ -891,7 +879,7 @@ fail_timeout: | |||
891 | } | 879 | } |
892 | 880 | ||
893 | static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | 881 | static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, |
894 | struct pxa3xx_nand_flash *f) | 882 | const struct pxa3xx_nand_flash *f) |
895 | { | 883 | { |
896 | struct platform_device *pdev = info->pdev; | 884 | struct platform_device *pdev = info->pdev; |
897 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; | 885 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; |
@@ -904,25 +892,25 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
904 | return -EINVAL; | 892 | return -EINVAL; |
905 | 893 | ||
906 | /* calculate flash information */ | 894 | /* calculate flash information */ |
907 | f->oob_size = (f->page_size == 2048) ? 64 : 16; | 895 | info->oob_size = (f->page_size == 2048) ? 64 : 16; |
908 | f->read_id_bytes = (f->page_size == 2048) ? 4 : 2; | 896 | info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; |
909 | 897 | ||
910 | /* calculate addressing information */ | 898 | /* calculate addressing information */ |
911 | f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; | 899 | info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; |
912 | 900 | ||
913 | if (f->num_blocks * f->page_per_block > 65536) | 901 | if (f->num_blocks * f->page_per_block > 65536) |
914 | f->row_addr_cycles = 3; | 902 | info->row_addr_cycles = 3; |
915 | else | 903 | else |
916 | f->row_addr_cycles = 2; | 904 | info->row_addr_cycles = 2; |
917 | 905 | ||
918 | ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; | 906 | ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; |
919 | ndcr |= (f->col_addr_cycles == 2) ? NDCR_RA_START : 0; | 907 | ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; |
920 | ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; | 908 | ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; |
921 | ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; | 909 | ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; |
922 | ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; | 910 | ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; |
923 | ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; | 911 | ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; |
924 | 912 | ||
925 | ndcr |= NDCR_RD_ID_CNT(f->read_id_bytes); | 913 | ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); |
926 | ndcr |= NDCR_SPARE_EN; /* enable spare by default */ | 914 | ndcr |= NDCR_SPARE_EN; /* enable spare by default */ |
927 | 915 | ||
928 | info->reg_ndcr = ndcr; | 916 | info->reg_ndcr = ndcr; |
@@ -932,12 +920,27 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
932 | return 0; | 920 | return 0; |
933 | } | 921 | } |
934 | 922 | ||
935 | static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info) | 923 | static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, |
924 | const struct pxa3xx_nand_platform_data *pdata) | ||
936 | { | 925 | { |
937 | struct pxa3xx_nand_flash *f; | 926 | const struct pxa3xx_nand_flash *f; |
938 | uint32_t id; | 927 | uint32_t id = -1; |
939 | int i; | 928 | int i; |
940 | 929 | ||
930 | for (i = 0; i<pdata->num_flash; ++i) { | ||
931 | f = pdata->flash + i; | ||
932 | |||
933 | if (pxa3xx_nand_config_flash(info, f)) | ||
934 | continue; | ||
935 | |||
936 | if (__readid(info, &id)) | ||
937 | continue; | ||
938 | |||
939 | if (id == f->chip_id) | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | #ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN | ||
941 | for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { | 944 | for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { |
942 | 945 | ||
943 | f = builtin_flash_types[i]; | 946 | f = builtin_flash_types[i]; |
@@ -951,7 +954,11 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info) | |||
951 | if (id == f->chip_id) | 954 | if (id == f->chip_id) |
952 | return 0; | 955 | return 0; |
953 | } | 956 | } |
957 | #endif | ||
954 | 958 | ||
959 | dev_warn(&info->pdev->dev, | ||
960 | "failed to detect configured nand flash; found %04x instead of\n", | ||
961 | id); | ||
955 | return -ENODEV; | 962 | return -ENODEV; |
956 | } | 963 | } |
957 | 964 | ||
@@ -1014,7 +1021,7 @@ static struct nand_ecclayout hw_largepage_ecclayout = { | |||
1014 | static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, | 1021 | static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, |
1015 | struct pxa3xx_nand_info *info) | 1022 | struct pxa3xx_nand_info *info) |
1016 | { | 1023 | { |
1017 | struct pxa3xx_nand_flash *f = info->flash_info; | 1024 | const struct pxa3xx_nand_flash *f = info->flash_info; |
1018 | struct nand_chip *this = &info->nand_chip; | 1025 | struct nand_chip *this = &info->nand_chip; |
1019 | 1026 | ||
1020 | this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; | 1027 | this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; |
@@ -1135,7 +1142,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) | |||
1135 | goto fail_free_buf; | 1142 | goto fail_free_buf; |
1136 | } | 1143 | } |
1137 | 1144 | ||
1138 | ret = pxa3xx_nand_detect_flash(info); | 1145 | ret = pxa3xx_nand_detect_flash(info, pdata); |
1139 | if (ret) { | 1146 | if (ret) { |
1140 | dev_err(&pdev->dev, "failed to detect flash\n"); | 1147 | dev_err(&pdev->dev, "failed to detect flash\n"); |
1141 | ret = -ENODEV; | 1148 | ret = -ENODEV; |
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c new file mode 100644 index 000000000000..821acb08ff1c --- /dev/null +++ b/drivers/mtd/nand/sh_flctl.c | |||
@@ -0,0 +1,878 @@ | |||
1 | /* | ||
2 | * SuperH FLCTL nand controller | ||
3 | * | ||
4 | * Copyright © 2008 Renesas Solutions Corp. | ||
5 | * Copyright © 2008 Atom Create Engineering Co., Ltd. | ||
6 | * | ||
7 | * Based on fsl_elbc_nand.c, Copyright © 2006-2007 Freescale Semiconductor | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | |||
30 | #include <linux/mtd/mtd.h> | ||
31 | #include <linux/mtd/nand.h> | ||
32 | #include <linux/mtd/partitions.h> | ||
33 | #include <linux/mtd/sh_flctl.h> | ||
34 | |||
35 | static struct nand_ecclayout flctl_4secc_oob_16 = { | ||
36 | .eccbytes = 10, | ||
37 | .eccpos = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, | ||
38 | .oobfree = { | ||
39 | {.offset = 12, | ||
40 | . length = 4} }, | ||
41 | }; | ||
42 | |||
43 | static struct nand_ecclayout flctl_4secc_oob_64 = { | ||
44 | .eccbytes = 10, | ||
45 | .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57}, | ||
46 | .oobfree = { | ||
47 | {.offset = 60, | ||
48 | . length = 4} }, | ||
49 | }; | ||
50 | |||
51 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | ||
52 | |||
53 | static struct nand_bbt_descr flctl_4secc_smallpage = { | ||
54 | .options = NAND_BBT_SCAN2NDPAGE, | ||
55 | .offs = 11, | ||
56 | .len = 1, | ||
57 | .pattern = scan_ff_pattern, | ||
58 | }; | ||
59 | |||
60 | static struct nand_bbt_descr flctl_4secc_largepage = { | ||
61 | .options = 0, | ||
62 | .offs = 58, | ||
63 | .len = 2, | ||
64 | .pattern = scan_ff_pattern, | ||
65 | }; | ||
66 | |||
67 | static void empty_fifo(struct sh_flctl *flctl) | ||
68 | { | ||
69 | writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */ | ||
70 | writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */ | ||
71 | } | ||
72 | |||
73 | static void start_translation(struct sh_flctl *flctl) | ||
74 | { | ||
75 | writeb(TRSTRT, FLTRCR(flctl)); | ||
76 | } | ||
77 | |||
78 | static void wait_completion(struct sh_flctl *flctl) | ||
79 | { | ||
80 | uint32_t timeout = LOOP_TIMEOUT_MAX; | ||
81 | |||
82 | while (timeout--) { | ||
83 | if (readb(FLTRCR(flctl)) & TREND) { | ||
84 | writeb(0x0, FLTRCR(flctl)); | ||
85 | return; | ||
86 | } | ||
87 | udelay(1); | ||
88 | } | ||
89 | |||
90 | printk(KERN_ERR "wait_completion(): Timeout occured \n"); | ||
91 | writeb(0x0, FLTRCR(flctl)); | ||
92 | } | ||
93 | |||
94 | static void set_addr(struct mtd_info *mtd, int column, int page_addr) | ||
95 | { | ||
96 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
97 | uint32_t addr = 0; | ||
98 | |||
99 | if (column == -1) { | ||
100 | addr = page_addr; /* ERASE1 */ | ||
101 | } else if (page_addr != -1) { | ||
102 | /* SEQIN, READ0, etc.. */ | ||
103 | if (flctl->page_size) { | ||
104 | addr = column & 0x0FFF; | ||
105 | addr |= (page_addr & 0xff) << 16; | ||
106 | addr |= ((page_addr >> 8) & 0xff) << 24; | ||
107 | /* big than 128MB */ | ||
108 | if (flctl->rw_ADRCNT == ADRCNT2_E) { | ||
109 | uint32_t addr2; | ||
110 | addr2 = (page_addr >> 16) & 0xff; | ||
111 | writel(addr2, FLADR2(flctl)); | ||
112 | } | ||
113 | } else { | ||
114 | addr = column; | ||
115 | addr |= (page_addr & 0xff) << 8; | ||
116 | addr |= ((page_addr >> 8) & 0xff) << 16; | ||
117 | addr |= ((page_addr >> 16) & 0xff) << 24; | ||
118 | } | ||
119 | } | ||
120 | writel(addr, FLADR(flctl)); | ||
121 | } | ||
122 | |||
123 | static void wait_rfifo_ready(struct sh_flctl *flctl) | ||
124 | { | ||
125 | uint32_t timeout = LOOP_TIMEOUT_MAX; | ||
126 | |||
127 | while (timeout--) { | ||
128 | uint32_t val; | ||
129 | /* check FIFO */ | ||
130 | val = readl(FLDTCNTR(flctl)) >> 16; | ||
131 | if (val & 0xFF) | ||
132 | return; | ||
133 | udelay(1); | ||
134 | } | ||
135 | printk(KERN_ERR "wait_rfifo_ready(): Timeout occured \n"); | ||
136 | } | ||
137 | |||
138 | static void wait_wfifo_ready(struct sh_flctl *flctl) | ||
139 | { | ||
140 | uint32_t len, timeout = LOOP_TIMEOUT_MAX; | ||
141 | |||
142 | while (timeout--) { | ||
143 | /* check FIFO */ | ||
144 | len = (readl(FLDTCNTR(flctl)) >> 16) & 0xFF; | ||
145 | if (len >= 4) | ||
146 | return; | ||
147 | udelay(1); | ||
148 | } | ||
149 | printk(KERN_ERR "wait_wfifo_ready(): Timeout occured \n"); | ||
150 | } | ||
151 | |||
152 | static int wait_recfifo_ready(struct sh_flctl *flctl) | ||
153 | { | ||
154 | uint32_t timeout = LOOP_TIMEOUT_MAX; | ||
155 | int checked[4]; | ||
156 | void __iomem *ecc_reg[4]; | ||
157 | int i; | ||
158 | uint32_t data, size; | ||
159 | |||
160 | memset(checked, 0, sizeof(checked)); | ||
161 | |||
162 | while (timeout--) { | ||
163 | size = readl(FLDTCNTR(flctl)) >> 24; | ||
164 | if (size & 0xFF) | ||
165 | return 0; /* success */ | ||
166 | |||
167 | if (readl(FL4ECCCR(flctl)) & _4ECCFA) | ||
168 | return 1; /* can't correct */ | ||
169 | |||
170 | udelay(1); | ||
171 | if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) | ||
172 | continue; | ||
173 | |||
174 | /* start error correction */ | ||
175 | ecc_reg[0] = FL4ECCRESULT0(flctl); | ||
176 | ecc_reg[1] = FL4ECCRESULT1(flctl); | ||
177 | ecc_reg[2] = FL4ECCRESULT2(flctl); | ||
178 | ecc_reg[3] = FL4ECCRESULT3(flctl); | ||
179 | |||
180 | for (i = 0; i < 3; i++) { | ||
181 | data = readl(ecc_reg[i]); | ||
182 | if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) { | ||
183 | uint8_t org; | ||
184 | int index; | ||
185 | |||
186 | index = data >> 16; | ||
187 | org = flctl->done_buff[index]; | ||
188 | flctl->done_buff[index] = org ^ (data & 0xFF); | ||
189 | checked[i] = 1; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | writel(0, FL4ECCCR(flctl)); | ||
194 | } | ||
195 | |||
196 | printk(KERN_ERR "wait_recfifo_ready(): Timeout occured \n"); | ||
197 | return 1; /* timeout */ | ||
198 | } | ||
199 | |||
200 | static void wait_wecfifo_ready(struct sh_flctl *flctl) | ||
201 | { | ||
202 | uint32_t timeout = LOOP_TIMEOUT_MAX; | ||
203 | uint32_t len; | ||
204 | |||
205 | while (timeout--) { | ||
206 | /* check FLECFIFO */ | ||
207 | len = (readl(FLDTCNTR(flctl)) >> 24) & 0xFF; | ||
208 | if (len >= 4) | ||
209 | return; | ||
210 | udelay(1); | ||
211 | } | ||
212 | printk(KERN_ERR "wait_wecfifo_ready(): Timeout occured \n"); | ||
213 | } | ||
214 | |||
215 | static void read_datareg(struct sh_flctl *flctl, int offset) | ||
216 | { | ||
217 | unsigned long data; | ||
218 | unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; | ||
219 | |||
220 | wait_completion(flctl); | ||
221 | |||
222 | data = readl(FLDATAR(flctl)); | ||
223 | *buf = le32_to_cpu(data); | ||
224 | } | ||
225 | |||
226 | static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | ||
227 | { | ||
228 | int i, len_4align; | ||
229 | unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; | ||
230 | void *fifo_addr = (void *)FLDTFIFO(flctl); | ||
231 | |||
232 | len_4align = (rlen + 3) / 4; | ||
233 | |||
234 | for (i = 0; i < len_4align; i++) { | ||
235 | wait_rfifo_ready(flctl); | ||
236 | buf[i] = readl(fifo_addr); | ||
237 | buf[i] = be32_to_cpu(buf[i]); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff) | ||
242 | { | ||
243 | int i; | ||
244 | unsigned long *ecc_buf = (unsigned long *)buff; | ||
245 | void *fifo_addr = (void *)FLECFIFO(flctl); | ||
246 | |||
247 | for (i = 0; i < 4; i++) { | ||
248 | if (wait_recfifo_ready(flctl)) | ||
249 | return 1; | ||
250 | ecc_buf[i] = readl(fifo_addr); | ||
251 | ecc_buf[i] = be32_to_cpu(ecc_buf[i]); | ||
252 | } | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) | ||
258 | { | ||
259 | int i, len_4align; | ||
260 | unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; | ||
261 | void *fifo_addr = (void *)FLDTFIFO(flctl); | ||
262 | |||
263 | len_4align = (rlen + 3) / 4; | ||
264 | for (i = 0; i < len_4align; i++) { | ||
265 | wait_wfifo_ready(flctl); | ||
266 | writel(cpu_to_be32(data[i]), fifo_addr); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) | ||
271 | { | ||
272 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
273 | uint32_t flcmncr_val = readl(FLCMNCR(flctl)); | ||
274 | uint32_t flcmdcr_val, addr_len_bytes = 0; | ||
275 | |||
276 | /* Set SNAND bit if page size is 2048byte */ | ||
277 | if (flctl->page_size) | ||
278 | flcmncr_val |= SNAND_E; | ||
279 | else | ||
280 | flcmncr_val &= ~SNAND_E; | ||
281 | |||
282 | /* default FLCMDCR val */ | ||
283 | flcmdcr_val = DOCMD1_E | DOADR_E; | ||
284 | |||
285 | /* Set for FLCMDCR */ | ||
286 | switch (cmd) { | ||
287 | case NAND_CMD_ERASE1: | ||
288 | addr_len_bytes = flctl->erase_ADRCNT; | ||
289 | flcmdcr_val |= DOCMD2_E; | ||
290 | break; | ||
291 | case NAND_CMD_READ0: | ||
292 | case NAND_CMD_READOOB: | ||
293 | addr_len_bytes = flctl->rw_ADRCNT; | ||
294 | flcmdcr_val |= CDSRC_E; | ||
295 | break; | ||
296 | case NAND_CMD_SEQIN: | ||
297 | /* This case is that cmd is READ0 or READ1 or READ00 */ | ||
298 | flcmdcr_val &= ~DOADR_E; /* ONLY execute 1st cmd */ | ||
299 | break; | ||
300 | case NAND_CMD_PAGEPROG: | ||
301 | addr_len_bytes = flctl->rw_ADRCNT; | ||
302 | flcmdcr_val |= DOCMD2_E | CDSRC_E | SELRW; | ||
303 | break; | ||
304 | case NAND_CMD_READID: | ||
305 | flcmncr_val &= ~SNAND_E; | ||
306 | addr_len_bytes = ADRCNT_1; | ||
307 | break; | ||
308 | case NAND_CMD_STATUS: | ||
309 | case NAND_CMD_RESET: | ||
310 | flcmncr_val &= ~SNAND_E; | ||
311 | flcmdcr_val &= ~(DOADR_E | DOSR_E); | ||
312 | break; | ||
313 | default: | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | /* Set address bytes parameter */ | ||
318 | flcmdcr_val |= addr_len_bytes; | ||
319 | |||
320 | /* Now actually write */ | ||
321 | writel(flcmncr_val, FLCMNCR(flctl)); | ||
322 | writel(flcmdcr_val, FLCMDCR(flctl)); | ||
323 | writel(flcmcdr_val, FLCMCDR(flctl)); | ||
324 | } | ||
325 | |||
326 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | ||
327 | uint8_t *buf) | ||
328 | { | ||
329 | int i, eccsize = chip->ecc.size; | ||
330 | int eccbytes = chip->ecc.bytes; | ||
331 | int eccsteps = chip->ecc.steps; | ||
332 | uint8_t *p = buf; | ||
333 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
334 | |||
335 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | ||
336 | chip->read_buf(mtd, p, eccsize); | ||
337 | |||
338 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | ||
339 | if (flctl->hwecc_cant_correct[i]) | ||
340 | mtd->ecc_stats.failed++; | ||
341 | else | ||
342 | mtd->ecc_stats.corrected += 0; | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | ||
349 | const uint8_t *buf) | ||
350 | { | ||
351 | int i, eccsize = chip->ecc.size; | ||
352 | int eccbytes = chip->ecc.bytes; | ||
353 | int eccsteps = chip->ecc.steps; | ||
354 | const uint8_t *p = buf; | ||
355 | |||
356 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | ||
357 | chip->write_buf(mtd, p, eccsize); | ||
358 | } | ||
359 | |||
360 | static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) | ||
361 | { | ||
362 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
363 | int sector, page_sectors; | ||
364 | |||
365 | if (flctl->page_size) | ||
366 | page_sectors = 4; | ||
367 | else | ||
368 | page_sectors = 1; | ||
369 | |||
370 | writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT, | ||
371 | FLCMNCR(flctl)); | ||
372 | |||
373 | set_cmd_regs(mtd, NAND_CMD_READ0, | ||
374 | (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); | ||
375 | |||
376 | for (sector = 0; sector < page_sectors; sector++) { | ||
377 | int ret; | ||
378 | |||
379 | empty_fifo(flctl); | ||
380 | writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl)); | ||
381 | writel(page_addr << 2 | sector, FLADR(flctl)); | ||
382 | |||
383 | start_translation(flctl); | ||
384 | read_fiforeg(flctl, 512, 512 * sector); | ||
385 | |||
386 | ret = read_ecfiforeg(flctl, | ||
387 | &flctl->done_buff[mtd->writesize + 16 * sector]); | ||
388 | |||
389 | if (ret) | ||
390 | flctl->hwecc_cant_correct[sector] = 1; | ||
391 | |||
392 | writel(0x0, FL4ECCCR(flctl)); | ||
393 | wait_completion(flctl); | ||
394 | } | ||
395 | writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT), | ||
396 | FLCMNCR(flctl)); | ||
397 | } | ||
398 | |||
399 | static void execmd_read_oob(struct mtd_info *mtd, int page_addr) | ||
400 | { | ||
401 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
402 | |||
403 | set_cmd_regs(mtd, NAND_CMD_READ0, | ||
404 | (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); | ||
405 | |||
406 | empty_fifo(flctl); | ||
407 | if (flctl->page_size) { | ||
408 | int i; | ||
409 | /* In case that the page size is 2k */ | ||
410 | for (i = 0; i < 16 * 3; i++) | ||
411 | flctl->done_buff[i] = 0xFF; | ||
412 | |||
413 | set_addr(mtd, 3 * 528 + 512, page_addr); | ||
414 | writel(16, FLDTCNTR(flctl)); | ||
415 | |||
416 | start_translation(flctl); | ||
417 | read_fiforeg(flctl, 16, 16 * 3); | ||
418 | wait_completion(flctl); | ||
419 | } else { | ||
420 | /* In case that the page size is 512b */ | ||
421 | set_addr(mtd, 512, page_addr); | ||
422 | writel(16, FLDTCNTR(flctl)); | ||
423 | |||
424 | start_translation(flctl); | ||
425 | read_fiforeg(flctl, 16, 0); | ||
426 | wait_completion(flctl); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static void execmd_write_page_sector(struct mtd_info *mtd) | ||
431 | { | ||
432 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
433 | int i, page_addr = flctl->seqin_page_addr; | ||
434 | int sector, page_sectors; | ||
435 | |||
436 | if (flctl->page_size) | ||
437 | page_sectors = 4; | ||
438 | else | ||
439 | page_sectors = 1; | ||
440 | |||
441 | writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl)); | ||
442 | |||
443 | set_cmd_regs(mtd, NAND_CMD_PAGEPROG, | ||
444 | (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); | ||
445 | |||
446 | for (sector = 0; sector < page_sectors; sector++) { | ||
447 | empty_fifo(flctl); | ||
448 | writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl)); | ||
449 | writel(page_addr << 2 | sector, FLADR(flctl)); | ||
450 | |||
451 | start_translation(flctl); | ||
452 | write_fiforeg(flctl, 512, 512 * sector); | ||
453 | |||
454 | for (i = 0; i < 4; i++) { | ||
455 | wait_wecfifo_ready(flctl); /* wait for write ready */ | ||
456 | writel(0xFFFFFFFF, FLECFIFO(flctl)); | ||
457 | } | ||
458 | wait_completion(flctl); | ||
459 | } | ||
460 | |||
461 | writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl)); | ||
462 | } | ||
463 | |||
464 | static void execmd_write_oob(struct mtd_info *mtd) | ||
465 | { | ||
466 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
467 | int page_addr = flctl->seqin_page_addr; | ||
468 | int sector, page_sectors; | ||
469 | |||
470 | if (flctl->page_size) { | ||
471 | sector = 3; | ||
472 | page_sectors = 4; | ||
473 | } else { | ||
474 | sector = 0; | ||
475 | page_sectors = 1; | ||
476 | } | ||
477 | |||
478 | set_cmd_regs(mtd, NAND_CMD_PAGEPROG, | ||
479 | (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); | ||
480 | |||
481 | for (; sector < page_sectors; sector++) { | ||
482 | empty_fifo(flctl); | ||
483 | set_addr(mtd, sector * 528 + 512, page_addr); | ||
484 | writel(16, FLDTCNTR(flctl)); /* set read size */ | ||
485 | |||
486 | start_translation(flctl); | ||
487 | write_fiforeg(flctl, 16, 16 * sector); | ||
488 | wait_completion(flctl); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, | ||
493 | int column, int page_addr) | ||
494 | { | ||
495 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
496 | uint32_t read_cmd = 0; | ||
497 | |||
498 | flctl->read_bytes = 0; | ||
499 | if (command != NAND_CMD_PAGEPROG) | ||
500 | flctl->index = 0; | ||
501 | |||
502 | switch (command) { | ||
503 | case NAND_CMD_READ1: | ||
504 | case NAND_CMD_READ0: | ||
505 | if (flctl->hwecc) { | ||
506 | /* read page with hwecc */ | ||
507 | execmd_read_page_sector(mtd, page_addr); | ||
508 | break; | ||
509 | } | ||
510 | empty_fifo(flctl); | ||
511 | if (flctl->page_size) | ||
512 | set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8) | ||
513 | | command); | ||
514 | else | ||
515 | set_cmd_regs(mtd, command, command); | ||
516 | |||
517 | set_addr(mtd, 0, page_addr); | ||
518 | |||
519 | flctl->read_bytes = mtd->writesize + mtd->oobsize; | ||
520 | flctl->index += column; | ||
521 | goto read_normal_exit; | ||
522 | |||
523 | case NAND_CMD_READOOB: | ||
524 | if (flctl->hwecc) { | ||
525 | /* read page with hwecc */ | ||
526 | execmd_read_oob(mtd, page_addr); | ||
527 | break; | ||
528 | } | ||
529 | |||
530 | empty_fifo(flctl); | ||
531 | if (flctl->page_size) { | ||
532 | set_cmd_regs(mtd, command, (NAND_CMD_READSTART << 8) | ||
533 | | NAND_CMD_READ0); | ||
534 | set_addr(mtd, mtd->writesize, page_addr); | ||
535 | } else { | ||
536 | set_cmd_regs(mtd, command, command); | ||
537 | set_addr(mtd, 0, page_addr); | ||
538 | } | ||
539 | flctl->read_bytes = mtd->oobsize; | ||
540 | goto read_normal_exit; | ||
541 | |||
542 | case NAND_CMD_READID: | ||
543 | empty_fifo(flctl); | ||
544 | set_cmd_regs(mtd, command, command); | ||
545 | set_addr(mtd, 0, 0); | ||
546 | |||
547 | flctl->read_bytes = 4; | ||
548 | writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */ | ||
549 | start_translation(flctl); | ||
550 | read_datareg(flctl, 0); /* read and end */ | ||
551 | break; | ||
552 | |||
553 | case NAND_CMD_ERASE1: | ||
554 | flctl->erase1_page_addr = page_addr; | ||
555 | break; | ||
556 | |||
557 | case NAND_CMD_ERASE2: | ||
558 | set_cmd_regs(mtd, NAND_CMD_ERASE1, | ||
559 | (command << 8) | NAND_CMD_ERASE1); | ||
560 | set_addr(mtd, -1, flctl->erase1_page_addr); | ||
561 | start_translation(flctl); | ||
562 | wait_completion(flctl); | ||
563 | break; | ||
564 | |||
565 | case NAND_CMD_SEQIN: | ||
566 | if (!flctl->page_size) { | ||
567 | /* output read command */ | ||
568 | if (column >= mtd->writesize) { | ||
569 | column -= mtd->writesize; | ||
570 | read_cmd = NAND_CMD_READOOB; | ||
571 | } else if (column < 256) { | ||
572 | read_cmd = NAND_CMD_READ0; | ||
573 | } else { | ||
574 | column -= 256; | ||
575 | read_cmd = NAND_CMD_READ1; | ||
576 | } | ||
577 | } | ||
578 | flctl->seqin_column = column; | ||
579 | flctl->seqin_page_addr = page_addr; | ||
580 | flctl->seqin_read_cmd = read_cmd; | ||
581 | break; | ||
582 | |||
583 | case NAND_CMD_PAGEPROG: | ||
584 | empty_fifo(flctl); | ||
585 | if (!flctl->page_size) { | ||
586 | set_cmd_regs(mtd, NAND_CMD_SEQIN, | ||
587 | flctl->seqin_read_cmd); | ||
588 | set_addr(mtd, -1, -1); | ||
589 | writel(0, FLDTCNTR(flctl)); /* set 0 size */ | ||
590 | start_translation(flctl); | ||
591 | wait_completion(flctl); | ||
592 | } | ||
593 | if (flctl->hwecc) { | ||
594 | /* write page with hwecc */ | ||
595 | if (flctl->seqin_column == mtd->writesize) | ||
596 | execmd_write_oob(mtd); | ||
597 | else if (!flctl->seqin_column) | ||
598 | execmd_write_page_sector(mtd); | ||
599 | else | ||
600 | printk(KERN_ERR "Invalid address !?\n"); | ||
601 | break; | ||
602 | } | ||
603 | set_cmd_regs(mtd, command, (command << 8) | NAND_CMD_SEQIN); | ||
604 | set_addr(mtd, flctl->seqin_column, flctl->seqin_page_addr); | ||
605 | writel(flctl->index, FLDTCNTR(flctl)); /* set write size */ | ||
606 | start_translation(flctl); | ||
607 | write_fiforeg(flctl, flctl->index, 0); | ||
608 | wait_completion(flctl); | ||
609 | break; | ||
610 | |||
611 | case NAND_CMD_STATUS: | ||
612 | set_cmd_regs(mtd, command, command); | ||
613 | set_addr(mtd, -1, -1); | ||
614 | |||
615 | flctl->read_bytes = 1; | ||
616 | writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */ | ||
617 | start_translation(flctl); | ||
618 | read_datareg(flctl, 0); /* read and end */ | ||
619 | break; | ||
620 | |||
621 | case NAND_CMD_RESET: | ||
622 | set_cmd_regs(mtd, command, command); | ||
623 | set_addr(mtd, -1, -1); | ||
624 | |||
625 | writel(0, FLDTCNTR(flctl)); /* set 0 size */ | ||
626 | start_translation(flctl); | ||
627 | wait_completion(flctl); | ||
628 | break; | ||
629 | |||
630 | default: | ||
631 | break; | ||
632 | } | ||
633 | return; | ||
634 | |||
635 | read_normal_exit: | ||
636 | writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */ | ||
637 | start_translation(flctl); | ||
638 | read_fiforeg(flctl, flctl->read_bytes, 0); | ||
639 | wait_completion(flctl); | ||
640 | return; | ||
641 | } | ||
642 | |||
643 | static void flctl_select_chip(struct mtd_info *mtd, int chipnr) | ||
644 | { | ||
645 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
646 | uint32_t flcmncr_val = readl(FLCMNCR(flctl)); | ||
647 | |||
648 | switch (chipnr) { | ||
649 | case -1: | ||
650 | flcmncr_val &= ~CE0_ENABLE; | ||
651 | writel(flcmncr_val, FLCMNCR(flctl)); | ||
652 | break; | ||
653 | case 0: | ||
654 | flcmncr_val |= CE0_ENABLE; | ||
655 | writel(flcmncr_val, FLCMNCR(flctl)); | ||
656 | break; | ||
657 | default: | ||
658 | BUG(); | ||
659 | } | ||
660 | } | ||
661 | |||
662 | static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | ||
663 | { | ||
664 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
665 | int i, index = flctl->index; | ||
666 | |||
667 | for (i = 0; i < len; i++) | ||
668 | flctl->done_buff[index + i] = buf[i]; | ||
669 | flctl->index += len; | ||
670 | } | ||
671 | |||
672 | static uint8_t flctl_read_byte(struct mtd_info *mtd) | ||
673 | { | ||
674 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
675 | int index = flctl->index; | ||
676 | uint8_t data; | ||
677 | |||
678 | data = flctl->done_buff[index]; | ||
679 | flctl->index++; | ||
680 | return data; | ||
681 | } | ||
682 | |||
683 | static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | ||
684 | { | ||
685 | int i; | ||
686 | |||
687 | for (i = 0; i < len; i++) | ||
688 | buf[i] = flctl_read_byte(mtd); | ||
689 | } | ||
690 | |||
691 | static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
692 | { | ||
693 | int i; | ||
694 | |||
695 | for (i = 0; i < len; i++) | ||
696 | if (buf[i] != flctl_read_byte(mtd)) | ||
697 | return -EFAULT; | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static void flctl_register_init(struct sh_flctl *flctl, unsigned long val) | ||
702 | { | ||
703 | writel(val, FLCMNCR(flctl)); | ||
704 | } | ||
705 | |||
706 | static int flctl_chip_init_tail(struct mtd_info *mtd) | ||
707 | { | ||
708 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | ||
709 | struct nand_chip *chip = &flctl->chip; | ||
710 | |||
711 | if (mtd->writesize == 512) { | ||
712 | flctl->page_size = 0; | ||
713 | if (chip->chipsize > (32 << 20)) { | ||
714 | /* big than 32MB */ | ||
715 | flctl->rw_ADRCNT = ADRCNT_4; | ||
716 | flctl->erase_ADRCNT = ADRCNT_3; | ||
717 | } else if (chip->chipsize > (2 << 16)) { | ||
718 | /* big than 128KB */ | ||
719 | flctl->rw_ADRCNT = ADRCNT_3; | ||
720 | flctl->erase_ADRCNT = ADRCNT_2; | ||
721 | } else { | ||
722 | flctl->rw_ADRCNT = ADRCNT_2; | ||
723 | flctl->erase_ADRCNT = ADRCNT_1; | ||
724 | } | ||
725 | } else { | ||
726 | flctl->page_size = 1; | ||
727 | if (chip->chipsize > (128 << 20)) { | ||
728 | /* big than 128MB */ | ||
729 | flctl->rw_ADRCNT = ADRCNT2_E; | ||
730 | flctl->erase_ADRCNT = ADRCNT_3; | ||
731 | } else if (chip->chipsize > (8 << 16)) { | ||
732 | /* big than 512KB */ | ||
733 | flctl->rw_ADRCNT = ADRCNT_4; | ||
734 | flctl->erase_ADRCNT = ADRCNT_2; | ||
735 | } else { | ||
736 | flctl->rw_ADRCNT = ADRCNT_3; | ||
737 | flctl->erase_ADRCNT = ADRCNT_1; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | if (flctl->hwecc) { | ||
742 | if (mtd->writesize == 512) { | ||
743 | chip->ecc.layout = &flctl_4secc_oob_16; | ||
744 | chip->badblock_pattern = &flctl_4secc_smallpage; | ||
745 | } else { | ||
746 | chip->ecc.layout = &flctl_4secc_oob_64; | ||
747 | chip->badblock_pattern = &flctl_4secc_largepage; | ||
748 | } | ||
749 | |||
750 | chip->ecc.size = 512; | ||
751 | chip->ecc.bytes = 10; | ||
752 | chip->ecc.read_page = flctl_read_page_hwecc; | ||
753 | chip->ecc.write_page = flctl_write_page_hwecc; | ||
754 | chip->ecc.mode = NAND_ECC_HW; | ||
755 | |||
756 | /* 4 symbols ECC enabled */ | ||
757 | writel(readl(FLCMNCR(flctl)) | _4ECCEN | ECCPOS2 | ECCPOS_02, | ||
758 | FLCMNCR(flctl)); | ||
759 | } else { | ||
760 | chip->ecc.mode = NAND_ECC_SOFT; | ||
761 | } | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static int __init flctl_probe(struct platform_device *pdev) | ||
767 | { | ||
768 | struct resource *res; | ||
769 | struct sh_flctl *flctl; | ||
770 | struct mtd_info *flctl_mtd; | ||
771 | struct nand_chip *nand; | ||
772 | struct sh_flctl_platform_data *pdata; | ||
773 | int ret; | ||
774 | |||
775 | pdata = pdev->dev.platform_data; | ||
776 | if (pdata == NULL) { | ||
777 | printk(KERN_ERR "sh_flctl platform_data not found.\n"); | ||
778 | return -ENODEV; | ||
779 | } | ||
780 | |||
781 | flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); | ||
782 | if (!flctl) { | ||
783 | printk(KERN_ERR "Unable to allocate NAND MTD dev structure.\n"); | ||
784 | return -ENOMEM; | ||
785 | } | ||
786 | |||
787 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
788 | if (!res) { | ||
789 | printk(KERN_ERR "%s: resource not found.\n", __func__); | ||
790 | ret = -ENODEV; | ||
791 | goto err; | ||
792 | } | ||
793 | |||
794 | flctl->reg = ioremap(res->start, res->end - res->start + 1); | ||
795 | if (flctl->reg == NULL) { | ||
796 | printk(KERN_ERR "%s: ioremap error.\n", __func__); | ||
797 | ret = -ENOMEM; | ||
798 | goto err; | ||
799 | } | ||
800 | |||
801 | platform_set_drvdata(pdev, flctl); | ||
802 | flctl_mtd = &flctl->mtd; | ||
803 | nand = &flctl->chip; | ||
804 | flctl_mtd->priv = nand; | ||
805 | flctl->hwecc = pdata->has_hwecc; | ||
806 | |||
807 | flctl_register_init(flctl, pdata->flcmncr_val); | ||
808 | |||
809 | nand->options = NAND_NO_AUTOINCR; | ||
810 | |||
811 | /* Set address of hardware control function */ | ||
812 | /* 20 us command delay time */ | ||
813 | nand->chip_delay = 20; | ||
814 | |||
815 | nand->read_byte = flctl_read_byte; | ||
816 | nand->write_buf = flctl_write_buf; | ||
817 | nand->read_buf = flctl_read_buf; | ||
818 | nand->verify_buf = flctl_verify_buf; | ||
819 | nand->select_chip = flctl_select_chip; | ||
820 | nand->cmdfunc = flctl_cmdfunc; | ||
821 | |||
822 | ret = nand_scan_ident(flctl_mtd, 1); | ||
823 | if (ret) | ||
824 | goto err; | ||
825 | |||
826 | ret = flctl_chip_init_tail(flctl_mtd); | ||
827 | if (ret) | ||
828 | goto err; | ||
829 | |||
830 | ret = nand_scan_tail(flctl_mtd); | ||
831 | if (ret) | ||
832 | goto err; | ||
833 | |||
834 | add_mtd_partitions(flctl_mtd, pdata->parts, pdata->nr_parts); | ||
835 | |||
836 | return 0; | ||
837 | |||
838 | err: | ||
839 | kfree(flctl); | ||
840 | return ret; | ||
841 | } | ||
842 | |||
843 | static int __exit flctl_remove(struct platform_device *pdev) | ||
844 | { | ||
845 | struct sh_flctl *flctl = platform_get_drvdata(pdev); | ||
846 | |||
847 | nand_release(&flctl->mtd); | ||
848 | kfree(flctl); | ||
849 | |||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | static struct platform_driver flctl_driver = { | ||
854 | .probe = flctl_probe, | ||
855 | .remove = flctl_remove, | ||
856 | .driver = { | ||
857 | .name = "sh_flctl", | ||
858 | .owner = THIS_MODULE, | ||
859 | }, | ||
860 | }; | ||
861 | |||
862 | static int __init flctl_nand_init(void) | ||
863 | { | ||
864 | return platform_driver_register(&flctl_driver); | ||
865 | } | ||
866 | |||
867 | static void __exit flctl_nand_cleanup(void) | ||
868 | { | ||
869 | platform_driver_unregister(&flctl_driver); | ||
870 | } | ||
871 | |||
872 | module_init(flctl_nand_init); | ||
873 | module_exit(flctl_nand_cleanup); | ||
874 | |||
875 | MODULE_LICENSE("GPL"); | ||
876 | MODULE_AUTHOR("Yoshihiro Shimoda"); | ||
877 | MODULE_DESCRIPTION("SuperH FLCTL driver"); | ||
878 | MODULE_ALIAS("platform:sh_flctl"); | ||
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c deleted file mode 100644 index bbf492e6830d..000000000000 --- a/drivers/mtd/nand/toto.c +++ /dev/null | |||
@@ -1,206 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/toto.c | ||
3 | * | ||
4 | * Copyright (c) 2003 Texas Instruments | ||
5 | * | ||
6 | * Derived from drivers/mtd/autcpu12.c | ||
7 | * | ||
8 | * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Overview: | ||
15 | * This is a device driver for the NAND flash device found on the | ||
16 | * TI fido board. It supports 32MiB and 64MiB cards | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/mtd/mtd.h> | ||
24 | #include <linux/mtd/nand.h> | ||
25 | #include <linux/mtd/partitions.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/arch/hardware.h> | ||
28 | #include <asm/sizes.h> | ||
29 | #include <asm/arch/toto.h> | ||
30 | #include <asm/arch-omap1510/hardware.h> | ||
31 | #include <asm/arch/gpio.h> | ||
32 | |||
33 | #define CONFIG_NAND_WORKAROUND 1 | ||
34 | |||
35 | /* | ||
36 | * MTD structure for TOTO board | ||
37 | */ | ||
38 | static struct mtd_info *toto_mtd = NULL; | ||
39 | |||
40 | static unsigned long toto_io_base = OMAP_FLASH_1_BASE; | ||
41 | |||
42 | /* | ||
43 | * Define partitions for flash devices | ||
44 | */ | ||
45 | |||
46 | static struct mtd_partition partition_info64M[] = { | ||
47 | { .name = "toto kernel partition 1", | ||
48 | .offset = 0, | ||
49 | .size = 2 * SZ_1M }, | ||
50 | { .name = "toto file sys partition 2", | ||
51 | .offset = 2 * SZ_1M, | ||
52 | .size = 14 * SZ_1M }, | ||
53 | { .name = "toto user partition 3", | ||
54 | .offset = 16 * SZ_1M, | ||
55 | .size = 16 * SZ_1M }, | ||
56 | { .name = "toto devboard extra partition 4", | ||
57 | .offset = 32 * SZ_1M, | ||
58 | .size = 32 * SZ_1M }, | ||
59 | }; | ||
60 | |||
61 | static struct mtd_partition partition_info32M[] = { | ||
62 | { .name = "toto kernel partition 1", | ||
63 | .offset = 0, | ||
64 | .size = 2 * SZ_1M }, | ||
65 | { .name = "toto file sys partition 2", | ||
66 | .offset = 2 * SZ_1M, | ||
67 | .size = 14 * SZ_1M }, | ||
68 | { .name = "toto user partition 3", | ||
69 | .offset = 16 * SZ_1M, | ||
70 | .size = 16 * SZ_1M }, | ||
71 | }; | ||
72 | |||
73 | #define NUM_PARTITIONS32M 3 | ||
74 | #define NUM_PARTITIONS64M 4 | ||
75 | |||
76 | /* | ||
77 | * hardware specific access to control-lines | ||
78 | * | ||
79 | * ctrl: | ||
80 | * NAND_NCE: bit 0 -> bit 14 (0x4000) | ||
81 | * NAND_CLE: bit 1 -> bit 12 (0x1000) | ||
82 | * NAND_ALE: bit 2 -> bit 1 (0x0002) | ||
83 | */ | ||
84 | static void toto_hwcontrol(struct mtd_info *mtd, int cmd, | ||
85 | unsigned int ctrl) | ||
86 | { | ||
87 | struct nand_chip *chip = mtd->priv; | ||
88 | |||
89 | if (ctrl & NAND_CTRL_CHANGE) { | ||
90 | unsigned long bits; | ||
91 | |||
92 | /* hopefully enough time for tc make proceding write to clear */ | ||
93 | udelay(1); | ||
94 | |||
95 | bits = (~ctrl & NAND_NCE) << 14; | ||
96 | bits |= (ctrl & NAND_CLE) << 12; | ||
97 | bits |= (ctrl & NAND_ALE) >> 1; | ||
98 | |||
99 | #warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx | ||
100 | gpiosetout(0x5002, bits); | ||
101 | |||
102 | #ifdef CONFIG_NAND_WORKAROUND | ||
103 | /* "some" dev boards busted, blue wired to rts2 :( */ | ||
104 | rts2setout(2, (ctrl & NAND_CLE) << 1); | ||
105 | #endif | ||
106 | /* allow time to ensure gpio state to over take memory write */ | ||
107 | udelay(1); | ||
108 | } | ||
109 | |||
110 | if (cmd != NAND_CMD_NONE) | ||
111 | writeb(cmd, chip->IO_ADDR_W); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Main initialization routine | ||
116 | */ | ||
117 | static int __init toto_init(void) | ||
118 | { | ||
119 | struct nand_chip *this; | ||
120 | int err = 0; | ||
121 | |||
122 | /* Allocate memory for MTD device structure and private data */ | ||
123 | toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); | ||
124 | if (!toto_mtd) { | ||
125 | printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n"); | ||
126 | err = -ENOMEM; | ||
127 | goto out; | ||
128 | } | ||
129 | |||
130 | /* Get pointer to private data */ | ||
131 | this = (struct nand_chip *)(&toto_mtd[1]); | ||
132 | |||
133 | /* Initialize structures */ | ||
134 | memset(toto_mtd, 0, sizeof(struct mtd_info)); | ||
135 | memset(this, 0, sizeof(struct nand_chip)); | ||
136 | |||
137 | /* Link the private data with the MTD structure */ | ||
138 | toto_mtd->priv = this; | ||
139 | toto_mtd->owner = THIS_MODULE; | ||
140 | |||
141 | /* Set address of NAND IO lines */ | ||
142 | this->IO_ADDR_R = toto_io_base; | ||
143 | this->IO_ADDR_W = toto_io_base; | ||
144 | this->cmd_ctrl = toto_hwcontrol; | ||
145 | this->dev_ready = NULL; | ||
146 | /* 25 us command delay time */ | ||
147 | this->chip_delay = 30; | ||
148 | this->ecc.mode = NAND_ECC_SOFT; | ||
149 | |||
150 | /* Scan to find existance of the device */ | ||
151 | if (nand_scan(toto_mtd, 1)) { | ||
152 | err = -ENXIO; | ||
153 | goto out_mtd; | ||
154 | } | ||
155 | |||
156 | /* Register the partitions */ | ||
157 | switch (toto_mtd->size) { | ||
158 | case SZ_64M: | ||
159 | add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); | ||
160 | break; | ||
161 | case SZ_32M: | ||
162 | add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); | ||
163 | break; | ||
164 | default:{ | ||
165 | printk(KERN_WARNING "Unsupported Nand device\n"); | ||
166 | err = -ENXIO; | ||
167 | goto out_buf; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | gpioreserve(NAND_MASK); /* claim our gpios */ | ||
172 | archflashwp(0, 0); /* open up flash for writing */ | ||
173 | |||
174 | goto out; | ||
175 | |||
176 | out_mtd: | ||
177 | kfree(toto_mtd); | ||
178 | out: | ||
179 | return err; | ||
180 | } | ||
181 | |||
182 | module_init(toto_init); | ||
183 | |||
184 | /* | ||
185 | * Clean up routine | ||
186 | */ | ||
187 | static void __exit toto_cleanup(void) | ||
188 | { | ||
189 | /* Release resources, unregister device */ | ||
190 | nand_release(toto_mtd); | ||
191 | |||
192 | /* Free the MTD device structure */ | ||
193 | kfree(toto_mtd); | ||
194 | |||
195 | /* stop flash writes */ | ||
196 | archflashwp(0, 1); | ||
197 | |||
198 | /* release gpios to system */ | ||
199 | gpiorelease(NAND_MASK); | ||
200 | } | ||
201 | |||
202 | module_exit(toto_cleanup); | ||
203 | |||
204 | MODULE_LICENSE("GPL"); | ||
205 | MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>"); | ||
206 | MODULE_DESCRIPTION("Glue layer for NAND flash on toto board"); | ||