diff options
author | Todd Poynor <tpoynor@mvista.com> | 2009-02-20 11:52:28 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-02-20 11:52:28 +0100 |
commit | ee6825c0c10bf29438531589ec14ecc51a4db326 (patch) | |
tree | c4b3dd90db619dae8d86e65483fbf2068ec3540d | |
parent | 1ea833264f7274aae2486e64e13dc9a7f3eed935 (diff) | |
download | linux-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.c | 27 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_util.c | 12 |
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++) { |