diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 13:07:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 13:07:49 -0400 |
commit | a7c367b95a9d8e65e0f0e7da31f700a556794efb (patch) | |
tree | 5b1bb202801e29e3237381aa7aad5aa288378d5b /drivers/mtd/nand | |
parent | 15f964bed054821d6d940d3752508c5f96a9ffd3 (diff) | |
parent | e1070211f7327a1f197d535aa886f721a241c32f (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (58 commits)
mtd: jedec_probe: add PSD4256G6V id
mtd: OneNand support for Nomadik 8815 SoC (on NHK8815 board)
mtd: nand: driver for Nomadik 8815 SoC (on NHK8815 board)
m25p80: Add Spansion S25FL129P serial flashes
jffs2: Use SLAB_HWCACHE_ALIGN for jffs2_raw_{dirent,inode} slabs
mtd: sh_flctl: register sh_flctl using platform_driver_probe()
mtd: nand: txx9ndfmc: transfer 512 byte at a time if possible
mtd: nand: fix tmio_nand ecc correction
mtd: nand: add __nand_correct_data helper function
mtd: cfi_cmdset_0002: add 0xFF intolerance for M29W128G
mtd: inftl: fix fold chain block number
mtd: jedec: fix compilation problem with I28F640C3B definition
mtd: nand: fix ECC Correction bug for SMC ordering for NDFC driver
mtd: ofpart: Check availability of reg property instead of name property
driver/Makefile: Initialize "mtd" and "spi" before "net"
mtd: omap: adding DMA mode support in nand prefetch/post-write
mtd: omap: add support for nand prefetch-read and post-write
mtd: add nand support for w90p910 (v2)
mtd: maps: add mtd-ram support to physmap_of
mtd: pxa3xx_nand: add single-bit error corrections reporting
...
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 30 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/cafe_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/davinci_nand.c | 45 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 16 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 167 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ecc.c | 31 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/nomadik_nand.c | 250 | ||||
-rw-r--r-- | drivers/mtd/nand/omap2.c | 347 | ||||
-rw-r--r-- | drivers/mtd/nand/orion_nand.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 17 | ||||
-rw-r--r-- | drivers/mtd/nand/sh_flctl.c | 5 | ||||
-rw-r--r-- | drivers/mtd/nand/tmio_nand.c | 17 | ||||
-rw-r--r-- | drivers/mtd/nand/txx9ndfmc.c | 52 | ||||
-rw-r--r-- | drivers/mtd/nand/w90p910_nand.c | 382 |
18 files changed, 1277 insertions, 98 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index ce96c091f01b..2fda0b615246 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -80,6 +80,23 @@ config MTD_NAND_OMAP2 | |||
80 | help | 80 | help |
81 | Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. | 81 | Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. |
82 | 82 | ||
83 | config MTD_NAND_OMAP_PREFETCH | ||
84 | bool "GPMC prefetch support for NAND Flash device" | ||
85 | depends on MTD_NAND && MTD_NAND_OMAP2 | ||
86 | default y | ||
87 | help | ||
88 | The NAND device can be accessed for Read/Write using GPMC PREFETCH engine | ||
89 | to improve the performance. | ||
90 | |||
91 | config MTD_NAND_OMAP_PREFETCH_DMA | ||
92 | depends on MTD_NAND_OMAP_PREFETCH | ||
93 | bool "DMA mode" | ||
94 | default n | ||
95 | help | ||
96 | The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode | ||
97 | or in DMA interrupt mode. | ||
98 | Say y for DMA mode or MPU mode will be used | ||
99 | |||
83 | config MTD_NAND_TS7250 | 100 | config MTD_NAND_TS7250 |
84 | tristate "NAND Flash device on TS-7250 board" | 101 | tristate "NAND Flash device on TS-7250 board" |
85 | depends on MACH_TS72XX | 102 | depends on MACH_TS72XX |
@@ -426,6 +443,12 @@ config MTD_NAND_MXC | |||
426 | This enables the driver for the NAND flash controller on the | 443 | This enables the driver for the NAND flash controller on the |
427 | MXC processors. | 444 | MXC processors. |
428 | 445 | ||
446 | config MTD_NAND_NOMADIK | ||
447 | tristate "ST Nomadik 8815 NAND support" | ||
448 | depends on ARCH_NOMADIK | ||
449 | help | ||
450 | Driver for the NAND flash controller on the Nomadik, with ECC. | ||
451 | |||
429 | config MTD_NAND_SH_FLCTL | 452 | config MTD_NAND_SH_FLCTL |
430 | tristate "Support for NAND on Renesas SuperH FLCTL" | 453 | tristate "Support for NAND on Renesas SuperH FLCTL" |
431 | depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 | 454 | depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723 |
@@ -452,4 +475,11 @@ config MTD_NAND_SOCRATES | |||
452 | help | 475 | help |
453 | Enables support for NAND Flash chips wired onto Socrates board. | 476 | Enables support for NAND Flash chips wired onto Socrates board. |
454 | 477 | ||
478 | config MTD_NAND_W90P910 | ||
479 | tristate "Support for NAND on w90p910 evaluation board." | ||
480 | depends on ARCH_W90X900 && MTD_PARTITIONS | ||
481 | help | ||
482 | This enables the driver for the NAND Flash on evaluation board based | ||
483 | on w90p910. | ||
484 | |||
455 | endif # MTD_NAND | 485 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index f3a786b3cff3..6950d3dabf10 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -40,5 +40,7 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o | |||
40 | obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o | 40 | obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o |
41 | obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o | 41 | obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o |
42 | obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o | 42 | obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o |
43 | obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o | ||
44 | obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o | ||
43 | 45 | ||
44 | nand-objs := nand_base.o nand_bbt.o | 46 | 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 20c828ba9405..f8e9975c86e5 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -218,7 +218,7 @@ static int atmel_nand_calculate(struct mtd_info *mtd, | |||
218 | * buf: buffer to store read data | 218 | * buf: buffer to store read data |
219 | */ | 219 | */ |
220 | static int atmel_nand_read_page(struct mtd_info *mtd, | 220 | static int atmel_nand_read_page(struct mtd_info *mtd, |
221 | struct nand_chip *chip, uint8_t *buf) | 221 | struct nand_chip *chip, uint8_t *buf, int page) |
222 | { | 222 | { |
223 | int eccsize = chip->ecc.size; | 223 | int eccsize = chip->ecc.size; |
224 | int eccbytes = chip->ecc.bytes; | 224 | int eccbytes = chip->ecc.bytes; |
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 1b4690bdfdb3..c828d9ac7bd7 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
@@ -381,7 +381,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, | |||
381 | * we need a special oob layout and handling. | 381 | * we need a special oob layout and handling. |
382 | */ | 382 | */ |
383 | static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, | 383 | static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
384 | uint8_t *buf) | 384 | uint8_t *buf, int page) |
385 | { | 385 | { |
386 | struct cafe_priv *cafe = mtd->priv; | 386 | struct cafe_priv *cafe = mtd->priv; |
387 | 387 | ||
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 0fad6487e6f4..f13f5b9afaf7 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c | |||
@@ -348,6 +348,12 @@ compare: | |||
348 | if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3])) | 348 | if (!(syndrome[0] | syndrome[1] | syndrome[2] | syndrome[3])) |
349 | return 0; | 349 | return 0; |
350 | 350 | ||
351 | /* | ||
352 | * Clear any previous address calculation by doing a dummy read of an | ||
353 | * error address register. | ||
354 | */ | ||
355 | davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET); | ||
356 | |||
351 | /* Start address calculation, and wait for it to complete. | 357 | /* Start address calculation, and wait for it to complete. |
352 | * We _could_ start reading more data while this is working, | 358 | * We _could_ start reading more data while this is working, |
353 | * to speed up the overall page read. | 359 | * to speed up the overall page read. |
@@ -359,8 +365,10 @@ compare: | |||
359 | 365 | ||
360 | switch ((fsr >> 8) & 0x0f) { | 366 | switch ((fsr >> 8) & 0x0f) { |
361 | case 0: /* no error, should not happen */ | 367 | case 0: /* no error, should not happen */ |
368 | davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); | ||
362 | return 0; | 369 | return 0; |
363 | case 1: /* five or more errors detected */ | 370 | case 1: /* five or more errors detected */ |
371 | davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); | ||
364 | return -EIO; | 372 | return -EIO; |
365 | case 2: /* error addresses computed */ | 373 | case 2: /* error addresses computed */ |
366 | case 3: | 374 | case 3: |
@@ -500,6 +508,26 @@ static struct nand_ecclayout hwecc4_small __initconst = { | |||
500 | }, | 508 | }, |
501 | }; | 509 | }; |
502 | 510 | ||
511 | /* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash, | ||
512 | * storing ten ECC bytes plus the manufacturer's bad block marker byte, | ||
513 | * and not overlapping the default BBT markers. | ||
514 | */ | ||
515 | static struct nand_ecclayout hwecc4_2048 __initconst = { | ||
516 | .eccbytes = 40, | ||
517 | .eccpos = { | ||
518 | /* at the end of spare sector */ | ||
519 | 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, | ||
520 | 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, | ||
521 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, | ||
522 | 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, | ||
523 | }, | ||
524 | .oobfree = { | ||
525 | /* 2 bytes at offset 0 hold manufacturer badblock markers */ | ||
526 | {.offset = 2, .length = 22, }, | ||
527 | /* 5 bytes at offset 8 hold BBT markers */ | ||
528 | /* 8 bytes at offset 16 hold JFFS2 clean markers */ | ||
529 | }, | ||
530 | }; | ||
503 | 531 | ||
504 | static int __init nand_davinci_probe(struct platform_device *pdev) | 532 | static int __init nand_davinci_probe(struct platform_device *pdev) |
505 | { | 533 | { |
@@ -690,15 +718,20 @@ static int __init nand_davinci_probe(struct platform_device *pdev) | |||
690 | info->mtd.oobsize - 16; | 718 | info->mtd.oobsize - 16; |
691 | goto syndrome_done; | 719 | goto syndrome_done; |
692 | } | 720 | } |
721 | if (chunks == 4) { | ||
722 | info->ecclayout = hwecc4_2048; | ||
723 | info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; | ||
724 | goto syndrome_done; | ||
725 | } | ||
693 | 726 | ||
694 | /* For large page chips we'll be wanting to use a | 727 | /* 4KiB page chips are not yet supported. The eccpos from |
695 | * not-yet-implemented mode that reads OOB data | 728 | * nand_ecclayout cannot hold 80 bytes and change to eccpos[] |
696 | * before reading the body of the page, to avoid | 729 | * breaks userspace ioctl interface with mtd-utils. Once we |
697 | * the "infix OOB" model of NAND_ECC_HW_SYNDROME | 730 | * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used |
698 | * (and preserve manufacturer badblock markings). | 731 | * for the 4KiB page chips. |
699 | */ | 732 | */ |
700 | dev_warn(&pdev->dev, "no 4-bit ECC support yet " | 733 | dev_warn(&pdev->dev, "no 4-bit ECC support yet " |
701 | "for large page NAND\n"); | 734 | "for 4KiB-page NAND\n"); |
702 | ret = -EIO; | 735 | ret = -EIO; |
703 | goto err_scan; | 736 | goto err_scan; |
704 | 737 | ||
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 1f6eb2578717..ddd37d2554ed 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -739,7 +739,8 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
739 | 739 | ||
740 | static int fsl_elbc_read_page(struct mtd_info *mtd, | 740 | static int fsl_elbc_read_page(struct mtd_info *mtd, |
741 | struct nand_chip *chip, | 741 | struct nand_chip *chip, |
742 | uint8_t *buf) | 742 | uint8_t *buf, |
743 | int page) | ||
743 | { | 744 | { |
744 | fsl_elbc_read_buf(mtd, buf, mtd->writesize); | 745 | fsl_elbc_read_buf(mtd, buf, mtd->writesize); |
745 | fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | 746 | fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); |
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 76beea40d2cf..65b26d5a5c0d 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -857,6 +857,17 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
857 | } | 857 | } |
858 | } | 858 | } |
859 | 859 | ||
860 | /* Define some generic bad / good block scan pattern which are used | ||
861 | * while scanning a device for factory marked good / bad blocks. */ | ||
862 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | ||
863 | |||
864 | static struct nand_bbt_descr smallpage_memorybased = { | ||
865 | .options = NAND_BBT_SCAN2NDPAGE, | ||
866 | .offs = 5, | ||
867 | .len = 1, | ||
868 | .pattern = scan_ff_pattern | ||
869 | }; | ||
870 | |||
860 | static int __init mxcnd_probe(struct platform_device *pdev) | 871 | static int __init mxcnd_probe(struct platform_device *pdev) |
861 | { | 872 | { |
862 | struct nand_chip *this; | 873 | struct nand_chip *this; |
@@ -973,7 +984,10 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
973 | goto escan; | 984 | goto escan; |
974 | } | 985 | } |
975 | 986 | ||
976 | host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0; | 987 | if (mtd->writesize == 2048) { |
988 | host->pagesize_2k = 1; | ||
989 | this->badblock_pattern = &smallpage_memorybased; | ||
990 | } | ||
977 | 991 | ||
978 | if (this->ecc.mode == NAND_ECC_HW) { | 992 | if (this->ecc.mode == NAND_ECC_HW) { |
979 | switch (mtd->oobsize) { | 993 | switch (mtd->oobsize) { |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8c21b89d2d0c..22113865438b 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -688,8 +688,7 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | |||
688 | retry: | 688 | retry: |
689 | spin_lock(lock); | 689 | spin_lock(lock); |
690 | 690 | ||
691 | /* Hardware controller shared among independend devices */ | 691 | /* Hardware controller shared among independent devices */ |
692 | /* Hardware controller shared among independend devices */ | ||
693 | if (!chip->controller->active) | 692 | if (!chip->controller->active) |
694 | chip->controller->active = chip; | 693 | chip->controller->active = chip; |
695 | 694 | ||
@@ -766,7 +765,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
766 | * Not for syndrome calculating ecc controllers, which use a special oob layout | 765 | * Not for syndrome calculating ecc controllers, which use a special oob layout |
767 | */ | 766 | */ |
768 | static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | 767 | static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
769 | uint8_t *buf) | 768 | uint8_t *buf, int page) |
770 | { | 769 | { |
771 | chip->read_buf(mtd, buf, mtd->writesize); | 770 | chip->read_buf(mtd, buf, mtd->writesize); |
772 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | 771 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); |
@@ -782,7 +781,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | |||
782 | * We need a special oob layout and handling even when OOB isn't used. | 781 | * We need a special oob layout and handling even when OOB isn't used. |
783 | */ | 782 | */ |
784 | static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 783 | static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, |
785 | uint8_t *buf) | 784 | uint8_t *buf, int page) |
786 | { | 785 | { |
787 | int eccsize = chip->ecc.size; | 786 | int eccsize = chip->ecc.size; |
788 | int eccbytes = chip->ecc.bytes; | 787 | int eccbytes = chip->ecc.bytes; |
@@ -821,7 +820,7 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *c | |||
821 | * @buf: buffer to store read data | 820 | * @buf: buffer to store read data |
822 | */ | 821 | */ |
823 | static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | 822 | static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, |
824 | uint8_t *buf) | 823 | uint8_t *buf, int page) |
825 | { | 824 | { |
826 | int i, eccsize = chip->ecc.size; | 825 | int i, eccsize = chip->ecc.size; |
827 | int eccbytes = chip->ecc.bytes; | 826 | int eccbytes = chip->ecc.bytes; |
@@ -831,7 +830,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
831 | uint8_t *ecc_code = chip->buffers->ecccode; | 830 | uint8_t *ecc_code = chip->buffers->ecccode; |
832 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 831 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
833 | 832 | ||
834 | chip->ecc.read_page_raw(mtd, chip, buf); | 833 | chip->ecc.read_page_raw(mtd, chip, buf, page); |
835 | 834 | ||
836 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | 835 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) |
837 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | 836 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
@@ -944,7 +943,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3 | |||
944 | * Not for syndrome calculating ecc controllers which need a special oob layout | 943 | * Not for syndrome calculating ecc controllers which need a special oob layout |
945 | */ | 944 | */ |
946 | static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 945 | static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
947 | uint8_t *buf) | 946 | uint8_t *buf, int page) |
948 | { | 947 | { |
949 | int i, eccsize = chip->ecc.size; | 948 | int i, eccsize = chip->ecc.size; |
950 | int eccbytes = chip->ecc.bytes; | 949 | int eccbytes = chip->ecc.bytes; |
@@ -980,6 +979,54 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
980 | } | 979 | } |
981 | 980 | ||
982 | /** | 981 | /** |
982 | * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first | ||
983 | * @mtd: mtd info structure | ||
984 | * @chip: nand chip info structure | ||
985 | * @buf: buffer to store read data | ||
986 | * | ||
987 | * Hardware ECC for large page chips, require OOB to be read first. | ||
988 | * For this ECC mode, the write_page method is re-used from ECC_HW. | ||
989 | * These methods read/write ECC from the OOB area, unlike the | ||
990 | * ECC_HW_SYNDROME support with multiple ECC steps, follows the | ||
991 | * "infix ECC" scheme and reads/writes ECC from the data area, by | ||
992 | * overwriting the NAND manufacturer bad block markings. | ||
993 | */ | ||
994 | static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, | ||
995 | struct nand_chip *chip, uint8_t *buf, int page) | ||
996 | { | ||
997 | int i, eccsize = chip->ecc.size; | ||
998 | int eccbytes = chip->ecc.bytes; | ||
999 | int eccsteps = chip->ecc.steps; | ||
1000 | uint8_t *p = buf; | ||
1001 | uint8_t *ecc_code = chip->buffers->ecccode; | ||
1002 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
1003 | uint8_t *ecc_calc = chip->buffers->ecccalc; | ||
1004 | |||
1005 | /* Read the OOB area first */ | ||
1006 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
1007 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
1008 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); | ||
1009 | |||
1010 | for (i = 0; i < chip->ecc.total; i++) | ||
1011 | ecc_code[i] = chip->oob_poi[eccpos[i]]; | ||
1012 | |||
1013 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { | ||
1014 | int stat; | ||
1015 | |||
1016 | chip->ecc.hwctl(mtd, NAND_ECC_READ); | ||
1017 | chip->read_buf(mtd, p, eccsize); | ||
1018 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | ||
1019 | |||
1020 | stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); | ||
1021 | if (stat < 0) | ||
1022 | mtd->ecc_stats.failed++; | ||
1023 | else | ||
1024 | mtd->ecc_stats.corrected += stat; | ||
1025 | } | ||
1026 | return 0; | ||
1027 | } | ||
1028 | |||
1029 | /** | ||
983 | * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read | 1030 | * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read |
984 | * @mtd: mtd info structure | 1031 | * @mtd: mtd info structure |
985 | * @chip: nand chip info structure | 1032 | * @chip: nand chip info structure |
@@ -989,7 +1036,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
989 | * we need a special oob layout and handling. | 1036 | * we need a special oob layout and handling. |
990 | */ | 1037 | */ |
991 | static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | 1038 | static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, |
992 | uint8_t *buf) | 1039 | uint8_t *buf, int page) |
993 | { | 1040 | { |
994 | int i, eccsize = chip->ecc.size; | 1041 | int i, eccsize = chip->ecc.size; |
995 | int eccbytes = chip->ecc.bytes; | 1042 | int eccbytes = chip->ecc.bytes; |
@@ -1131,11 +1178,13 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
1131 | 1178 | ||
1132 | /* Now read the page into the buffer */ | 1179 | /* Now read the page into the buffer */ |
1133 | if (unlikely(ops->mode == MTD_OOB_RAW)) | 1180 | if (unlikely(ops->mode == MTD_OOB_RAW)) |
1134 | ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); | 1181 | ret = chip->ecc.read_page_raw(mtd, chip, |
1182 | bufpoi, page); | ||
1135 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) | 1183 | else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) |
1136 | ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); | 1184 | ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); |
1137 | else | 1185 | else |
1138 | ret = chip->ecc.read_page(mtd, chip, bufpoi); | 1186 | ret = chip->ecc.read_page(mtd, chip, bufpoi, |
1187 | page); | ||
1139 | if (ret < 0) | 1188 | if (ret < 0) |
1140 | break; | 1189 | break; |
1141 | 1190 | ||
@@ -1413,8 +1462,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1413 | int len; | 1462 | int len; |
1414 | uint8_t *buf = ops->oobbuf; | 1463 | uint8_t *buf = ops->oobbuf; |
1415 | 1464 | ||
1416 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", | 1465 | DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", |
1417 | (unsigned long long)from, readlen); | 1466 | __func__, (unsigned long long)from, readlen); |
1418 | 1467 | ||
1419 | if (ops->mode == MTD_OOB_AUTO) | 1468 | if (ops->mode == MTD_OOB_AUTO) |
1420 | len = chip->ecc.layout->oobavail; | 1469 | len = chip->ecc.layout->oobavail; |
@@ -1422,8 +1471,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1422 | len = mtd->oobsize; | 1471 | len = mtd->oobsize; |
1423 | 1472 | ||
1424 | if (unlikely(ops->ooboffs >= len)) { | 1473 | if (unlikely(ops->ooboffs >= len)) { |
1425 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " | 1474 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " |
1426 | "Attempt to start read outside oob\n"); | 1475 | "outside oob\n", __func__); |
1427 | return -EINVAL; | 1476 | return -EINVAL; |
1428 | } | 1477 | } |
1429 | 1478 | ||
@@ -1431,8 +1480,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1431 | if (unlikely(from >= mtd->size || | 1480 | if (unlikely(from >= mtd->size || |
1432 | ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - | 1481 | ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - |
1433 | (from >> chip->page_shift)) * len)) { | 1482 | (from >> chip->page_shift)) * len)) { |
1434 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " | 1483 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " |
1435 | "Attempt read beyond end of device\n"); | 1484 | "of device\n", __func__); |
1436 | return -EINVAL; | 1485 | return -EINVAL; |
1437 | } | 1486 | } |
1438 | 1487 | ||
@@ -1506,8 +1555,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, | |||
1506 | 1555 | ||
1507 | /* Do not allow reads past end of device */ | 1556 | /* Do not allow reads past end of device */ |
1508 | if (ops->datbuf && (from + ops->len) > mtd->size) { | 1557 | if (ops->datbuf && (from + ops->len) > mtd->size) { |
1509 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " | 1558 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " |
1510 | "Attempt read beyond end of device\n"); | 1559 | "beyond end of device\n", __func__); |
1511 | return -EINVAL; | 1560 | return -EINVAL; |
1512 | } | 1561 | } |
1513 | 1562 | ||
@@ -1816,8 +1865,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
1816 | 1865 | ||
1817 | /* reject writes, which are not page aligned */ | 1866 | /* reject writes, which are not page aligned */ |
1818 | if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { | 1867 | if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { |
1819 | printk(KERN_NOTICE "nand_write: " | 1868 | printk(KERN_NOTICE "%s: Attempt to write not " |
1820 | "Attempt to write not page aligned data\n"); | 1869 | "page aligned data\n", __func__); |
1821 | return -EINVAL; | 1870 | return -EINVAL; |
1822 | } | 1871 | } |
1823 | 1872 | ||
@@ -1944,8 +1993,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1944 | int chipnr, page, status, len; | 1993 | int chipnr, page, status, len; |
1945 | struct nand_chip *chip = mtd->priv; | 1994 | struct nand_chip *chip = mtd->priv; |
1946 | 1995 | ||
1947 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", | 1996 | DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", |
1948 | (unsigned int)to, (int)ops->ooblen); | 1997 | __func__, (unsigned int)to, (int)ops->ooblen); |
1949 | 1998 | ||
1950 | if (ops->mode == MTD_OOB_AUTO) | 1999 | if (ops->mode == MTD_OOB_AUTO) |
1951 | len = chip->ecc.layout->oobavail; | 2000 | len = chip->ecc.layout->oobavail; |
@@ -1954,14 +2003,14 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1954 | 2003 | ||
1955 | /* Do not allow write past end of page */ | 2004 | /* Do not allow write past end of page */ |
1956 | if ((ops->ooboffs + ops->ooblen) > len) { | 2005 | if ((ops->ooboffs + ops->ooblen) > len) { |
1957 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | 2006 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " |
1958 | "Attempt to write past end of page\n"); | 2007 | "past end of page\n", __func__); |
1959 | return -EINVAL; | 2008 | return -EINVAL; |
1960 | } | 2009 | } |
1961 | 2010 | ||
1962 | if (unlikely(ops->ooboffs >= len)) { | 2011 | if (unlikely(ops->ooboffs >= len)) { |
1963 | DEBUG(MTD_DEBUG_LEVEL0, "nand_do_write_oob: " | 2012 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " |
1964 | "Attempt to start write outside oob\n"); | 2013 | "write outside oob\n", __func__); |
1965 | return -EINVAL; | 2014 | return -EINVAL; |
1966 | } | 2015 | } |
1967 | 2016 | ||
@@ -1970,8 +2019,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1970 | ops->ooboffs + ops->ooblen > | 2019 | ops->ooboffs + ops->ooblen > |
1971 | ((mtd->size >> chip->page_shift) - | 2020 | ((mtd->size >> chip->page_shift) - |
1972 | (to >> chip->page_shift)) * len)) { | 2021 | (to >> chip->page_shift)) * len)) { |
1973 | DEBUG(MTD_DEBUG_LEVEL0, "nand_do_write_oob: " | 2022 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " |
1974 | "Attempt write beyond end of device\n"); | 2023 | "end of device\n", __func__); |
1975 | return -EINVAL; | 2024 | return -EINVAL; |
1976 | } | 2025 | } |
1977 | 2026 | ||
@@ -2026,8 +2075,8 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, | |||
2026 | 2075 | ||
2027 | /* Do not allow writes past end of device */ | 2076 | /* Do not allow writes past end of device */ |
2028 | if (ops->datbuf && (to + ops->len) > mtd->size) { | 2077 | if (ops->datbuf && (to + ops->len) > mtd->size) { |
2029 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | 2078 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " |
2030 | "Attempt write beyond end of device\n"); | 2079 | "end of device\n", __func__); |
2031 | return -EINVAL; | 2080 | return -EINVAL; |
2032 | } | 2081 | } |
2033 | 2082 | ||
@@ -2117,26 +2166,27 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2117 | unsigned int bbt_masked_page = 0xffffffff; | 2166 | unsigned int bbt_masked_page = 0xffffffff; |
2118 | loff_t len; | 2167 | loff_t len; |
2119 | 2168 | ||
2120 | DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n", | 2169 | DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", |
2121 | (unsigned long long)instr->addr, (unsigned long long)instr->len); | 2170 | __func__, (unsigned long long)instr->addr, |
2171 | (unsigned long long)instr->len); | ||
2122 | 2172 | ||
2123 | /* Start address must align on block boundary */ | 2173 | /* Start address must align on block boundary */ |
2124 | if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { | 2174 | if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { |
2125 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); | 2175 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); |
2126 | return -EINVAL; | 2176 | return -EINVAL; |
2127 | } | 2177 | } |
2128 | 2178 | ||
2129 | /* Length must align on block boundary */ | 2179 | /* Length must align on block boundary */ |
2130 | if (instr->len & ((1 << chip->phys_erase_shift) - 1)) { | 2180 | if (instr->len & ((1 << chip->phys_erase_shift) - 1)) { |
2131 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " | 2181 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", |
2132 | "Length not block aligned\n"); | 2182 | __func__); |
2133 | return -EINVAL; | 2183 | return -EINVAL; |
2134 | } | 2184 | } |
2135 | 2185 | ||
2136 | /* Do not allow erase past end of device */ | 2186 | /* Do not allow erase past end of device */ |
2137 | if ((instr->len + instr->addr) > mtd->size) { | 2187 | if ((instr->len + instr->addr) > mtd->size) { |
2138 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " | 2188 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Erase past end of device\n", |
2139 | "Erase past end of device\n"); | 2189 | __func__); |
2140 | return -EINVAL; | 2190 | return -EINVAL; |
2141 | } | 2191 | } |
2142 | 2192 | ||
@@ -2157,8 +2207,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2157 | 2207 | ||
2158 | /* Check, if it is write protected */ | 2208 | /* Check, if it is write protected */ |
2159 | if (nand_check_wp(mtd)) { | 2209 | if (nand_check_wp(mtd)) { |
2160 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " | 2210 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", |
2161 | "Device is write protected!!!\n"); | 2211 | __func__); |
2162 | instr->state = MTD_ERASE_FAILED; | 2212 | instr->state = MTD_ERASE_FAILED; |
2163 | goto erase_exit; | 2213 | goto erase_exit; |
2164 | } | 2214 | } |
@@ -2183,8 +2233,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2183 | */ | 2233 | */ |
2184 | if (nand_block_checkbad(mtd, ((loff_t) page) << | 2234 | if (nand_block_checkbad(mtd, ((loff_t) page) << |
2185 | chip->page_shift, 0, allowbbt)) { | 2235 | chip->page_shift, 0, allowbbt)) { |
2186 | printk(KERN_WARNING "nand_erase: attempt to erase a " | 2236 | printk(KERN_WARNING "%s: attempt to erase a bad block " |
2187 | "bad block at page 0x%08x\n", page); | 2237 | "at page 0x%08x\n", __func__, page); |
2188 | instr->state = MTD_ERASE_FAILED; | 2238 | instr->state = MTD_ERASE_FAILED; |
2189 | goto erase_exit; | 2239 | goto erase_exit; |
2190 | } | 2240 | } |
@@ -2211,8 +2261,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2211 | 2261 | ||
2212 | /* See if block erase succeeded */ | 2262 | /* See if block erase succeeded */ |
2213 | if (status & NAND_STATUS_FAIL) { | 2263 | if (status & NAND_STATUS_FAIL) { |
2214 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " | 2264 | DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " |
2215 | "Failed erase, page 0x%08x\n", page); | 2265 | "page 0x%08x\n", __func__, page); |
2216 | instr->state = MTD_ERASE_FAILED; | 2266 | instr->state = MTD_ERASE_FAILED; |
2217 | instr->fail_addr = | 2267 | instr->fail_addr = |
2218 | ((loff_t)page << chip->page_shift); | 2268 | ((loff_t)page << chip->page_shift); |
@@ -2272,9 +2322,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2272 | if (!rewrite_bbt[chipnr]) | 2322 | if (!rewrite_bbt[chipnr]) |
2273 | continue; | 2323 | continue; |
2274 | /* update the BBT for chip */ | 2324 | /* update the BBT for chip */ |
2275 | DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " | 2325 | DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " |
2276 | "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr], | 2326 | "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, |
2277 | chip->bbt_td->pages[chipnr]); | 2327 | rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); |
2278 | nand_update_bbt(mtd, rewrite_bbt[chipnr]); | 2328 | nand_update_bbt(mtd, rewrite_bbt[chipnr]); |
2279 | } | 2329 | } |
2280 | 2330 | ||
@@ -2292,7 +2342,7 @@ static void nand_sync(struct mtd_info *mtd) | |||
2292 | { | 2342 | { |
2293 | struct nand_chip *chip = mtd->priv; | 2343 | struct nand_chip *chip = mtd->priv; |
2294 | 2344 | ||
2295 | DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n"); | 2345 | DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); |
2296 | 2346 | ||
2297 | /* Grab the lock and see if the device is available */ | 2347 | /* Grab the lock and see if the device is available */ |
2298 | nand_get_device(chip, mtd, FL_SYNCING); | 2348 | nand_get_device(chip, mtd, FL_SYNCING); |
@@ -2356,8 +2406,8 @@ static void nand_resume(struct mtd_info *mtd) | |||
2356 | if (chip->state == FL_PM_SUSPENDED) | 2406 | if (chip->state == FL_PM_SUSPENDED) |
2357 | nand_release_device(mtd); | 2407 | nand_release_device(mtd); |
2358 | else | 2408 | else |
2359 | printk(KERN_ERR "nand_resume() called for a chip which is not " | 2409 | printk(KERN_ERR "%s called for a chip which is not " |
2360 | "in suspended state\n"); | 2410 | "in suspended state\n", __func__); |
2361 | } | 2411 | } |
2362 | 2412 | ||
2363 | /* | 2413 | /* |
@@ -2671,6 +2721,17 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2671 | */ | 2721 | */ |
2672 | 2722 | ||
2673 | switch (chip->ecc.mode) { | 2723 | switch (chip->ecc.mode) { |
2724 | case NAND_ECC_HW_OOB_FIRST: | ||
2725 | /* Similar to NAND_ECC_HW, but a separate read_page handle */ | ||
2726 | if (!chip->ecc.calculate || !chip->ecc.correct || | ||
2727 | !chip->ecc.hwctl) { | ||
2728 | printk(KERN_WARNING "No ECC functions supplied; " | ||
2729 | "Hardware ECC not possible\n"); | ||
2730 | BUG(); | ||
2731 | } | ||
2732 | if (!chip->ecc.read_page) | ||
2733 | chip->ecc.read_page = nand_read_page_hwecc_oob_first; | ||
2734 | |||
2674 | case NAND_ECC_HW: | 2735 | case NAND_ECC_HW: |
2675 | /* Use standard hwecc read page function ? */ | 2736 | /* Use standard hwecc read page function ? */ |
2676 | if (!chip->ecc.read_page) | 2737 | if (!chip->ecc.read_page) |
@@ -2693,7 +2754,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2693 | chip->ecc.read_page == nand_read_page_hwecc || | 2754 | chip->ecc.read_page == nand_read_page_hwecc || |
2694 | !chip->ecc.write_page || | 2755 | !chip->ecc.write_page || |
2695 | chip->ecc.write_page == nand_write_page_hwecc)) { | 2756 | chip->ecc.write_page == nand_write_page_hwecc)) { |
2696 | printk(KERN_WARNING "No ECC functions supplied, " | 2757 | printk(KERN_WARNING "No ECC functions supplied; " |
2697 | "Hardware ECC not possible\n"); | 2758 | "Hardware ECC not possible\n"); |
2698 | BUG(); | 2759 | BUG(); |
2699 | } | 2760 | } |
@@ -2728,7 +2789,8 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2728 | chip->ecc.write_page_raw = nand_write_page_raw; | 2789 | chip->ecc.write_page_raw = nand_write_page_raw; |
2729 | chip->ecc.read_oob = nand_read_oob_std; | 2790 | chip->ecc.read_oob = nand_read_oob_std; |
2730 | chip->ecc.write_oob = nand_write_oob_std; | 2791 | chip->ecc.write_oob = nand_write_oob_std; |
2731 | chip->ecc.size = 256; | 2792 | if (!chip->ecc.size) |
2793 | chip->ecc.size = 256; | ||
2732 | chip->ecc.bytes = 3; | 2794 | chip->ecc.bytes = 3; |
2733 | break; | 2795 | break; |
2734 | 2796 | ||
@@ -2858,7 +2920,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2858 | 2920 | ||
2859 | /* Many callers got this wrong, so check for it for a while... */ | 2921 | /* Many callers got this wrong, so check for it for a while... */ |
2860 | if (!mtd->owner && caller_is_module()) { | 2922 | if (!mtd->owner && caller_is_module()) { |
2861 | printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); | 2923 | printk(KERN_CRIT "%s called with NULL mtd->owner!\n", |
2924 | __func__); | ||
2862 | BUG(); | 2925 | BUG(); |
2863 | } | 2926 | } |
2864 | 2927 | ||
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index c0cb87d6d16e..db7ae9d6a296 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -417,22 +417,22 @@ int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, | |||
417 | EXPORT_SYMBOL(nand_calculate_ecc); | 417 | EXPORT_SYMBOL(nand_calculate_ecc); |
418 | 418 | ||
419 | /** | 419 | /** |
420 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) | 420 | * __nand_correct_data - [NAND Interface] Detect and correct bit error(s) |
421 | * @mtd: MTD block structure | ||
422 | * @buf: raw data read from the chip | 421 | * @buf: raw data read from the chip |
423 | * @read_ecc: ECC from the chip | 422 | * @read_ecc: ECC from the chip |
424 | * @calc_ecc: the ECC calculated from raw data | 423 | * @calc_ecc: the ECC calculated from raw data |
424 | * @eccsize: data bytes per ecc step (256 or 512) | ||
425 | * | 425 | * |
426 | * Detect and correct a 1 bit error for 256/512 byte block | 426 | * Detect and correct a 1 bit error for eccsize byte block |
427 | */ | 427 | */ |
428 | int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | 428 | int __nand_correct_data(unsigned char *buf, |
429 | unsigned char *read_ecc, unsigned char *calc_ecc) | 429 | unsigned char *read_ecc, unsigned char *calc_ecc, |
430 | unsigned int eccsize) | ||
430 | { | 431 | { |
431 | unsigned char b0, b1, b2, bit_addr; | 432 | unsigned char b0, b1, b2, bit_addr; |
432 | unsigned int byte_addr; | 433 | unsigned int byte_addr; |
433 | /* 256 or 512 bytes/ecc */ | 434 | /* 256 or 512 bytes/ecc */ |
434 | const uint32_t eccsize_mult = | 435 | const uint32_t eccsize_mult = eccsize >> 8; |
435 | (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; | ||
436 | 436 | ||
437 | /* | 437 | /* |
438 | * b0 to b2 indicate which bit is faulty (if any) | 438 | * b0 to b2 indicate which bit is faulty (if any) |
@@ -495,6 +495,23 @@ int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | |||
495 | printk(KERN_ERR "uncorrectable error : "); | 495 | printk(KERN_ERR "uncorrectable error : "); |
496 | return -1; | 496 | return -1; |
497 | } | 497 | } |
498 | EXPORT_SYMBOL(__nand_correct_data); | ||
499 | |||
500 | /** | ||
501 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) | ||
502 | * @mtd: MTD block structure | ||
503 | * @buf: raw data read from the chip | ||
504 | * @read_ecc: ECC from the chip | ||
505 | * @calc_ecc: the ECC calculated from raw data | ||
506 | * | ||
507 | * Detect and correct a 1 bit error for 256/512 byte block | ||
508 | */ | ||
509 | int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | ||
510 | unsigned char *read_ecc, unsigned char *calc_ecc) | ||
511 | { | ||
512 | return __nand_correct_data(buf, read_ecc, calc_ecc, | ||
513 | ((struct nand_chip *)mtd->priv)->ecc.size); | ||
514 | } | ||
498 | EXPORT_SYMBOL(nand_correct_data); | 515 | EXPORT_SYMBOL(nand_correct_data); |
499 | 516 | ||
500 | MODULE_LICENSE("GPL"); | 517 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 89bf85af642c..40b5658bdbe6 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -102,8 +102,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, | |||
102 | wmb(); | 102 | wmb(); |
103 | ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); | 103 | ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); |
104 | /* The NDFC uses Smart Media (SMC) bytes order */ | 104 | /* The NDFC uses Smart Media (SMC) bytes order */ |
105 | ecc_code[0] = p[2]; | 105 | ecc_code[0] = p[1]; |
106 | ecc_code[1] = p[1]; | 106 | ecc_code[1] = p[2]; |
107 | ecc_code[2] = p[3]; | 107 | ecc_code[2] = p[3]; |
108 | 108 | ||
109 | return 0; | 109 | return 0; |
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c new file mode 100644 index 000000000000..7c302d55910e --- /dev/null +++ b/drivers/mtd/nand/nomadik_nand.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/nomadik_nand.c | ||
3 | * | ||
4 | * Overview: | ||
5 | * Driver for on-board NAND flash on Nomadik Platforms | ||
6 | * | ||
7 | * Copyright © 2007 STMicroelectronics Pvt. Ltd. | ||
8 | * Author: Sachin Verma <sachin.verma@st.com> | ||
9 | * | ||
10 | * Copyright © 2009 Alessandro Rubini | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/mtd/mtd.h> | ||
28 | #include <linux/mtd/nand.h> | ||
29 | #include <linux/mtd/nand_ecc.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/mtd/partitions.h> | ||
32 | #include <linux/io.h> | ||
33 | #include <mach/nand.h> | ||
34 | #include <mach/fsmc.h> | ||
35 | |||
36 | #include <mtd/mtd-abi.h> | ||
37 | |||
38 | struct nomadik_nand_host { | ||
39 | struct mtd_info mtd; | ||
40 | struct nand_chip nand; | ||
41 | void __iomem *data_va; | ||
42 | void __iomem *cmd_va; | ||
43 | void __iomem *addr_va; | ||
44 | struct nand_bbt_descr *bbt_desc; | ||
45 | }; | ||
46 | |||
47 | static struct nand_ecclayout nomadik_ecc_layout = { | ||
48 | .eccbytes = 3 * 4, | ||
49 | .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */ | ||
50 | 0x02, 0x03, 0x04, | ||
51 | 0x12, 0x13, 0x14, | ||
52 | 0x22, 0x23, 0x24, | ||
53 | 0x32, 0x33, 0x34}, | ||
54 | /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */ | ||
55 | .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} }, | ||
56 | }; | ||
57 | |||
58 | static void nomadik_ecc_control(struct mtd_info *mtd, int mode) | ||
59 | { | ||
60 | /* No need to enable hw ecc, it's on by default */ | ||
61 | } | ||
62 | |||
63 | static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
64 | { | ||
65 | struct nand_chip *nand = mtd->priv; | ||
66 | struct nomadik_nand_host *host = nand->priv; | ||
67 | |||
68 | if (cmd == NAND_CMD_NONE) | ||
69 | return; | ||
70 | |||
71 | if (ctrl & NAND_CLE) | ||
72 | writeb(cmd, host->cmd_va); | ||
73 | else | ||
74 | writeb(cmd, host->addr_va); | ||
75 | } | ||
76 | |||
77 | static int nomadik_nand_probe(struct platform_device *pdev) | ||
78 | { | ||
79 | struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data; | ||
80 | struct nomadik_nand_host *host; | ||
81 | struct mtd_info *mtd; | ||
82 | struct nand_chip *nand; | ||
83 | struct resource *res; | ||
84 | int ret = 0; | ||
85 | |||
86 | /* Allocate memory for the device structure (and zero it) */ | ||
87 | host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL); | ||
88 | if (!host) { | ||
89 | dev_err(&pdev->dev, "Failed to allocate device structure.\n"); | ||
90 | return -ENOMEM; | ||
91 | } | ||
92 | |||
93 | /* Call the client's init function, if any */ | ||
94 | if (pdata->init) | ||
95 | ret = pdata->init(); | ||
96 | if (ret < 0) { | ||
97 | dev_err(&pdev->dev, "Init function failed\n"); | ||
98 | goto err; | ||
99 | } | ||
100 | |||
101 | /* ioremap three regions */ | ||
102 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); | ||
103 | if (!res) { | ||
104 | ret = -EIO; | ||
105 | goto err_unmap; | ||
106 | } | ||
107 | host->addr_va = ioremap(res->start, res->end - res->start + 1); | ||
108 | |||
109 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); | ||
110 | if (!res) { | ||
111 | ret = -EIO; | ||
112 | goto err_unmap; | ||
113 | } | ||
114 | host->data_va = ioremap(res->start, res->end - res->start + 1); | ||
115 | |||
116 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd"); | ||
117 | if (!res) { | ||
118 | ret = -EIO; | ||
119 | goto err_unmap; | ||
120 | } | ||
121 | host->cmd_va = ioremap(res->start, res->end - res->start + 1); | ||
122 | |||
123 | if (!host->addr_va || !host->data_va || !host->cmd_va) { | ||
124 | ret = -ENOMEM; | ||
125 | goto err_unmap; | ||
126 | } | ||
127 | |||
128 | /* Link all private pointers */ | ||
129 | mtd = &host->mtd; | ||
130 | nand = &host->nand; | ||
131 | mtd->priv = nand; | ||
132 | nand->priv = host; | ||
133 | |||
134 | host->mtd.owner = THIS_MODULE; | ||
135 | nand->IO_ADDR_R = host->data_va; | ||
136 | nand->IO_ADDR_W = host->data_va; | ||
137 | nand->cmd_ctrl = nomadik_cmd_ctrl; | ||
138 | |||
139 | /* | ||
140 | * This stanza declares ECC_HW but uses soft routines. It's because | ||
141 | * HW claims to make the calculation but not the correction. However, | ||
142 | * I haven't managed to get the desired data out of it until now. | ||
143 | */ | ||
144 | nand->ecc.mode = NAND_ECC_SOFT; | ||
145 | nand->ecc.layout = &nomadik_ecc_layout; | ||
146 | nand->ecc.hwctl = nomadik_ecc_control; | ||
147 | nand->ecc.size = 512; | ||
148 | nand->ecc.bytes = 3; | ||
149 | |||
150 | nand->options = pdata->options; | ||
151 | |||
152 | /* | ||
153 | * Scan to find existance of the device | ||
154 | */ | ||
155 | if (nand_scan(&host->mtd, 1)) { | ||
156 | ret = -ENXIO; | ||
157 | goto err_unmap; | ||
158 | } | ||
159 | |||
160 | #ifdef CONFIG_MTD_PARTITIONS | ||
161 | add_mtd_partitions(&host->mtd, pdata->parts, pdata->nparts); | ||
162 | #else | ||
163 | pr_info("Registering %s as whole device\n", mtd->name); | ||
164 | add_mtd_device(mtd); | ||
165 | #endif | ||
166 | |||
167 | platform_set_drvdata(pdev, host); | ||
168 | return 0; | ||
169 | |||
170 | err_unmap: | ||
171 | if (host->cmd_va) | ||
172 | iounmap(host->cmd_va); | ||
173 | if (host->data_va) | ||
174 | iounmap(host->data_va); | ||
175 | if (host->addr_va) | ||
176 | iounmap(host->addr_va); | ||
177 | err: | ||
178 | kfree(host); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Clean up routine | ||
184 | */ | ||
185 | static int nomadik_nand_remove(struct platform_device *pdev) | ||
186 | { | ||
187 | struct nomadik_nand_host *host = platform_get_drvdata(pdev); | ||
188 | struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data; | ||
189 | |||
190 | if (pdata->exit) | ||
191 | pdata->exit(); | ||
192 | |||
193 | if (host) { | ||
194 | iounmap(host->cmd_va); | ||
195 | iounmap(host->data_va); | ||
196 | iounmap(host->addr_va); | ||
197 | kfree(host); | ||
198 | } | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int nomadik_nand_suspend(struct device *dev) | ||
203 | { | ||
204 | struct nomadik_nand_host *host = dev_get_drvdata(dev); | ||
205 | int ret = 0; | ||
206 | if (host) | ||
207 | ret = host->mtd.suspend(&host->mtd); | ||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | static int nomadik_nand_resume(struct device *dev) | ||
212 | { | ||
213 | struct nomadik_nand_host *host = dev_get_drvdata(dev); | ||
214 | if (host) | ||
215 | host->mtd.resume(&host->mtd); | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static struct dev_pm_ops nomadik_nand_pm_ops = { | ||
220 | .suspend = nomadik_nand_suspend, | ||
221 | .resume = nomadik_nand_resume, | ||
222 | }; | ||
223 | |||
224 | static struct platform_driver nomadik_nand_driver = { | ||
225 | .probe = nomadik_nand_probe, | ||
226 | .remove = nomadik_nand_remove, | ||
227 | .driver = { | ||
228 | .owner = THIS_MODULE, | ||
229 | .name = "nomadik_nand", | ||
230 | .pm = &nomadik_nand_pm_ops, | ||
231 | }, | ||
232 | }; | ||
233 | |||
234 | static int __init nand_nomadik_init(void) | ||
235 | { | ||
236 | pr_info("Nomadik NAND driver\n"); | ||
237 | return platform_driver_register(&nomadik_nand_driver); | ||
238 | } | ||
239 | |||
240 | static void __exit nand_nomadik_exit(void) | ||
241 | { | ||
242 | platform_driver_unregister(&nomadik_nand_driver); | ||
243 | } | ||
244 | |||
245 | module_init(nand_nomadik_init); | ||
246 | module_exit(nand_nomadik_exit); | ||
247 | |||
248 | MODULE_LICENSE("GPL"); | ||
249 | MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)"); | ||
250 | MODULE_DESCRIPTION("NAND driver for Nomadik Platform"); | ||
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ebd07e95b814..090ab87086b5 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -18,8 +18,7 @@ | |||
18 | #include <linux/mtd/partitions.h> | 18 | #include <linux/mtd/partitions.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | #include <asm/dma.h> | 21 | #include <mach/dma.h> |
22 | |||
23 | #include <mach/gpmc.h> | 22 | #include <mach/gpmc.h> |
24 | #include <mach/nand.h> | 23 | #include <mach/nand.h> |
25 | 24 | ||
@@ -112,6 +111,27 @@ | |||
112 | static const char *part_probes[] = { "cmdlinepart", NULL }; | 111 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
113 | #endif | 112 | #endif |
114 | 113 | ||
114 | #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH | ||
115 | static int use_prefetch = 1; | ||
116 | |||
117 | /* "modprobe ... use_prefetch=0" etc */ | ||
118 | module_param(use_prefetch, bool, 0); | ||
119 | MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH"); | ||
120 | |||
121 | #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA | ||
122 | static int use_dma = 1; | ||
123 | |||
124 | /* "modprobe ... use_dma=0" etc */ | ||
125 | module_param(use_dma, bool, 0); | ||
126 | MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); | ||
127 | #else | ||
128 | const int use_dma; | ||
129 | #endif | ||
130 | #else | ||
131 | const int use_prefetch; | ||
132 | const int use_dma; | ||
133 | #endif | ||
134 | |||
115 | struct omap_nand_info { | 135 | struct omap_nand_info { |
116 | struct nand_hw_control controller; | 136 | struct nand_hw_control controller; |
117 | struct omap_nand_platform_data *pdata; | 137 | struct omap_nand_platform_data *pdata; |
@@ -124,6 +144,9 @@ struct omap_nand_info { | |||
124 | unsigned long phys_base; | 144 | unsigned long phys_base; |
125 | void __iomem *gpmc_cs_baseaddr; | 145 | void __iomem *gpmc_cs_baseaddr; |
126 | void __iomem *gpmc_baseaddr; | 146 | void __iomem *gpmc_baseaddr; |
147 | void __iomem *nand_pref_fifo_add; | ||
148 | struct completion comp; | ||
149 | int dma_ch; | ||
127 | }; | 150 | }; |
128 | 151 | ||
129 | /** | 152 | /** |
@@ -189,6 +212,38 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
189 | } | 212 | } |
190 | 213 | ||
191 | /** | 214 | /** |
215 | * omap_read_buf8 - read data from NAND controller into buffer | ||
216 | * @mtd: MTD device structure | ||
217 | * @buf: buffer to store date | ||
218 | * @len: number of bytes to read | ||
219 | */ | ||
220 | static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len) | ||
221 | { | ||
222 | struct nand_chip *nand = mtd->priv; | ||
223 | |||
224 | ioread8_rep(nand->IO_ADDR_R, buf, len); | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * omap_write_buf8 - write buffer to NAND controller | ||
229 | * @mtd: MTD device structure | ||
230 | * @buf: data buffer | ||
231 | * @len: number of bytes to write | ||
232 | */ | ||
233 | static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) | ||
234 | { | ||
235 | struct omap_nand_info *info = container_of(mtd, | ||
236 | struct omap_nand_info, mtd); | ||
237 | u_char *p = (u_char *)buf; | ||
238 | |||
239 | while (len--) { | ||
240 | iowrite8(*p++, info->nand.IO_ADDR_W); | ||
241 | while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + | ||
242 | GPMC_STATUS) & GPMC_BUF_FULL)); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /** | ||
192 | * omap_read_buf16 - read data from NAND controller into buffer | 247 | * omap_read_buf16 - read data from NAND controller into buffer |
193 | * @mtd: MTD device structure | 248 | * @mtd: MTD device structure |
194 | * @buf: buffer to store date | 249 | * @buf: buffer to store date |
@@ -198,7 +253,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len) | |||
198 | { | 253 | { |
199 | struct nand_chip *nand = mtd->priv; | 254 | struct nand_chip *nand = mtd->priv; |
200 | 255 | ||
201 | __raw_readsw(nand->IO_ADDR_R, buf, len / 2); | 256 | ioread16_rep(nand->IO_ADDR_R, buf, len / 2); |
202 | } | 257 | } |
203 | 258 | ||
204 | /** | 259 | /** |
@@ -217,13 +272,242 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) | |||
217 | len >>= 1; | 272 | len >>= 1; |
218 | 273 | ||
219 | while (len--) { | 274 | while (len--) { |
220 | writew(*p++, info->nand.IO_ADDR_W); | 275 | iowrite16(*p++, info->nand.IO_ADDR_W); |
221 | 276 | ||
222 | while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + | 277 | while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + |
223 | GPMC_STATUS) & GPMC_BUF_FULL)) | 278 | GPMC_STATUS) & GPMC_BUF_FULL)) |
224 | ; | 279 | ; |
225 | } | 280 | } |
226 | } | 281 | } |
282 | |||
283 | /** | ||
284 | * omap_read_buf_pref - read data from NAND controller into buffer | ||
285 | * @mtd: MTD device structure | ||
286 | * @buf: buffer to store date | ||
287 | * @len: number of bytes to read | ||
288 | */ | ||
289 | static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) | ||
290 | { | ||
291 | struct omap_nand_info *info = container_of(mtd, | ||
292 | struct omap_nand_info, mtd); | ||
293 | uint32_t pfpw_status = 0, r_count = 0; | ||
294 | int ret = 0; | ||
295 | u32 *p = (u32 *)buf; | ||
296 | |||
297 | /* take care of subpage reads */ | ||
298 | for (; len % 4 != 0; ) { | ||
299 | *buf++ = __raw_readb(info->nand.IO_ADDR_R); | ||
300 | len--; | ||
301 | } | ||
302 | p = (u32 *) buf; | ||
303 | |||
304 | /* configure and start prefetch transfer */ | ||
305 | ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0); | ||
306 | if (ret) { | ||
307 | /* PFPW engine is busy, use cpu copy method */ | ||
308 | if (info->nand.options & NAND_BUSWIDTH_16) | ||
309 | omap_read_buf16(mtd, buf, len); | ||
310 | else | ||
311 | omap_read_buf8(mtd, buf, len); | ||
312 | } else { | ||
313 | do { | ||
314 | pfpw_status = gpmc_prefetch_status(); | ||
315 | r_count = ((pfpw_status >> 24) & 0x7F) >> 2; | ||
316 | ioread32_rep(info->nand_pref_fifo_add, p, r_count); | ||
317 | p += r_count; | ||
318 | len -= r_count << 2; | ||
319 | } while (len); | ||
320 | |||
321 | /* disable and stop the PFPW engine */ | ||
322 | gpmc_prefetch_reset(); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * omap_write_buf_pref - write buffer to NAND controller | ||
328 | * @mtd: MTD device structure | ||
329 | * @buf: data buffer | ||
330 | * @len: number of bytes to write | ||
331 | */ | ||
332 | static void omap_write_buf_pref(struct mtd_info *mtd, | ||
333 | const u_char *buf, int len) | ||
334 | { | ||
335 | struct omap_nand_info *info = container_of(mtd, | ||
336 | struct omap_nand_info, mtd); | ||
337 | uint32_t pfpw_status = 0, w_count = 0; | ||
338 | int i = 0, ret = 0; | ||
339 | u16 *p = (u16 *) buf; | ||
340 | |||
341 | /* take care of subpage writes */ | ||
342 | if (len % 2 != 0) { | ||
343 | writeb(*buf, info->nand.IO_ADDR_R); | ||
344 | p = (u16 *)(buf + 1); | ||
345 | len--; | ||
346 | } | ||
347 | |||
348 | /* configure and start prefetch transfer */ | ||
349 | ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1); | ||
350 | if (ret) { | ||
351 | /* PFPW engine is busy, use cpu copy method */ | ||
352 | if (info->nand.options & NAND_BUSWIDTH_16) | ||
353 | omap_write_buf16(mtd, buf, len); | ||
354 | else | ||
355 | omap_write_buf8(mtd, buf, len); | ||
356 | } else { | ||
357 | pfpw_status = gpmc_prefetch_status(); | ||
358 | while (pfpw_status & 0x3FFF) { | ||
359 | w_count = ((pfpw_status >> 24) & 0x7F) >> 1; | ||
360 | for (i = 0; (i < w_count) && len; i++, len -= 2) | ||
361 | iowrite16(*p++, info->nand_pref_fifo_add); | ||
362 | pfpw_status = gpmc_prefetch_status(); | ||
363 | } | ||
364 | |||
365 | /* disable and stop the PFPW engine */ | ||
366 | gpmc_prefetch_reset(); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | #ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA | ||
371 | /* | ||
372 | * omap_nand_dma_cb: callback on the completion of dma transfer | ||
373 | * @lch: logical channel | ||
374 | * @ch_satuts: channel status | ||
375 | * @data: pointer to completion data structure | ||
376 | */ | ||
377 | static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) | ||
378 | { | ||
379 | complete((struct completion *) data); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * omap_nand_dma_transfer: configer and start dma transfer | ||
384 | * @mtd: MTD device structure | ||
385 | * @addr: virtual address in RAM of source/destination | ||
386 | * @len: number of data bytes to be transferred | ||
387 | * @is_write: flag for read/write operation | ||
388 | */ | ||
389 | static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | ||
390 | unsigned int len, int is_write) | ||
391 | { | ||
392 | struct omap_nand_info *info = container_of(mtd, | ||
393 | struct omap_nand_info, mtd); | ||
394 | uint32_t prefetch_status = 0; | ||
395 | enum dma_data_direction dir = is_write ? DMA_TO_DEVICE : | ||
396 | DMA_FROM_DEVICE; | ||
397 | dma_addr_t dma_addr; | ||
398 | int ret; | ||
399 | |||
400 | /* The fifo depth is 64 bytes. We have a sync at each frame and frame | ||
401 | * length is 64 bytes. | ||
402 | */ | ||
403 | int buf_len = len >> 6; | ||
404 | |||
405 | if (addr >= high_memory) { | ||
406 | struct page *p1; | ||
407 | |||
408 | if (((size_t)addr & PAGE_MASK) != | ||
409 | ((size_t)(addr + len - 1) & PAGE_MASK)) | ||
410 | goto out_copy; | ||
411 | p1 = vmalloc_to_page(addr); | ||
412 | if (!p1) | ||
413 | goto out_copy; | ||
414 | addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK); | ||
415 | } | ||
416 | |||
417 | dma_addr = dma_map_single(&info->pdev->dev, addr, len, dir); | ||
418 | if (dma_mapping_error(&info->pdev->dev, dma_addr)) { | ||
419 | dev_err(&info->pdev->dev, | ||
420 | "Couldn't DMA map a %d byte buffer\n", len); | ||
421 | goto out_copy; | ||
422 | } | ||
423 | |||
424 | if (is_write) { | ||
425 | omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, | ||
426 | info->phys_base, 0, 0); | ||
427 | omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, | ||
428 | dma_addr, 0, 0); | ||
429 | omap_set_dma_transfer_params(info->dma_ch, OMAP_DMA_DATA_TYPE_S32, | ||
430 | 0x10, buf_len, OMAP_DMA_SYNC_FRAME, | ||
431 | OMAP24XX_DMA_GPMC, OMAP_DMA_DST_SYNC); | ||
432 | } else { | ||
433 | omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, | ||
434 | info->phys_base, 0, 0); | ||
435 | omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, | ||
436 | dma_addr, 0, 0); | ||
437 | omap_set_dma_transfer_params(info->dma_ch, OMAP_DMA_DATA_TYPE_S32, | ||
438 | 0x10, buf_len, OMAP_DMA_SYNC_FRAME, | ||
439 | OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC); | ||
440 | } | ||
441 | /* configure and start prefetch transfer */ | ||
442 | ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write); | ||
443 | if (ret) | ||
444 | /* PFPW engine is busy, use cpu copy methode */ | ||
445 | goto out_copy; | ||
446 | |||
447 | init_completion(&info->comp); | ||
448 | |||
449 | omap_start_dma(info->dma_ch); | ||
450 | |||
451 | /* setup and start DMA using dma_addr */ | ||
452 | wait_for_completion(&info->comp); | ||
453 | |||
454 | while (0x3fff & (prefetch_status = gpmc_prefetch_status())) | ||
455 | ; | ||
456 | /* disable and stop the PFPW engine */ | ||
457 | gpmc_prefetch_reset(); | ||
458 | |||
459 | dma_unmap_single(&info->pdev->dev, dma_addr, len, dir); | ||
460 | return 0; | ||
461 | |||
462 | out_copy: | ||
463 | if (info->nand.options & NAND_BUSWIDTH_16) | ||
464 | is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len) | ||
465 | : omap_write_buf16(mtd, (u_char *) addr, len); | ||
466 | else | ||
467 | is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len) | ||
468 | : omap_write_buf8(mtd, (u_char *) addr, len); | ||
469 | return 0; | ||
470 | } | ||
471 | #else | ||
472 | static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {} | ||
473 | static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, | ||
474 | unsigned int len, int is_write) | ||
475 | { | ||
476 | return 0; | ||
477 | } | ||
478 | #endif | ||
479 | |||
480 | /** | ||
481 | * omap_read_buf_dma_pref - read data from NAND controller into buffer | ||
482 | * @mtd: MTD device structure | ||
483 | * @buf: buffer to store date | ||
484 | * @len: number of bytes to read | ||
485 | */ | ||
486 | static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len) | ||
487 | { | ||
488 | if (len <= mtd->oobsize) | ||
489 | omap_read_buf_pref(mtd, buf, len); | ||
490 | else | ||
491 | /* start transfer in DMA mode */ | ||
492 | omap_nand_dma_transfer(mtd, buf, len, 0x0); | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * omap_write_buf_dma_pref - write buffer to NAND controller | ||
497 | * @mtd: MTD device structure | ||
498 | * @buf: data buffer | ||
499 | * @len: number of bytes to write | ||
500 | */ | ||
501 | static void omap_write_buf_dma_pref(struct mtd_info *mtd, | ||
502 | const u_char *buf, int len) | ||
503 | { | ||
504 | if (len <= mtd->oobsize) | ||
505 | omap_write_buf_pref(mtd, buf, len); | ||
506 | else | ||
507 | /* start transfer in DMA mode */ | ||
508 | omap_nand_dma_transfer(mtd, buf, len, 0x1); | ||
509 | } | ||
510 | |||
227 | /** | 511 | /** |
228 | * omap_verify_buf - Verify chip data against buffer | 512 | * omap_verify_buf - Verify chip data against buffer |
229 | * @mtd: MTD device structure | 513 | * @mtd: MTD device structure |
@@ -658,17 +942,12 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
658 | err = -ENOMEM; | 942 | err = -ENOMEM; |
659 | goto out_release_mem_region; | 943 | goto out_release_mem_region; |
660 | } | 944 | } |
945 | |||
661 | info->nand.controller = &info->controller; | 946 | info->nand.controller = &info->controller; |
662 | 947 | ||
663 | info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; | 948 | info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; |
664 | info->nand.cmd_ctrl = omap_hwcontrol; | 949 | info->nand.cmd_ctrl = omap_hwcontrol; |
665 | 950 | ||
666 | /* REVISIT: only supports 16-bit NAND flash */ | ||
667 | |||
668 | info->nand.read_buf = omap_read_buf16; | ||
669 | info->nand.write_buf = omap_write_buf16; | ||
670 | info->nand.verify_buf = omap_verify_buf; | ||
671 | |||
672 | /* | 951 | /* |
673 | * If RDY/BSY line is connected to OMAP then use the omap ready | 952 | * If RDY/BSY line is connected to OMAP then use the omap ready |
674 | * funcrtion and the generic nand_wait function which reads the status | 953 | * funcrtion and the generic nand_wait function which reads the status |
@@ -689,6 +968,40 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) | |||
689 | == 0x1000) | 968 | == 0x1000) |
690 | info->nand.options |= NAND_BUSWIDTH_16; | 969 | info->nand.options |= NAND_BUSWIDTH_16; |
691 | 970 | ||
971 | if (use_prefetch) { | ||
972 | /* copy the virtual address of nand base for fifo access */ | ||
973 | info->nand_pref_fifo_add = info->nand.IO_ADDR_R; | ||
974 | |||
975 | info->nand.read_buf = omap_read_buf_pref; | ||
976 | info->nand.write_buf = omap_write_buf_pref; | ||
977 | if (use_dma) { | ||
978 | err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND", | ||
979 | omap_nand_dma_cb, &info->comp, &info->dma_ch); | ||
980 | if (err < 0) { | ||
981 | info->dma_ch = -1; | ||
982 | printk(KERN_WARNING "DMA request failed." | ||
983 | " Non-dma data transfer mode\n"); | ||
984 | } else { | ||
985 | omap_set_dma_dest_burst_mode(info->dma_ch, | ||
986 | OMAP_DMA_DATA_BURST_16); | ||
987 | omap_set_dma_src_burst_mode(info->dma_ch, | ||
988 | OMAP_DMA_DATA_BURST_16); | ||
989 | |||
990 | info->nand.read_buf = omap_read_buf_dma_pref; | ||
991 | info->nand.write_buf = omap_write_buf_dma_pref; | ||
992 | } | ||
993 | } | ||
994 | } else { | ||
995 | if (info->nand.options & NAND_BUSWIDTH_16) { | ||
996 | info->nand.read_buf = omap_read_buf16; | ||
997 | info->nand.write_buf = omap_write_buf16; | ||
998 | } else { | ||
999 | info->nand.read_buf = omap_read_buf8; | ||
1000 | info->nand.write_buf = omap_write_buf8; | ||
1001 | } | ||
1002 | } | ||
1003 | info->nand.verify_buf = omap_verify_buf; | ||
1004 | |||
692 | #ifdef CONFIG_MTD_NAND_OMAP_HWECC | 1005 | #ifdef CONFIG_MTD_NAND_OMAP_HWECC |
693 | info->nand.ecc.bytes = 3; | 1006 | info->nand.ecc.bytes = 3; |
694 | info->nand.ecc.size = 512; | 1007 | info->nand.ecc.size = 512; |
@@ -744,9 +1057,12 @@ static int omap_nand_remove(struct platform_device *pdev) | |||
744 | struct omap_nand_info *info = mtd->priv; | 1057 | struct omap_nand_info *info = mtd->priv; |
745 | 1058 | ||
746 | platform_set_drvdata(pdev, NULL); | 1059 | platform_set_drvdata(pdev, NULL); |
1060 | if (use_dma) | ||
1061 | omap_free_dma(info->dma_ch); | ||
1062 | |||
747 | /* Release NAND device, its internal structures and partitions */ | 1063 | /* Release NAND device, its internal structures and partitions */ |
748 | nand_release(&info->mtd); | 1064 | nand_release(&info->mtd); |
749 | iounmap(info->nand.IO_ADDR_R); | 1065 | iounmap(info->nand_pref_fifo_add); |
750 | kfree(&info->mtd); | 1066 | kfree(&info->mtd); |
751 | return 0; | 1067 | return 0; |
752 | } | 1068 | } |
@@ -763,6 +1079,15 @@ static struct platform_driver omap_nand_driver = { | |||
763 | static int __init omap_nand_init(void) | 1079 | static int __init omap_nand_init(void) |
764 | { | 1080 | { |
765 | printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME); | 1081 | printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME); |
1082 | |||
1083 | /* This check is required if driver is being | ||
1084 | * loaded run time as a module | ||
1085 | */ | ||
1086 | if ((1 == use_dma) && (0 == use_prefetch)) { | ||
1087 | printk(KERN_INFO"Wrong parameters: 'use_dma' can not be 1 " | ||
1088 | "without use_prefetch'. Prefetch will not be" | ||
1089 | " used in either mode (mpu or dma)\n"); | ||
1090 | } | ||
766 | return platform_driver_register(&omap_nand_driver); | 1091 | return platform_driver_register(&omap_nand_driver); |
767 | } | 1092 | } |
768 | 1093 | ||
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 0d9d4bc9c762..f59c07427af3 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c | |||
@@ -171,7 +171,6 @@ static int __devexit orion_nand_remove(struct platform_device *pdev) | |||
171 | } | 171 | } |
172 | 172 | ||
173 | static struct platform_driver orion_nand_driver = { | 173 | static struct platform_driver orion_nand_driver = { |
174 | .probe = orion_nand_probe, | ||
175 | .remove = __devexit_p(orion_nand_remove), | 174 | .remove = __devexit_p(orion_nand_remove), |
176 | .driver = { | 175 | .driver = { |
177 | .name = "orion_nand", | 176 | .name = "orion_nand", |
@@ -181,7 +180,7 @@ static struct platform_driver orion_nand_driver = { | |||
181 | 180 | ||
182 | static int __init orion_nand_init(void) | 181 | static int __init orion_nand_init(void) |
183 | { | 182 | { |
184 | return platform_driver_register(&orion_nand_driver); | 183 | return platform_driver_probe(&orion_nand_driver, orion_nand_probe); |
185 | } | 184 | } |
186 | 185 | ||
187 | static void __exit orion_nand_exit(void) | 186 | static void __exit orion_nand_exit(void) |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 30a8ce6d3e69..6ea520ae2410 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -102,6 +102,7 @@ enum { | |||
102 | ERR_SENDCMD = -2, | 102 | ERR_SENDCMD = -2, |
103 | ERR_DBERR = -3, | 103 | ERR_DBERR = -3, |
104 | ERR_BBERR = -4, | 104 | ERR_BBERR = -4, |
105 | ERR_SBERR = -5, | ||
105 | }; | 106 | }; |
106 | 107 | ||
107 | enum { | 108 | enum { |
@@ -564,11 +565,13 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
564 | 565 | ||
565 | status = nand_readl(info, NDSR); | 566 | status = nand_readl(info, NDSR); |
566 | 567 | ||
567 | if (status & (NDSR_RDDREQ | NDSR_DBERR)) { | 568 | if (status & (NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR)) { |
568 | if (status & NDSR_DBERR) | 569 | if (status & NDSR_DBERR) |
569 | info->retcode = ERR_DBERR; | 570 | info->retcode = ERR_DBERR; |
571 | else if (status & NDSR_SBERR) | ||
572 | info->retcode = ERR_SBERR; | ||
570 | 573 | ||
571 | disable_int(info, NDSR_RDDREQ | NDSR_DBERR); | 574 | disable_int(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); |
572 | 575 | ||
573 | if (info->use_dma) { | 576 | if (info->use_dma) { |
574 | info->state = STATE_DMA_READING; | 577 | info->state = STATE_DMA_READING; |
@@ -670,7 +673,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
670 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) | 673 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) |
671 | break; | 674 | break; |
672 | 675 | ||
673 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR); | 676 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); |
674 | 677 | ||
675 | /* We only are OOB, so if the data has error, does not matter */ | 678 | /* We only are OOB, so if the data has error, does not matter */ |
676 | if (info->retcode == ERR_DBERR) | 679 | if (info->retcode == ERR_DBERR) |
@@ -687,7 +690,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
687 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) | 690 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) |
688 | break; | 691 | break; |
689 | 692 | ||
690 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR); | 693 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); |
691 | 694 | ||
692 | if (info->retcode == ERR_DBERR) { | 695 | if (info->retcode == ERR_DBERR) { |
693 | /* for blank page (all 0xff), HW will calculate its ECC as | 696 | /* for blank page (all 0xff), HW will calculate its ECC as |
@@ -861,8 +864,12 @@ static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, | |||
861 | * consider it as a ecc error which will tell the caller the | 864 | * consider it as a ecc error which will tell the caller the |
862 | * read fail We have distinguish all the errors, but the | 865 | * read fail We have distinguish all the errors, but the |
863 | * nand_read_ecc only check this function return value | 866 | * nand_read_ecc only check this function return value |
867 | * | ||
868 | * Corrected (single-bit) errors must also be noted. | ||
864 | */ | 869 | */ |
865 | if (info->retcode != ERR_NONE) | 870 | if (info->retcode == ERR_SBERR) |
871 | return 1; | ||
872 | else if (info->retcode != ERR_NONE) | ||
866 | return -1; | 873 | return -1; |
867 | 874 | ||
868 | return 0; | 875 | return 0; |
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 2bc896623e2d..02bef21f2e4b 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
@@ -329,7 +329,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va | |||
329 | } | 329 | } |
330 | 330 | ||
331 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | 331 | static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, |
332 | uint8_t *buf) | 332 | uint8_t *buf, int page) |
333 | { | 333 | { |
334 | int i, eccsize = chip->ecc.size; | 334 | int i, eccsize = chip->ecc.size; |
335 | int eccbytes = chip->ecc.bytes; | 335 | int eccbytes = chip->ecc.bytes; |
@@ -857,7 +857,6 @@ static int __exit flctl_remove(struct platform_device *pdev) | |||
857 | } | 857 | } |
858 | 858 | ||
859 | static struct platform_driver flctl_driver = { | 859 | static struct platform_driver flctl_driver = { |
860 | .probe = flctl_probe, | ||
861 | .remove = flctl_remove, | 860 | .remove = flctl_remove, |
862 | .driver = { | 861 | .driver = { |
863 | .name = "sh_flctl", | 862 | .name = "sh_flctl", |
@@ -867,7 +866,7 @@ static struct platform_driver flctl_driver = { | |||
867 | 866 | ||
868 | static int __init flctl_nand_init(void) | 867 | static int __init flctl_nand_init(void) |
869 | { | 868 | { |
870 | return platform_driver_register(&flctl_driver); | 869 | return platform_driver_probe(&flctl_driver, flctl_probe); |
871 | } | 870 | } |
872 | 871 | ||
873 | static void __exit flctl_nand_cleanup(void) | 872 | static void __exit flctl_nand_cleanup(void) |
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index daa6a4c3b8ce..92c73344a669 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c | |||
@@ -301,6 +301,21 @@ static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | |||
301 | return 0; | 301 | return 0; |
302 | } | 302 | } |
303 | 303 | ||
304 | static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | ||
305 | unsigned char *read_ecc, unsigned char *calc_ecc) | ||
306 | { | ||
307 | int r0, r1; | ||
308 | |||
309 | /* assume ecc.size = 512 and ecc.bytes = 6 */ | ||
310 | r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256); | ||
311 | if (r0 < 0) | ||
312 | return r0; | ||
313 | r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256); | ||
314 | if (r1 < 0) | ||
315 | return r1; | ||
316 | return r0 + r1; | ||
317 | } | ||
318 | |||
304 | static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) | 319 | static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) |
305 | { | 320 | { |
306 | struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; | 321 | struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; |
@@ -424,7 +439,7 @@ static int tmio_probe(struct platform_device *dev) | |||
424 | nand_chip->ecc.bytes = 6; | 439 | nand_chip->ecc.bytes = 6; |
425 | nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; | 440 | nand_chip->ecc.hwctl = tmio_nand_enable_hwecc; |
426 | nand_chip->ecc.calculate = tmio_nand_calculate_ecc; | 441 | nand_chip->ecc.calculate = tmio_nand_calculate_ecc; |
427 | nand_chip->ecc.correct = nand_correct_data; | 442 | nand_chip->ecc.correct = tmio_nand_correct_data; |
428 | 443 | ||
429 | if (data) | 444 | if (data) |
430 | nand_chip->badblock_pattern = data->badblock_pattern; | 445 | nand_chip->badblock_pattern = data->badblock_pattern; |
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 488088eff2ca..73af8324d0d0 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c | |||
@@ -189,18 +189,43 @@ static int txx9ndfmc_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, | |||
189 | uint8_t *ecc_code) | 189 | uint8_t *ecc_code) |
190 | { | 190 | { |
191 | struct platform_device *dev = mtd_to_platdev(mtd); | 191 | struct platform_device *dev = mtd_to_platdev(mtd); |
192 | struct nand_chip *chip = mtd->priv; | ||
193 | int eccbytes; | ||
192 | u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); | 194 | u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR); |
193 | 195 | ||
194 | mcr &= ~TXX9_NDFMCR_ECC_ALL; | 196 | mcr &= ~TXX9_NDFMCR_ECC_ALL; |
195 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); | 197 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); |
196 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR); | 198 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_READ, TXX9_NDFMCR); |
197 | ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR); | 199 | for (eccbytes = chip->ecc.bytes; eccbytes > 0; eccbytes -= 3) { |
198 | ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR); | 200 | ecc_code[1] = txx9ndfmc_read(dev, TXX9_NDFDTR); |
199 | ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR); | 201 | ecc_code[0] = txx9ndfmc_read(dev, TXX9_NDFDTR); |
202 | ecc_code[2] = txx9ndfmc_read(dev, TXX9_NDFDTR); | ||
203 | ecc_code += 3; | ||
204 | } | ||
200 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); | 205 | txx9ndfmc_write(dev, mcr | TXX9_NDFMCR_ECC_OFF, TXX9_NDFMCR); |
201 | return 0; | 206 | return 0; |
202 | } | 207 | } |
203 | 208 | ||
209 | static int txx9ndfmc_correct_data(struct mtd_info *mtd, unsigned char *buf, | ||
210 | unsigned char *read_ecc, unsigned char *calc_ecc) | ||
211 | { | ||
212 | struct nand_chip *chip = mtd->priv; | ||
213 | int eccsize; | ||
214 | int corrected = 0; | ||
215 | int stat; | ||
216 | |||
217 | for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) { | ||
218 | stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256); | ||
219 | if (stat < 0) | ||
220 | return stat; | ||
221 | corrected += stat; | ||
222 | buf += 256; | ||
223 | read_ecc += 3; | ||
224 | calc_ecc += 3; | ||
225 | } | ||
226 | return corrected; | ||
227 | } | ||
228 | |||
204 | static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) | 229 | static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) |
205 | { | 230 | { |
206 | struct platform_device *dev = mtd_to_platdev(mtd); | 231 | struct platform_device *dev = mtd_to_platdev(mtd); |
@@ -244,6 +269,22 @@ static void txx9ndfmc_initialize(struct platform_device *dev) | |||
244 | #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \ | 269 | #define TXX9NDFMC_NS_TO_CYC(gbusclk, ns) \ |
245 | DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000) | 270 | DIV_ROUND_UP((ns) * DIV_ROUND_UP(gbusclk, 1000), 1000000) |
246 | 271 | ||
272 | static int txx9ndfmc_nand_scan(struct mtd_info *mtd) | ||
273 | { | ||
274 | struct nand_chip *chip = mtd->priv; | ||
275 | int ret; | ||
276 | |||
277 | ret = nand_scan_ident(mtd, 1); | ||
278 | if (!ret) { | ||
279 | if (mtd->writesize >= 512) { | ||
280 | chip->ecc.size = mtd->writesize; | ||
281 | chip->ecc.bytes = 3 * (mtd->writesize / 256); | ||
282 | } | ||
283 | ret = nand_scan_tail(mtd); | ||
284 | } | ||
285 | return ret; | ||
286 | } | ||
287 | |||
247 | static int __init txx9ndfmc_probe(struct platform_device *dev) | 288 | static int __init txx9ndfmc_probe(struct platform_device *dev) |
248 | { | 289 | { |
249 | struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; | 290 | struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; |
@@ -321,9 +362,10 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) | |||
321 | chip->cmd_ctrl = txx9ndfmc_cmd_ctrl; | 362 | chip->cmd_ctrl = txx9ndfmc_cmd_ctrl; |
322 | chip->dev_ready = txx9ndfmc_dev_ready; | 363 | chip->dev_ready = txx9ndfmc_dev_ready; |
323 | chip->ecc.calculate = txx9ndfmc_calculate_ecc; | 364 | chip->ecc.calculate = txx9ndfmc_calculate_ecc; |
324 | chip->ecc.correct = nand_correct_data; | 365 | chip->ecc.correct = txx9ndfmc_correct_data; |
325 | chip->ecc.hwctl = txx9ndfmc_enable_hwecc; | 366 | chip->ecc.hwctl = txx9ndfmc_enable_hwecc; |
326 | chip->ecc.mode = NAND_ECC_HW; | 367 | chip->ecc.mode = NAND_ECC_HW; |
368 | /* txx9ndfmc_nand_scan will overwrite ecc.size and ecc.bytes */ | ||
327 | chip->ecc.size = 256; | 369 | chip->ecc.size = 256; |
328 | chip->ecc.bytes = 3; | 370 | chip->ecc.bytes = 3; |
329 | chip->chip_delay = 100; | 371 | chip->chip_delay = 100; |
@@ -349,7 +391,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) | |||
349 | if (plat->wide_mask & (1 << i)) | 391 | if (plat->wide_mask & (1 << i)) |
350 | chip->options |= NAND_BUSWIDTH_16; | 392 | chip->options |= NAND_BUSWIDTH_16; |
351 | 393 | ||
352 | if (nand_scan(mtd, 1)) { | 394 | if (txx9ndfmc_nand_scan(mtd)) { |
353 | kfree(txx9_priv->mtdname); | 395 | kfree(txx9_priv->mtdname); |
354 | kfree(txx9_priv); | 396 | kfree(txx9_priv); |
355 | continue; | 397 | continue; |
diff --git a/drivers/mtd/nand/w90p910_nand.c b/drivers/mtd/nand/w90p910_nand.c new file mode 100644 index 000000000000..7680e731348a --- /dev/null +++ b/drivers/mtd/nand/w90p910_nand.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2009 Nuvoton technology corporation. | ||
3 | * | ||
4 | * Wan ZongShun <mcuos.com@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation;version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include <linux/mtd/mtd.h> | ||
23 | #include <linux/mtd/nand.h> | ||
24 | #include <linux/mtd/partitions.h> | ||
25 | |||
26 | #define REG_FMICSR 0x00 | ||
27 | #define REG_SMCSR 0xa0 | ||
28 | #define REG_SMISR 0xac | ||
29 | #define REG_SMCMD 0xb0 | ||
30 | #define REG_SMADDR 0xb4 | ||
31 | #define REG_SMDATA 0xb8 | ||
32 | |||
33 | #define RESET_FMI 0x01 | ||
34 | #define NAND_EN 0x08 | ||
35 | #define READYBUSY (0x01 << 18) | ||
36 | |||
37 | #define SWRST 0x01 | ||
38 | #define PSIZE (0x01 << 3) | ||
39 | #define DMARWEN (0x03 << 1) | ||
40 | #define BUSWID (0x01 << 4) | ||
41 | #define ECC4EN (0x01 << 5) | ||
42 | #define WP (0x01 << 24) | ||
43 | #define NANDCS (0x01 << 25) | ||
44 | #define ENDADDR (0x01 << 31) | ||
45 | |||
46 | #define read_data_reg(dev) \ | ||
47 | __raw_readl((dev)->reg + REG_SMDATA) | ||
48 | |||
49 | #define write_data_reg(dev, val) \ | ||
50 | __raw_writel((val), (dev)->reg + REG_SMDATA) | ||
51 | |||
52 | #define write_cmd_reg(dev, val) \ | ||
53 | __raw_writel((val), (dev)->reg + REG_SMCMD) | ||
54 | |||
55 | #define write_addr_reg(dev, val) \ | ||
56 | __raw_writel((val), (dev)->reg + REG_SMADDR) | ||
57 | |||
58 | struct w90p910_nand { | ||
59 | struct mtd_info mtd; | ||
60 | struct nand_chip chip; | ||
61 | void __iomem *reg; | ||
62 | struct clk *clk; | ||
63 | spinlock_t lock; | ||
64 | }; | ||
65 | |||
66 | static const struct mtd_partition partitions[] = { | ||
67 | { | ||
68 | .name = "NAND FS 0", | ||
69 | .offset = 0, | ||
70 | .size = 8 * 1024 * 1024 | ||
71 | }, | ||
72 | { | ||
73 | .name = "NAND FS 1", | ||
74 | .offset = MTDPART_OFS_APPEND, | ||
75 | .size = MTDPART_SIZ_FULL | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | static unsigned char w90p910_nand_read_byte(struct mtd_info *mtd) | ||
80 | { | ||
81 | unsigned char ret; | ||
82 | struct w90p910_nand *nand; | ||
83 | |||
84 | nand = container_of(mtd, struct w90p910_nand, mtd); | ||
85 | |||
86 | ret = (unsigned char)read_data_reg(nand); | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | static void w90p910_nand_read_buf(struct mtd_info *mtd, | ||
92 | unsigned char *buf, int len) | ||
93 | { | ||
94 | int i; | ||
95 | struct w90p910_nand *nand; | ||
96 | |||
97 | nand = container_of(mtd, struct w90p910_nand, mtd); | ||
98 | |||
99 | for (i = 0; i < len; i++) | ||
100 | buf[i] = (unsigned char)read_data_reg(nand); | ||
101 | } | ||
102 | |||
103 | static void w90p910_nand_write_buf(struct mtd_info *mtd, | ||
104 | const unsigned char *buf, int len) | ||
105 | { | ||
106 | int i; | ||
107 | struct w90p910_nand *nand; | ||
108 | |||
109 | nand = container_of(mtd, struct w90p910_nand, mtd); | ||
110 | |||
111 | for (i = 0; i < len; i++) | ||
112 | write_data_reg(nand, buf[i]); | ||
113 | } | ||
114 | |||
115 | static int w90p910_verify_buf(struct mtd_info *mtd, | ||
116 | const unsigned char *buf, int len) | ||
117 | { | ||
118 | int i; | ||
119 | struct w90p910_nand *nand; | ||
120 | |||
121 | nand = container_of(mtd, struct w90p910_nand, mtd); | ||
122 | |||
123 | for (i = 0; i < len; i++) { | ||
124 | if (buf[i] != (unsigned char)read_data_reg(nand)) | ||
125 | return -EFAULT; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int w90p910_check_rb(struct w90p910_nand *nand) | ||
132 | { | ||
133 | unsigned int val; | ||
134 | spin_lock(&nand->lock); | ||
135 | val = __raw_readl(REG_SMISR); | ||
136 | val &= READYBUSY; | ||
137 | spin_unlock(&nand->lock); | ||
138 | |||
139 | return val; | ||
140 | } | ||
141 | |||
142 | static int w90p910_nand_devready(struct mtd_info *mtd) | ||
143 | { | ||
144 | struct w90p910_nand *nand; | ||
145 | int ready; | ||
146 | |||
147 | nand = container_of(mtd, struct w90p910_nand, mtd); | ||
148 | |||
149 | ready = (w90p910_check_rb(nand)) ? 1 : 0; | ||
150 | return ready; | ||
151 | } | ||
152 | |||
153 | static void w90p910_nand_command_lp(struct mtd_info *mtd, | ||
154 | unsigned int command, int column, int page_addr) | ||
155 | { | ||
156 | register struct nand_chip *chip = mtd->priv; | ||
157 | struct w90p910_nand *nand; | ||
158 | |||
159 | nand = container_of(mtd, struct w90p910_nand, mtd); | ||
160 | |||
161 | if (command == NAND_CMD_READOOB) { | ||
162 | column += mtd->writesize; | ||
163 | command = NAND_CMD_READ0; | ||
164 | } | ||
165 | |||
166 | write_cmd_reg(nand, command & 0xff); | ||
167 | |||
168 | if (column != -1 || page_addr != -1) { | ||
169 | |||
170 | if (column != -1) { | ||
171 | if (chip->options & NAND_BUSWIDTH_16) | ||
172 | column >>= 1; | ||
173 | write_addr_reg(nand, column); | ||
174 | write_addr_reg(nand, column >> 8 | ENDADDR); | ||
175 | } | ||
176 | if (page_addr != -1) { | ||
177 | write_addr_reg(nand, page_addr); | ||
178 | |||
179 | if (chip->chipsize > (128 << 20)) { | ||
180 | write_addr_reg(nand, page_addr >> 8); | ||
181 | write_addr_reg(nand, page_addr >> 16 | ENDADDR); | ||
182 | } else { | ||
183 | write_addr_reg(nand, page_addr >> 8 | ENDADDR); | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | switch (command) { | ||
189 | case NAND_CMD_CACHEDPROG: | ||
190 | case NAND_CMD_PAGEPROG: | ||
191 | case NAND_CMD_ERASE1: | ||
192 | case NAND_CMD_ERASE2: | ||
193 | case NAND_CMD_SEQIN: | ||
194 | case NAND_CMD_RNDIN: | ||
195 | case NAND_CMD_STATUS: | ||
196 | case NAND_CMD_DEPLETE1: | ||
197 | return; | ||
198 | |||
199 | case NAND_CMD_STATUS_ERROR: | ||
200 | case NAND_CMD_STATUS_ERROR0: | ||
201 | case NAND_CMD_STATUS_ERROR1: | ||
202 | case NAND_CMD_STATUS_ERROR2: | ||
203 | case NAND_CMD_STATUS_ERROR3: | ||
204 | udelay(chip->chip_delay); | ||
205 | return; | ||
206 | |||
207 | case NAND_CMD_RESET: | ||
208 | if (chip->dev_ready) | ||
209 | break; | ||
210 | udelay(chip->chip_delay); | ||
211 | |||
212 | write_cmd_reg(nand, NAND_CMD_STATUS); | ||
213 | write_cmd_reg(nand, command); | ||
214 | |||
215 | while (!w90p910_check_rb(nand)) | ||
216 | ; | ||
217 | |||
218 | return; | ||
219 | |||
220 | case NAND_CMD_RNDOUT: | ||
221 | write_cmd_reg(nand, NAND_CMD_RNDOUTSTART); | ||
222 | return; | ||
223 | |||
224 | case NAND_CMD_READ0: | ||
225 | |||
226 | write_cmd_reg(nand, NAND_CMD_READSTART); | ||
227 | default: | ||
228 | |||
229 | if (!chip->dev_ready) { | ||
230 | udelay(chip->chip_delay); | ||
231 | return; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /* Apply this short delay always to ensure that we do wait tWB in | ||
236 | * any case on any machine. */ | ||
237 | ndelay(100); | ||
238 | |||
239 | while (!chip->dev_ready(mtd)) | ||
240 | ; | ||
241 | } | ||
242 | |||
243 | |||
244 | static void w90p910_nand_enable(struct w90p910_nand *nand) | ||
245 | { | ||
246 | unsigned int val; | ||
247 | spin_lock(&nand->lock); | ||
248 | __raw_writel(RESET_FMI, (nand->reg + REG_FMICSR)); | ||
249 | |||
250 | val = __raw_readl(nand->reg + REG_FMICSR); | ||
251 | |||
252 | if (!(val & NAND_EN)) | ||
253 | __raw_writel(val | NAND_EN, REG_FMICSR); | ||
254 | |||
255 | val = __raw_readl(nand->reg + REG_SMCSR); | ||
256 | |||
257 | val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS); | ||
258 | val |= WP; | ||
259 | |||
260 | __raw_writel(val, nand->reg + REG_SMCSR); | ||
261 | |||
262 | spin_unlock(&nand->lock); | ||
263 | } | ||
264 | |||
265 | static int __devinit w90p910_nand_probe(struct platform_device *pdev) | ||
266 | { | ||
267 | struct w90p910_nand *w90p910_nand; | ||
268 | struct nand_chip *chip; | ||
269 | int retval; | ||
270 | struct resource *res; | ||
271 | |||
272 | retval = 0; | ||
273 | |||
274 | w90p910_nand = kzalloc(sizeof(struct w90p910_nand), GFP_KERNEL); | ||
275 | if (!w90p910_nand) | ||
276 | return -ENOMEM; | ||
277 | chip = &(w90p910_nand->chip); | ||
278 | |||
279 | w90p910_nand->mtd.priv = chip; | ||
280 | w90p910_nand->mtd.owner = THIS_MODULE; | ||
281 | spin_lock_init(&w90p910_nand->lock); | ||
282 | |||
283 | w90p910_nand->clk = clk_get(&pdev->dev, NULL); | ||
284 | if (IS_ERR(w90p910_nand->clk)) { | ||
285 | retval = -ENOENT; | ||
286 | goto fail1; | ||
287 | } | ||
288 | clk_enable(w90p910_nand->clk); | ||
289 | |||
290 | chip->cmdfunc = w90p910_nand_command_lp; | ||
291 | chip->dev_ready = w90p910_nand_devready; | ||
292 | chip->read_byte = w90p910_nand_read_byte; | ||
293 | chip->write_buf = w90p910_nand_write_buf; | ||
294 | chip->read_buf = w90p910_nand_read_buf; | ||
295 | chip->verify_buf = w90p910_verify_buf; | ||
296 | chip->chip_delay = 50; | ||
297 | chip->options = 0; | ||
298 | chip->ecc.mode = NAND_ECC_SOFT; | ||
299 | |||
300 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
301 | if (!res) { | ||
302 | retval = -ENXIO; | ||
303 | goto fail1; | ||
304 | } | ||
305 | |||
306 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | ||
307 | retval = -EBUSY; | ||
308 | goto fail1; | ||
309 | } | ||
310 | |||
311 | w90p910_nand->reg = ioremap(res->start, resource_size(res)); | ||
312 | if (!w90p910_nand->reg) { | ||
313 | retval = -ENOMEM; | ||
314 | goto fail2; | ||
315 | } | ||
316 | |||
317 | w90p910_nand_enable(w90p910_nand); | ||
318 | |||
319 | if (nand_scan(&(w90p910_nand->mtd), 1)) { | ||
320 | retval = -ENXIO; | ||
321 | goto fail3; | ||
322 | } | ||
323 | |||
324 | add_mtd_partitions(&(w90p910_nand->mtd), partitions, | ||
325 | ARRAY_SIZE(partitions)); | ||
326 | |||
327 | platform_set_drvdata(pdev, w90p910_nand); | ||
328 | |||
329 | return retval; | ||
330 | |||
331 | fail3: iounmap(w90p910_nand->reg); | ||
332 | fail2: release_mem_region(res->start, resource_size(res)); | ||
333 | fail1: kfree(w90p910_nand); | ||
334 | return retval; | ||
335 | } | ||
336 | |||
337 | static int __devexit w90p910_nand_remove(struct platform_device *pdev) | ||
338 | { | ||
339 | struct w90p910_nand *w90p910_nand = platform_get_drvdata(pdev); | ||
340 | struct resource *res; | ||
341 | |||
342 | iounmap(w90p910_nand->reg); | ||
343 | |||
344 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
345 | release_mem_region(res->start, resource_size(res)); | ||
346 | |||
347 | clk_disable(w90p910_nand->clk); | ||
348 | clk_put(w90p910_nand->clk); | ||
349 | |||
350 | kfree(w90p910_nand); | ||
351 | |||
352 | platform_set_drvdata(pdev, NULL); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static struct platform_driver w90p910_nand_driver = { | ||
358 | .probe = w90p910_nand_probe, | ||
359 | .remove = __devexit_p(w90p910_nand_remove), | ||
360 | .driver = { | ||
361 | .name = "w90p910-fmi", | ||
362 | .owner = THIS_MODULE, | ||
363 | }, | ||
364 | }; | ||
365 | |||
366 | static int __init w90p910_nand_init(void) | ||
367 | { | ||
368 | return platform_driver_register(&w90p910_nand_driver); | ||
369 | } | ||
370 | |||
371 | static void __exit w90p910_nand_exit(void) | ||
372 | { | ||
373 | platform_driver_unregister(&w90p910_nand_driver); | ||
374 | } | ||
375 | |||
376 | module_init(w90p910_nand_init); | ||
377 | module_exit(w90p910_nand_exit); | ||
378 | |||
379 | MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); | ||
380 | MODULE_DESCRIPTION("w90p910 nand driver!"); | ||
381 | MODULE_LICENSE("GPL"); | ||
382 | MODULE_ALIAS("platform:w90p910-fmi"); | ||