diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 21 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/diskonchip.c | 96 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 299 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 114 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_ids.c | 18 | ||||
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 41 | ||||
-rw-r--r-- | drivers/mtd/nand/rtc_from4.c | 140 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 297 | ||||
-rw-r--r--[-rwxr-xr-x] | drivers/mtd/nand/sharpsl.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/tx4925ndfmc.c | 416 | ||||
-rw-r--r-- | drivers/mtd/nand/tx4938ndfmc.c | 406 |
12 files changed, 679 insertions, 1175 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f7801eb730ce..36d34e5e5a5a 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/nand/Kconfig | 1 | # drivers/mtd/nand/Kconfig |
2 | # $Id: Kconfig,v 1.26 2005/01/05 12:42:24 dwmw2 Exp $ | 2 | # $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $ |
3 | 3 | ||
4 | menu "NAND Flash Device Drivers" | 4 | menu "NAND Flash Device Drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -58,20 +58,6 @@ config MTD_NAND_TOTO | |||
58 | config MTD_NAND_IDS | 58 | config MTD_NAND_IDS |
59 | tristate | 59 | tristate |
60 | 60 | ||
61 | config MTD_NAND_TX4925NDFMC | ||
62 | tristate "SmartMedia Card on Toshiba RBTX4925 reference board" | ||
63 | depends on TOSHIBA_RBTX4925 && MTD_NAND && TOSHIBA_RBTX4925_MPLEX_NAND | ||
64 | help | ||
65 | This enables the driver for the NAND flash device found on the | ||
66 | Toshiba RBTX4925 reference board, which is a SmartMediaCard. | ||
67 | |||
68 | config MTD_NAND_TX4938NDFMC | ||
69 | tristate "NAND Flash device on Toshiba RBTX4938 reference board" | ||
70 | depends on TOSHIBA_RBTX4938 && MTD_NAND && TOSHIBA_RBTX4938_MPLEX_NAND | ||
71 | help | ||
72 | This enables the driver for the NAND flash device found on the | ||
73 | Toshiba RBTX4938 reference board. | ||
74 | |||
75 | config MTD_NAND_AU1550 | 61 | config MTD_NAND_AU1550 |
76 | tristate "Au1550 NAND support" | 62 | tristate "Au1550 NAND support" |
77 | depends on SOC_AU1550 && MTD_NAND | 63 | depends on SOC_AU1550 && MTD_NAND |
@@ -95,10 +81,11 @@ config MTD_NAND_PPCHAMELEONEVB | |||
95 | This enables the NAND flash driver on the PPChameleon EVB Board. | 81 | This enables the NAND flash driver on the PPChameleon EVB Board. |
96 | 82 | ||
97 | config MTD_NAND_S3C2410 | 83 | config MTD_NAND_S3C2410 |
98 | tristate "NAND Flash support for S3C2410 SoC" | 84 | tristate "NAND Flash support for S3C2410/S3C2440 SoC" |
99 | depends on ARCH_S3C2410 && MTD_NAND | 85 | depends on ARCH_S3C2410 && MTD_NAND |
100 | help | 86 | help |
101 | This enables the NAND flash controller on the S3C2410. | 87 | This enables the NAND flash controller on the S3C2410 and S3C2440 |
88 | SoCs | ||
102 | 89 | ||
103 | No board specfic support is done by this driver, each board | 90 | No board specfic support is done by this driver, each board |
104 | must advertise a platform_device for the driver to attach. | 91 | must advertise a platform_device for the driver to attach. |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d9dc8cc2da8c..41742026a52e 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -10,8 +10,6 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o | |||
10 | obj-$(CONFIG_MTD_NAND_TOTO) += toto.o | 10 | obj-$(CONFIG_MTD_NAND_TOTO) += toto.o |
11 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o | 11 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o |
12 | obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o | 12 | obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o |
13 | obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o | ||
14 | obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o | ||
15 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o | 13 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o |
16 | obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o | 14 | obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o |
17 | obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o | 15 | obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o |
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 02135c3ac29a..fdb5d4ad3d52 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -16,7 +16,7 @@ | |||
16 | * | 16 | * |
17 | * Interface to generic NAND code for M-Systems DiskOnChip devices | 17 | * Interface to generic NAND code for M-Systems DiskOnChip devices |
18 | * | 18 | * |
19 | * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ | 19 | * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $ |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
@@ -35,13 +35,13 @@ | |||
35 | #include <linux/mtd/inftl.h> | 35 | #include <linux/mtd/inftl.h> |
36 | 36 | ||
37 | /* Where to look for the devices? */ | 37 | /* Where to look for the devices? */ |
38 | #ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS | 38 | #ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS |
39 | #define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0 | 39 | #define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0 |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | static unsigned long __initdata doc_locations[] = { | 42 | static unsigned long __initdata doc_locations[] = { |
43 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) | 43 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) |
44 | #ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH | 44 | #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH |
45 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, | 45 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, |
46 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, | 46 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, |
47 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, | 47 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, |
@@ -81,11 +81,6 @@ struct doc_priv { | |||
81 | struct mtd_info *nextdoc; | 81 | struct mtd_info *nextdoc; |
82 | }; | 82 | }; |
83 | 83 | ||
84 | /* Max number of eraseblocks to scan (from start of device) for the (I)NFTL | ||
85 | MediaHeader. The spec says to just keep going, I think, but that's just | ||
86 | silly. */ | ||
87 | #define MAX_MEDIAHEADER_SCAN 8 | ||
88 | |||
89 | /* This is the syndrome computed by the HW ecc generator upon reading an empty | 84 | /* This is the syndrome computed by the HW ecc generator upon reading an empty |
90 | page, one with all 0xff for data and stored ecc code. */ | 85 | page, one with all 0xff for data and stored ecc code. */ |
91 | static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; | 86 | static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; |
@@ -111,10 +106,11 @@ module_param(try_dword, int, 0); | |||
111 | static int no_ecc_failures=0; | 106 | static int no_ecc_failures=0; |
112 | module_param(no_ecc_failures, int, 0); | 107 | module_param(no_ecc_failures, int, 0); |
113 | 108 | ||
114 | #ifdef CONFIG_MTD_PARTITIONS | ||
115 | static int no_autopart=0; | 109 | static int no_autopart=0; |
116 | module_param(no_autopart, int, 0); | 110 | module_param(no_autopart, int, 0); |
117 | #endif | 111 | |
112 | static int show_firmware_partition=0; | ||
113 | module_param(show_firmware_partition, int, 0); | ||
118 | 114 | ||
119 | #ifdef MTD_NAND_DISKONCHIP_BBTWRITE | 115 | #ifdef MTD_NAND_DISKONCHIP_BBTWRITE |
120 | static int inftl_bbt_write=1; | 116 | static int inftl_bbt_write=1; |
@@ -123,7 +119,7 @@ static int inftl_bbt_write=0; | |||
123 | #endif | 119 | #endif |
124 | module_param(inftl_bbt_write, int, 0); | 120 | module_param(inftl_bbt_write, int, 0); |
125 | 121 | ||
126 | static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; | 122 | static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS; |
127 | module_param(doc_config_location, ulong, 0); | 123 | module_param(doc_config_location, ulong, 0); |
128 | MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); | 124 | MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); |
129 | 125 | ||
@@ -410,7 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
410 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); | 406 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); |
411 | this->write_byte(mtd, 0); | 407 | this->write_byte(mtd, 0); |
412 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); | 408 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); |
413 | 409 | ||
410 | /* We cant' use dev_ready here, but at least we wait for the | ||
411 | * command to complete | ||
412 | */ | ||
413 | udelay(50); | ||
414 | |||
414 | ret = this->read_byte(mtd) << 8; | 415 | ret = this->read_byte(mtd) << 8; |
415 | ret |= this->read_byte(mtd); | 416 | ret |= this->read_byte(mtd); |
416 | 417 | ||
@@ -429,6 +430,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
429 | doc2000_write_byte(mtd, 0); | 430 | doc2000_write_byte(mtd, 0); |
430 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); | 431 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); |
431 | 432 | ||
433 | udelay(50); | ||
434 | |||
432 | ident.dword = readl(docptr + DoC_2k_CDSN_IO); | 435 | ident.dword = readl(docptr + DoC_2k_CDSN_IO); |
433 | if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { | 436 | if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { |
434 | printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); | 437 | printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); |
@@ -1046,11 +1049,21 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
1046 | 1049 | ||
1047 | //u_char mydatabuf[528]; | 1050 | //u_char mydatabuf[528]; |
1048 | 1051 | ||
1052 | /* The strange out-of-order .oobfree list below is a (possibly unneeded) | ||
1053 | * attempt to retain compatibility. It used to read: | ||
1054 | * .oobfree = { {8, 8} } | ||
1055 | * Since that leaves two bytes unusable, it was changed. But the following | ||
1056 | * scheme might affect existing jffs2 installs by moving the cleanmarker: | ||
1057 | * .oobfree = { {6, 10} } | ||
1058 | * jffs2 seems to handle the above gracefully, but the current scheme seems | ||
1059 | * safer. The only problem with it is that any code that parses oobfree must | ||
1060 | * be able to handle out-of-order segments. | ||
1061 | */ | ||
1049 | static struct nand_oobinfo doc200x_oobinfo = { | 1062 | static struct nand_oobinfo doc200x_oobinfo = { |
1050 | .useecc = MTD_NANDECC_AUTOPLACE, | 1063 | .useecc = MTD_NANDECC_AUTOPLACE, |
1051 | .eccbytes = 6, | 1064 | .eccbytes = 6, |
1052 | .eccpos = {0, 1, 2, 3, 4, 5}, | 1065 | .eccpos = {0, 1, 2, 3, 4, 5}, |
1053 | .oobfree = { {8, 8} } | 1066 | .oobfree = { {8, 8}, {6, 2} } |
1054 | }; | 1067 | }; |
1055 | 1068 | ||
1056 | /* Find the (I)NFTL Media Header, and optionally also the mirror media header. | 1069 | /* Find the (I)NFTL Media Header, and optionally also the mirror media header. |
@@ -1064,12 +1077,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, | |||
1064 | { | 1077 | { |
1065 | struct nand_chip *this = mtd->priv; | 1078 | struct nand_chip *this = mtd->priv; |
1066 | struct doc_priv *doc = this->priv; | 1079 | struct doc_priv *doc = this->priv; |
1067 | unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift); | 1080 | unsigned offs; |
1068 | int ret; | 1081 | int ret; |
1069 | size_t retlen; | 1082 | size_t retlen; |
1070 | 1083 | ||
1071 | end = min(end, mtd->size); // paranoia | 1084 | for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { |
1072 | for (offs = 0; offs < end; offs += mtd->erasesize) { | ||
1073 | ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); | 1085 | ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); |
1074 | if (retlen != mtd->oobblock) continue; | 1086 | if (retlen != mtd->oobblock) continue; |
1075 | if (ret) { | 1087 | if (ret) { |
@@ -1111,6 +1123,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, | |||
1111 | u_char *buf; | 1123 | u_char *buf; |
1112 | struct NFTLMediaHeader *mh; | 1124 | struct NFTLMediaHeader *mh; |
1113 | const unsigned psize = 1 << this->page_shift; | 1125 | const unsigned psize = 1 << this->page_shift; |
1126 | int numparts = 0; | ||
1114 | unsigned blocks, maxblocks; | 1127 | unsigned blocks, maxblocks; |
1115 | int offs, numheaders; | 1128 | int offs, numheaders; |
1116 | 1129 | ||
@@ -1122,8 +1135,10 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, | |||
1122 | if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; | 1135 | if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; |
1123 | mh = (struct NFTLMediaHeader *) buf; | 1136 | mh = (struct NFTLMediaHeader *) buf; |
1124 | 1137 | ||
1125 | //#ifdef CONFIG_MTD_DEBUG_VERBOSE | 1138 | mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); |
1126 | // if (CONFIG_MTD_DEBUG_VERBOSE >= 2) | 1139 | mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); |
1140 | mh->FormattedSize = le32_to_cpu(mh->FormattedSize); | ||
1141 | |||
1127 | printk(KERN_INFO " DataOrgID = %s\n" | 1142 | printk(KERN_INFO " DataOrgID = %s\n" |
1128 | " NumEraseUnits = %d\n" | 1143 | " NumEraseUnits = %d\n" |
1129 | " FirstPhysicalEUN = %d\n" | 1144 | " FirstPhysicalEUN = %d\n" |
@@ -1132,7 +1147,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, | |||
1132 | mh->DataOrgID, mh->NumEraseUnits, | 1147 | mh->DataOrgID, mh->NumEraseUnits, |
1133 | mh->FirstPhysicalEUN, mh->FormattedSize, | 1148 | mh->FirstPhysicalEUN, mh->FormattedSize, |
1134 | mh->UnitSizeFactor); | 1149 | mh->UnitSizeFactor); |
1135 | //#endif | ||
1136 | 1150 | ||
1137 | blocks = mtd->size >> this->phys_erase_shift; | 1151 | blocks = mtd->size >> this->phys_erase_shift; |
1138 | maxblocks = min(32768U, mtd->erasesize - psize); | 1152 | maxblocks = min(32768U, mtd->erasesize - psize); |
@@ -1175,23 +1189,28 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, | |||
1175 | offs <<= this->page_shift; | 1189 | offs <<= this->page_shift; |
1176 | offs += mtd->erasesize; | 1190 | offs += mtd->erasesize; |
1177 | 1191 | ||
1178 | //parts[0].name = " DiskOnChip Boot / Media Header partition"; | 1192 | if (show_firmware_partition == 1) { |
1179 | //parts[0].offset = 0; | 1193 | parts[0].name = " DiskOnChip Firmware / Media Header partition"; |
1180 | //parts[0].size = offs; | 1194 | parts[0].offset = 0; |
1195 | parts[0].size = offs; | ||
1196 | numparts = 1; | ||
1197 | } | ||
1181 | 1198 | ||
1182 | parts[0].name = " DiskOnChip BDTL partition"; | 1199 | parts[numparts].name = " DiskOnChip BDTL partition"; |
1183 | parts[0].offset = offs; | 1200 | parts[numparts].offset = offs; |
1184 | parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; | 1201 | parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; |
1202 | |||
1203 | offs += parts[numparts].size; | ||
1204 | numparts++; | ||
1185 | 1205 | ||
1186 | offs += parts[0].size; | ||
1187 | if (offs < mtd->size) { | 1206 | if (offs < mtd->size) { |
1188 | parts[1].name = " DiskOnChip Remainder partition"; | 1207 | parts[numparts].name = " DiskOnChip Remainder partition"; |
1189 | parts[1].offset = offs; | 1208 | parts[numparts].offset = offs; |
1190 | parts[1].size = mtd->size - offs; | 1209 | parts[numparts].size = mtd->size - offs; |
1191 | ret = 2; | 1210 | numparts++; |
1192 | goto out; | ||
1193 | } | 1211 | } |
1194 | ret = 1; | 1212 | |
1213 | ret = numparts; | ||
1195 | out: | 1214 | out: |
1196 | kfree(buf); | 1215 | kfree(buf); |
1197 | return ret; | 1216 | return ret; |
@@ -1233,8 +1252,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, | |||
1233 | mh->FormatFlags = le32_to_cpu(mh->FormatFlags); | 1252 | mh->FormatFlags = le32_to_cpu(mh->FormatFlags); |
1234 | mh->PercentUsed = le32_to_cpu(mh->PercentUsed); | 1253 | mh->PercentUsed = le32_to_cpu(mh->PercentUsed); |
1235 | 1254 | ||
1236 | //#ifdef CONFIG_MTD_DEBUG_VERBOSE | ||
1237 | // if (CONFIG_MTD_DEBUG_VERBOSE >= 2) | ||
1238 | printk(KERN_INFO " bootRecordID = %s\n" | 1255 | printk(KERN_INFO " bootRecordID = %s\n" |
1239 | " NoOfBootImageBlocks = %d\n" | 1256 | " NoOfBootImageBlocks = %d\n" |
1240 | " NoOfBinaryPartitions = %d\n" | 1257 | " NoOfBinaryPartitions = %d\n" |
@@ -1252,7 +1269,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, | |||
1252 | ((unsigned char *) &mh->OsakVersion)[2] & 0xf, | 1269 | ((unsigned char *) &mh->OsakVersion)[2] & 0xf, |
1253 | ((unsigned char *) &mh->OsakVersion)[3] & 0xf, | 1270 | ((unsigned char *) &mh->OsakVersion)[3] & 0xf, |
1254 | mh->PercentUsed); | 1271 | mh->PercentUsed); |
1255 | //#endif | ||
1256 | 1272 | ||
1257 | vshift = this->phys_erase_shift + mh->BlockMultiplierBits; | 1273 | vshift = this->phys_erase_shift + mh->BlockMultiplierBits; |
1258 | 1274 | ||
@@ -1278,8 +1294,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, | |||
1278 | ip->spareUnits = le32_to_cpu(ip->spareUnits); | 1294 | ip->spareUnits = le32_to_cpu(ip->spareUnits); |
1279 | ip->Reserved0 = le32_to_cpu(ip->Reserved0); | 1295 | ip->Reserved0 = le32_to_cpu(ip->Reserved0); |
1280 | 1296 | ||
1281 | //#ifdef CONFIG_MTD_DEBUG_VERBOSE | ||
1282 | // if (CONFIG_MTD_DEBUG_VERBOSE >= 2) | ||
1283 | printk(KERN_INFO " PARTITION[%d] ->\n" | 1297 | printk(KERN_INFO " PARTITION[%d] ->\n" |
1284 | " virtualUnits = %d\n" | 1298 | " virtualUnits = %d\n" |
1285 | " firstUnit = %d\n" | 1299 | " firstUnit = %d\n" |
@@ -1289,16 +1303,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, | |||
1289 | i, ip->virtualUnits, ip->firstUnit, | 1303 | i, ip->virtualUnits, ip->firstUnit, |
1290 | ip->lastUnit, ip->flags, | 1304 | ip->lastUnit, ip->flags, |
1291 | ip->spareUnits); | 1305 | ip->spareUnits); |
1292 | //#endif | ||
1293 | 1306 | ||
1294 | /* | 1307 | if ((show_firmware_partition == 1) && |
1295 | if ((i == 0) && (ip->firstUnit > 0)) { | 1308 | (i == 0) && (ip->firstUnit > 0)) { |
1296 | parts[0].name = " DiskOnChip IPL / Media Header partition"; | 1309 | parts[0].name = " DiskOnChip IPL / Media Header partition"; |
1297 | parts[0].offset = 0; | 1310 | parts[0].offset = 0; |
1298 | parts[0].size = mtd->erasesize * ip->firstUnit; | 1311 | parts[0].size = mtd->erasesize * ip->firstUnit; |
1299 | numparts = 1; | 1312 | numparts = 1; |
1300 | } | 1313 | } |
1301 | */ | ||
1302 | 1314 | ||
1303 | if (ip->flags & INFTL_BINARY) | 1315 | if (ip->flags & INFTL_BINARY) |
1304 | parts[numparts].name = " DiskOnChip BDK partition"; | 1316 | parts[numparts].name = " DiskOnChip BDK partition"; |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 44d5b128911f..1bd71a598c79 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -28,6 +28,24 @@ | |||
28 | * among multiple independend devices. Suggestions and initial patch | 28 | * among multiple independend devices. Suggestions and initial patch |
29 | * from Ben Dooks <ben-mtd@fluff.org> | 29 | * from Ben Dooks <ben-mtd@fluff.org> |
30 | * | 30 | * |
31 | * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. | ||
32 | * Basically, any block not rewritten may lose data when surrounding blocks | ||
33 | * are rewritten many times. JFFS2 ensures this doesn't happen for blocks | ||
34 | * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they | ||
35 | * do not lose data, force them to be rewritten when some of the surrounding | ||
36 | * blocks are erased. Rather than tracking a specific nearby block (which | ||
37 | * could itself go bad), use a page address 'mask' to select several blocks | ||
38 | * in the same area, and rewrite the BBT when any of them are erased. | ||
39 | * | ||
40 | * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas | ||
41 | * AG-AND chips. If there was a sudden loss of power during an erase operation, | ||
42 | * a "device recovery" operation must be performed when power is restored | ||
43 | * to ensure correct operation. | ||
44 | * | ||
45 | * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to | ||
46 | * perform extra error status checks on erase and write failures. This required | ||
47 | * adding a wrapper function for nand_read_ecc. | ||
48 | * | ||
31 | * Credits: | 49 | * Credits: |
32 | * David Woodhouse for adding multichip support | 50 | * David Woodhouse for adding multichip support |
33 | * | 51 | * |
@@ -41,7 +59,7 @@ | |||
41 | * The AG-AND chips have nice features for speed improvement, | 59 | * The AG-AND chips have nice features for speed improvement, |
42 | * which are not supported yet. Read / program 4 pages in one go. | 60 | * which are not supported yet. Read / program 4 pages in one go. |
43 | * | 61 | * |
44 | * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $ | 62 | * $Id: nand_base.c,v 1.146 2005/06/17 15:02:06 gleixner Exp $ |
45 | * | 63 | * |
46 | * This program is free software; you can redistribute it and/or modify | 64 | * This program is free software; you can redistribute it and/or modify |
47 | * it under the terms of the GNU General Public License version 2 as | 65 | * it under the terms of the GNU General Public License version 2 as |
@@ -149,17 +167,21 @@ static void nand_release_device (struct mtd_info *mtd) | |||
149 | 167 | ||
150 | /* De-select the NAND device */ | 168 | /* De-select the NAND device */ |
151 | this->select_chip(mtd, -1); | 169 | this->select_chip(mtd, -1); |
152 | /* Do we have a hardware controller ? */ | 170 | |
153 | if (this->controller) { | 171 | if (this->controller) { |
172 | /* Release the controller and the chip */ | ||
154 | spin_lock(&this->controller->lock); | 173 | spin_lock(&this->controller->lock); |
155 | this->controller->active = NULL; | 174 | this->controller->active = NULL; |
175 | this->state = FL_READY; | ||
176 | wake_up(&this->controller->wq); | ||
156 | spin_unlock(&this->controller->lock); | 177 | spin_unlock(&this->controller->lock); |
178 | } else { | ||
179 | /* Release the chip */ | ||
180 | spin_lock(&this->chip_lock); | ||
181 | this->state = FL_READY; | ||
182 | wake_up(&this->wq); | ||
183 | spin_unlock(&this->chip_lock); | ||
157 | } | 184 | } |
158 | /* Release the chip */ | ||
159 | spin_lock (&this->chip_lock); | ||
160 | this->state = FL_READY; | ||
161 | wake_up (&this->wq); | ||
162 | spin_unlock (&this->chip_lock); | ||
163 | } | 185 | } |
164 | 186 | ||
165 | /** | 187 | /** |
@@ -443,7 +465,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
443 | 465 | ||
444 | /* Get block number */ | 466 | /* Get block number */ |
445 | block = ((int) ofs) >> this->bbt_erase_shift; | 467 | block = ((int) ofs) >> this->bbt_erase_shift; |
446 | this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); | 468 | if (this->bbt) |
469 | this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); | ||
447 | 470 | ||
448 | /* Do we have a flash based bad block table ? */ | 471 | /* Do we have a flash based bad block table ? */ |
449 | if (this->options & NAND_USE_FLASH_BBT) | 472 | if (this->options & NAND_USE_FLASH_BBT) |
@@ -466,7 +489,7 @@ static int nand_check_wp (struct mtd_info *mtd) | |||
466 | struct nand_chip *this = mtd->priv; | 489 | struct nand_chip *this = mtd->priv; |
467 | /* Check the WP bit */ | 490 | /* Check the WP bit */ |
468 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); | 491 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); |
469 | return (this->read_byte(mtd) & 0x80) ? 0 : 1; | 492 | return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; |
470 | } | 493 | } |
471 | 494 | ||
472 | /** | 495 | /** |
@@ -490,6 +513,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i | |||
490 | return nand_isbad_bbt (mtd, ofs, allowbbt); | 513 | return nand_isbad_bbt (mtd, ofs, allowbbt); |
491 | } | 514 | } |
492 | 515 | ||
516 | /* | ||
517 | * Wait for the ready pin, after a command | ||
518 | * The timeout is catched later. | ||
519 | */ | ||
520 | static void nand_wait_ready(struct mtd_info *mtd) | ||
521 | { | ||
522 | struct nand_chip *this = mtd->priv; | ||
523 | unsigned long timeo = jiffies + 2; | ||
524 | |||
525 | /* wait until command is processed or timeout occures */ | ||
526 | do { | ||
527 | if (this->dev_ready(mtd)) | ||
528 | return; | ||
529 | } while (time_before(jiffies, timeo)); | ||
530 | } | ||
531 | |||
493 | /** | 532 | /** |
494 | * nand_command - [DEFAULT] Send command to NAND device | 533 | * nand_command - [DEFAULT] Send command to NAND device |
495 | * @mtd: MTD device structure | 534 | * @mtd: MTD device structure |
@@ -571,7 +610,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
571 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 610 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
572 | this->write_byte(mtd, NAND_CMD_STATUS); | 611 | this->write_byte(mtd, NAND_CMD_STATUS); |
573 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 612 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); |
574 | while ( !(this->read_byte(mtd) & 0x40)); | 613 | while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); |
575 | return; | 614 | return; |
576 | 615 | ||
577 | /* This applies to read commands */ | 616 | /* This applies to read commands */ |
@@ -585,12 +624,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
585 | return; | 624 | return; |
586 | } | 625 | } |
587 | } | 626 | } |
588 | |||
589 | /* Apply this short delay always to ensure that we do wait tWB in | 627 | /* Apply this short delay always to ensure that we do wait tWB in |
590 | * any case on any machine. */ | 628 | * any case on any machine. */ |
591 | ndelay (100); | 629 | ndelay (100); |
592 | /* wait until command is processed */ | 630 | |
593 | while (!this->dev_ready(mtd)); | 631 | nand_wait_ready(mtd); |
594 | } | 632 | } |
595 | 633 | ||
596 | /** | 634 | /** |
@@ -619,7 +657,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
619 | /* Begin command latch cycle */ | 657 | /* Begin command latch cycle */ |
620 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 658 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
621 | /* Write out the command to the device. */ | 659 | /* Write out the command to the device. */ |
622 | this->write_byte(mtd, command); | 660 | this->write_byte(mtd, (command & 0xff)); |
623 | /* End command latch cycle */ | 661 | /* End command latch cycle */ |
624 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 662 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); |
625 | 663 | ||
@@ -647,8 +685,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
647 | 685 | ||
648 | /* | 686 | /* |
649 | * program and erase have their own busy handlers | 687 | * program and erase have their own busy handlers |
650 | * status and sequential in needs no delay | 688 | * status, sequential in, and deplete1 need no delay |
651 | */ | 689 | */ |
652 | switch (command) { | 690 | switch (command) { |
653 | 691 | ||
654 | case NAND_CMD_CACHEDPROG: | 692 | case NAND_CMD_CACHEDPROG: |
@@ -657,8 +695,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
657 | case NAND_CMD_ERASE2: | 695 | case NAND_CMD_ERASE2: |
658 | case NAND_CMD_SEQIN: | 696 | case NAND_CMD_SEQIN: |
659 | case NAND_CMD_STATUS: | 697 | case NAND_CMD_STATUS: |
698 | case NAND_CMD_DEPLETE1: | ||
660 | return; | 699 | return; |
661 | 700 | ||
701 | /* | ||
702 | * read error status commands require only a short delay | ||
703 | */ | ||
704 | case NAND_CMD_STATUS_ERROR: | ||
705 | case NAND_CMD_STATUS_ERROR0: | ||
706 | case NAND_CMD_STATUS_ERROR1: | ||
707 | case NAND_CMD_STATUS_ERROR2: | ||
708 | case NAND_CMD_STATUS_ERROR3: | ||
709 | udelay(this->chip_delay); | ||
710 | return; | ||
662 | 711 | ||
663 | case NAND_CMD_RESET: | 712 | case NAND_CMD_RESET: |
664 | if (this->dev_ready) | 713 | if (this->dev_ready) |
@@ -667,7 +716,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
667 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 716 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
668 | this->write_byte(mtd, NAND_CMD_STATUS); | 717 | this->write_byte(mtd, NAND_CMD_STATUS); |
669 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 718 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); |
670 | while ( !(this->read_byte(mtd) & 0x40)); | 719 | while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); |
671 | return; | 720 | return; |
672 | 721 | ||
673 | case NAND_CMD_READ0: | 722 | case NAND_CMD_READ0: |
@@ -690,12 +739,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
690 | return; | 739 | return; |
691 | } | 740 | } |
692 | } | 741 | } |
693 | 742 | ||
694 | /* Apply this short delay always to ensure that we do wait tWB in | 743 | /* Apply this short delay always to ensure that we do wait tWB in |
695 | * any case on any machine. */ | 744 | * any case on any machine. */ |
696 | ndelay (100); | 745 | ndelay (100); |
697 | /* wait until command is processed */ | 746 | |
698 | while (!this->dev_ready(mtd)); | 747 | nand_wait_ready(mtd); |
699 | } | 748 | } |
700 | 749 | ||
701 | /** | 750 | /** |
@@ -708,37 +757,34 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
708 | */ | 757 | */ |
709 | static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) | 758 | static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) |
710 | { | 759 | { |
711 | struct nand_chip *active = this; | 760 | struct nand_chip *active; |
712 | 761 | spinlock_t *lock; | |
762 | wait_queue_head_t *wq; | ||
713 | DECLARE_WAITQUEUE (wait, current); | 763 | DECLARE_WAITQUEUE (wait, current); |
714 | 764 | ||
715 | /* | 765 | lock = (this->controller) ? &this->controller->lock : &this->chip_lock; |
716 | * Grab the lock and see if the device is available | 766 | wq = (this->controller) ? &this->controller->wq : &this->wq; |
717 | */ | ||
718 | retry: | 767 | retry: |
768 | active = this; | ||
769 | spin_lock(lock); | ||
770 | |||
719 | /* Hardware controller shared among independend devices */ | 771 | /* Hardware controller shared among independend devices */ |
720 | if (this->controller) { | 772 | if (this->controller) { |
721 | spin_lock (&this->controller->lock); | ||
722 | if (this->controller->active) | 773 | if (this->controller->active) |
723 | active = this->controller->active; | 774 | active = this->controller->active; |
724 | else | 775 | else |
725 | this->controller->active = this; | 776 | this->controller->active = this; |
726 | spin_unlock (&this->controller->lock); | ||
727 | } | 777 | } |
728 | 778 | if (active == this && this->state == FL_READY) { | |
729 | if (active == this) { | 779 | this->state = new_state; |
730 | spin_lock (&this->chip_lock); | 780 | spin_unlock(lock); |
731 | if (this->state == FL_READY) { | 781 | return; |
732 | this->state = new_state; | 782 | } |
733 | spin_unlock (&this->chip_lock); | 783 | set_current_state(TASK_UNINTERRUPTIBLE); |
734 | return; | 784 | add_wait_queue(wq, &wait); |
735 | } | 785 | spin_unlock(lock); |
736 | } | 786 | schedule(); |
737 | set_current_state (TASK_UNINTERRUPTIBLE); | 787 | remove_wait_queue(wq, &wait); |
738 | add_wait_queue (&active->wq, &wait); | ||
739 | spin_unlock (&active->chip_lock); | ||
740 | schedule (); | ||
741 | remove_wait_queue (&active->wq, &wait); | ||
742 | goto retry; | 788 | goto retry; |
743 | } | 789 | } |
744 | 790 | ||
@@ -785,7 +831,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
785 | if (this->read_byte(mtd) & NAND_STATUS_READY) | 831 | if (this->read_byte(mtd) & NAND_STATUS_READY) |
786 | break; | 832 | break; |
787 | } | 833 | } |
788 | yield (); | 834 | cond_resched(); |
789 | } | 835 | } |
790 | status = (int) this->read_byte(mtd); | 836 | status = (int) this->read_byte(mtd); |
791 | return status; | 837 | return status; |
@@ -871,8 +917,14 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
871 | if (!cached) { | 917 | if (!cached) { |
872 | /* call wait ready function */ | 918 | /* call wait ready function */ |
873 | status = this->waitfunc (mtd, this, FL_WRITING); | 919 | status = this->waitfunc (mtd, this, FL_WRITING); |
920 | |||
921 | /* See if operation failed and additional status checks are available */ | ||
922 | if ((status & NAND_STATUS_FAIL) && (this->errstat)) { | ||
923 | status = this->errstat(mtd, this, FL_WRITING, status, page); | ||
924 | } | ||
925 | |||
874 | /* See if device thinks it succeeded */ | 926 | /* See if device thinks it succeeded */ |
875 | if (status & 0x01) { | 927 | if (status & NAND_STATUS_FAIL) { |
876 | DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); | 928 | DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); |
877 | return -EIO; | 929 | return -EIO; |
878 | } | 930 | } |
@@ -975,7 +1027,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
975 | if (!this->dev_ready) | 1027 | if (!this->dev_ready) |
976 | udelay (this->chip_delay); | 1028 | udelay (this->chip_delay); |
977 | else | 1029 | else |
978 | while (!this->dev_ready(mtd)); | 1030 | nand_wait_ready(mtd); |
979 | 1031 | ||
980 | /* All done, return happy */ | 1032 | /* All done, return happy */ |
981 | if (!numpages) | 1033 | if (!numpages) |
@@ -997,23 +1049,24 @@ out: | |||
997 | #endif | 1049 | #endif |
998 | 1050 | ||
999 | /** | 1051 | /** |
1000 | * nand_read - [MTD Interface] MTD compability function for nand_read_ecc | 1052 | * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc |
1001 | * @mtd: MTD device structure | 1053 | * @mtd: MTD device structure |
1002 | * @from: offset to read from | 1054 | * @from: offset to read from |
1003 | * @len: number of bytes to read | 1055 | * @len: number of bytes to read |
1004 | * @retlen: pointer to variable to store the number of read bytes | 1056 | * @retlen: pointer to variable to store the number of read bytes |
1005 | * @buf: the databuffer to put data | 1057 | * @buf: the databuffer to put data |
1006 | * | 1058 | * |
1007 | * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL | 1059 | * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL |
1008 | */ | 1060 | * and flags = 0xff |
1061 | */ | ||
1009 | static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) | 1062 | static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) |
1010 | { | 1063 | { |
1011 | return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); | 1064 | return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); |
1012 | } | 1065 | } |
1013 | 1066 | ||
1014 | 1067 | ||
1015 | /** | 1068 | /** |
1016 | * nand_read_ecc - [MTD Interface] Read data with ECC | 1069 | * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc |
1017 | * @mtd: MTD device structure | 1070 | * @mtd: MTD device structure |
1018 | * @from: offset to read from | 1071 | * @from: offset to read from |
1019 | * @len: number of bytes to read | 1072 | * @len: number of bytes to read |
@@ -1022,11 +1075,39 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re | |||
1022 | * @oob_buf: filesystem supplied oob data buffer | 1075 | * @oob_buf: filesystem supplied oob data buffer |
1023 | * @oobsel: oob selection structure | 1076 | * @oobsel: oob selection structure |
1024 | * | 1077 | * |
1025 | * NAND read with ECC | 1078 | * This function simply calls nand_do_read_ecc with flags = 0xff |
1026 | */ | 1079 | */ |
1027 | static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 1080 | static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
1028 | size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) | 1081 | size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) |
1029 | { | 1082 | { |
1083 | /* use userspace supplied oobinfo, if zero */ | ||
1084 | if (oobsel == NULL) | ||
1085 | oobsel = &mtd->oobinfo; | ||
1086 | return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); | ||
1087 | } | ||
1088 | |||
1089 | |||
1090 | /** | ||
1091 | * nand_do_read_ecc - [MTD Interface] Read data with ECC | ||
1092 | * @mtd: MTD device structure | ||
1093 | * @from: offset to read from | ||
1094 | * @len: number of bytes to read | ||
1095 | * @retlen: pointer to variable to store the number of read bytes | ||
1096 | * @buf: the databuffer to put data | ||
1097 | * @oob_buf: filesystem supplied oob data buffer (can be NULL) | ||
1098 | * @oobsel: oob selection structure | ||
1099 | * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed | ||
1100 | * and how many corrected error bits are acceptable: | ||
1101 | * bits 0..7 - number of tolerable errors | ||
1102 | * bit 8 - 0 == do not get/release chip, 1 == get/release chip | ||
1103 | * | ||
1104 | * NAND read with ECC | ||
1105 | */ | ||
1106 | int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | ||
1107 | size_t * retlen, u_char * buf, u_char * oob_buf, | ||
1108 | struct nand_oobinfo *oobsel, int flags) | ||
1109 | { | ||
1110 | |||
1030 | int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; | 1111 | int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; |
1031 | int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; | 1112 | int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; |
1032 | struct nand_chip *this = mtd->priv; | 1113 | struct nand_chip *this = mtd->priv; |
@@ -1051,12 +1132,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1051 | } | 1132 | } |
1052 | 1133 | ||
1053 | /* Grab the lock and see if the device is available */ | 1134 | /* Grab the lock and see if the device is available */ |
1054 | nand_get_device (this, mtd ,FL_READING); | 1135 | if (flags & NAND_GET_DEVICE) |
1136 | nand_get_device (this, mtd, FL_READING); | ||
1055 | 1137 | ||
1056 | /* use userspace supplied oobinfo, if zero */ | ||
1057 | if (oobsel == NULL) | ||
1058 | oobsel = &mtd->oobinfo; | ||
1059 | |||
1060 | /* Autoplace of oob data ? Use the default placement scheme */ | 1138 | /* Autoplace of oob data ? Use the default placement scheme */ |
1061 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) | 1139 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) |
1062 | oobsel = this->autooob; | 1140 | oobsel = this->autooob; |
@@ -1118,7 +1196,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1118 | } | 1196 | } |
1119 | 1197 | ||
1120 | /* get oob area, if we have no oob buffer from fs-driver */ | 1198 | /* get oob area, if we have no oob buffer from fs-driver */ |
1121 | if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE) | 1199 | if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || |
1200 | oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | ||
1122 | oob_data = &this->data_buf[end]; | 1201 | oob_data = &this->data_buf[end]; |
1123 | 1202 | ||
1124 | eccsteps = this->eccsteps; | 1203 | eccsteps = this->eccsteps; |
@@ -1155,7 +1234,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1155 | /* We calc error correction directly, it checks the hw | 1234 | /* We calc error correction directly, it checks the hw |
1156 | * generator for an error, reads back the syndrome and | 1235 | * generator for an error, reads back the syndrome and |
1157 | * does the error correction on the fly */ | 1236 | * does the error correction on the fly */ |
1158 | if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { | 1237 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); |
1238 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { | ||
1159 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " | 1239 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " |
1160 | "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); | 1240 | "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); |
1161 | ecc_failed++; | 1241 | ecc_failed++; |
@@ -1194,7 +1274,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1194 | p[i] = ecc_status; | 1274 | p[i] = ecc_status; |
1195 | } | 1275 | } |
1196 | 1276 | ||
1197 | if (ecc_status == -1) { | 1277 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { |
1198 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); | 1278 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); |
1199 | ecc_failed++; | 1279 | ecc_failed++; |
1200 | } | 1280 | } |
@@ -1206,14 +1286,14 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1206 | /* without autoplace. Legacy mode used by YAFFS1 */ | 1286 | /* without autoplace. Legacy mode used by YAFFS1 */ |
1207 | switch(oobsel->useecc) { | 1287 | switch(oobsel->useecc) { |
1208 | case MTD_NANDECC_AUTOPLACE: | 1288 | case MTD_NANDECC_AUTOPLACE: |
1289 | case MTD_NANDECC_AUTOPL_USR: | ||
1209 | /* Walk through the autoplace chunks */ | 1290 | /* Walk through the autoplace chunks */ |
1210 | for (i = 0, j = 0; j < mtd->oobavail; i++) { | 1291 | for (i = 0; oobsel->oobfree[i][1]; i++) { |
1211 | int from = oobsel->oobfree[i][0]; | 1292 | int from = oobsel->oobfree[i][0]; |
1212 | int num = oobsel->oobfree[i][1]; | 1293 | int num = oobsel->oobfree[i][1]; |
1213 | memcpy(&oob_buf[oob], &oob_data[from], num); | 1294 | memcpy(&oob_buf[oob], &oob_data[from], num); |
1214 | j+= num; | 1295 | oob += num; |
1215 | } | 1296 | } |
1216 | oob += mtd->oobavail; | ||
1217 | break; | 1297 | break; |
1218 | case MTD_NANDECC_PLACE: | 1298 | case MTD_NANDECC_PLACE: |
1219 | /* YAFFS1 legacy mode */ | 1299 | /* YAFFS1 legacy mode */ |
@@ -1239,7 +1319,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1239 | if (!this->dev_ready) | 1319 | if (!this->dev_ready) |
1240 | udelay (this->chip_delay); | 1320 | udelay (this->chip_delay); |
1241 | else | 1321 | else |
1242 | while (!this->dev_ready(mtd)); | 1322 | nand_wait_ready(mtd); |
1243 | 1323 | ||
1244 | if (read == len) | 1324 | if (read == len) |
1245 | break; | 1325 | break; |
@@ -1264,7 +1344,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1264 | } | 1344 | } |
1265 | 1345 | ||
1266 | /* Deselect and wake up anyone waiting on the device */ | 1346 | /* Deselect and wake up anyone waiting on the device */ |
1267 | nand_release_device(mtd); | 1347 | if (flags & NAND_GET_DEVICE) |
1348 | nand_release_device(mtd); | ||
1268 | 1349 | ||
1269 | /* | 1350 | /* |
1270 | * Return success, if no ECC failures, else -EBADMSG | 1351 | * Return success, if no ECC failures, else -EBADMSG |
@@ -1337,7 +1418,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1337 | if (!this->dev_ready) | 1418 | if (!this->dev_ready) |
1338 | udelay (this->chip_delay); | 1419 | udelay (this->chip_delay); |
1339 | else | 1420 | else |
1340 | while (!this->dev_ready(mtd)); | 1421 | nand_wait_ready(mtd); |
1341 | 1422 | ||
1342 | /* Read more ? */ | 1423 | /* Read more ? */ |
1343 | if (i < len) { | 1424 | if (i < len) { |
@@ -1417,7 +1498,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, | |||
1417 | if (!this->dev_ready) | 1498 | if (!this->dev_ready) |
1418 | udelay (this->chip_delay); | 1499 | udelay (this->chip_delay); |
1419 | else | 1500 | else |
1420 | while (!this->dev_ready(mtd)); | 1501 | nand_wait_ready(mtd); |
1421 | 1502 | ||
1422 | /* Check, if the chip supports auto page increment */ | 1503 | /* Check, if the chip supports auto page increment */ |
1423 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) | 1504 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) |
@@ -1567,6 +1648,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1567 | oobsel = this->autooob; | 1648 | oobsel = this->autooob; |
1568 | autoplace = 1; | 1649 | autoplace = 1; |
1569 | } | 1650 | } |
1651 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | ||
1652 | autoplace = 1; | ||
1570 | 1653 | ||
1571 | /* Setup variables and oob buffer */ | 1654 | /* Setup variables and oob buffer */ |
1572 | totalpages = len >> this->page_shift; | 1655 | totalpages = len >> this->page_shift; |
@@ -1733,7 +1816,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * | |||
1733 | status = this->waitfunc (mtd, this, FL_WRITING); | 1816 | status = this->waitfunc (mtd, this, FL_WRITING); |
1734 | 1817 | ||
1735 | /* See if device thinks it succeeded */ | 1818 | /* See if device thinks it succeeded */ |
1736 | if (status & 0x01) { | 1819 | if (status & NAND_STATUS_FAIL) { |
1737 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); | 1820 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); |
1738 | ret = -EIO; | 1821 | ret = -EIO; |
1739 | goto out; | 1822 | goto out; |
@@ -1841,6 +1924,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1841 | oobsel = this->autooob; | 1924 | oobsel = this->autooob; |
1842 | autoplace = 1; | 1925 | autoplace = 1; |
1843 | } | 1926 | } |
1927 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | ||
1928 | autoplace = 1; | ||
1844 | 1929 | ||
1845 | /* Setup start page */ | 1930 | /* Setup start page */ |
1846 | page = (int) (to >> this->page_shift); | 1931 | page = (int) (to >> this->page_shift); |
@@ -1987,6 +2072,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) | |||
1987 | return nand_erase_nand (mtd, instr, 0); | 2072 | return nand_erase_nand (mtd, instr, 0); |
1988 | } | 2073 | } |
1989 | 2074 | ||
2075 | #define BBT_PAGE_MASK 0xffffff3f | ||
1990 | /** | 2076 | /** |
1991 | * nand_erase_intern - [NAND Interface] erase block(s) | 2077 | * nand_erase_intern - [NAND Interface] erase block(s) |
1992 | * @mtd: MTD device structure | 2078 | * @mtd: MTD device structure |
@@ -1999,6 +2085,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
1999 | { | 2085 | { |
2000 | int page, len, status, pages_per_block, ret, chipnr; | 2086 | int page, len, status, pages_per_block, ret, chipnr; |
2001 | struct nand_chip *this = mtd->priv; | 2087 | struct nand_chip *this = mtd->priv; |
2088 | int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */ | ||
2089 | unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */ | ||
2090 | /* It is used to see if the current page is in the same */ | ||
2091 | /* 256 block group and the same bank as the bbt. */ | ||
2002 | 2092 | ||
2003 | DEBUG (MTD_DEBUG_LEVEL3, | 2093 | DEBUG (MTD_DEBUG_LEVEL3, |
2004 | "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); | 2094 | "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); |
@@ -2044,6 +2134,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2044 | goto erase_exit; | 2134 | goto erase_exit; |
2045 | } | 2135 | } |
2046 | 2136 | ||
2137 | /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */ | ||
2138 | if (this->options & BBT_AUTO_REFRESH) { | ||
2139 | bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; | ||
2140 | } else { | ||
2141 | bbt_masked_page = 0xffffffff; /* should not match anything */ | ||
2142 | } | ||
2143 | |||
2047 | /* Loop through the pages */ | 2144 | /* Loop through the pages */ |
2048 | len = instr->len; | 2145 | len = instr->len; |
2049 | 2146 | ||
@@ -2066,13 +2163,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2066 | 2163 | ||
2067 | status = this->waitfunc (mtd, this, FL_ERASING); | 2164 | status = this->waitfunc (mtd, this, FL_ERASING); |
2068 | 2165 | ||
2166 | /* See if operation failed and additional status checks are available */ | ||
2167 | if ((status & NAND_STATUS_FAIL) && (this->errstat)) { | ||
2168 | status = this->errstat(mtd, this, FL_ERASING, status, page); | ||
2169 | } | ||
2170 | |||
2069 | /* See if block erase succeeded */ | 2171 | /* See if block erase succeeded */ |
2070 | if (status & 0x01) { | 2172 | if (status & NAND_STATUS_FAIL) { |
2071 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); | 2173 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); |
2072 | instr->state = MTD_ERASE_FAILED; | 2174 | instr->state = MTD_ERASE_FAILED; |
2073 | instr->fail_addr = (page << this->page_shift); | 2175 | instr->fail_addr = (page << this->page_shift); |
2074 | goto erase_exit; | 2176 | goto erase_exit; |
2075 | } | 2177 | } |
2178 | |||
2179 | /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ | ||
2180 | if (this->options & BBT_AUTO_REFRESH) { | ||
2181 | if (((page & BBT_PAGE_MASK) == bbt_masked_page) && | ||
2182 | (page != this->bbt_td->pages[chipnr])) { | ||
2183 | rewrite_bbt[chipnr] = (page << this->page_shift); | ||
2184 | } | ||
2185 | } | ||
2076 | 2186 | ||
2077 | /* Increment page address and decrement length */ | 2187 | /* Increment page address and decrement length */ |
2078 | len -= (1 << this->phys_erase_shift); | 2188 | len -= (1 << this->phys_erase_shift); |
@@ -2083,6 +2193,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2083 | chipnr++; | 2193 | chipnr++; |
2084 | this->select_chip(mtd, -1); | 2194 | this->select_chip(mtd, -1); |
2085 | this->select_chip(mtd, chipnr); | 2195 | this->select_chip(mtd, chipnr); |
2196 | |||
2197 | /* if BBT requires refresh and BBT-PERCHIP, | ||
2198 | * set the BBT page mask to see if this BBT should be rewritten */ | ||
2199 | if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { | ||
2200 | bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; | ||
2201 | } | ||
2202 | |||
2086 | } | 2203 | } |
2087 | } | 2204 | } |
2088 | instr->state = MTD_ERASE_DONE; | 2205 | instr->state = MTD_ERASE_DONE; |
@@ -2097,6 +2214,18 @@ erase_exit: | |||
2097 | /* Deselect and wake up anyone waiting on the device */ | 2214 | /* Deselect and wake up anyone waiting on the device */ |
2098 | nand_release_device(mtd); | 2215 | nand_release_device(mtd); |
2099 | 2216 | ||
2217 | /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */ | ||
2218 | if ((this->options & BBT_AUTO_REFRESH) && (!ret)) { | ||
2219 | for (chipnr = 0; chipnr < this->numchips; chipnr++) { | ||
2220 | if (rewrite_bbt[chipnr]) { | ||
2221 | /* update the BBT for chip */ | ||
2222 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", | ||
2223 | chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); | ||
2224 | nand_update_bbt (mtd, rewrite_bbt[chipnr]); | ||
2225 | } | ||
2226 | } | ||
2227 | } | ||
2228 | |||
2100 | /* Return more or less happy */ | 2229 | /* Return more or less happy */ |
2101 | return ret; | 2230 | return ret; |
2102 | } | 2231 | } |
@@ -2168,7 +2297,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) | |||
2168 | */ | 2297 | */ |
2169 | int nand_scan (struct mtd_info *mtd, int maxchips) | 2298 | int nand_scan (struct mtd_info *mtd, int maxchips) |
2170 | { | 2299 | { |
2171 | int i, j, nand_maf_id, nand_dev_id, busw; | 2300 | int i, nand_maf_id, nand_dev_id, busw, maf_id; |
2172 | struct nand_chip *this = mtd->priv; | 2301 | struct nand_chip *this = mtd->priv; |
2173 | 2302 | ||
2174 | /* Get buswidth to select the correct functions*/ | 2303 | /* Get buswidth to select the correct functions*/ |
@@ -2256,12 +2385,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2256 | busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; | 2385 | busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; |
2257 | } | 2386 | } |
2258 | 2387 | ||
2388 | /* Try to identify manufacturer */ | ||
2389 | for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { | ||
2390 | if (nand_manuf_ids[maf_id].id == nand_maf_id) | ||
2391 | break; | ||
2392 | } | ||
2393 | |||
2259 | /* Check, if buswidth is correct. Hardware drivers should set | 2394 | /* Check, if buswidth is correct. Hardware drivers should set |
2260 | * this correct ! */ | 2395 | * this correct ! */ |
2261 | if (busw != (this->options & NAND_BUSWIDTH_16)) { | 2396 | if (busw != (this->options & NAND_BUSWIDTH_16)) { |
2262 | printk (KERN_INFO "NAND device: Manufacturer ID:" | 2397 | printk (KERN_INFO "NAND device: Manufacturer ID:" |
2263 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, | 2398 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, |
2264 | nand_manuf_ids[i].name , mtd->name); | 2399 | nand_manuf_ids[maf_id].name , mtd->name); |
2265 | printk (KERN_WARNING | 2400 | printk (KERN_WARNING |
2266 | "NAND bus width %d instead %d bit\n", | 2401 | "NAND bus width %d instead %d bit\n", |
2267 | (this->options & NAND_BUSWIDTH_16) ? 16 : 8, | 2402 | (this->options & NAND_BUSWIDTH_16) ? 16 : 8, |
@@ -2300,14 +2435,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2300 | if (mtd->oobblock > 512 && this->cmdfunc == nand_command) | 2435 | if (mtd->oobblock > 512 && this->cmdfunc == nand_command) |
2301 | this->cmdfunc = nand_command_lp; | 2436 | this->cmdfunc = nand_command_lp; |
2302 | 2437 | ||
2303 | /* Try to identify manufacturer */ | ||
2304 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { | ||
2305 | if (nand_manuf_ids[j].id == nand_maf_id) | ||
2306 | break; | ||
2307 | } | ||
2308 | printk (KERN_INFO "NAND device: Manufacturer ID:" | 2438 | printk (KERN_INFO "NAND device: Manufacturer ID:" |
2309 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, | 2439 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, |
2310 | nand_manuf_ids[j].name , nand_flash_ids[i].name); | 2440 | nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); |
2311 | break; | 2441 | break; |
2312 | } | 2442 | } |
2313 | 2443 | ||
@@ -2388,12 +2518,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2388 | 2518 | ||
2389 | /* The number of bytes available for the filesystem to place fs dependend | 2519 | /* The number of bytes available for the filesystem to place fs dependend |
2390 | * oob data */ | 2520 | * oob data */ |
2391 | if (this->options & NAND_BUSWIDTH_16) { | 2521 | mtd->oobavail = 0; |
2392 | mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2); | 2522 | for (i = 0; this->autooob->oobfree[i][1]; i++) |
2393 | if (this->autooob->eccbytes & 0x01) | 2523 | mtd->oobavail += this->autooob->oobfree[i][1]; |
2394 | mtd->oobavail--; | ||
2395 | } else | ||
2396 | mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1); | ||
2397 | 2524 | ||
2398 | /* | 2525 | /* |
2399 | * check ECC mode, default to software | 2526 | * check ECC mode, default to software |
@@ -2524,6 +2651,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2524 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); | 2651 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); |
2525 | 2652 | ||
2526 | mtd->owner = THIS_MODULE; | 2653 | mtd->owner = THIS_MODULE; |
2654 | |||
2655 | /* Check, if we should skip the bad block table scan */ | ||
2656 | if (this->options & NAND_SKIP_BBTSCAN) | ||
2657 | return 0; | ||
2527 | 2658 | ||
2528 | /* Build bad block table */ | 2659 | /* Build bad block table */ |
2529 | return this->scan_bbt (mtd); | 2660 | return this->scan_bbt (mtd); |
@@ -2555,8 +2686,8 @@ void nand_release (struct mtd_info *mtd) | |||
2555 | kfree (this->data_buf); | 2686 | kfree (this->data_buf); |
2556 | } | 2687 | } |
2557 | 2688 | ||
2558 | EXPORT_SYMBOL (nand_scan); | 2689 | EXPORT_SYMBOL_GPL (nand_scan); |
2559 | EXPORT_SYMBOL (nand_release); | 2690 | EXPORT_SYMBOL_GPL (nand_release); |
2560 | 2691 | ||
2561 | MODULE_LICENSE ("GPL"); | 2692 | MODULE_LICENSE ("GPL"); |
2562 | MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); | 2693 | MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 9a1949751c1f..5ac2d2962220 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ | 9 | * $Id: nand_bbt.c,v 1.33 2005/06/14 15:47:56 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -77,7 +77,7 @@ | |||
77 | */ | 77 | */ |
78 | static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) | 78 | static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) |
79 | { | 79 | { |
80 | int i, end; | 80 | int i, end = 0; |
81 | uint8_t *p = buf; | 81 | uint8_t *p = buf; |
82 | 82 | ||
83 | end = paglen + td->offs; | 83 | end = paglen + td->offs; |
@@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
95 | return -1; | 95 | return -1; |
96 | } | 96 | } |
97 | 97 | ||
98 | p += td->len; | ||
99 | end += td->len; | ||
100 | if (td->options & NAND_BBT_SCANEMPTY) { | 98 | if (td->options & NAND_BBT_SCANEMPTY) { |
99 | p += td->len; | ||
100 | end += td->len; | ||
101 | for (i = end; i < len; i++) { | 101 | for (i = end; i < len; i++) { |
102 | if (*p++ != 0xff) | 102 | if (*p++ != 0xff) |
103 | return -1; | 103 | return -1; |
@@ -106,6 +106,32 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | 108 | ||
109 | /** | ||
110 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | ||
111 | * @buf: the buffer to search | ||
112 | * @len: the length of buffer to search | ||
113 | * @paglen: the pagelength | ||
114 | * @td: search pattern descriptor | ||
115 | * | ||
116 | * Check for a pattern at the given place. Used to search bad block | ||
117 | * tables and good / bad block identifiers. Same as check_pattern, but | ||
118 | * no optional empty check and the pattern is expected to start | ||
119 | * at offset 0. | ||
120 | * | ||
121 | */ | ||
122 | static int check_short_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) | ||
123 | { | ||
124 | int i; | ||
125 | uint8_t *p = buf; | ||
126 | |||
127 | /* Compare the pattern */ | ||
128 | for (i = 0; i < td->len; i++) { | ||
129 | if (p[i] != td->pattern[i]) | ||
130 | return -1; | ||
131 | } | ||
132 | return 0; | ||
133 | } | ||
134 | |||
109 | /** | 135 | /** |
110 | * read_bbt - [GENERIC] Read the bad block table starting from page | 136 | * read_bbt - [GENERIC] Read the bad block table starting from page |
111 | * @mtd: MTD device structure | 137 | * @mtd: MTD device structure |
@@ -252,7 +278,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de | |||
252 | * Create a bad block table by scanning the device | 278 | * Create a bad block table by scanning the device |
253 | * for the given good/bad block identify pattern | 279 | * for the given good/bad block identify pattern |
254 | */ | 280 | */ |
255 | static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) | 281 | static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) |
256 | { | 282 | { |
257 | struct nand_chip *this = mtd->priv; | 283 | struct nand_chip *this = mtd->priv; |
258 | int i, j, numblocks, len, scanlen; | 284 | int i, j, numblocks, len, scanlen; |
@@ -270,9 +296,17 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
270 | else | 296 | else |
271 | len = 1; | 297 | len = 1; |
272 | } | 298 | } |
273 | scanlen = mtd->oobblock + mtd->oobsize; | 299 | |
274 | readlen = len * mtd->oobblock; | 300 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
275 | ooblen = len * mtd->oobsize; | 301 | /* We need only read few bytes from the OOB area */ |
302 | scanlen = ooblen = 0; | ||
303 | readlen = bd->len; | ||
304 | } else { | ||
305 | /* Full page content should be read */ | ||
306 | scanlen = mtd->oobblock + mtd->oobsize; | ||
307 | readlen = len * mtd->oobblock; | ||
308 | ooblen = len * mtd->oobsize; | ||
309 | } | ||
276 | 310 | ||
277 | if (chip == -1) { | 311 | if (chip == -1) { |
278 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it | 312 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it |
@@ -284,7 +318,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
284 | if (chip >= this->numchips) { | 318 | if (chip >= this->numchips) { |
285 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", | 319 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", |
286 | chip + 1, this->numchips); | 320 | chip + 1, this->numchips); |
287 | return; | 321 | return -EINVAL; |
288 | } | 322 | } |
289 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); | 323 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); |
290 | startblock = chip * numblocks; | 324 | startblock = chip * numblocks; |
@@ -293,18 +327,41 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
293 | } | 327 | } |
294 | 328 | ||
295 | for (i = startblock; i < numblocks;) { | 329 | for (i = startblock; i < numblocks;) { |
296 | nand_read_raw (mtd, buf, from, readlen, ooblen); | 330 | int ret; |
331 | |||
332 | if (bd->options & NAND_BBT_SCANEMPTY) | ||
333 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) | ||
334 | return ret; | ||
335 | |||
297 | for (j = 0; j < len; j++) { | 336 | for (j = 0; j < len; j++) { |
298 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | 337 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
299 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 338 | size_t retlen; |
300 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 339 | |
301 | i >> 1, (unsigned int) from); | 340 | /* No need to read pages fully, just read required OOB bytes */ |
302 | break; | 341 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, |
342 | readlen, &retlen, &buf[0]); | ||
343 | if (ret) | ||
344 | return ret; | ||
345 | |||
346 | if (check_short_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | ||
347 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | ||
348 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | ||
349 | i >> 1, (unsigned int) from); | ||
350 | break; | ||
351 | } | ||
352 | } else { | ||
353 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | ||
354 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | ||
355 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | ||
356 | i >> 1, (unsigned int) from); | ||
357 | break; | ||
358 | } | ||
303 | } | 359 | } |
304 | } | 360 | } |
305 | i += 2; | 361 | i += 2; |
306 | from += (1 << this->bbt_erase_shift); | 362 | from += (1 << this->bbt_erase_shift); |
307 | } | 363 | } |
364 | return 0; | ||
308 | } | 365 | } |
309 | 366 | ||
310 | /** | 367 | /** |
@@ -589,14 +646,12 @@ write: | |||
589 | * The function creates a memory based bbt by scanning the device | 646 | * The function creates a memory based bbt by scanning the device |
590 | * for manufacturer / software marked good / bad blocks | 647 | * for manufacturer / software marked good / bad blocks |
591 | */ | 648 | */ |
592 | static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | 649 | static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) |
593 | { | 650 | { |
594 | struct nand_chip *this = mtd->priv; | 651 | struct nand_chip *this = mtd->priv; |
595 | 652 | ||
596 | /* Ensure that we only scan for the pattern and nothing else */ | 653 | bd->options &= ~NAND_BBT_SCANEMPTY; |
597 | bd->options = 0; | 654 | return create_bbt (mtd, this->data_buf, bd, -1); |
598 | create_bbt (mtd, this->data_buf, bd, -1); | ||
599 | return 0; | ||
600 | } | 655 | } |
601 | 656 | ||
602 | /** | 657 | /** |
@@ -808,8 +863,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
808 | /* If no primary table decriptor is given, scan the device | 863 | /* If no primary table decriptor is given, scan the device |
809 | * to build a memory based bad block table | 864 | * to build a memory based bad block table |
810 | */ | 865 | */ |
811 | if (!td) | 866 | if (!td) { |
812 | return nand_memory_bbt(mtd, bd); | 867 | if ((res = nand_memory_bbt(mtd, bd))) { |
868 | printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); | ||
869 | kfree (this->bbt); | ||
870 | this->bbt = NULL; | ||
871 | } | ||
872 | return res; | ||
873 | } | ||
813 | 874 | ||
814 | /* Allocate a temporary buffer for one eraseblock incl. oob */ | 875 | /* Allocate a temporary buffer for one eraseblock incl. oob */ |
815 | len = (1 << this->bbt_erase_shift); | 876 | len = (1 << this->bbt_erase_shift); |
@@ -904,14 +965,11 @@ out: | |||
904 | } | 965 | } |
905 | 966 | ||
906 | /* Define some generic bad / good block scan pattern which are used | 967 | /* Define some generic bad / good block scan pattern which are used |
907 | * while scanning a device for factory marked good / bad blocks | 968 | * while scanning a device for factory marked good / bad blocks. */ |
908 | * | ||
909 | * The memory based patterns just | ||
910 | */ | ||
911 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 969 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
912 | 970 | ||
913 | static struct nand_bbt_descr smallpage_memorybased = { | 971 | static struct nand_bbt_descr smallpage_memorybased = { |
914 | .options = 0, | 972 | .options = NAND_BBT_SCAN2NDPAGE, |
915 | .offs = 5, | 973 | .offs = 5, |
916 | .len = 1, | 974 | .len = 1, |
917 | .pattern = scan_ff_pattern | 975 | .pattern = scan_ff_pattern |
@@ -1042,7 +1100,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1042 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; | 1100 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
1043 | 1101 | ||
1044 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", | 1102 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", |
1045 | (unsigned int)offs, res, block >> 1); | 1103 | (unsigned int)offs, block >> 1, res); |
1046 | 1104 | ||
1047 | switch ((int)res) { | 1105 | switch ((int)res) { |
1048 | case 0x00: return 0; | 1106 | case 0x00: return 0; |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2d8c4321275b..efe246961b69 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
@@ -2,8 +2,8 @@ | |||
2 | * drivers/mtd/nandids.c | 2 | * drivers/mtd/nandids.c |
3 | * | 3 | * |
4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) | 4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) |
5 | * | 5 | * |
6 | * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $ | 6 | * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -56,17 +56,24 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
56 | {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, | 56 | {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, |
57 | 57 | ||
58 | {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, | 58 | {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, |
59 | {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, | ||
59 | {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, | 60 | {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, |
60 | {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 61 | {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
62 | {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | ||
61 | {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 63 | {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
64 | {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | ||
62 | 65 | ||
63 | {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, | 66 | {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, |
64 | 67 | ||
65 | {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, | ||
66 | |||
67 | /* These are the new chips with large page size. The pagesize | 68 | /* These are the new chips with large page size. The pagesize |
68 | * and the erasesize is determined from the extended id bytes | 69 | * and the erasesize is determined from the extended id bytes |
69 | */ | 70 | */ |
71 | /*512 Megabit */ | ||
72 | {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | ||
73 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | ||
74 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | ||
75 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | ||
76 | |||
70 | /* 1 Gigabit */ | 77 | /* 1 Gigabit */ |
71 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 78 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
72 | {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 79 | {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
@@ -103,7 +110,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
103 | * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go | 110 | * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go |
104 | * There are more speed improvements for reads and writes possible, but not implemented now | 111 | * There are more speed improvements for reads and writes possible, but not implemented now |
105 | */ | 112 | */ |
106 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY}, | 113 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, |
107 | 114 | ||
108 | {NULL,} | 115 | {NULL,} |
109 | }; | 116 | }; |
@@ -118,6 +125,7 @@ struct nand_manufacturers nand_manuf_ids[] = { | |||
118 | {NAND_MFR_NATIONAL, "National"}, | 125 | {NAND_MFR_NATIONAL, "National"}, |
119 | {NAND_MFR_RENESAS, "Renesas"}, | 126 | {NAND_MFR_RENESAS, "Renesas"}, |
120 | {NAND_MFR_STMICRO, "ST Micro"}, | 127 | {NAND_MFR_STMICRO, "ST Micro"}, |
128 | {NAND_MFR_HYNIX, "Hynix"}, | ||
121 | {0x0, "Unknown"} | 129 | {0x0, "Unknown"} |
122 | }; | 130 | }; |
123 | 131 | ||
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 13feefd7d8ca..754b6ed7ce14 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA |
24 | * | 24 | * |
25 | * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $ | 25 | * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/config.h> | 28 | #include <linux/config.h> |
@@ -1484,33 +1484,6 @@ ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
1484 | } | 1484 | } |
1485 | 1485 | ||
1486 | /* | 1486 | /* |
1487 | * Having only NAND chip IDs we call nand_scan which detects NAND flash | ||
1488 | * parameters and then calls scan_bbt in order to scan/find/build the | ||
1489 | * NAND flash bad block table. But since at that moment the NAND flash | ||
1490 | * image isn't allocated in the simulator, errors arise. To avoid this | ||
1491 | * we redefine the scan_bbt callback and initialize the nandsim structure | ||
1492 | * before the flash media scanning. | ||
1493 | */ | ||
1494 | int ns_scan_bbt(struct mtd_info *mtd) | ||
1495 | { | ||
1496 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | ||
1497 | struct nandsim *ns = (struct nandsim *)(chip->priv); | ||
1498 | int retval; | ||
1499 | |||
1500 | if (!NS_IS_INITIALIZED(ns)) | ||
1501 | if ((retval = init_nandsim(mtd)) != 0) { | ||
1502 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | ||
1503 | return retval; | ||
1504 | } | ||
1505 | if ((retval = nand_default_bbt(mtd)) != 0) { | ||
1506 | free_nandsim(ns); | ||
1507 | return retval; | ||
1508 | } | ||
1509 | |||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
1513 | /* | ||
1514 | * Module initialization function | 1487 | * Module initialization function |
1515 | */ | 1488 | */ |
1516 | int __init ns_init_module(void) | 1489 | int __init ns_init_module(void) |
@@ -1544,7 +1517,6 @@ int __init ns_init_module(void) | |||
1544 | chip->hwcontrol = ns_hwcontrol; | 1517 | chip->hwcontrol = ns_hwcontrol; |
1545 | chip->read_byte = ns_nand_read_byte; | 1518 | chip->read_byte = ns_nand_read_byte; |
1546 | chip->dev_ready = ns_device_ready; | 1519 | chip->dev_ready = ns_device_ready; |
1547 | chip->scan_bbt = ns_scan_bbt; | ||
1548 | chip->write_byte = ns_nand_write_byte; | 1520 | chip->write_byte = ns_nand_write_byte; |
1549 | chip->write_buf = ns_nand_write_buf; | 1521 | chip->write_buf = ns_nand_write_buf; |
1550 | chip->read_buf = ns_nand_read_buf; | 1522 | chip->read_buf = ns_nand_read_buf; |
@@ -1552,6 +1524,7 @@ int __init ns_init_module(void) | |||
1552 | chip->write_word = ns_nand_write_word; | 1524 | chip->write_word = ns_nand_write_word; |
1553 | chip->read_word = ns_nand_read_word; | 1525 | chip->read_word = ns_nand_read_word; |
1554 | chip->eccmode = NAND_ECC_SOFT; | 1526 | chip->eccmode = NAND_ECC_SOFT; |
1527 | chip->options |= NAND_SKIP_BBTSCAN; | ||
1555 | 1528 | ||
1556 | /* | 1529 | /* |
1557 | * Perform minimum nandsim structure initialization to handle | 1530 | * Perform minimum nandsim structure initialization to handle |
@@ -1580,6 +1553,16 @@ int __init ns_init_module(void) | |||
1580 | goto error; | 1553 | goto error; |
1581 | } | 1554 | } |
1582 | 1555 | ||
1556 | if ((retval = init_nandsim(nsmtd)) != 0) { | ||
1557 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | ||
1558 | goto error; | ||
1559 | } | ||
1560 | |||
1561 | if ((retval = nand_default_bbt(nsmtd)) != 0) { | ||
1562 | free_nandsim(nand); | ||
1563 | goto error; | ||
1564 | } | ||
1565 | |||
1583 | /* Register NAND as one big partition */ | 1566 | /* Register NAND as one big partition */ |
1584 | add_mtd_partitions(nsmtd, &nand->part, 1); | 1567 | add_mtd_partitions(nsmtd, &nand->part, 1); |
1585 | 1568 | ||
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 02305a2adca7..031051cbde76 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $ | 9 | * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -83,13 +83,18 @@ static struct mtd_info *rtc_from4_mtd = NULL; | |||
83 | #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) | 83 | #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) |
84 | #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) | 84 | #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) |
85 | 85 | ||
86 | #define ERR_STAT_ECC_AVAILABLE 0x20 | ||
87 | |||
86 | /* Undefine for software ECC */ | 88 | /* Undefine for software ECC */ |
87 | #define RTC_FROM4_HWECC 1 | 89 | #define RTC_FROM4_HWECC 1 |
88 | 90 | ||
91 | /* Define as 1 for no virtual erase blocks (in JFFS2) */ | ||
92 | #define RTC_FROM4_NO_VIRTBLOCKS 0 | ||
93 | |||
89 | /* | 94 | /* |
90 | * Module stuff | 95 | * Module stuff |
91 | */ | 96 | */ |
92 | static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE); | 97 | static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE); |
93 | 98 | ||
94 | const static struct mtd_partition partition_info[] = { | 99 | const static struct mtd_partition partition_info[] = { |
95 | { | 100 | { |
@@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) | |||
267 | } | 272 | } |
268 | 273 | ||
269 | 274 | ||
270 | |||
271 | /* | 275 | /* |
272 | * rtc_from4_nand_device_ready - hardware specific ready/busy check | 276 | * rtc_from4_nand_device_ready - hardware specific ready/busy check |
273 | * @mtd: MTD device structure | 277 | * @mtd: MTD device structure |
@@ -286,6 +290,40 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) | |||
286 | 290 | ||
287 | } | 291 | } |
288 | 292 | ||
293 | |||
294 | /* | ||
295 | * deplete - code to perform device recovery in case there was a power loss | ||
296 | * @mtd: MTD device structure | ||
297 | * @chip: Chip to select (0 == slot 3, 1 == slot 4) | ||
298 | * | ||
299 | * If there was a sudden loss of power during an erase operation, a | ||
300 | * "device recovery" operation must be performed when power is restored | ||
301 | * to ensure correct operation. This routine performs the required steps | ||
302 | * for the requested chip. | ||
303 | * | ||
304 | * See page 86 of the data sheet for details. | ||
305 | * | ||
306 | */ | ||
307 | static void deplete(struct mtd_info *mtd, int chip) | ||
308 | { | ||
309 | struct nand_chip *this = mtd->priv; | ||
310 | |||
311 | /* wait until device is ready */ | ||
312 | while (!this->dev_ready(mtd)); | ||
313 | |||
314 | this->select_chip(mtd, chip); | ||
315 | |||
316 | /* Send the commands for device recovery, phase 1 */ | ||
317 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); | ||
318 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); | ||
319 | |||
320 | /* Send the commands for device recovery, phase 2 */ | ||
321 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); | ||
322 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); | ||
323 | |||
324 | } | ||
325 | |||
326 | |||
289 | #ifdef RTC_FROM4_HWECC | 327 | #ifdef RTC_FROM4_HWECC |
290 | /* | 328 | /* |
291 | * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function | 329 | * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function |
@@ -329,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
329 | 367 | ||
330 | } | 368 | } |
331 | 369 | ||
370 | |||
332 | /* | 371 | /* |
333 | * rtc_from4_calculate_ecc - hardware specific code to read ECC code | 372 | * rtc_from4_calculate_ecc - hardware specific code to read ECC code |
334 | * @mtd: MTD device structure | 373 | * @mtd: MTD device structure |
@@ -356,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
356 | ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ | 395 | ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ |
357 | } | 396 | } |
358 | 397 | ||
398 | |||
359 | /* | 399 | /* |
360 | * rtc_from4_correct_data - hardware specific code to correct data using ECC code | 400 | * rtc_from4_correct_data - hardware specific code to correct data using ECC code |
361 | * @mtd: MTD device structure | 401 | * @mtd: MTD device structure |
@@ -365,16 +405,14 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
365 | * | 405 | * |
366 | * The FPGA tells us fast, if there's an error or not. If no, we go back happy | 406 | * The FPGA tells us fast, if there's an error or not. If no, we go back happy |
367 | * else we read the ecc results from the fpga and call the rs library to decode | 407 | * else we read the ecc results from the fpga and call the rs library to decode |
368 | * and hopefully correct the error | 408 | * and hopefully correct the error. |
369 | * | 409 | * |
370 | * For now I use the code, which we read from the FLASH to use the RS lib, | ||
371 | * as the syndrom conversion has a unresolved issue. | ||
372 | */ | 410 | */ |
373 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) | 411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) |
374 | { | 412 | { |
375 | int i, j, res; | 413 | int i, j, res; |
376 | unsigned short status; | 414 | unsigned short status; |
377 | uint16_t par[6], syn[6], tmp; | 415 | uint16_t par[6], syn[6]; |
378 | uint8_t ecc[8]; | 416 | uint8_t ecc[8]; |
379 | volatile unsigned short *rs_ecc; | 417 | volatile unsigned short *rs_ecc; |
380 | 418 | ||
@@ -416,15 +454,86 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
416 | } | 454 | } |
417 | 455 | ||
418 | /* Let the library code do its magic.*/ | 456 | /* Let the library code do its magic.*/ |
419 | res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL); | 457 | res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); |
420 | if (res > 0) { | 458 | if (res > 0) { |
421 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " | 459 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " |
422 | "ECC corrected %d errors on read\n", res); | 460 | "ECC corrected %d errors on read\n", res); |
423 | } | 461 | } |
424 | return res; | 462 | return res; |
425 | } | 463 | } |
464 | |||
465 | |||
466 | /** | ||
467 | * rtc_from4_errstat - perform additional error status checks | ||
468 | * @mtd: MTD device structure | ||
469 | * @this: NAND chip structure | ||
470 | * @state: state or the operation | ||
471 | * @status: status code returned from read status | ||
472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) | ||
473 | * | ||
474 | * Perform additional error status checks on erase and write failures | ||
475 | * to determine if errors are correctable. For this device, correctable | ||
476 | * 1-bit errors on erase and write are considered acceptable. | ||
477 | * | ||
478 | * note: see pages 34..37 of data sheet for details. | ||
479 | * | ||
480 | */ | ||
481 | static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) | ||
482 | { | ||
483 | int er_stat=0; | ||
484 | int rtn, retlen; | ||
485 | size_t len; | ||
486 | uint8_t *buf; | ||
487 | int i; | ||
488 | |||
489 | this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1); | ||
490 | |||
491 | if (state == FL_ERASING) { | ||
492 | for (i=0; i<4; i++) { | ||
493 | if (status & 1<<(i+1)) { | ||
494 | this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); | ||
495 | rtn = this->read_byte(mtd); | ||
496 | this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); | ||
497 | if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { | ||
498 | er_stat |= 1<<(i+1); /* err_ecc_not_avail */ | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | } else if (state == FL_WRITING) { | ||
503 | /* single bank write logic */ | ||
504 | this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1); | ||
505 | rtn = this->read_byte(mtd); | ||
506 | this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); | ||
507 | if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { | ||
508 | er_stat |= 1<<1; /* err_ecc_not_avail */ | ||
509 | } else { | ||
510 | len = mtd->oobblock; | ||
511 | buf = kmalloc (len, GFP_KERNEL); | ||
512 | if (!buf) { | ||
513 | printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n"); | ||
514 | er_stat = 1; /* if we can't check, assume failed */ | ||
515 | } else { | ||
516 | /* recovery read */ | ||
517 | /* page read */ | ||
518 | rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1); | ||
519 | if (rtn) { /* if read failed or > 1-bit error corrected */ | ||
520 | er_stat |= 1<<1; /* ECC read failed */ | ||
521 | } | ||
522 | kfree(buf); | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | rtn = status; | ||
528 | if (er_stat == 0) { /* if ECC is available */ | ||
529 | rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ | ||
530 | } | ||
531 | |||
532 | return rtn; | ||
533 | } | ||
426 | #endif | 534 | #endif |
427 | 535 | ||
536 | |||
428 | /* | 537 | /* |
429 | * Main initialization routine | 538 | * Main initialization routine |
430 | */ | 539 | */ |
@@ -432,6 +541,7 @@ int __init rtc_from4_init (void) | |||
432 | { | 541 | { |
433 | struct nand_chip *this; | 542 | struct nand_chip *this; |
434 | unsigned short bcr1, bcr2, wcr2; | 543 | unsigned short bcr1, bcr2, wcr2; |
544 | int i; | ||
435 | 545 | ||
436 | /* Allocate memory for MTD device structure and private data */ | 546 | /* Allocate memory for MTD device structure and private data */ |
437 | rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), | 547 | rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), |
@@ -483,6 +593,8 @@ int __init rtc_from4_init (void) | |||
483 | 593 | ||
484 | this->eccmode = NAND_ECC_HW8_512; | 594 | this->eccmode = NAND_ECC_HW8_512; |
485 | this->options |= NAND_HWECC_SYNDROME; | 595 | this->options |= NAND_HWECC_SYNDROME; |
596 | /* return the status of extra status and ECC checks */ | ||
597 | this->errstat = rtc_from4_errstat; | ||
486 | /* set the nand_oobinfo to support FPGA H/W error detection */ | 598 | /* set the nand_oobinfo to support FPGA H/W error detection */ |
487 | this->autooob = &rtc_from4_nand_oobinfo; | 599 | this->autooob = &rtc_from4_nand_oobinfo; |
488 | this->enable_hwecc = rtc_from4_enable_hwecc; | 600 | this->enable_hwecc = rtc_from4_enable_hwecc; |
@@ -504,6 +616,18 @@ int __init rtc_from4_init (void) | |||
504 | return -ENXIO; | 616 | return -ENXIO; |
505 | } | 617 | } |
506 | 618 | ||
619 | /* Perform 'device recovery' for each chip in case there was a power loss. */ | ||
620 | for (i=0; i < this->numchips; i++) { | ||
621 | deplete(rtc_from4_mtd, i); | ||
622 | } | ||
623 | |||
624 | #if RTC_FROM4_NO_VIRTBLOCKS | ||
625 | /* use a smaller erase block to minimize wasted space when a block is bad */ | ||
626 | /* note: this uses eight times as much RAM as using the default and makes */ | ||
627 | /* mounts take four times as long. */ | ||
628 | rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS; | ||
629 | #endif | ||
630 | |||
507 | /* Register the partitions */ | 631 | /* Register the partitions */ |
508 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); | 632 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); |
509 | 633 | ||
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d05e9b97947d..891e3a1b9110 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -1,17 +1,24 @@ | |||
1 | /* linux/drivers/mtd/nand/s3c2410.c | 1 | /* linux/drivers/mtd/nand/s3c2410.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004,2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * http://www.simtec.co.uk/products/SWLINUX/ |
5 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | 6 | * |
6 | * Samsung S3C2410 NAND driver | 7 | * Samsung S3C2410/S3C240 NAND driver |
7 | * | 8 | * |
8 | * Changelog: | 9 | * Changelog: |
9 | * 21-Sep-2004 BJD Initial version | 10 | * 21-Sep-2004 BJD Initial version |
10 | * 23-Sep-2004 BJD Mulitple device support | 11 | * 23-Sep-2004 BJD Mulitple device support |
11 | * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode | 12 | * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode |
12 | * 12-Oct-2004 BJD Fixed errors in use of platform data | 13 | * 12-Oct-2004 BJD Fixed errors in use of platform data |
14 | * 18-Feb-2005 BJD Fix sparse errors | ||
15 | * 14-Mar-2005 BJD Applied tglx's code reduction patch | ||
16 | * 02-May-2005 BJD Fixed s3c2440 support | ||
17 | * 02-May-2005 BJD Reduced hwcontrol decode | ||
18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug | ||
19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied | ||
13 | * | 20 | * |
14 | * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $ | 21 | * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $ |
15 | * | 22 | * |
16 | * This program is free software; you can redistribute it and/or modify | 23 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License as published by | 24 | * it under the terms of the GNU General Public License as published by |
@@ -69,10 +76,10 @@ static int hardware_ecc = 0; | |||
69 | */ | 76 | */ |
70 | 77 | ||
71 | static struct nand_oobinfo nand_hw_eccoob = { | 78 | static struct nand_oobinfo nand_hw_eccoob = { |
72 | .useecc = MTD_NANDECC_AUTOPLACE, | 79 | .useecc = MTD_NANDECC_AUTOPLACE, |
73 | .eccbytes = 3, | 80 | .eccbytes = 3, |
74 | .eccpos = {0, 1, 2 }, | 81 | .eccpos = {0, 1, 2 }, |
75 | .oobfree = { {8, 8} } | 82 | .oobfree = { {8, 8} } |
76 | }; | 83 | }; |
77 | 84 | ||
78 | /* controller and mtd information */ | 85 | /* controller and mtd information */ |
@@ -99,8 +106,10 @@ struct s3c2410_nand_info { | |||
99 | struct device *device; | 106 | struct device *device; |
100 | struct resource *area; | 107 | struct resource *area; |
101 | struct clk *clk; | 108 | struct clk *clk; |
102 | void *regs; | 109 | void __iomem *regs; |
103 | int mtd_count; | 110 | int mtd_count; |
111 | |||
112 | unsigned char is_s3c2440; | ||
104 | }; | 113 | }; |
105 | 114 | ||
106 | /* conversion functions */ | 115 | /* conversion functions */ |
@@ -165,12 +174,12 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
165 | /* calculate the timing information for the controller */ | 174 | /* calculate the timing information for the controller */ |
166 | 175 | ||
167 | if (plat != NULL) { | 176 | if (plat != NULL) { |
168 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8); | 177 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); |
169 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); | 178 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); |
170 | twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); | 179 | twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); |
171 | } else { | 180 | } else { |
172 | /* default timings */ | 181 | /* default timings */ |
173 | tacls = 8; | 182 | tacls = 4; |
174 | twrph0 = 8; | 183 | twrph0 = 8; |
175 | twrph1 = 8; | 184 | twrph1 = 8; |
176 | } | 185 | } |
@@ -185,10 +194,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
185 | to_ns(twrph0, clkrate), | 194 | to_ns(twrph0, clkrate), |
186 | to_ns(twrph1, clkrate)); | 195 | to_ns(twrph1, clkrate)); |
187 | 196 | ||
188 | cfg = S3C2410_NFCONF_EN; | 197 | if (!info->is_s3c2440) { |
189 | cfg |= S3C2410_NFCONF_TACLS(tacls-1); | 198 | cfg = S3C2410_NFCONF_EN; |
190 | cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); | 199 | cfg |= S3C2410_NFCONF_TACLS(tacls-1); |
191 | cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); | 200 | cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); |
201 | cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); | ||
202 | } else { | ||
203 | cfg = S3C2440_NFCONF_TACLS(tacls-1); | ||
204 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0-1); | ||
205 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1-1); | ||
206 | } | ||
192 | 207 | ||
193 | pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); | 208 | pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); |
194 | 209 | ||
@@ -203,17 +218,22 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
203 | struct s3c2410_nand_info *info; | 218 | struct s3c2410_nand_info *info; |
204 | struct s3c2410_nand_mtd *nmtd; | 219 | struct s3c2410_nand_mtd *nmtd; |
205 | struct nand_chip *this = mtd->priv; | 220 | struct nand_chip *this = mtd->priv; |
221 | void __iomem *reg; | ||
206 | unsigned long cur; | 222 | unsigned long cur; |
223 | unsigned long bit; | ||
207 | 224 | ||
208 | nmtd = this->priv; | 225 | nmtd = this->priv; |
209 | info = nmtd->info; | 226 | info = nmtd->info; |
210 | 227 | ||
211 | cur = readl(info->regs + S3C2410_NFCONF); | 228 | bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; |
229 | reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF); | ||
230 | |||
231 | cur = readl(reg); | ||
212 | 232 | ||
213 | if (chip == -1) { | 233 | if (chip == -1) { |
214 | cur |= S3C2410_NFCONF_nFCE; | 234 | cur |= bit; |
215 | } else { | 235 | } else { |
216 | if (chip > nmtd->set->nr_chips) { | 236 | if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { |
217 | printk(KERN_ERR PFX "chip %d out of range\n", chip); | 237 | printk(KERN_ERR PFX "chip %d out of range\n", chip); |
218 | return; | 238 | return; |
219 | } | 239 | } |
@@ -223,143 +243,76 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
223 | (info->platform->select_chip)(nmtd->set, chip); | 243 | (info->platform->select_chip)(nmtd->set, chip); |
224 | } | 244 | } |
225 | 245 | ||
226 | cur &= ~S3C2410_NFCONF_nFCE; | 246 | cur &= ~bit; |
227 | } | 247 | } |
228 | 248 | ||
229 | writel(cur, info->regs + S3C2410_NFCONF); | 249 | writel(cur, reg); |
230 | } | 250 | } |
231 | 251 | ||
232 | /* command and control functions */ | 252 | /* command and control functions |
253 | * | ||
254 | * Note, these all use tglx's method of changing the IO_ADDR_W field | ||
255 | * to make the code simpler, and use the nand layer's code to issue the | ||
256 | * command and address sequences via the proper IO ports. | ||
257 | * | ||
258 | */ | ||
233 | 259 | ||
234 | static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) | 260 | static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) |
235 | { | 261 | { |
236 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 262 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
237 | unsigned long cur; | 263 | struct nand_chip *chip = mtd->priv; |
238 | 264 | ||
239 | switch (cmd) { | 265 | switch (cmd) { |
240 | case NAND_CTL_SETNCE: | 266 | case NAND_CTL_SETNCE: |
241 | cur = readl(info->regs + S3C2410_NFCONF); | ||
242 | cur &= ~S3C2410_NFCONF_nFCE; | ||
243 | writel(cur, info->regs + S3C2410_NFCONF); | ||
244 | break; | ||
245 | |||
246 | case NAND_CTL_CLRNCE: | 267 | case NAND_CTL_CLRNCE: |
247 | cur = readl(info->regs + S3C2410_NFCONF); | 268 | printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); |
248 | cur |= S3C2410_NFCONF_nFCE; | ||
249 | writel(cur, info->regs + S3C2410_NFCONF); | ||
250 | break; | 269 | break; |
251 | 270 | ||
252 | /* we don't need to implement these */ | ||
253 | case NAND_CTL_SETCLE: | 271 | case NAND_CTL_SETCLE: |
254 | case NAND_CTL_CLRCLE: | 272 | chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; |
273 | break; | ||
274 | |||
255 | case NAND_CTL_SETALE: | 275 | case NAND_CTL_SETALE: |
256 | case NAND_CTL_CLRALE: | 276 | chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; |
257 | pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd); | 277 | break; |
278 | |||
279 | /* NAND_CTL_CLRCLE: */ | ||
280 | /* NAND_CTL_CLRALE: */ | ||
281 | default: | ||
282 | chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; | ||
258 | break; | 283 | break; |
259 | } | 284 | } |
260 | } | 285 | } |
261 | 286 | ||
262 | /* s3c2410_nand_command | 287 | /* command and control functions */ |
263 | * | ||
264 | * This function implements sending commands and the relevant address | ||
265 | * information to the chip, via the hardware controller. Since the | ||
266 | * S3C2410 generates the correct ALE/CLE signaling automatically, we | ||
267 | * do not need to use hwcontrol. | ||
268 | */ | ||
269 | 288 | ||
270 | static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command, | 289 | static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) |
271 | int column, int page_addr) | ||
272 | { | 290 | { |
273 | register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 291 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
274 | register struct nand_chip *this = mtd->priv; | 292 | struct nand_chip *chip = mtd->priv; |
275 | 293 | ||
276 | /* | 294 | switch (cmd) { |
277 | * Write out the command to the device. | 295 | case NAND_CTL_SETNCE: |
278 | */ | 296 | case NAND_CTL_CLRNCE: |
279 | if (command == NAND_CMD_SEQIN) { | 297 | printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); |
280 | int readcmd; | 298 | break; |
281 | |||
282 | if (column >= mtd->oobblock) { | ||
283 | /* OOB area */ | ||
284 | column -= mtd->oobblock; | ||
285 | readcmd = NAND_CMD_READOOB; | ||
286 | } else if (column < 256) { | ||
287 | /* First 256 bytes --> READ0 */ | ||
288 | readcmd = NAND_CMD_READ0; | ||
289 | } else { | ||
290 | column -= 256; | ||
291 | readcmd = NAND_CMD_READ1; | ||
292 | } | ||
293 | |||
294 | writeb(readcmd, info->regs + S3C2410_NFCMD); | ||
295 | } | ||
296 | writeb(command, info->regs + S3C2410_NFCMD); | ||
297 | 299 | ||
298 | /* Set ALE and clear CLE to start address cycle */ | 300 | case NAND_CTL_SETCLE: |
301 | chip->IO_ADDR_W = info->regs + S3C2440_NFCMD; | ||
302 | break; | ||
299 | 303 | ||
300 | if (column != -1 || page_addr != -1) { | 304 | case NAND_CTL_SETALE: |
305 | chip->IO_ADDR_W = info->regs + S3C2440_NFADDR; | ||
306 | break; | ||
301 | 307 | ||
302 | /* Serially input address */ | 308 | /* NAND_CTL_CLRCLE: */ |
303 | if (column != -1) { | 309 | /* NAND_CTL_CLRALE: */ |
304 | /* Adjust columns for 16 bit buswidth */ | ||
305 | if (this->options & NAND_BUSWIDTH_16) | ||
306 | column >>= 1; | ||
307 | writeb(column, info->regs + S3C2410_NFADDR); | ||
308 | } | ||
309 | if (page_addr != -1) { | ||
310 | writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR); | ||
311 | writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR); | ||
312 | /* One more address cycle for higher density devices */ | ||
313 | if (this->chipsize & 0x0c000000) | ||
314 | writeb((unsigned char) ((page_addr >> 16) & 0x0f), | ||
315 | info->regs + S3C2410_NFADDR); | ||
316 | } | ||
317 | /* Latch in address */ | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * program and erase have their own busy handlers | ||
322 | * status and sequential in needs no delay | ||
323 | */ | ||
324 | switch (command) { | ||
325 | |||
326 | case NAND_CMD_PAGEPROG: | ||
327 | case NAND_CMD_ERASE1: | ||
328 | case NAND_CMD_ERASE2: | ||
329 | case NAND_CMD_SEQIN: | ||
330 | case NAND_CMD_STATUS: | ||
331 | return; | ||
332 | |||
333 | case NAND_CMD_RESET: | ||
334 | if (this->dev_ready) | ||
335 | break; | ||
336 | |||
337 | udelay(this->chip_delay); | ||
338 | writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD); | ||
339 | |||
340 | while ( !(this->read_byte(mtd) & 0x40)); | ||
341 | return; | ||
342 | |||
343 | /* This applies to read commands */ | ||
344 | default: | 310 | default: |
345 | /* | 311 | chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; |
346 | * If we don't have access to the busy pin, we apply the given | 312 | break; |
347 | * command delay | ||
348 | */ | ||
349 | if (!this->dev_ready) { | ||
350 | udelay (this->chip_delay); | ||
351 | return; | ||
352 | } | ||
353 | } | 313 | } |
354 | |||
355 | /* Apply this short delay always to ensure that we do wait tWB in | ||
356 | * any case on any machine. */ | ||
357 | ndelay (100); | ||
358 | /* wait until command is processed */ | ||
359 | while (!this->dev_ready(mtd)); | ||
360 | } | 314 | } |
361 | 315 | ||
362 | |||
363 | /* s3c2410_nand_devready() | 316 | /* s3c2410_nand_devready() |
364 | * | 317 | * |
365 | * returns 0 if the nand is busy, 1 if it is ready | 318 | * returns 0 if the nand is busy, 1 if it is ready |
@@ -369,9 +322,12 @@ static int s3c2410_nand_devready(struct mtd_info *mtd) | |||
369 | { | 322 | { |
370 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 323 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
371 | 324 | ||
325 | if (info->is_s3c2440) | ||
326 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; | ||
372 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; | 327 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; |
373 | } | 328 | } |
374 | 329 | ||
330 | |||
375 | /* ECC handling functions */ | 331 | /* ECC handling functions */ |
376 | 332 | ||
377 | static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | 333 | static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, |
@@ -394,6 +350,12 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
394 | return -1; | 350 | return -1; |
395 | } | 351 | } |
396 | 352 | ||
353 | /* ECC functions | ||
354 | * | ||
355 | * These allow the s3c2410 and s3c2440 to use the controller's ECC | ||
356 | * generator block to ECC the data as it passes through] | ||
357 | */ | ||
358 | |||
397 | static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) | 359 | static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) |
398 | { | 360 | { |
399 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 361 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
@@ -404,6 +366,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) | |||
404 | writel(ctrl, info->regs + S3C2410_NFCONF); | 366 | writel(ctrl, info->regs + S3C2410_NFCONF); |
405 | } | 367 | } |
406 | 368 | ||
369 | static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) | ||
370 | { | ||
371 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | ||
372 | unsigned long ctrl; | ||
373 | |||
374 | ctrl = readl(info->regs + S3C2440_NFCONT); | ||
375 | writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT); | ||
376 | } | ||
377 | |||
407 | static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, | 378 | static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, |
408 | const u_char *dat, u_char *ecc_code) | 379 | const u_char *dat, u_char *ecc_code) |
409 | { | 380 | { |
@@ -420,7 +391,26 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, | |||
420 | } | 391 | } |
421 | 392 | ||
422 | 393 | ||
423 | /* over-ride the standard functions for a little more speed? */ | 394 | static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, |
395 | const u_char *dat, u_char *ecc_code) | ||
396 | { | ||
397 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | ||
398 | unsigned long ecc = readl(info->regs + S3C2440_NFMECC0); | ||
399 | |||
400 | ecc_code[0] = ecc; | ||
401 | ecc_code[1] = ecc >> 8; | ||
402 | ecc_code[2] = ecc >> 16; | ||
403 | |||
404 | pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", | ||
405 | ecc_code[0], ecc_code[1], ecc_code[2]); | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | |||
411 | /* over-ride the standard functions for a little more speed. We can | ||
412 | * use read/write block to move the data buffers to/from the controller | ||
413 | */ | ||
424 | 414 | ||
425 | static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | 415 | static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) |
426 | { | 416 | { |
@@ -523,11 +513,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
523 | { | 513 | { |
524 | struct nand_chip *chip = &nmtd->chip; | 514 | struct nand_chip *chip = &nmtd->chip; |
525 | 515 | ||
526 | chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA; | 516 | chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; |
527 | chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA; | 517 | chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; |
528 | chip->hwcontrol = s3c2410_nand_hwcontrol; | 518 | chip->hwcontrol = s3c2410_nand_hwcontrol; |
529 | chip->dev_ready = s3c2410_nand_devready; | 519 | chip->dev_ready = s3c2410_nand_devready; |
530 | chip->cmdfunc = s3c2410_nand_command; | ||
531 | chip->write_buf = s3c2410_nand_write_buf; | 520 | chip->write_buf = s3c2410_nand_write_buf; |
532 | chip->read_buf = s3c2410_nand_read_buf; | 521 | chip->read_buf = s3c2410_nand_read_buf; |
533 | chip->select_chip = s3c2410_nand_select_chip; | 522 | chip->select_chip = s3c2410_nand_select_chip; |
@@ -536,6 +525,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
536 | chip->options = 0; | 525 | chip->options = 0; |
537 | chip->controller = &info->controller; | 526 | chip->controller = &info->controller; |
538 | 527 | ||
528 | if (info->is_s3c2440) { | ||
529 | chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; | ||
530 | chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; | ||
531 | chip->hwcontrol = s3c2440_nand_hwcontrol; | ||
532 | } | ||
533 | |||
539 | nmtd->info = info; | 534 | nmtd->info = info; |
540 | nmtd->mtd.priv = chip; | 535 | nmtd->mtd.priv = chip; |
541 | nmtd->set = set; | 536 | nmtd->set = set; |
@@ -546,6 +541,11 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
546 | chip->calculate_ecc = s3c2410_nand_calculate_ecc; | 541 | chip->calculate_ecc = s3c2410_nand_calculate_ecc; |
547 | chip->eccmode = NAND_ECC_HW3_512; | 542 | chip->eccmode = NAND_ECC_HW3_512; |
548 | chip->autooob = &nand_hw_eccoob; | 543 | chip->autooob = &nand_hw_eccoob; |
544 | |||
545 | if (info->is_s3c2440) { | ||
546 | chip->enable_hwecc = s3c2440_nand_enable_hwecc; | ||
547 | chip->calculate_ecc = s3c2440_nand_calculate_ecc; | ||
548 | } | ||
549 | } else { | 549 | } else { |
550 | chip->eccmode = NAND_ECC_SOFT; | 550 | chip->eccmode = NAND_ECC_SOFT; |
551 | } | 551 | } |
@@ -559,7 +559,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
559 | * nand layer to look for devices | 559 | * nand layer to look for devices |
560 | */ | 560 | */ |
561 | 561 | ||
562 | static int s3c2410_nand_probe(struct device *dev) | 562 | static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) |
563 | { | 563 | { |
564 | struct platform_device *pdev = to_platform_device(dev); | 564 | struct platform_device *pdev = to_platform_device(dev); |
565 | struct s3c2410_platform_nand *plat = to_nand_plat(dev); | 565 | struct s3c2410_platform_nand *plat = to_nand_plat(dev); |
@@ -585,6 +585,7 @@ static int s3c2410_nand_probe(struct device *dev) | |||
585 | dev_set_drvdata(dev, info); | 585 | dev_set_drvdata(dev, info); |
586 | 586 | ||
587 | spin_lock_init(&info->controller.lock); | 587 | spin_lock_init(&info->controller.lock); |
588 | init_waitqueue_head(&info->controller.wq); | ||
588 | 589 | ||
589 | /* get the clock source and enable it */ | 590 | /* get the clock source and enable it */ |
590 | 591 | ||
@@ -600,7 +601,8 @@ static int s3c2410_nand_probe(struct device *dev) | |||
600 | 601 | ||
601 | /* allocate and map the resource */ | 602 | /* allocate and map the resource */ |
602 | 603 | ||
603 | res = pdev->resource; /* assume that the flash has one resource */ | 604 | /* currently we assume we have the one resource */ |
605 | res = pdev->resource; | ||
604 | size = res->end - res->start + 1; | 606 | size = res->end - res->start + 1; |
605 | 607 | ||
606 | info->area = request_mem_region(res->start, size, pdev->name); | 608 | info->area = request_mem_region(res->start, size, pdev->name); |
@@ -611,9 +613,10 @@ static int s3c2410_nand_probe(struct device *dev) | |||
611 | goto exit_error; | 613 | goto exit_error; |
612 | } | 614 | } |
613 | 615 | ||
614 | info->device = dev; | 616 | info->device = dev; |
615 | info->platform = plat; | 617 | info->platform = plat; |
616 | info->regs = ioremap(res->start, size); | 618 | info->regs = ioremap(res->start, size); |
619 | info->is_s3c2440 = is_s3c2440; | ||
617 | 620 | ||
618 | if (info->regs == NULL) { | 621 | if (info->regs == NULL) { |
619 | printk(KERN_ERR PFX "cannot reserve register region\n"); | 622 | printk(KERN_ERR PFX "cannot reserve register region\n"); |
@@ -678,6 +681,18 @@ static int s3c2410_nand_probe(struct device *dev) | |||
678 | return err; | 681 | return err; |
679 | } | 682 | } |
680 | 683 | ||
684 | /* driver device registration */ | ||
685 | |||
686 | static int s3c2410_nand_probe(struct device *dev) | ||
687 | { | ||
688 | return s3c24xx_nand_probe(dev, 0); | ||
689 | } | ||
690 | |||
691 | static int s3c2440_nand_probe(struct device *dev) | ||
692 | { | ||
693 | return s3c24xx_nand_probe(dev, 1); | ||
694 | } | ||
695 | |||
681 | static struct device_driver s3c2410_nand_driver = { | 696 | static struct device_driver s3c2410_nand_driver = { |
682 | .name = "s3c2410-nand", | 697 | .name = "s3c2410-nand", |
683 | .bus = &platform_bus_type, | 698 | .bus = &platform_bus_type, |
@@ -685,14 +700,24 @@ static struct device_driver s3c2410_nand_driver = { | |||
685 | .remove = s3c2410_nand_remove, | 700 | .remove = s3c2410_nand_remove, |
686 | }; | 701 | }; |
687 | 702 | ||
703 | static struct device_driver s3c2440_nand_driver = { | ||
704 | .name = "s3c2440-nand", | ||
705 | .bus = &platform_bus_type, | ||
706 | .probe = s3c2440_nand_probe, | ||
707 | .remove = s3c2410_nand_remove, | ||
708 | }; | ||
709 | |||
688 | static int __init s3c2410_nand_init(void) | 710 | static int __init s3c2410_nand_init(void) |
689 | { | 711 | { |
690 | printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n"); | 712 | printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); |
713 | |||
714 | driver_register(&s3c2440_nand_driver); | ||
691 | return driver_register(&s3c2410_nand_driver); | 715 | return driver_register(&s3c2410_nand_driver); |
692 | } | 716 | } |
693 | 717 | ||
694 | static void __exit s3c2410_nand_exit(void) | 718 | static void __exit s3c2410_nand_exit(void) |
695 | { | 719 | { |
720 | driver_unregister(&s3c2440_nand_driver); | ||
696 | driver_unregister(&s3c2410_nand_driver); | 721 | driver_unregister(&s3c2410_nand_driver); |
697 | } | 722 | } |
698 | 723 | ||
@@ -701,4 +726,4 @@ module_exit(s3c2410_nand_exit); | |||
701 | 726 | ||
702 | MODULE_LICENSE("GPL"); | 727 | MODULE_LICENSE("GPL"); |
703 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 728 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
704 | MODULE_DESCRIPTION("S3C2410 MTD NAND driver"); | 729 | MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); |
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 29572793334c..9853b87bb756 100755..100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Richard Purdie | 4 | * Copyright (C) 2004 Richard Purdie |
5 | * | 5 | * |
6 | * $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $ | 6 | * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $ |
7 | * | 7 | * |
8 | * Based on Sharp's NAND driver sharp_sl.c | 8 | * Based on Sharp's NAND driver sharp_sl.c |
9 | * | 9 | * |
@@ -216,7 +216,7 @@ sharpsl_nand_init(void) | |||
216 | nr_partitions = DEFAULT_NUM_PARTITIONS; | 216 | nr_partitions = DEFAULT_NUM_PARTITIONS; |
217 | sharpsl_partition_info = sharpsl_nand_default_partition_info; | 217 | sharpsl_partition_info = sharpsl_nand_default_partition_info; |
218 | if (machine_is_poodle()) { | 218 | if (machine_is_poodle()) { |
219 | sharpsl_partition_info[1].size=22 * 1024 * 1024; | 219 | sharpsl_partition_info[1].size=30 * 1024 * 1024; |
220 | } else if (machine_is_corgi() || machine_is_shepherd()) { | 220 | } else if (machine_is_corgi() || machine_is_shepherd()) { |
221 | sharpsl_partition_info[1].size=25 * 1024 * 1024; | 221 | sharpsl_partition_info[1].size=25 * 1024 * 1024; |
222 | } else if (machine_is_husky()) { | 222 | } else if (machine_is_husky()) { |
diff --git a/drivers/mtd/nand/tx4925ndfmc.c b/drivers/mtd/nand/tx4925ndfmc.c deleted file mode 100644 index bba688830c9b..000000000000 --- a/drivers/mtd/nand/tx4925ndfmc.c +++ /dev/null | |||
@@ -1,416 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/mtd/tx4925ndfmc.c | ||
3 | * | ||
4 | * Overview: | ||
5 | * This is a device driver for the NAND flash device found on the | ||
6 | * Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports | ||
7 | * 16MiB, 32MiB and 64MiB cards. | ||
8 | * | ||
9 | * Author: MontaVista Software, Inc. source@mvista.com | ||
10 | * | ||
11 | * Derived from drivers/mtd/autcpu12.c | ||
12 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | ||
13 | * | ||
14 | * $Id: tx4925ndfmc.c,v 1.5 2004/10/05 13:50:20 gleixner Exp $ | ||
15 | * | ||
16 | * Copyright (C) 2001 Toshiba Corporation | ||
17 | * | ||
18 | * 2003 (c) MontaVista Software, Inc. This file is licensed under | ||
19 | * the terms of the GNU General Public License version 2. This program | ||
20 | * is licensed "as is" without any warranty of any kind, whether express | ||
21 | * or implied. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/slab.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/mtd/mtd.h> | ||
29 | #include <linux/mtd/nand.h> | ||
30 | #include <linux/mtd/partitions.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/tx4925/tx4925_nand.h> | ||
34 | |||
35 | extern struct nand_oobinfo jffs2_oobinfo; | ||
36 | |||
37 | /* | ||
38 | * MTD structure for RBTX4925 board | ||
39 | */ | ||
40 | static struct mtd_info *tx4925ndfmc_mtd = NULL; | ||
41 | |||
42 | /* | ||
43 | * Define partitions for flash devices | ||
44 | */ | ||
45 | |||
46 | static struct mtd_partition partition_info16k[] = { | ||
47 | { .name = "RBTX4925 flash partition 1", | ||
48 | .offset = 0, | ||
49 | .size = 8 * 0x00100000 }, | ||
50 | { .name = "RBTX4925 flash partition 2", | ||
51 | .offset = 8 * 0x00100000, | ||
52 | .size = 8 * 0x00100000 }, | ||
53 | }; | ||
54 | |||
55 | static struct mtd_partition partition_info32k[] = { | ||
56 | { .name = "RBTX4925 flash partition 1", | ||
57 | .offset = 0, | ||
58 | .size = 8 * 0x00100000 }, | ||
59 | { .name = "RBTX4925 flash partition 2", | ||
60 | .offset = 8 * 0x00100000, | ||
61 | .size = 24 * 0x00100000 }, | ||
62 | }; | ||
63 | |||
64 | static struct mtd_partition partition_info64k[] = { | ||
65 | { .name = "User FS", | ||
66 | .offset = 0, | ||
67 | .size = 16 * 0x00100000 }, | ||
68 | { .name = "RBTX4925 flash partition 2", | ||
69 | .offset = 16 * 0x00100000, | ||
70 | .size = 48 * 0x00100000}, | ||
71 | }; | ||
72 | |||
73 | static struct mtd_partition partition_info128k[] = { | ||
74 | { .name = "Skip bad section", | ||
75 | .offset = 0, | ||
76 | .size = 16 * 0x00100000 }, | ||
77 | { .name = "User FS", | ||
78 | .offset = 16 * 0x00100000, | ||
79 | .size = 112 * 0x00100000 }, | ||
80 | }; | ||
81 | #define NUM_PARTITIONS16K 2 | ||
82 | #define NUM_PARTITIONS32K 2 | ||
83 | #define NUM_PARTITIONS64K 2 | ||
84 | #define NUM_PARTITIONS128K 2 | ||
85 | |||
86 | /* | ||
87 | * hardware specific access to control-lines | ||
88 | */ | ||
89 | static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd) | ||
90 | { | ||
91 | |||
92 | switch(cmd){ | ||
93 | |||
94 | case NAND_CTL_SETCLE: | ||
95 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE; | ||
96 | break; | ||
97 | case NAND_CTL_CLRCLE: | ||
98 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE; | ||
99 | break; | ||
100 | case NAND_CTL_SETALE: | ||
101 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE; | ||
102 | break; | ||
103 | case NAND_CTL_CLRALE: | ||
104 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE; | ||
105 | break; | ||
106 | case NAND_CTL_SETNCE: | ||
107 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE; | ||
108 | break; | ||
109 | case NAND_CTL_CLRNCE: | ||
110 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE; | ||
111 | break; | ||
112 | case NAND_CTL_SETWP: | ||
113 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE; | ||
114 | break; | ||
115 | case NAND_CTL_CLRWP: | ||
116 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE; | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * read device ready pin | ||
123 | */ | ||
124 | static int tx4925ndfmc_device_ready(struct mtd_info *mtd) | ||
125 | { | ||
126 | int ready; | ||
127 | ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1; | ||
128 | return ready; | ||
129 | } | ||
130 | void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) | ||
131 | { | ||
132 | /* reset first */ | ||
133 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK; | ||
134 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; | ||
135 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB; | ||
136 | } | ||
137 | static void tx4925ndfmc_disable_ecc(void) | ||
138 | { | ||
139 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; | ||
140 | } | ||
141 | static void tx4925ndfmc_enable_read_ecc(void) | ||
142 | { | ||
143 | tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; | ||
144 | tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ; | ||
145 | } | ||
146 | void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ | ||
147 | int i; | ||
148 | u_char *ecc = ecc_code; | ||
149 | tx4925ndfmc_enable_read_ecc(); | ||
150 | for (i = 0;i < 6;i++,ecc++) | ||
151 | *ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr)); | ||
152 | tx4925ndfmc_disable_ecc(); | ||
153 | } | ||
154 | void tx4925ndfmc_device_setup(void) | ||
155 | { | ||
156 | |||
157 | *(unsigned char *)0xbb005000 &= ~0x08; | ||
158 | |||
159 | /* reset NDFMC */ | ||
160 | tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST; | ||
161 | while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST); | ||
162 | |||
163 | /* setup BusSeparete, Hold Time, Strobe Pulse Width */ | ||
164 | tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0; | ||
165 | tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW; | ||
166 | } | ||
167 | static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd) | ||
168 | { | ||
169 | struct nand_chip *this = mtd->priv; | ||
170 | return tx4925_read_nfmc(this->IO_ADDR_R); | ||
171 | } | ||
172 | |||
173 | static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte) | ||
174 | { | ||
175 | struct nand_chip *this = mtd->priv; | ||
176 | tx4925_write_nfmc(byte, this->IO_ADDR_W); | ||
177 | } | ||
178 | |||
179 | static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
180 | { | ||
181 | int i; | ||
182 | struct nand_chip *this = mtd->priv; | ||
183 | |||
184 | for (i=0; i<len; i++) | ||
185 | tx4925_write_nfmc(buf[i], this->IO_ADDR_W); | ||
186 | } | ||
187 | |||
188 | static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | ||
189 | { | ||
190 | int i; | ||
191 | struct nand_chip *this = mtd->priv; | ||
192 | |||
193 | for (i=0; i<len; i++) | ||
194 | buf[i] = tx4925_read_nfmc(this->IO_ADDR_R); | ||
195 | } | ||
196 | |||
197 | static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
198 | { | ||
199 | int i; | ||
200 | struct nand_chip *this = mtd->priv; | ||
201 | |||
202 | for (i=0; i<len; i++) | ||
203 | if (buf[i] != tx4925_read_nfmc(this->IO_ADDR_R)) | ||
204 | return -EFAULT; | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Send command to NAND device | ||
211 | */ | ||
212 | static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) | ||
213 | { | ||
214 | register struct nand_chip *this = mtd->priv; | ||
215 | |||
216 | /* Begin command latch cycle */ | ||
217 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
218 | /* | ||
219 | * Write out the command to the device. | ||
220 | */ | ||
221 | if (command == NAND_CMD_SEQIN) { | ||
222 | int readcmd; | ||
223 | |||
224 | if (column >= mtd->oobblock) { | ||
225 | /* OOB area */ | ||
226 | column -= mtd->oobblock; | ||
227 | readcmd = NAND_CMD_READOOB; | ||
228 | } else if (column < 256) { | ||
229 | /* First 256 bytes --> READ0 */ | ||
230 | readcmd = NAND_CMD_READ0; | ||
231 | } else { | ||
232 | column -= 256; | ||
233 | readcmd = NAND_CMD_READ1; | ||
234 | } | ||
235 | this->write_byte(mtd, readcmd); | ||
236 | } | ||
237 | this->write_byte(mtd, command); | ||
238 | |||
239 | /* Set ALE and clear CLE to start address cycle */ | ||
240 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
241 | |||
242 | if (column != -1 || page_addr != -1) { | ||
243 | this->hwcontrol(mtd, NAND_CTL_SETALE); | ||
244 | |||
245 | /* Serially input address */ | ||
246 | if (column != -1) | ||
247 | this->write_byte(mtd, column); | ||
248 | if (page_addr != -1) { | ||
249 | this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); | ||
250 | this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); | ||
251 | /* One more address cycle for higher density devices */ | ||
252 | if (mtd->size & 0x0c000000) | ||
253 | this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); | ||
254 | } | ||
255 | /* Latch in address */ | ||
256 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * program and erase have their own busy handlers | ||
261 | * status and sequential in needs no delay | ||
262 | */ | ||
263 | switch (command) { | ||
264 | |||
265 | case NAND_CMD_PAGEPROG: | ||
266 | /* Turn off WE */ | ||
267 | this->hwcontrol (mtd, NAND_CTL_CLRWP); | ||
268 | return; | ||
269 | |||
270 | case NAND_CMD_SEQIN: | ||
271 | /* Turn on WE */ | ||
272 | this->hwcontrol (mtd, NAND_CTL_SETWP); | ||
273 | return; | ||
274 | |||
275 | case NAND_CMD_ERASE1: | ||
276 | case NAND_CMD_ERASE2: | ||
277 | case NAND_CMD_STATUS: | ||
278 | return; | ||
279 | |||
280 | case NAND_CMD_RESET: | ||
281 | if (this->dev_ready) | ||
282 | break; | ||
283 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
284 | this->write_byte(mtd, NAND_CMD_STATUS); | ||
285 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
286 | while ( !(this->read_byte(mtd) & 0x40)); | ||
287 | return; | ||
288 | |||
289 | /* This applies to read commands */ | ||
290 | default: | ||
291 | /* | ||
292 | * If we don't have access to the busy pin, we apply the given | ||
293 | * command delay | ||
294 | */ | ||
295 | if (!this->dev_ready) { | ||
296 | udelay (this->chip_delay); | ||
297 | return; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /* wait until command is processed */ | ||
302 | while (!this->dev_ready(mtd)); | ||
303 | } | ||
304 | |||
305 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
306 | extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio | ||
307 | n **pparts, char *); | ||
308 | #endif | ||
309 | |||
310 | /* | ||
311 | * Main initialization routine | ||
312 | */ | ||
313 | extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); | ||
314 | int __init tx4925ndfmc_init (void) | ||
315 | { | ||
316 | struct nand_chip *this; | ||
317 | int err = 0; | ||
318 | |||
319 | /* Allocate memory for MTD device structure and private data */ | ||
320 | tx4925ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), | ||
321 | GFP_KERNEL); | ||
322 | if (!tx4925ndfmc_mtd) { | ||
323 | printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n"); | ||
324 | err = -ENOMEM; | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | tx4925ndfmc_device_setup(); | ||
329 | |||
330 | /* io is indirect via a register so don't need to ioremap address */ | ||
331 | |||
332 | /* Get pointer to private data */ | ||
333 | this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]); | ||
334 | |||
335 | /* Initialize structures */ | ||
336 | memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info)); | ||
337 | memset((char *) this, 0, sizeof(struct nand_chip)); | ||
338 | |||
339 | /* Link the private data with the MTD structure */ | ||
340 | tx4925ndfmc_mtd->priv = this; | ||
341 | |||
342 | /* Set address of NAND IO lines */ | ||
343 | this->IO_ADDR_R = (void __iomem *)&(tx4925_ndfmcptr->dtr); | ||
344 | this->IO_ADDR_W = (void __iomem *)&(tx4925_ndfmcptr->dtr); | ||
345 | this->hwcontrol = tx4925ndfmc_hwcontrol; | ||
346 | this->enable_hwecc = tx4925ndfmc_enable_hwecc; | ||
347 | this->calculate_ecc = tx4925ndfmc_readecc; | ||
348 | this->correct_data = nand_correct_data; | ||
349 | this->eccmode = NAND_ECC_HW6_512; | ||
350 | this->dev_ready = tx4925ndfmc_device_ready; | ||
351 | /* 20 us command delay time */ | ||
352 | this->chip_delay = 20; | ||
353 | this->read_byte = tx4925ndfmc_nand_read_byte; | ||
354 | this->write_byte = tx4925ndfmc_nand_write_byte; | ||
355 | this->cmdfunc = tx4925ndfmc_nand_command; | ||
356 | this->write_buf = tx4925ndfmc_nand_write_buf; | ||
357 | this->read_buf = tx4925ndfmc_nand_read_buf; | ||
358 | this->verify_buf = tx4925ndfmc_nand_verify_buf; | ||
359 | |||
360 | /* Scan to find existance of the device */ | ||
361 | if (nand_scan (tx4925ndfmc_mtd, 1)) { | ||
362 | err = -ENXIO; | ||
363 | goto out_ior; | ||
364 | } | ||
365 | |||
366 | /* Register the partitions */ | ||
367 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
368 | { | ||
369 | int mtd_parts_nb = 0; | ||
370 | struct mtd_partition *mtd_parts = 0; | ||
371 | mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc"); | ||
372 | if (mtd_parts_nb > 0) | ||
373 | add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb); | ||
374 | else | ||
375 | add_mtd_device(tx4925ndfmc_mtd); | ||
376 | } | ||
377 | #else /* ifdef CONFIG_MTD_CMDLINE_PARTS */ | ||
378 | switch(tx4925ndfmc_mtd->size){ | ||
379 | case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break; | ||
380 | case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break; | ||
381 | case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break; | ||
382 | case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break; | ||
383 | default: { | ||
384 | printk ("Unsupported SmartMedia device\n"); | ||
385 | err = -ENXIO; | ||
386 | goto out_ior; | ||
387 | } | ||
388 | } | ||
389 | #endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */ | ||
390 | goto out; | ||
391 | |||
392 | out_ior: | ||
393 | out: | ||
394 | return err; | ||
395 | } | ||
396 | |||
397 | module_init(tx4925ndfmc_init); | ||
398 | |||
399 | /* | ||
400 | * Clean up routine | ||
401 | */ | ||
402 | #ifdef MODULE | ||
403 | static void __exit tx4925ndfmc_cleanup (void) | ||
404 | { | ||
405 | /* Release resources, unregister device */ | ||
406 | nand_release (tx4925ndfmc_mtd); | ||
407 | |||
408 | /* Free the MTD device structure */ | ||
409 | kfree (tx4925ndfmc_mtd); | ||
410 | } | ||
411 | module_exit(tx4925ndfmc_cleanup); | ||
412 | #endif | ||
413 | |||
414 | MODULE_LICENSE("GPL"); | ||
415 | MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>"); | ||
416 | MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925"); | ||
diff --git a/drivers/mtd/nand/tx4938ndfmc.c b/drivers/mtd/nand/tx4938ndfmc.c deleted file mode 100644 index df26e58820b3..000000000000 --- a/drivers/mtd/nand/tx4938ndfmc.c +++ /dev/null | |||
@@ -1,406 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/tx4938ndfmc.c | ||
3 | * | ||
4 | * Overview: | ||
5 | * This is a device driver for the NAND flash device connected to | ||
6 | * TX4938 internal NAND Memory Controller. | ||
7 | * TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit. | ||
8 | * | ||
9 | * Author: source@mvista.com | ||
10 | * | ||
11 | * Based on spia.c by Steven J. Hill | ||
12 | * | ||
13 | * $Id: tx4938ndfmc.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ | ||
14 | * | ||
15 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
16 | * | ||
17 | * 2003 (c) MontaVista Software, Inc. This file is licensed under the | ||
18 | * terms of the GNU General Public License version 2. This program is | ||
19 | * licensed "as is" without any warranty of any kind, whether express | ||
20 | * or implied. | ||
21 | */ | ||
22 | #include <linux/config.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/mtd/mtd.h> | ||
27 | #include <linux/mtd/nand.h> | ||
28 | #include <linux/mtd/nand_ecc.h> | ||
29 | #include <linux/mtd/partitions.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/bootinfo.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <asm/tx4938/rbtx4938.h> | ||
34 | |||
35 | extern struct nand_oobinfo jffs2_oobinfo; | ||
36 | |||
37 | /* | ||
38 | * MTD structure for TX4938 NDFMC | ||
39 | */ | ||
40 | static struct mtd_info *tx4938ndfmc_mtd; | ||
41 | |||
42 | /* | ||
43 | * Define partitions for flash device | ||
44 | */ | ||
45 | #define flush_wb() (void)tx4938_ndfmcptr->mcr; | ||
46 | |||
47 | #define NUM_PARTITIONS 3 | ||
48 | #define NUMBER_OF_CIS_BLOCKS 24 | ||
49 | #define SIZE_OF_BLOCK 0x00004000 | ||
50 | #define NUMBER_OF_BLOCK_PER_ZONE 1024 | ||
51 | #define SIZE_OF_ZONE (NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK) | ||
52 | #ifndef CONFIG_MTD_CMDLINE_PARTS | ||
53 | /* | ||
54 | * You can use the following sample of MTD partitions | ||
55 | * on the NAND Flash Memory 32MB or more. | ||
56 | * | ||
57 | * The following figure shows the image of the sample partition on | ||
58 | * the 32MB NAND Flash Memory. | ||
59 | * | ||
60 | * Block No. | ||
61 | * 0 +-----------------------------+ ------ | ||
62 | * | CIS | ^ | ||
63 | * 24 +-----------------------------+ | | ||
64 | * | kernel image | | Zone 0 | ||
65 | * | | | | ||
66 | * +-----------------------------+ | | ||
67 | * 1023 | unused area | v | ||
68 | * +-----------------------------+ ------ | ||
69 | * 1024 | JFFS2 | ^ | ||
70 | * | | | | ||
71 | * | | | Zone 1 | ||
72 | * | | | | ||
73 | * | | | | ||
74 | * | | v | ||
75 | * 2047 +-----------------------------+ ------ | ||
76 | * | ||
77 | */ | ||
78 | static struct mtd_partition partition_info[NUM_PARTITIONS] = { | ||
79 | { | ||
80 | .name = "RBTX4938 CIS Area", | ||
81 | .offset = 0, | ||
82 | .size = (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK), | ||
83 | .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */ | ||
84 | }, | ||
85 | { | ||
86 | .name = "RBTX4938 kernel image", | ||
87 | .offset = MTDPART_OFS_APPEND, | ||
88 | .size = 8 * 0x00100000, /* 8MB (Depends on size of kernel image) */ | ||
89 | .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */ | ||
90 | }, | ||
91 | { | ||
92 | .name = "Root FS (JFFS2)", | ||
93 | .offset = (0 + SIZE_OF_ZONE), /* start address of next zone */ | ||
94 | .size = MTDPART_SIZ_FULL | ||
95 | }, | ||
96 | }; | ||
97 | #endif | ||
98 | |||
99 | static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd) | ||
100 | { | ||
101 | switch (cmd) { | ||
102 | case NAND_CTL_SETCLE: | ||
103 | tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE; | ||
104 | break; | ||
105 | case NAND_CTL_CLRCLE: | ||
106 | tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE; | ||
107 | break; | ||
108 | case NAND_CTL_SETALE: | ||
109 | tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE; | ||
110 | break; | ||
111 | case NAND_CTL_CLRALE: | ||
112 | tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE; | ||
113 | break; | ||
114 | /* TX4938_NDFMCR_CE bit is 0:high 1:low */ | ||
115 | case NAND_CTL_SETNCE: | ||
116 | tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE; | ||
117 | break; | ||
118 | case NAND_CTL_CLRNCE: | ||
119 | tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE; | ||
120 | break; | ||
121 | case NAND_CTL_SETWP: | ||
122 | tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE; | ||
123 | break; | ||
124 | case NAND_CTL_CLRWP: | ||
125 | tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE; | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | static int tx4938ndfmc_dev_ready(struct mtd_info *mtd) | ||
130 | { | ||
131 | flush_wb(); | ||
132 | return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY); | ||
133 | } | ||
134 | static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) | ||
135 | { | ||
136 | u32 mcr = tx4938_ndfmcptr->mcr; | ||
137 | mcr &= ~TX4938_NDFMCR_ECC_ALL; | ||
138 | tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; | ||
139 | tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ; | ||
140 | ecc_code[1] = tx4938_ndfmcptr->dtr; | ||
141 | ecc_code[0] = tx4938_ndfmcptr->dtr; | ||
142 | ecc_code[2] = tx4938_ndfmcptr->dtr; | ||
143 | tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; | ||
144 | } | ||
145 | static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) | ||
146 | { | ||
147 | u32 mcr = tx4938_ndfmcptr->mcr; | ||
148 | mcr &= ~TX4938_NDFMCR_ECC_ALL; | ||
149 | tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET; | ||
150 | tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; | ||
151 | tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON; | ||
152 | } | ||
153 | |||
154 | static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd) | ||
155 | { | ||
156 | struct nand_chip *this = mtd->priv; | ||
157 | return tx4938_read_nfmc(this->IO_ADDR_R); | ||
158 | } | ||
159 | |||
160 | static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte) | ||
161 | { | ||
162 | struct nand_chip *this = mtd->priv; | ||
163 | tx4938_write_nfmc(byte, this->IO_ADDR_W); | ||
164 | } | ||
165 | |||
166 | static void tx4938ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
167 | { | ||
168 | int i; | ||
169 | struct nand_chip *this = mtd->priv; | ||
170 | |||
171 | for (i=0; i<len; i++) | ||
172 | tx4938_write_nfmc(buf[i], this->IO_ADDR_W); | ||
173 | } | ||
174 | |||
175 | static void tx4938ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | ||
176 | { | ||
177 | int i; | ||
178 | struct nand_chip *this = mtd->priv; | ||
179 | |||
180 | for (i=0; i<len; i++) | ||
181 | buf[i] = tx4938_read_nfmc(this->IO_ADDR_R); | ||
182 | } | ||
183 | |||
184 | static int tx4938ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
185 | { | ||
186 | int i; | ||
187 | struct nand_chip *this = mtd->priv; | ||
188 | |||
189 | for (i=0; i<len; i++) | ||
190 | if (buf[i] != tx4938_read_nfmc(this->IO_ADDR_R)) | ||
191 | return -EFAULT; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Send command to NAND device | ||
198 | */ | ||
199 | static void tx4938ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) | ||
200 | { | ||
201 | register struct nand_chip *this = mtd->priv; | ||
202 | |||
203 | /* Begin command latch cycle */ | ||
204 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
205 | /* | ||
206 | * Write out the command to the device. | ||
207 | */ | ||
208 | if (command == NAND_CMD_SEQIN) { | ||
209 | int readcmd; | ||
210 | |||
211 | if (column >= mtd->oobblock) { | ||
212 | /* OOB area */ | ||
213 | column -= mtd->oobblock; | ||
214 | readcmd = NAND_CMD_READOOB; | ||
215 | } else if (column < 256) { | ||
216 | /* First 256 bytes --> READ0 */ | ||
217 | readcmd = NAND_CMD_READ0; | ||
218 | } else { | ||
219 | column -= 256; | ||
220 | readcmd = NAND_CMD_READ1; | ||
221 | } | ||
222 | this->write_byte(mtd, readcmd); | ||
223 | } | ||
224 | this->write_byte(mtd, command); | ||
225 | |||
226 | /* Set ALE and clear CLE to start address cycle */ | ||
227 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
228 | |||
229 | if (column != -1 || page_addr != -1) { | ||
230 | this->hwcontrol(mtd, NAND_CTL_SETALE); | ||
231 | |||
232 | /* Serially input address */ | ||
233 | if (column != -1) | ||
234 | this->write_byte(mtd, column); | ||
235 | if (page_addr != -1) { | ||
236 | this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); | ||
237 | this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); | ||
238 | /* One more address cycle for higher density devices */ | ||
239 | if (mtd->size & 0x0c000000) | ||
240 | this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); | ||
241 | } | ||
242 | /* Latch in address */ | ||
243 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * program and erase have their own busy handlers | ||
248 | * status and sequential in needs no delay | ||
249 | */ | ||
250 | switch (command) { | ||
251 | |||
252 | case NAND_CMD_PAGEPROG: | ||
253 | /* Turn off WE */ | ||
254 | this->hwcontrol (mtd, NAND_CTL_CLRWP); | ||
255 | return; | ||
256 | |||
257 | case NAND_CMD_SEQIN: | ||
258 | /* Turn on WE */ | ||
259 | this->hwcontrol (mtd, NAND_CTL_SETWP); | ||
260 | return; | ||
261 | |||
262 | case NAND_CMD_ERASE1: | ||
263 | case NAND_CMD_ERASE2: | ||
264 | case NAND_CMD_STATUS: | ||
265 | return; | ||
266 | |||
267 | case NAND_CMD_RESET: | ||
268 | if (this->dev_ready) | ||
269 | break; | ||
270 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
271 | this->write_byte(mtd, NAND_CMD_STATUS); | ||
272 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
273 | while ( !(this->read_byte(mtd) & 0x40)); | ||
274 | return; | ||
275 | |||
276 | /* This applies to read commands */ | ||
277 | default: | ||
278 | /* | ||
279 | * If we don't have access to the busy pin, we apply the given | ||
280 | * command delay | ||
281 | */ | ||
282 | if (!this->dev_ready) { | ||
283 | udelay (this->chip_delay); | ||
284 | return; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | /* wait until command is processed */ | ||
289 | while (!this->dev_ready(mtd)); | ||
290 | } | ||
291 | |||
292 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
293 | extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); | ||
294 | #endif | ||
295 | /* | ||
296 | * Main initialization routine | ||
297 | */ | ||
298 | int __init tx4938ndfmc_init (void) | ||
299 | { | ||
300 | struct nand_chip *this; | ||
301 | int bsprt = 0, hold = 0xf, spw = 0xf; | ||
302 | int protected = 0; | ||
303 | |||
304 | if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) { | ||
305 | printk("TX4938 NDFMC: disabled by IOC PIOSEL\n"); | ||
306 | return -ENODEV; | ||
307 | } | ||
308 | bsprt = 1; | ||
309 | hold = 2; | ||
310 | spw = 9 - 1; /* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */ | ||
311 | |||
312 | if ((tx4938_ccfgptr->pcfg & | ||
313 | (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL)) | ||
314 | != TX4938_PCFG_NDF_SEL) { | ||
315 | printk("TX4938 NDFMC: disabled by PCFG.\n"); | ||
316 | return -ENODEV; | ||
317 | } | ||
318 | |||
319 | /* reset NDFMC */ | ||
320 | tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST; | ||
321 | while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST) | ||
322 | ; | ||
323 | /* setup BusSeparete, Hold Time, Strobe Pulse Width */ | ||
324 | tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0; | ||
325 | tx4938_ndfmcptr->spr = hold << 4 | spw; | ||
326 | |||
327 | /* Allocate memory for MTD device structure and private data */ | ||
328 | tx4938ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), | ||
329 | GFP_KERNEL); | ||
330 | if (!tx4938ndfmc_mtd) { | ||
331 | printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n"); | ||
332 | return -ENOMEM; | ||
333 | } | ||
334 | |||
335 | /* Get pointer to private data */ | ||
336 | this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]); | ||
337 | |||
338 | /* Initialize structures */ | ||
339 | memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info)); | ||
340 | memset((char *) this, 0, sizeof(struct nand_chip)); | ||
341 | |||
342 | /* Link the private data with the MTD structure */ | ||
343 | tx4938ndfmc_mtd->priv = this; | ||
344 | |||
345 | /* Set address of NAND IO lines */ | ||
346 | this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr; | ||
347 | this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr; | ||
348 | this->hwcontrol = tx4938ndfmc_hwcontrol; | ||
349 | this->dev_ready = tx4938ndfmc_dev_ready; | ||
350 | this->calculate_ecc = tx4938ndfmc_calculate_ecc; | ||
351 | this->correct_data = nand_correct_data; | ||
352 | this->enable_hwecc = tx4938ndfmc_enable_hwecc; | ||
353 | this->eccmode = NAND_ECC_HW3_256; | ||
354 | this->chip_delay = 100; | ||
355 | this->read_byte = tx4938ndfmc_nand_read_byte; | ||
356 | this->write_byte = tx4938ndfmc_nand_write_byte; | ||
357 | this->cmdfunc = tx4938ndfmc_nand_command; | ||
358 | this->write_buf = tx4938ndfmc_nand_write_buf; | ||
359 | this->read_buf = tx4938ndfmc_nand_read_buf; | ||
360 | this->verify_buf = tx4938ndfmc_nand_verify_buf; | ||
361 | |||
362 | /* Scan to find existance of the device */ | ||
363 | if (nand_scan (tx4938ndfmc_mtd, 1)) { | ||
364 | kfree (tx4938ndfmc_mtd); | ||
365 | return -ENXIO; | ||
366 | } | ||
367 | |||
368 | if (protected) { | ||
369 | printk(KERN_INFO "TX4938 NDFMC: write protected.\n"); | ||
370 | tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE); | ||
371 | } | ||
372 | |||
373 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
374 | { | ||
375 | int mtd_parts_nb = 0; | ||
376 | struct mtd_partition *mtd_parts = 0; | ||
377 | mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc"); | ||
378 | if (mtd_parts_nb > 0) | ||
379 | add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb); | ||
380 | else | ||
381 | add_mtd_device(tx4938ndfmc_mtd); | ||
382 | } | ||
383 | #else | ||
384 | add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS ); | ||
385 | #endif | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | module_init(tx4938ndfmc_init); | ||
390 | |||
391 | /* | ||
392 | * Clean up routine | ||
393 | */ | ||
394 | static void __exit tx4938ndfmc_cleanup (void) | ||
395 | { | ||
396 | /* Release resources, unregister device */ | ||
397 | nand_release (tx4938ndfmc_mtd); | ||
398 | |||
399 | /* Free the MTD device structure */ | ||
400 | kfree (tx4938ndfmc_mtd); | ||
401 | } | ||
402 | module_exit(tx4938ndfmc_cleanup); | ||
403 | |||
404 | MODULE_LICENSE("GPL"); | ||
405 | MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>"); | ||
406 | MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC"); | ||