/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: jedec_probe.c,v 1.51 2004/07/14 14:44:30 thayne Exp $
+ $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
#define MANUFACTURER_HYUNDAI 0x00AD
#define MANUFACTURER_INTEL 0x0089
#define MANUFACTURER_MACRONIX 0x00C2
+#define MANUFACTURER_NEC 0x0010
#define MANUFACTURER_PMC 0x009D
#define MANUFACTURER_SST 0x00BF
#define MANUFACTURER_ST 0x0020
#define I82802AC 0x00ac
/* Macronix */
+#define MX29LV040C 0x004F
#define MX29LV160T 0x22C4
#define MX29LV160B 0x2249
#define MX29F016 0x00AD
#define MX29F004T 0x0045
#define MX29F004B 0x0046
+/* NEC */
+#define UPD29F064115 0x221C
+
/* PMC */
#define PM49FL002 0x006D
#define PM49FL004 0x006E
#define M50FW040 0x002C
#define M50FW080 0x002D
#define M50FW016 0x002E
+#define M50LPW080 0x002F
/* SST */
#define SST29EE020 0x0010
struct unlock_addr {
- int addr1;
- int addr2;
+ u32 addr1;
+ u32 addr2;
};
[MTD_UADDR_DONT_CARE] = {
.addr1 = 0x0000, /* Doesn't matter which address */
.addr2 = 0x0000 /* is used - must be last entry */
+ },
+
+ [MTD_UADDR_UNNECESSARY] = {
+ .addr1 = 0x0000,
+ .addr2 = 0x0000
}
};
ERASEINFO(0x10000,8),
}
}, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29F002T,
- .name = "AMD AM29F002T",
- .DevSize = SIZE_256KiB,
- .NumEraseRegions = 4,
- .regions = {ERASEINFO(0x10000,3),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
+ .mfr_id = MANUFACTURER_AMD,
+ .dev_id = AM29F002T,
+ .name = "AMD AM29F002T",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,3),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_ATMEL,
ERASEINFO(0x04000,1)
}
}, {
- .mfr_id = MANUFACTURER_HYUNDAI,
- .dev_id = HY29F002T,
- .name = "Hyundai HY29F002T",
- .DevSize = SIZE_256KiB,
- .NumEraseRegions = 4,
- .regions = {ERASEINFO(0x10000,3),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
+ .mfr_id = MANUFACTURER_HYUNDAI,
+ .dev_id = HY29F002T,
+ .name = "Hyundai HY29F002T",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,3),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_INTEL,
.regions = {
ERASEINFO(0x10000,16),
}
+ }, {
+ .mfr_id = MANUFACTURER_MACRONIX,
+ .dev_id = MX29LV040C,
+ .name = "Macronix MX29LV040C",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,8),
+ }
}, {
.mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29LV160T,
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1)
}
+ }, {
+ .mfr_id = MANUFACTURER_NEC,
+ .dev_id = UPD29F064115,
+ .name = "NEC uPD29F064115",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_8MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 3,
+ .regions = {
+ ERASEINFO(0x2000,8),
+ ERASEINFO(0x10000,126),
+ ERASEINFO(0x2000,8),
+ }
}, {
.mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29LV160B,
ERASEINFO(0x10000,7),
}
}, {
- .mfr_id = MANUFACTURER_MACRONIX,
- .dev_id = MX29F002T,
- .name = "Macronix MX29F002T",
- .DevSize = SIZE_256KiB,
- .NumEraseRegions = 4,
- .regions = {ERASEINFO(0x10000,3),
- ERASEINFO(0x08000,1),
- ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
+ .mfr_id = MANUFACTURER_MACRONIX,
+ .dev_id = MX29F002T,
+ .name = "Macronix MX29F002T",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,3),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_PMC,
ERASEINFO(0x01000,256),
}
}, {
+ .mfr_id = MANUFACTURER_SST, /* should be CFI */
+ .dev_id = SST39LF160,
+ .name = "SST 39LF160",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
+ },
+ .DevSize = SIZE_2MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 2,
+ .regions = {
+ ERASEINFO(0x1000,256),
+ ERASEINFO(0x1000,256)
+ }
+
+ }, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
.dev_id = M29W800DT,
.name = "ST M29W800DT",
.regions = {
ERASEINFO(0x10000,32),
}
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M50LPW080,
+ .name = "ST M50LPW080",
+ .uaddr = {
+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_INTEL_EXT,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,16),
+ }
}, {
.mfr_id = MANUFACTURER_TOSHIBA,
.dev_id = TC58FVT160,
static int jedec_probe_chip(struct map_info *map, __u32 base,
unsigned long *chip_map, struct cfi_private *cfi);
-struct mtd_info *jedec_probe(struct map_info *map);
+static 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)
{
map_word result;
unsigned long mask;
+ u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type);
mask = (1 << (cfi->device_type * 8)) -1;
- result = map_read(map, base);
+ result = map_read(map, base + ofs);
return result.x[0] & mask;
}
static inline u32 jedec_read_id(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
- int osf;
map_word result;
unsigned long mask;
- osf = cfi->interleave *cfi->device_type;
+ u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), cfi->device_type);
mask = (1 << (cfi->device_type * 8)) -1;
- result = map_read(map, base + osf);
+ result = map_read(map, base + ofs);
return result.x[0] & mask;
}
* 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);
+ DEBUG( MTD_DEBUG_LEVEL3,
+ "reset unlock called %x %x \n",
+ cfi->addr_unlock1,cfi->addr_unlock2);
+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
}
cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
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);
return 0;
}
- /* 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;
+ p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
+ p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
return 1; /* ok */
}
int rc = 0; /* failure until all tests pass */
u32 mfr, id;
__u8 uaddr;
- unsigned long mask;
/*
* The IDs must match. For X16 and X32 devices operating in
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 + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) {
+ if ( base + cfi_interleave(cfi) * ( 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,
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 & mask) != cfi->addr_unlock1 ||
- (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) {
+ && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 ||
+ unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
DEBUG( MTD_DEBUG_LEVEL3,
- "MTD %s(): 0x%.4lx 0x%.4lx did not match\n",
- __func__,
- unlock_addrs[uaddr].addr1 & mask,
- unlock_addrs[uaddr].addr2 & mask);
+ "MTD %s(): 0x%.4x 0x%.4x did not match\n",
+ __func__,
+ unlock_addrs[uaddr].addr1,
+ unlock_addrs[uaddr].addr2);
goto match_done;
}
*/
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
if(cfi->addr_unlock1) {
- 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(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
}
- cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
/* FIXME - should have a delay before continuing */
match_done:
{
int i;
enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
+ u32 probe_offset1, probe_offset2;
retry:
if (!cfi->numchips) {
- 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;
+ cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
+ cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
}
/* Make certain we aren't probing past the end of map */
return 0;
}
- if ((base + cfi->addr_unlock1) >= map->size) {
- printk(KERN_NOTICE
- "Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
- base, cfi->addr_unlock1, map->size -1);
-
- return 0;
+ /* Ensure the unlock addresses we try stay inside the map */
+ probe_offset1 = cfi_build_cmd_addr(
+ cfi->addr_unlock1,
+ cfi_interleave(cfi),
+ cfi->device_type);
+ probe_offset2 = cfi_build_cmd_addr(
+ cfi->addr_unlock1,
+ cfi_interleave(cfi),
+ cfi->device_type);
+ if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) ||
+ ((base + probe_offset2 + map_bankwidth(map)) >= map->size))
+ {
+ goto retry;
}
- if ((base + cfi->addr_unlock2) >= map->size) {
- printk(KERN_NOTICE
- "Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
- base, cfi->addr_unlock2, map->size -1);
- return 0;
- }
-
/* Reset */
jedec_reset(base, map, cfi);
/* Autoselect Mode */
if(cfi->addr_unlock1) {
- 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(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
}
- cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
/* FIXME - should have a delay before continuing */
if (!cfi->numchips) {
cfi->id = jedec_read_id(map, base, cfi);
DEBUG(MTD_DEBUG_LEVEL3,
"Search for id:(%02x %02x) interleave(%d) type(%d)\n",
- cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
+ cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type);
for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
DEBUG( MTD_DEBUG_LEVEL3,
jedec_reset(base, map, cfi);
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->name, cfi_interleave(cfi), cfi->device_type*8, base,
map->bankwidth*8);
return 1;
.probe_chip = jedec_probe_chip
};
-struct mtd_info *jedec_probe(struct map_info *map)
+static struct mtd_info *jedec_probe(struct map_info *map)
{
/*
* Just use the generic probe stuff to call our CFI-specific
.module = THIS_MODULE
};
-int __init jedec_probe_init(void)
+static int __init jedec_probe_init(void)
{
register_mtd_chip_driver(&jedec_chipdrv);
return 0;