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