mtd/drivers/mtd/chips cfi_util.c,NONE,1.1 Makefile.common,1.1,1.2
cfi_cmdset_0001.c,1.127,1.128 cfi_cmdset_0002.c,1.75,1.76
cfi_cmdset_0020.c,1.7,1.8 cfi_probe.c,1.71,1.72
Stuart Menefy
stuart at infradead.org
Tue Jul 22 09:23:41 EDT 2003
Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv24911/drivers/mtd/chips
Modified Files:
Makefile.common cfi_cmdset_0001.c cfi_cmdset_0002.c
cfi_cmdset_0020.c cfi_probe.c
Added Files:
cfi_util.c
Log Message:
Added generic support for reading CFI extended query tables, and device IDs,
and applying fixups for buggy CFI data.
Moved all current workarounds to this structure.
***** Error reading new file: [Errno 2] No such file or directory: 'cfi_util.c'
Index: Makefile.common
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/Makefile.common,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Makefile.common 21 May 2003 15:00:01 -0000 1.1
+++ Makefile.common 22 Jul 2003 13:23:38 -0000 1.2
@@ -17,7 +17,7 @@
obj-$(CONFIG_MTD) += chipreg.o
obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
-obj-$(CONFIG_MTD_CFI) += cfi_probe.o
+obj-$(CONFIG_MTD_CFI) += cfi_probe.o cfi_util.o
obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
Index: cfi_cmdset_0001.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0001.c,v
retrieving revision 1.127
retrieving revision 1.128
diff -u -r1.127 -r1.128
--- cfi_cmdset_0001.c 2 Jul 2003 20:29:38 -0000 1.127
+++ cfi_cmdset_0001.c 22 Jul 2003 13:23:38 -0000 1.128
@@ -34,6 +34,8 @@
#include <linux/mtd/compatmac.h>
#include <linux/mtd/cfi.h>
+/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
+
// debugging, turns off buffer write mode if set to 1
#define FORCE_WORD_WRITE 0
@@ -110,13 +112,63 @@
}
printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
- extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+ extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
if (extp->VppOptimal)
printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
- extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+ extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
+}
+#endif
+
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
+static void fixup_intel_strataflash(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+
+ printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
+ "erase on write disabled.\n");
+ extp->SuspendCmdSupport &= ~1;
}
#endif
+static void fixup_st_m28w320ct(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */
+ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
+}
+
+static void fixup_st_m28w320cb(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ /* Note this is done after the region info is endian swapped */
+ cfi->cfiq->EraseRegionInfo[1] =
+ (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
+};
+
+static struct cfi_fixup fixup_table[] = {
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+ {
+ CFI_MFR_ANY, CFI_ID_ANY,
+ fixup_intel_strataflash, NULL
+ },
+#endif
+ {
+ 0x0020, /* STMicroelectronics */
+ 0x00ba, /* M28W320CT */
+ fixup_st_m28w320ct, NULL
+ }, {
+ 0x0020, /* STMicroelectronics */
+ 0x00bb, /* M28W320CB */
+ fixup_st_m28w320cb, NULL
+ }, {
+ 0, 0, NULL, NULL
+ }
+};
+
/* This routine is made available to other mtd code via
* inter_module_register. It must only be accessed through
* inter_module_get which will bump the use count of this module. The
@@ -128,7 +180,6 @@
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
- __u32 base = cfi->chips[0].start;
if (cfi->cfi_mode == CFI_MODE_CFI) {
/*
@@ -138,40 +189,17 @@
*/
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
struct cfi_pri_intelext *extp;
- int ofs_factor = cfi->interleave * cfi->device_type;
- //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
- if (!adr)
- return NULL;
-
- /* Switch it into Query Mode */
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
- if (!extp) {
- printk(KERN_ERR "Failed to allocate memory\n");
- return NULL;
- }
-
- /* Read in the Extended Query Table */
- for (i=0; i<sizeof(*extp); i++) {
- ((unsigned char *)extp)[i] =
- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
- }
-
- if (extp->MajorVersion != '1' ||
- (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
- printk(KERN_WARNING " Unknown IntelExt Extended Query "
- "version %c.%c.\n", extp->MajorVersion,
- extp->MinorVersion);
- kfree(extp);
+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
+ if (!extp)
return NULL;
- }
/* Do some byteswapping if necessary */
extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+
+ cfi_fixup(map, fixup_table);
#ifdef DEBUG_CFI_FEATURES
/* Tell the user about it in lots of lovely detail */
@@ -179,15 +207,7 @@
#endif
if(extp->SuspendCmdSupport & 1) {
-//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
- printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
- "erase on write disabled.\n");
- extp->SuspendCmdSupport &= ~1;
-#else
printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
-#endif
}
/* Install our own private info structure */
cfi->cmdset_priv = extp;
@@ -202,8 +222,6 @@
map->fldrv = &cfi_intelext_chipdrv;
- /* Make sure it's in read mode */
- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_intelext_setup(map);
}
Index: cfi_cmdset_0002.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0002.c,v
retrieving revision 1.75
retrieving revision 1.76
diff -u -r1.75 -r1.76
--- cfi_cmdset_0002.c 29 May 2003 10:35:42 -0000 1.75
+++ cfi_cmdset_0002.c 22 Jul 2003 13:23:38 -0000 1.76
@@ -54,51 +54,123 @@
.module = THIS_MODULE
};
+/* #define DEBUG_CFI_FEATURES */
+
+#ifdef DEBUG_CFI_FEATURES
+static void cfi_tell_features(struct cfi_pri_amdstd *extp)
+{
+ const char* erase_suspend[3] = {
+ "Not supported", "Read only", "Read/write"
+ };
+ const char* top_bottom[6] = {
+ "No WP", "8x8KiB sectors at top & bottom, no WP",
+ "Bottom boot", "Top boot",
+ "Uniform, Bottom WP", "Uniform, Top WP"
+ };
+
+ printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1);
+ printk(" Address sensitive unlock: %s\n",
+ (extp->SiliconRevision & 1) ? "Not required" : "Required");
+
+ if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
+ printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
+ else
+ printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
+
+ if (extp->BlkProt == 0)
+ printk(" Block protection: Not supported\n");
+ else
+ printk(" Block protection: %d sectors per group\n", extp->BlkProt);
+
+
+ printk(" Temporary block unprotect: %s\n",
+ extp->TmpBlkUnprotect ? "Supported" : "Not supported");
+ printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
+ printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps);
+ printk(" Burst mode: %s\n",
+ extp->BurstMode ? "Supported" : "Not supported");
+ if (extp->PageMode == 0)
+ printk(" Page mode: Not supported\n");
+ else
+ printk(" Page mode: %d word page\n", extp->PageMode << 2);
+
+ printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
+ extp->VppMin >> 4, extp->VppMin & 0xf);
+ printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
+ extp->VppMax >> 4, extp->VppMax & 0xf);
+
+ if (extp->TopBottom < ARRAY_SIZE(top_bottom))
+ printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
+ else
+ printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
+}
+#endif
+
+#ifdef AMD_BOOTLOC_BUG
+/* Wheee. Bring me the head of someone at AMD. */
+static void fixup_amd_bootblock(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+ __u8 major = extp->MajorVersion;
+ __u8 minor = extp->MinorVersion;
+
+ if (((major << 8) | minor) < 0x3131) {
+ /* CFI version 1.0 => don't trust bootloc */
+ if (cfi->id & 0x80) {
+ printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
+ extp->TopBottom = 3; /* top boot */
+ } else {
+ extp->TopBottom = 2; /* bottom boot */
+ }
+ }
+}
+#endif
+
+static struct cfi_fixup fixup_table[] = {
+#ifdef AMD_BOOTLOC_BUG
+ {
+ 0x0001, /* AMD */
+ CFI_ID_ANY,
+ fixup_amd_bootblock, NULL
+ },
+#endif
+ { 0, 0, NULL, NULL }
+};
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned char bootloc;
- int ofs_factor = cfi->interleave * cfi->device_type;
int i;
- __u8 major, minor;
- __u32 base = cfi->chips[0].start;
if (cfi->cfi_mode==CFI_MODE_CFI){
+ /*
+ * It's a real CFI chip, not one for which the probe
+ * routine faked a CFI structure. So we read the feature
+ * table from it.
+ */
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+ struct cfi_pri_amdstd *extp;
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- major = cfi_read_query(map, base + (adr+3)*ofs_factor);
- minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
-
- printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
- major, minor, adr);
- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
- /* FIXME - should have a delay before continuing */
- cfi->mfr = cfi_read_query(map, base);
- cfi->id = cfi_read_query(map, base + ofs_factor);
+ extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
+ if (!extp)
+ return NULL;
+
+ cfi_fixup(map, fixup_table);
+
+#ifdef DEBUG_CFI_FEATURES
+ /* Tell the user about it in lots of lovely detail */
+ cfi_tell_features(extp);
+#endif
+
+ bootloc = extp->TopBottom;
+ if ((bootloc != 2) && (bootloc != 3)) {
+ printk(KERN_WARNING "%s: CFI does not contain boot "
+ "bank location. Assuming top.\n", map->name);
+ bootloc = 2;
+ }
- /* Wheee. Bring me the head of someone at AMD. */
-#ifdef AMD_BOOTLOC_BUG
- if (((major << 8) | minor) < 0x3131) {
- /* CFI version 1.0 => don't trust bootloc */
- if (cfi->id & 0x80) {
- printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
- bootloc = 3; /* top boot */
- } else {
- bootloc = 2; /* bottom boot */
- }
- } else
-#endif
- {
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
- bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor);
- }
if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
@@ -137,6 +209,10 @@
printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type);
return NULL;
}
+
+ /* Install our own private info structure */
+ cfi->cmdset_priv = extp;
+
} /* CFI mode */
for (i=0; i< cfi->numchips; i++) {
@@ -147,7 +223,6 @@
map->fldrv = &cfi_amdstd_chipdrv;
- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_amdstd_setup(map);
}
Index: cfi_cmdset_0020.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0020.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- cfi_cmdset_0020.c 29 May 2003 10:35:42 -0000 1.7
+++ cfi_cmdset_0020.c 22 Jul 2003 13:23:38 -0000 1.8
@@ -116,7 +116,6 @@
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
- __u32 base = cfi->chips[0].start;
if (cfi->cfi_mode) {
/*
@@ -126,36 +125,11 @@
*/
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
struct cfi_pri_intelext *extp;
- int ofs_factor = cfi->interleave * cfi->device_type;
- printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
- if (!adr)
+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics");
+ if (!extp)
return NULL;
- /* Switch it into Query Mode */
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
- if (!extp) {
- printk(KERN_ERR "Failed to allocate memory\n");
- return NULL;
- }
-
- /* Read in the Extended Query Table */
- for (i=0; i<sizeof(*extp); i++) {
- ((unsigned char *)extp)[i] =
- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
- }
-
- if (extp->MajorVersion != '1' ||
- (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
- printk(KERN_WARNING " Unknown staa Extended Query "
- "version %c.%c.\n", extp->MajorVersion,
- extp->MinorVersion);
- kfree(extp);
- return NULL;
- }
-
/* Do some byteswapping if necessary */
extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
@@ -175,8 +149,6 @@
cfi->chips[i].erase_time = 1024;
}
- /* Make sure it's in read mode */
- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_staa_setup(map);
}
Index: cfi_probe.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_probe.c,v
retrieving revision 1.71
retrieving revision 1.72
diff -u -r1.71 -r1.72
--- cfi_probe.c 28 May 2003 12:51:48 -0000 1.71
+++ cfi_probe.c 22 Jul 2003 13:23:38 -0000 1.72
@@ -180,9 +180,28 @@
(cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
#endif
}
+
+ /* Note we put the device back into Read Mode BEFORE going into Auto
+ * Select Mode, as some devices support nesting of modes, others
+ * don't. This way should always work.
+ * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
+ * so should be treated as nops or illegal (and so put the device
+ * back into Read Mode, which is a nop in this case).
+ */
+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
+ cfi->mfr = cfi_read_query(map, base);
+ cfi->id = cfi_read_query(map, base + ofs_factor);
+
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+ map->name, cfi->interleave, cfi->device_type*8, base,
+ map->buswidth*8);
+
return 1;
}
@@ -241,11 +260,11 @@
printk("No Alternate Algorithm Table\n");
- printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
- printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
+ printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
+ printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
if (cfip->VppMin) {
- printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
- printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
+ printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
+ printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
}
else
printk("No Vpp line\n");
More information about the linux-mtd-cvs
mailing list