Spansion S29WS-N MirrorBit flash chips

Todd Poynor tpoynor at mvista.com
Tue Nov 15 19:38:25 EST 2005


Previously I sent an FYI patch on how to use Spansion S29WS-N MirrorBit
flash chips.  Although nominally CFI-compliant, these chips require CFI
query mode to be entered by writing to chip address 0x555 instead of
0x55, which seems a clear violation of the CFI specs I've seen.

The previous patch can cause harm to certain other AMD/Spansion chips
that do not discard the extraneous write to 0x555 and instead fail to
probe the 'QRY' magic.  So here's a new version that works harder to
figure out what address is needed, in case its helpful for anybody using
those chips.  Note that a previous commit for reading 16-bit CFI device
IDs is needed as well.

I think this is probably too ugly to live in CVS, and the datasheet
actually says they won't do this again in future models.

Index: drivers/mtd/chips/cfi_probe.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_probe.c,v
retrieving revision 1.85
diff -u -r1.85 cfi_probe.c
--- drivers/mtd/chips/cfi_probe.c	15 Nov 2005 23:28:17 -0000	1.85
+++ drivers/mtd/chips/cfi_probe.c	16 Nov 2005 00:20:41 -0000
@@ -28,7 +28,8 @@
 
 static int cfi_probe_chip(struct map_info *map, __u32 base,
 			  unsigned long *chip_map, struct cfi_private *cfi);
-static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
+static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi,
+			  int amd555);
 
 struct mtd_info *cfi_probe(struct map_info *map);
 
@@ -51,12 +52,12 @@
 	xip_allowed(base, map); \
 } while (0)
 
-#define xip_disable_qry(base, map, cfi) \
+#define xip_disable_qry(base, map, cfi, amd555)	\
 do { \
 	xip_disable(); \
 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
 	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
-	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \
+	cfi_send_gen_cmd(0x98, amd555 ? 0x555 : 0x55, base, map, cfi, cfi->device_type, NULL); \
 } while (0)
 
 #else
@@ -64,7 +65,7 @@
 #define xip_disable()			do { } while (0)
 #define xip_allowed(base, map)		do { } while (0)
 #define xip_enable(base, map, cfi)	do { } while (0)
-#define xip_disable_qry(base, map, cfi) do { } while (0)
+#define xip_disable_qry(base, map, cfi, amd555) do { } while (0)
 
 #endif
 
@@ -103,6 +104,7 @@
 				   unsigned long *chip_map, struct cfi_private *cfi)
 {
 	int i;
+	int amd555 = 0;
 
 	if ((base + 0) >= map->size) {
 		printk(KERN_NOTICE
@@ -123,14 +125,21 @@
 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
 
 	if (!qry_present(map,base,cfi)) {
-		xip_enable(base, map, cfi);
-		return 0;
+		cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type,
+				 NULL);
+
+		if (!qry_present(map,base,cfi)) {
+			xip_enable(base, map, cfi);
+			return 0;
+		}
+
+		amd555 = 1;
 	}
 
 	if (!cfi->numchips) {
 		/* This is the first time we're called. Set up the CFI
 		   stuff accordingly and return */
-		return cfi_chip_setup(map, cfi);
+		return cfi_chip_setup(map, cfi, amd555);
 	}
 
 	/* Check each previous chip to see if it's an alias */
@@ -190,7 +199,7 @@
 }
 
 static int __xipram cfi_chip_setup(struct map_info *map,
-				   struct cfi_private *cfi)
+				   struct cfi_private *cfi, int amd555)
 {
 	int ofs_factor = cfi->interleave*cfi->device_type;
 	__u32 base = 0;
@@ -215,7 +224,7 @@
 	cfi->cfi_mode = CFI_MODE_CFI;
 
 	/* Read the CFI info structure */
-	xip_disable_qry(base, map, cfi);
+	xip_disable_qry(base, map, cfi, amd555);
 	for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
 		((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
 
Index: drivers/mtd/chips/cfi_util.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_util.c,v
retrieving revision 1.10
diff -u -r1.10 cfi_util.c
--- drivers/mtd/chips/cfi_util.c	7 Nov 2005 11:14:23 -0000	1.10
+++ drivers/mtd/chips/cfi_util.c	16 Nov 2005 00:20:41 -0000
@@ -51,8 +51,16 @@
 	local_irq_disable();
 #endif
 
-	/* Switch it into Query Mode */
-	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+	/* Switch it into Query Mode.*/
+
+	/* Address 0x555 for Spansion S29WS-N MirrorBit flash chips. */
+
+	if ((cfi->mfr == CFI_MFR_AMD) && (cfi->id == 0x227E))
+		cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type,
+				 NULL);
+	else
+		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type,
+				 NULL);
 
 	/* Read in the Extended Query Table */
 	for (i=0; i<size; i++) {




More information about the linux-mtd mailing list