diff options
author | Nicolas Pitre <nico@cam.org> | 2005-08-06 00:40:46 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-11-06 14:12:17 -0500 |
commit | 638d983840bb64e02c29bdd6160bb9963f4090f7 (patch) | |
tree | f07e85847009236731f8cb2b9afcba35d40849b1 /drivers/mtd/chips | |
parent | 4843653cab0db036399f77d9355db31ce39cb8b9 (diff) |
{MTD] add support for Intel's "Sibley" flash
This updates the Primary Vendor-Specific Extended Query parsing to
version 1.4 in order to get the information about the Configurable
Programming Mode regions implemented in the Sibley flash, as well as
selecting the appropriate write command code.
This flash does not behave like traditional NOR flash when writing data.
While mtdblock should just work, further changes are needed for JFFS2 use.
Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/chips')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 88 | ||||
-rw-r--r-- | drivers/mtd/chips/gen_probe.c | 3 |
2 files changed, 67 insertions, 24 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 308855e80f66..10c50604bcd5 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * | 4 | * |
5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
6 | * | 6 | * |
7 | * $Id: cfi_cmdset_0001.c,v 1.181 2005/08/06 04:16:48 nico Exp $ | 7 | * $Id: cfi_cmdset_0001.c,v 1.182 2005/08/06 04:40:41 nico Exp $ |
8 | * | 8 | * |
9 | * | 9 | * |
10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
@@ -105,6 +105,7 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = { | |||
105 | static void cfi_tell_features(struct cfi_pri_intelext *extp) | 105 | static void cfi_tell_features(struct cfi_pri_intelext *extp) |
106 | { | 106 | { |
107 | int i; | 107 | int i; |
108 | printk(" Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion); | ||
108 | printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); | 109 | printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); |
109 | printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); | 110 | printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); |
110 | printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); | 111 | printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); |
@@ -116,7 +117,8 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
116 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); | 117 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); |
117 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); | 118 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); |
118 | printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); | 119 | printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); |
119 | for (i=10; i<32; i++) { | 120 | printk(" - Extended Flash Array: %s\n", extp->FeatureSupport&1024?"supported":"unsupported"); |
121 | for (i=11; i<32; i++) { | ||
120 | if (extp->FeatureSupport & (1<<i)) | 122 | if (extp->FeatureSupport & (1<<i)) |
121 | printk(" - Unknown Bit %X: supported\n", i); | 123 | printk(" - Unknown Bit %X: supported\n", i); |
122 | } | 124 | } |
@@ -130,12 +132,18 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
130 | 132 | ||
131 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); | 133 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); |
132 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); | 134 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); |
133 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); | 135 | printk(" - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); |
134 | for (i=2; i<16; i++) { | 136 | for (i=2; i<3; i++) { |
135 | if (extp->BlkStatusRegMask & (1<<i)) | 137 | if (extp->BlkStatusRegMask & (1<<i)) |
136 | printk(" - Unknown Bit %X Active: yes\n",i); | 138 | printk(" - Unknown Bit %X Active: yes\n",i); |
137 | } | 139 | } |
138 | 140 | printk(" - EFA Lock Bit: %s\n", extp->BlkStatusRegMask&16?"yes":"no"); | |
141 | printk(" - EFA Lock-Down Bit: %s\n", extp->BlkStatusRegMask&32?"yes":"no"); | ||
142 | for (i=6; i<16; i++) { | ||
143 | if (extp->BlkStatusRegMask & (1<<i)) | ||
144 | printk(" - Unknown Bit %X Active: yes\n",i); | ||
145 | } | ||
146 | |||
139 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | 147 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", |
140 | extp->VccOptimal >> 4, extp->VccOptimal & 0xf); | 148 | extp->VccOptimal >> 4, extp->VccOptimal & 0xf); |
141 | if (extp->VppOptimal) | 149 | if (extp->VppOptimal) |
@@ -253,7 +261,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
253 | return NULL; | 261 | return NULL; |
254 | 262 | ||
255 | if (extp->MajorVersion != '1' || | 263 | if (extp->MajorVersion != '1' || |
256 | (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { | 264 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { |
257 | printk(KERN_ERR " Unknown Intel/Sharp Extended Query " | 265 | printk(KERN_ERR " Unknown Intel/Sharp Extended Query " |
258 | "version %c.%c.\n", extp->MajorVersion, | 266 | "version %c.%c.\n", extp->MajorVersion, |
259 | extp->MinorVersion); | 267 | extp->MinorVersion); |
@@ -266,7 +274,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
266 | extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); | 274 | extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); |
267 | extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); | 275 | extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); |
268 | 276 | ||
269 | if (extp->MajorVersion == '1' && extp->MinorVersion == '3') { | 277 | if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') { |
270 | unsigned int extra_size = 0; | 278 | unsigned int extra_size = 0; |
271 | int nb_parts, i; | 279 | int nb_parts, i; |
272 | 280 | ||
@@ -275,7 +283,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
275 | sizeof(struct cfi_intelext_otpinfo); | 283 | sizeof(struct cfi_intelext_otpinfo); |
276 | 284 | ||
277 | /* Burst Read info */ | 285 | /* Burst Read info */ |
278 | extra_size += 6; | 286 | extra_size += (extp->MinorVersion < '4') ? 6 : 5; |
279 | 287 | ||
280 | /* Number of hardware-partitions */ | 288 | /* Number of hardware-partitions */ |
281 | extra_size += 1; | 289 | extra_size += 1; |
@@ -283,6 +291,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
283 | goto need_more; | 291 | goto need_more; |
284 | nb_parts = extp->extra[extra_size - 1]; | 292 | nb_parts = extp->extra[extra_size - 1]; |
285 | 293 | ||
294 | /* skip the sizeof(partregion) field in CFI 1.4 */ | ||
295 | if (extp->MinorVersion >= '4') | ||
296 | extra_size += 2; | ||
297 | |||
286 | for (i = 0; i < nb_parts; i++) { | 298 | for (i = 0; i < nb_parts; i++) { |
287 | struct cfi_intelext_regioninfo *rinfo; | 299 | struct cfi_intelext_regioninfo *rinfo; |
288 | rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; | 300 | rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; |
@@ -294,6 +306,9 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
294 | * sizeof(struct cfi_intelext_blockinfo); | 306 | * sizeof(struct cfi_intelext_blockinfo); |
295 | } | 307 | } |
296 | 308 | ||
309 | if (extp->MinorVersion >= '4') | ||
310 | extra_size += sizeof(struct cfi_intelext_programming_regioninfo); | ||
311 | |||
297 | if (extp_size < sizeof(*extp) + extra_size) { | 312 | if (extp_size < sizeof(*extp) + extra_size) { |
298 | need_more: | 313 | need_more: |
299 | extp_size = sizeof(*extp) + extra_size; | 314 | extp_size = sizeof(*extp) + extra_size; |
@@ -490,7 +505,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
490 | * arrangement at this point. This can be rearranged in the future | 505 | * arrangement at this point. This can be rearranged in the future |
491 | * if someone feels motivated enough. --nico | 506 | * if someone feels motivated enough. --nico |
492 | */ | 507 | */ |
493 | if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3' | 508 | if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3' |
494 | && extp->FeatureSupport & (1 << 9)) { | 509 | && extp->FeatureSupport & (1 << 9)) { |
495 | struct cfi_private *newcfi; | 510 | struct cfi_private *newcfi; |
496 | struct flchip *chip; | 511 | struct flchip *chip; |
@@ -502,12 +517,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
502 | sizeof(struct cfi_intelext_otpinfo); | 517 | sizeof(struct cfi_intelext_otpinfo); |
503 | 518 | ||
504 | /* Burst Read info */ | 519 | /* Burst Read info */ |
505 | offs += 6; | 520 | offs += (extp->MinorVersion < '4') ? 6 : 5; |
506 | 521 | ||
507 | /* Number of partition regions */ | 522 | /* Number of partition regions */ |
508 | numregions = extp->extra[offs]; | 523 | numregions = extp->extra[offs]; |
509 | offs += 1; | 524 | offs += 1; |
510 | 525 | ||
526 | /* skip the sizeof(partregion) field in CFI 1.4 */ | ||
527 | if (extp->MinorVersion >= '4') | ||
528 | offs += 2; | ||
529 | |||
511 | /* Number of hardware partitions */ | 530 | /* Number of hardware partitions */ |
512 | numparts = 0; | 531 | numparts = 0; |
513 | for (i = 0; i < numregions; i++) { | 532 | for (i = 0; i < numregions; i++) { |
@@ -519,6 +538,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
519 | sizeof(struct cfi_intelext_blockinfo); | 538 | sizeof(struct cfi_intelext_blockinfo); |
520 | } | 539 | } |
521 | 540 | ||
541 | /* Programming Region info */ | ||
542 | if (extp->MinorVersion >= '4') { | ||
543 | struct cfi_intelext_programming_regioninfo *prinfo; | ||
544 | prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs]; | ||
545 | MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift; | ||
546 | MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid; | ||
547 | MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid; | ||
548 | mtd->flags |= MTD_PROGRAM_REGIONS; | ||
549 | printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n", | ||
550 | map->name, MTD_PROGREGION_SIZE(mtd), | ||
551 | MTD_PROGREGION_CTRLMODE_VALID(mtd), | ||
552 | MTD_PROGREGION_CTRLMODE_INVALID(mtd)); | ||
553 | } | ||
554 | |||
522 | /* | 555 | /* |
523 | * All functions below currently rely on all chips having | 556 | * All functions below currently rely on all chips having |
524 | * the same geometry so we'll just assume that all hardware | 557 | * the same geometry so we'll just assume that all hardware |
@@ -1222,12 +1255,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1222 | 1255 | ||
1223 | adr += chip->start; | 1256 | adr += chip->start; |
1224 | 1257 | ||
1225 | /* Let's determine this according to the interleave only once */ | 1258 | /* Let's determine those according to the interleave only once */ |
1226 | status_OK = CMD(0x80); | 1259 | status_OK = CMD(0x80); |
1227 | switch (mode) { | 1260 | switch (mode) { |
1228 | case FL_WRITING: write_cmd = CMD(0x40); break; | 1261 | case FL_WRITING: |
1229 | case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; | 1262 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); |
1230 | default: return -EINVAL; | 1263 | break; |
1264 | case FL_OTP_WRITE: | ||
1265 | write_cmd = CMD(0xc0); | ||
1266 | break; | ||
1267 | default: | ||
1268 | return -EINVAL; | ||
1231 | } | 1269 | } |
1232 | 1270 | ||
1233 | spin_lock(chip->mutex); | 1271 | spin_lock(chip->mutex); |
@@ -1410,16 +1448,17 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1410 | unsigned long adr, const u_char *buf, int len) | 1448 | unsigned long adr, const u_char *buf, int len) |
1411 | { | 1449 | { |
1412 | struct cfi_private *cfi = map->fldrv_priv; | 1450 | struct cfi_private *cfi = map->fldrv_priv; |
1413 | map_word status, status_OK; | 1451 | map_word status, status_OK, write_cmd; |
1414 | unsigned long cmd_adr, timeo; | 1452 | unsigned long cmd_adr, timeo; |
1415 | int wbufsize, z, ret=0, bytes, words; | 1453 | int wbufsize, z, ret=0, bytes, words; |
1416 | 1454 | ||
1417 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 1455 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
1418 | adr += chip->start; | 1456 | adr += chip->start; |
1419 | cmd_adr = adr & ~(wbufsize-1); | 1457 | cmd_adr = adr & ~(wbufsize-1); |
1420 | 1458 | ||
1421 | /* Let's determine this according to the interleave only once */ | 1459 | /* Let's determine this according to the interleave only once */ |
1422 | status_OK = CMD(0x80); | 1460 | status_OK = CMD(0x80); |
1461 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); | ||
1423 | 1462 | ||
1424 | spin_lock(chip->mutex); | 1463 | spin_lock(chip->mutex); |
1425 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); | 1464 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); |
@@ -1451,7 +1490,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1451 | 1490 | ||
1452 | z = 0; | 1491 | z = 0; |
1453 | for (;;) { | 1492 | for (;;) { |
1454 | map_write(map, CMD(0xe8), cmd_adr); | 1493 | map_write(map, write_cmd, cmd_adr); |
1455 | 1494 | ||
1456 | status = map_read(map, cmd_adr); | 1495 | status = map_read(map, cmd_adr); |
1457 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1496 | if (map_word_andequal(map, status, status_OK, status_OK)) |
@@ -2380,20 +2419,23 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) | |||
2380 | kfree(mtd->eraseregions); | 2419 | kfree(mtd->eraseregions); |
2381 | } | 2420 | } |
2382 | 2421 | ||
2383 | static char im_name_1[]="cfi_cmdset_0001"; | 2422 | static char im_name_0001[] = "cfi_cmdset_0001"; |
2384 | static char im_name_3[]="cfi_cmdset_0003"; | 2423 | static char im_name_0003[] = "cfi_cmdset_0003"; |
2424 | static char im_name_0200[] = "cfi_cmdset_0200"; | ||
2385 | 2425 | ||
2386 | static int __init cfi_intelext_init(void) | 2426 | static int __init cfi_intelext_init(void) |
2387 | { | 2427 | { |
2388 | inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001); | 2428 | inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001); |
2389 | inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001); | 2429 | inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001); |
2430 | inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001); | ||
2390 | return 0; | 2431 | return 0; |
2391 | } | 2432 | } |
2392 | 2433 | ||
2393 | static void __exit cfi_intelext_exit(void) | 2434 | static void __exit cfi_intelext_exit(void) |
2394 | { | 2435 | { |
2395 | inter_module_unregister(im_name_1); | 2436 | inter_module_unregister(im_name_0001); |
2396 | inter_module_unregister(im_name_3); | 2437 | inter_module_unregister(im_name_0003); |
2438 | inter_module_unregister(im_name_0200); | ||
2397 | } | 2439 | } |
2398 | 2440 | ||
2399 | module_init(cfi_intelext_init); | 2441 | module_init(cfi_intelext_init); |
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index dc065b22f79e..28807eb9fc86 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Routines common to all CFI-type probes. | 2 | * Routines common to all CFI-type probes. |
3 | * (C) 2001-2003 Red Hat, Inc. | 3 | * (C) 2001-2003 Red Hat, Inc. |
4 | * GPL'd | 4 | * GPL'd |
5 | * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ | 5 | * $Id: gen_probe.c,v 1.23 2005/08/06 04:40:41 nico Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
@@ -235,6 +235,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |||
235 | #ifdef CONFIG_MTD_CFI_INTELEXT | 235 | #ifdef CONFIG_MTD_CFI_INTELEXT |
236 | case 0x0001: | 236 | case 0x0001: |
237 | case 0x0003: | 237 | case 0x0003: |
238 | case 0x0200: | ||
238 | return cfi_cmdset_0001(map, primary); | 239 | return cfi_cmdset_0001(map, primary); |
239 | #endif | 240 | #endif |
240 | #ifdef CONFIG_MTD_CFI_AMDSTD | 241 | #ifdef CONFIG_MTD_CFI_AMDSTD |