diff options
author | Vladimir Barinov <vova.barinov@gmail.com> | 2009-05-25 05:06:17 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-06-05 13:15:41 -0400 |
commit | bd3fd62ecc99c709739cb969be76f44903a4043b (patch) | |
tree | a0dd30dac98177e35bb097c4cd6b3974b202b139 /drivers/mtd | |
parent | f36e20c01ad0104688f2eaebdf2213e749929c97 (diff) |
mtd: MXC NAND support for 2KiB page size flashes
- Add support for 2KiB page size flashes
- Fix page address access for large pages
- Detect oob layout at runtime
- handle pagesize_2k variable
- Fix oob16 layout: reserve location 5 of oob area since it's used for bbt
Signed-off-by: Vladimir Barinov <vova.barinov@gmail.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index d5aea6951d0b..d03bd4eff722 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -138,7 +138,14 @@ static struct nand_ecclayout nand_hw_eccoob_8 = { | |||
138 | static struct nand_ecclayout nand_hw_eccoob_16 = { | 138 | static struct nand_ecclayout nand_hw_eccoob_16 = { |
139 | .eccbytes = 5, | 139 | .eccbytes = 5, |
140 | .eccpos = {6, 7, 8, 9, 10}, | 140 | .eccpos = {6, 7, 8, 9, 10}, |
141 | .oobfree = {{0, 6}, {12, 4}, } | 141 | .oobfree = {{0, 5}, {11, 5}, } |
142 | }; | ||
143 | |||
144 | static struct nand_ecclayout nand_hw_eccoob_64 = { | ||
145 | .eccbytes = 20, | ||
146 | .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, | ||
147 | 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, | ||
148 | .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } | ||
142 | }; | 149 | }; |
143 | 150 | ||
144 | #ifdef CONFIG_MTD_PARTITIONS | 151 | #ifdef CONFIG_MTD_PARTITIONS |
@@ -795,9 +802,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
795 | send_addr(host, (page_addr & 0xff), false); | 802 | send_addr(host, (page_addr & 0xff), false); |
796 | 803 | ||
797 | if (host->pagesize_2k) { | 804 | if (host->pagesize_2k) { |
798 | send_addr(host, (page_addr >> 8) & 0xFF, false); | 805 | if (mtd->size >= 0x10000000) { |
799 | if (mtd->size >= 0x40000000) | 806 | /* paddr_8 - paddr_15 */ |
807 | send_addr(host, (page_addr >> 8) & 0xff, false); | ||
800 | send_addr(host, (page_addr >> 16) & 0xff, true); | 808 | send_addr(host, (page_addr >> 16) & 0xff, true); |
809 | } else | ||
810 | /* paddr_8 - paddr_15 */ | ||
811 | send_addr(host, (page_addr >> 8) & 0xff, true); | ||
801 | } else { | 812 | } else { |
802 | /* One more address cycle for higher density devices */ | 813 | /* One more address cycle for higher density devices */ |
803 | if (mtd->size >= 0x4000000) { | 814 | if (mtd->size >= 0x4000000) { |
@@ -919,7 +930,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
919 | this->ecc.mode = NAND_ECC_HW; | 930 | this->ecc.mode = NAND_ECC_HW; |
920 | this->ecc.size = 512; | 931 | this->ecc.size = 512; |
921 | this->ecc.bytes = 3; | 932 | this->ecc.bytes = 3; |
922 | this->ecc.layout = &nand_hw_eccoob_8; | ||
923 | tmp = readw(host->regs + NFC_CONFIG1); | 933 | tmp = readw(host->regs + NFC_CONFIG1); |
924 | tmp |= NFC_ECC_EN; | 934 | tmp |= NFC_ECC_EN; |
925 | writew(tmp, host->regs + NFC_CONFIG1); | 935 | writew(tmp, host->regs + NFC_CONFIG1); |
@@ -953,12 +963,44 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
953 | this->ecc.layout = &nand_hw_eccoob_16; | 963 | this->ecc.layout = &nand_hw_eccoob_16; |
954 | } | 964 | } |
955 | 965 | ||
956 | host->pagesize_2k = 0; | 966 | /* first scan to find the device and get the page size */ |
967 | if (nand_scan_ident(mtd, 1)) { | ||
968 | err = -ENXIO; | ||
969 | goto escan; | ||
970 | } | ||
957 | 971 | ||
958 | /* Scan to find existence of the device */ | 972 | host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0; |
959 | if (nand_scan(mtd, 1)) { | 973 | |
960 | DEBUG(MTD_DEBUG_LEVEL0, | 974 | if (this->ecc.mode == NAND_ECC_HW) { |
961 | "MXC_ND: Unable to find any NAND device.\n"); | 975 | switch (mtd->oobsize) { |
976 | case 8: | ||
977 | this->ecc.layout = &nand_hw_eccoob_8; | ||
978 | break; | ||
979 | case 16: | ||
980 | this->ecc.layout = &nand_hw_eccoob_16; | ||
981 | break; | ||
982 | case 64: | ||
983 | this->ecc.layout = &nand_hw_eccoob_64; | ||
984 | break; | ||
985 | default: | ||
986 | /* page size not handled by HW ECC */ | ||
987 | /* switching back to soft ECC */ | ||
988 | this->ecc.size = 512; | ||
989 | this->ecc.bytes = 3; | ||
990 | this->ecc.layout = &nand_hw_eccoob_8; | ||
991 | this->ecc.mode = NAND_ECC_SOFT; | ||
992 | this->ecc.calculate = NULL; | ||
993 | this->ecc.correct = NULL; | ||
994 | this->ecc.hwctl = NULL; | ||
995 | tmp = readw(host->regs + NFC_CONFIG1); | ||
996 | tmp &= ~NFC_ECC_EN; | ||
997 | writew(tmp, host->regs + NFC_CONFIG1); | ||
998 | break; | ||
999 | } | ||
1000 | } | ||
1001 | |||
1002 | /* second phase scan */ | ||
1003 | if (nand_scan_tail(mtd)) { | ||
962 | err = -ENXIO; | 1004 | err = -ENXIO; |
963 | goto escan; | 1005 | goto escan; |
964 | } | 1006 | } |