VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / mtd / chips / jedec_probe.c
index 159ccc0..daf554c 100644 (file)
@@ -1,9 +1,11 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.29 2003/05/28 13:57:46 dwmw2 Exp $
+   $Id: jedec_probe.c,v 1.51 2004/07/14 14:44:30 thayne Exp $
    See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
    for the standard this probe goes back to.
+
+   Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
 */
 
 #include <linux/config.h>
@@ -16,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 
 
 /* AMD */
+#define AM29DL800BB    0x22C8
+#define AM29DL800BT    0x224A
+
 #define AM29F800BB     0x2258
 #define AM29F800BT     0x22D6
+#define AM29LV400BB    0x22BA
+#define AM29LV400BT    0x22B9
 #define AM29LV800BB    0x225B
 #define AM29LV800BT    0x22DA
 #define AM29LV160DT    0x22C4
@@ -58,6 +66,7 @@
 #define AT49BV32XT     0x00C9
 
 /* Fujitsu */
+#define MBM29F040C     0x00A4
 #define MBM29LV650UE   0x22D7
 #define MBM29LV320TE   0x22F6
 #define MBM29LV320BE   0x22F9
@@ -65,6 +74,9 @@
 #define MBM29LV160BE   0x2249
 #define MBM29LV800BA   0x225B
 #define MBM29LV800TA   0x22DA
+#define MBM29LV400TC   0x22B9
+#define MBM29LV400BC   0x22BA
+
 
 /* Intel */
 #define I28F004B3T     0x00d4
 #define M50FW016       0x002E
 
 /* SST */
+#define SST29EE020     0x0010
+#define SST29LE020     0x0012
 #define SST29EE512     0x005d
 #define SST29LE512     0x003d
 #define SST39LF800     0x2781
 #define SST39LF040     0x00D7
 #define SST39SF010A    0x00B5
 #define SST39SF020A    0x00B6
+#define SST49LF004B    0x0060
+#define SST49LF008A    0x005a
 #define SST49LF030A    0x001C
 #define SST49LF040A    0x0051
 #define SST49LF080A    0x005B
@@ -213,11 +229,10 @@ struct amd_flash_info {
        const __u16 dev_id;
        const char *name;
        const int DevSize;
-       const int InterfaceDesc;
        const int NumEraseRegions;
        const int CmdSet;
-       const __u8 uaddr[3];            /* unlock addrs for 8, 16, 32 modes */
-       const ulong regions[4];
+       const __u8 uaddr[4];            /* unlock addrs for 8, 16, 32, 64 */
+       const ulong regions[6];
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
@@ -285,6 +300,40 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x08000,1),
                        ERASEINFO(0x10000,31)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29LV400BB,
+               .name           = "AMD AM29LV400BB",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x10000,7)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29LV400BT,
+               .name           = "AMD AM29LV400BT",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x10000,7),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x04000,1)
+               }
        }, {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV800BB,
@@ -303,6 +352,45 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x10000,15),
                }
        }, {
+/* add DL */
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29DL800BB,
+               .name           = "AMD AM29DL800BB",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 6,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,4),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x10000,14)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29DL800BT,
+               .name           = "AMD AM29DL800BT",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 6,
+               .regions        = {
+                       ERASEINFO(0x10000,14),
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,4),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x04000,1)
+               }
+       }, {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F800BB,
                .name           = "AMD AM29F800BB",
@@ -505,6 +593,19 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29F040C,
+               .name           = "Fujitsu MBM29F040C",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 1,
+               .regions        = {
+                       ERASEINFO(0x10000,8)
+               }
        }, {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV650UE,
@@ -616,6 +717,40 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x02000,2),
                        ERASEINFO(0x04000,1)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29LV400BC,
+               .name           = "Fujitsu MBM29LV400BC",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x10000,7)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29LV400TC,
+               .name           = "Fujitsu MBM29LV400TC",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x10000,7),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x04000,1)
+               }
        }, {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F004B3B,
@@ -1065,6 +1200,30 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x01000,32),
                }
         }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST29EE020,
