summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTodd Poynor <tpoynor@mvista.com>2009-02-20 11:52:28 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2009-02-20 11:52:28 +0100
commitee6825c0c10bf29438531589ec14ecc51a4db326 (patch)
treec4b3dd90db619dae8d86e65483fbf2068ec3540d
parent1ea833264f7274aae2486e64e13dc9a7f3eed935 (diff)
downloadlinux-2.6-ee6825c0c10bf29438531589ec14ecc51a4db326.tar.gz
linux-2.6-ee6825c0c10bf29438531589ec14ecc51a4db326.tar.xz
fix Spansion S29WS-N MirrorBit flash chips
This patch comes from http://lists.infradead.org/pipermail/linux-mtd/2005-November/014339.html We need this patch only for the i.MX27ads board which so far is the only one we have with this chips equipped. - sha (patch follows) 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.
-rw-r--r--drivers/mtd/chips/cfi_probe.c27
-rw-r--r--drivers/mtd/chips/cfi_util.c12
2 files changed, 28 insertions, 11 deletions
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
index 60e11a0ada9..43655d6b366 100644
--- a/drivers/mtd/chips/cfi_probe.c
+++ b/drivers/mtd/chips/cfi_probe.c
@@ -27,7 +27,8 @@ static void print_cfi_ident(struct cfi_ident *);
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);
@@ -50,12 +51,12 @@ do { \
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
@@ -63,7 +64,7 @@ do { \
#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
@@ -102,6 +103,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
unsigned long *chip_map, struct cfi_private *cfi)
{
int i;
+ int amd555 = 0;
if ((base + 0) >= map->size) {
printk(KERN_NOTICE
@@ -122,14 +124,21 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
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 */
@@ -189,7 +198,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
}
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;
@@ -214,7 +223,7 @@ static int __xipram cfi_chip_setup(struct map_info *map,
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);
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index 2e51496c248..de9435c79bb 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -50,8 +50,16 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
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++) {