+               .name           = "SST 29EE020",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_256KiB,
+               .CmdSet         = P_ID_SST_PAGE,
+               .NumEraseRegions= 1,
+               regions: {ERASEINFO(0x01000,64),
+               }
+         }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST29LE020,
+               .name           = "SST 29LE020",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_256KiB,
+               .CmdSet         = P_ID_SST_PAGE,
+               .NumEraseRegions= 1,
+               regions: {ERASEINFO(0x01000,64),
+               }
+       }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF020,
                .name           = "SST 39LF020",
@@ -1116,6 +1275,32 @@ static const struct amd_flash_info jedec_table[] = {
                .regions        = {
                        ERASEINFO(0x01000,64),
                }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST49LF004B,
+               .name           = "SST 49LF004B",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 1,
+               .regions        = {
+                       ERASEINFO(0x01000,128),
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST49LF008A,
+               .name           = "SST 49LF008A",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 1,
+               .regions        = {
+                       ERASEINFO(0x01000,256),
+               }
        }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF030A,
@@ -1392,37 +1577,50 @@ static const struct amd_flash_info jedec_table[] = {
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
 
 static int jedec_probe_chip(struct map_info *map, __u32 base,
-                           struct flchip *chips, struct cfi_private *cfi);
+                           unsigned long *chip_map, struct cfi_private *cfi);
 
 struct mtd_info *jedec_probe(struct map_info *map);
 
 static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, 
        struct cfi_private *cfi)
 {
-       u32 result, mask;
+       map_word result;
+       unsigned long mask;
        mask = (1 << (cfi->device_type * 8)) -1;
-       result = cfi_read(map, base);
-       result &= mask;
-       return result;
+       result = map_read(map, base);
+       return result.x[0] & mask;
 }
 
 static inline u32 jedec_read_id(struct map_info *map, __u32 base, 
        struct cfi_private *cfi)
 {
        int osf;
-       u32 result, mask;
+       map_word result;
+       unsigned long mask;
        osf = cfi->interleave *cfi->device_type;
        mask = (1 << (cfi->device_type * 8)) -1;
-       result = cfi_read(map, base + osf);
-       result &= mask;
-       return result;
+       result = map_read(map, base + osf);
+       return result.x[0] & mask;
 }
 
 static inline void jedec_reset(u32 base, struct map_info *map, 
        struct cfi_private *cfi)
 {
        /* Reset */
-       cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+
+       /* after checking the datasheets for SST, MACRONIX and ATMEL
+        * (oh and incidentaly the jedec spec - 3.5.3.3) the reset
+        * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at
+        * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips
+        * as they will ignore the writes and dont care what address
+        * the F0 is written to */
+       if(cfi->addr_unlock1) {
+               /*printk("reset unlock called %x %x \n",cfi->addr_unlock1,cfi->addr_unlock2);*/
+               cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+               cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       }
+
+       cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
        /* Some misdesigned intel chips do not respond for 0xF0 for a reset,
         * so ensure we're in read mode.  Send both the Intel and the AMD command
         * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
@@ -1450,6 +1648,12 @@ static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_ty
 
        uaddr = finfo->uaddr[uaddr_idx];
 
+       if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
+               /* ASSERT("The unlock addresses for non-8-bit mode
+                  are bollocks. We don't really need an array."); */
+               uaddr = finfo->uaddr[0];
+       }
+
  uaddr_done:
        return uaddr;
 }
@@ -1458,6 +1662,7 @@ static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_ty
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
        int i,num_erase_regions;
+       unsigned long mask;
        __u8 uaddr;
 
        printk("Found: %s\n",jedec_table[index].name);
@@ -1480,19 +1685,22 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
        for (i=0; i<num_erase_regions; i++){
                p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
        }
-       p_cfi->cmdset_priv = 0;
+       p_cfi->cmdset_priv = NULL;
 
        /* This may be redundant for some cases, but it doesn't hurt */
        p_cfi->mfr = jedec_table[index].mfr_id;
        p_cfi->id = jedec_table[index].dev_id;
 
        uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
-       if ( MTD_UADDR_NOT_SUPPORTED ) {
+       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
                kfree( p_cfi->cfiq );
                return 0;
        }
-       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
-       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
+
+       /* Mask out address bits which are smaller than the device type */
+       mask = ~(p_cfi->device_type-1);
+       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask;
+       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask;
 
        return 1;       /* ok */
 }
@@ -1513,9 +1721,37 @@ static inline int jedec_match( __u32 base,
        int rc = 0;           /* failure until all tests pass */
        u32 mfr, id;
        __u8 uaddr;
+       unsigned long mask;
 
-       /* The ID's must match */
-       if ( cfi->mfr != finfo->mfr_id || cfi->id != finfo->dev_id ) {
+       /*
+        * The IDs must match.  For X16 and X32 devices operating in
+        * a lower width ( X8 or X16 ), the device ID's are usually just
+        * the lower byte(s) of the larger device ID for wider mode.  If
+        * a part is found that doesn't fit this assumption (device id for
+        * smaller width mode is completely unrealated to full-width mode)
+        * then the jedec_table[] will have to be augmented with the IDs
+        * for different widths.
+        */
+       switch (cfi->device_type) {
+       case CFI_DEVICETYPE_X8:
+               mfr = (__u8)finfo->mfr_id;
+               id = (__u8)finfo->dev_id;
+               break;
+       case CFI_DEVICETYPE_X16:
+               mfr = (__u16)finfo->mfr_id;
+               id = (__u16)finfo->dev_id;
+               break;
+       case CFI_DEVICETYPE_X32:
+               mfr = (__u16)finfo->mfr_id;
+               id = (__u32)finfo->dev_id;
+               break;
+       default:
+               printk(KERN_WARNING
+                      "MTD %s(): Unsupported device type %d\n",
+                      __func__, cfi->device_type);
+               goto match_done;
+       }
+       if ( cfi->mfr != mfr || cfi->id != id ) {
                goto match_done;
        }
 
@@ -1523,7 +1759,7 @@ static inline int jedec_match( __u32 base,
        DEBUG( MTD_DEBUG_LEVEL3,
               "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
               __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
-       if ( base + ( 1 << finfo->DevSize ) > map->size ) {
+       if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) {
                DEBUG( MTD_DEBUG_LEVEL3,
                       "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
                       __func__, finfo->mfr_id, finfo->dev_id,
@@ -1532,20 +1768,22 @@ static inline int jedec_match( __u32 base,
        }
 
        uaddr = finfo_uaddr(finfo, cfi->device_type);
-       if ( MTD_UADDR_NOT_SUPPORTED ) {
+       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
                goto match_done;
        }
 
+       mask = ~(cfi->device_type-1);
+
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
               __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
        if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
-            && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1
-                 || unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
+            && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 ||
+                 (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) {
                DEBUG( MTD_DEBUG_LEVEL3,
-                      "MTD %s(): 0x%.4x 0x%.4x did not match\n",
+                      "MTD %s(): 0x%.4lx 0x%.4lx did not match\n",
                       __func__,
-                      unlock_addrs[uaddr].addr1,
-                      unlock_addrs[uaddr].addr2 );
+                      unlock_addrs[uaddr].addr1 & mask,
+                      unlock_addrs[uaddr].addr2 & mask);
                goto match_done;
        }
 
@@ -1593,41 +1831,25 @@ static inline int jedec_match( __u32 base,
 
 
 static int jedec_probe_chip(struct map_info *map, __u32 base,
-                             struct flchip *chips, struct cfi_private *cfi)
+                           unsigned long *chip_map, struct cfi_private *cfi)
 {
        int i;
-       int unlockpass = 0;
+       enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
 
-       /*
-        * FIXME - eventually replace these unlock address seeds with
-        * information from unlock_addrs[].
-        */
+ retry:
        if (!cfi->numchips) {
-               switch (cfi->device_type) {
-               case CFI_DEVICETYPE_X8:
-                       cfi->addr_unlock1 = 0x555;
-                       cfi->addr_unlock2 = 0x2aa;
-                       break;
-               case CFI_DEVICETYPE_X16:
-                       cfi->addr_unlock1 = 0xaaa;
-                       if (map->buswidth == cfi->interleave) {
-                               /* X16 chip(s) in X8 mode */
-                               cfi->addr_unlock2 = 0x555;
-                       } else {
-                               cfi->addr_unlock2 = 0x554;
-                       }
-                       break;
-               case CFI_DEVICETYPE_X32:
-                       cfi->addr_unlock1 = 0x1555; 
-                       cfi->addr_unlock2 = 0xaaa; 
-                       break;
-               default:
-                       printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type);
-               return 0;
-               }
+               unsigned long mask = ~(cfi->device_type-1);
+
+               uaddr_idx++;
+
+               if (MTD_UADDR_UNNECESSARY == uaddr_idx)
+                       return 0;
+
+               /* Mask out address bits which are smaller than the device type */
+               cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask;
+               cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask;
        }
 
- retry:
        /* Make certain we aren't probing past the end of map */
        if (base >= map->size) {
                printk(KERN_NOTICE
@@ -1668,7 +1890,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                
                cfi->mfr = jedec_read_mfr(map, base, cfi);
                cfi->id = jedec_read_id(map, base, cfi);
-               printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
+               DEBUG(MTD_DEBUG_LEVEL3,
+                     "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
                        cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
                for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
                        if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
@@ -1681,16 +1904,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                                goto ok_out;
                        }
                }
-               switch(unlockpass++) {
-               case 0:
-                       cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
-                       cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
-                       goto retry;
-               case 1:
-                       cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
-                       goto retry;
-               }
-               return 0;
+               goto retry;
        } else {
                __u16 mfr;
                __u16 id;
@@ -1707,21 +1921,24 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                }
        }
        
-       /* Check each previous chip to see if it's an alias */
-       for (i=0; i<cfi->numchips; i++) {
-               /* This chip should be in read mode if it's one
-                  we've already touched. */
-               if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
-                   jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
+       /* Check each previous chip locations to see if it's an alias */
+       for (i=0; i < (base >> cfi->chipshift); i++) {
+               unsigned long start;
+               if(!test_bit(i, chip_map)) {
+                       continue; /* Skip location; no valid chip at this address */
+               }
+               start = i << cfi->chipshift;
+               if (jedec_read_mfr(map, start, cfi) == cfi->mfr &&
+                   jedec_read_id(map, start, cfi) == cfi->id) {
                        /* Eep. This chip also looks like it's in autoselect mode.
                           Is it an alias for the new one? */
-                       jedec_reset(chips[i].start, map, cfi);
+                       jedec_reset(start, map, cfi);
 
                        /* If the device IDs go away, it's an alias */
                        if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
                            jedec_read_id(map, base, cfi) != cfi->id) {
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-                                      map->name, base, chips[i].start);
+                                      map->name, base, start);
                                return 0;
                        }
                        
@@ -1733,7 +1950,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                        if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
                            jedec_read_id(map, base, cfi) == cfi->id) {
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-                                      map->name, base, chips[i].start);
+                                      map->name, base, start);
                                return 0;
                        }
                }
@@ -1741,22 +1958,16 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                
        /* OK, if we got to here, then none of the previous chips appear to
           be aliases for the current one. */
-       if (cfi->numchips == MAX_CFI_CHIPS) {
-               printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-               /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-               return -1;
-       }
-       chips[cfi->numchips].start = base;
-       chips[cfi->numchips].state = FL_READY;
+       set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
        cfi->numchips++;
                
 ok_out:
        /* Put it back into Read Mode */
        jedec_reset(base, map, cfi);
 
-       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
               map->name, cfi->interleave, cfi->device_type*8, base, 
-              map->buswidth*8);
+              map->bankwidth*8);
        
        return 1;
 }