void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, struct cfi_private *cfi) { 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); /* M29W128G flashes require an additional reset command when exit qry mode */ if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E)) cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); }
struct cfi_extquery * cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) { struct cfi_private *cfi = map->fldrv_priv; __u32 base = 0; // cfi->chips[0].start; int ofs_factor = cfi->interleave * cfi->device_type; int i; struct cfi_extquery *extp = NULL; printk(" %s Extended Query Table at 0x%4.4X\n", name, adr); if (!adr) goto out; /* Switch it into Query Mode */ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); extp = kmalloc(size, GFP_KERNEL); if (!extp) { printk(KERN_ERR "Failed to allocate memory\n"); goto out; } /* Read in the Extended Query Table */ for (i=0; i<size; i++) { ((unsigned char *)extp)[i] = cfi_read_query(map, base+((adr+i)*ofs_factor)); } #ifndef CONFIG_BCM96348 /* XXX: Some AMD flashes do not report the correct version (they * return zero instead).*/ if (extp->MajorVersion != '1' || (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { printk(KERN_WARNING " Unknown %s Extended Query " "version %c.%c.\n", name, extp->MajorVersion, extp->MinorVersion); kfree(extp); extp = NULL; goto out; } #endif out: /* Make sure it's in read mode */ 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); return extp; }
static inline int cfi_isSST(struct map_info *map,struct cfi_private *cfi, __u32 base) { int man_id; cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL); man_id = cfi_read_query(map, base); /* SST manufacture id = 0xBF */ if(man_id==0xBF){ return 1; }else{ return 0; } }
static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi) { int ofs_factor = cfi->interleave*cfi->device_type; __u32 base = 0; int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor); int i; #ifdef DEBUG_CFI printk("Number of erase regions: %d\n", num_erase_regions); #endif if (!num_erase_regions) return 0; cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); if (!cfi->cfiq) { printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); return 0; } memset(cfi->cfiq,0,sizeof(struct cfi_ident)); cfi->cfi_mode = CFI_MODE_CFI; cfi->fast_prog=1; /* CFI supports fast programming */ /* Read the CFI info structure */ 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); } /* Do any necessary byteswapping */ cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID); cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR); cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID); cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR); cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc); cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize); #ifdef DEBUG_CFI /* Dump the information therein */ print_cfi_ident(cfi->cfiq); #endif for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); #ifdef DEBUG_CFI printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); #endif } /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); return 1; }
/* * Set the Intel flash back to read mode since some old boot * loaders don't. */ static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v) { struct cfi_private *cfi = nettel_intel_map.fldrv_priv; unsigned long b; /* Make sure all FLASH chips are put back into read mode */ for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, cfi->device_type, NULL); } return(NOTIFY_OK); }
static int nettel_reboot_notifier( struct notifier_block *nb, unsigned long val, void *v) { struct cfi_private *cfi = nettel_flash_map.fldrv_priv; int i; for (i = 0; cfi && i < cfi->numchips; i++) cfi_send_gen_cmd(0xff, 0x55, cfi->chips[i].start, &nettel_flash_map, cfi, cfi->device_type, NULL); return(NOTIFY_OK); }
static int cfi_probe_chip(struct map_info *map, __u32 base, struct flchip *chips, struct cfi_private *cfi) { int i; if ((base + 0) >= map->size) { printk(KERN_NOTICE "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", (unsigned long)base, map->size -1); return 0; } if ((base + 0xff) >= map->size) { printk(KERN_NOTICE "Probe at base[0x55](0x%08lx) past the end of the map(0x%08lx)\n", (unsigned long)base + 0x55, map->size -1); return 0; } cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); /* SST Flash on board ? */ isSST=cfi_isSST(map,cfi,base); if(isSST) { cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); } else { cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); } if (!qry_present(map,base,cfi)) return 0; 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); } /* 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 (qry_present(map,chips[i].start,cfi)) { /* Eep. This chip also had the QRY marker. * Is it an alias for the new one? */ cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL); /* If the QRY marker goes away, it's an alias */ if (!qry_present(map, chips[i].start, cfi)) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", map->name, base, chips[i].start); return 0; } /* Yes, it's actually got QRY for data. Most * unfortunate. Stick the new chip in read mode * too and if it's the same, assume it's an alias. */ /* FIXME: Use other modes to do a proper check */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); if (qry_present(map, base, cfi)) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", map->name, base, chips[i].start); return 0; } } } /* 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; cfi->numchips++; /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n", map->name, cfi->interleave, cfi->device_type*8, base, map->buswidth*8); return 1; }
static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi) { int ofs_factor = cfi->interleave*cfi->device_type; __u32 base = 0; int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor); int i; #ifdef DEBUG_CFI printk("Number of erase regions: %d\n", num_erase_regions); #endif if (!num_erase_regions) return 0; cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); if (!cfi->cfiq) { printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); return 0; } memset(cfi->cfiq,0,sizeof(struct cfi_ident)); cfi->cfi_mode = CFI_MODE_CFI; cfi->fast_prog=1; /* CFI supports fast programming */ /* Read the CFI info structure */ 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); } /* Do any necessary byteswapping */ cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID); cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR); cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID); cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR); cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc); cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize); /* * ST screwed up the CFI interface for buffer writes on their parts, * so this needs to be fixed up by hand here. * * A possible enhancment is that instead of just reverting back * to word write (as this does), we could use the ST specific double * word write instead. */ if (cfi_read_query(map,base) == 0x20) { cfi->cfiq->BufWriteTimeoutTyp = 0; cfi->cfiq->BufWriteTimeoutMax = 0; } #ifdef DEBUG_CFI /* Dump the information therein */ print_cfi_ident(cfi->cfiq); #endif for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); #ifdef DEBUG_CFI printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); #endif } /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); /* some devices don't respond to 0xF0, so send 0xFF to be sure */ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); return 1; }
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; unsigned char bootloc; int ofs_factor = cfi->interleave * cfi->device_type; int i; __u8 major, minor; __u32 base = cfi->chips[0].start; if (cfi->cfi_mode==CFI_MODE_CFI){ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); major = cfi_read_query(map, base + (adr+3)*ofs_factor); minor = cfi_read_query(map, base + (adr+4)*ofs_factor); printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n", major, minor, adr); cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); cfi->mfr = cfi_read_query(map, base); cfi->id = cfi_read_query(map, base + ofs_factor); /* Wheee. Bring me the head of someone at AMD. */ #ifdef AMD_BOOTLOC_BUG if (((major << 8) | minor) < 0x3131) { /* CFI version 1.0 => don't trust bootloc */ if (cfi->id & 0x80) { printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id); bootloc = 3; /* top boot */ } else { bootloc = 2; /* bottom boot */ } } else #endif { cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor); } if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { int j = (cfi->cfiq->NumEraseRegions-1)-i; __u32 swap; swap = cfi->cfiq->EraseRegionInfo[i]; cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; cfi->cfiq->EraseRegionInfo[j] = swap; } } 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_unlock2 = 0xaaa; if (map->buswidth == cfi->interleave) { cfi->addr_unlock1 = 0x1555; } else { cfi->addr_unlock1 = 0x1554; } break; default: printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type); return NULL; } } /* CFI mode */ for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; } map->fldrv = &cfi_amdstd_chipdrv; cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); return cfi_amdstd_setup(map); }
int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, struct cfi_private *cfi) { cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); if (cfi_qry_present(map, base, cfi)) return 1; /* QRY not found probably we deal with some odd CFI chips */ /* Some revisions of some old Intel chips? */ 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); if (cfi_qry_present(map, base, cfi)) return 1; /* ST M29DW chips */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); if (cfi_qry_present(map, base, cfi)) return 1; /* some old SST chips, e.g. 39VF160x/39VF320x */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); if (cfi_qry_present(map, base, cfi)) return 1; /* SST 39VF640xB */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xAA, 0x555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); if (cfi_qry_present(map, base, cfi)) return 1; /* QRY not found */ return 0; }
struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; int ofs_factor = cfi->interleave * cfi->device_type; int i; __u8 major, minor; __u32 base = cfi->chips[0].start; if (cfi->cfi_mode==1){ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); major = cfi_read_query(map, base + (adr+3)*ofs_factor); minor = cfi_read_query(map, base + (adr+4)*ofs_factor); printk(" SST Query Table v%c.%c at 0x%4.4X\n", major, minor, adr); cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi->mfr = cfi_read_query(map, base); cfi->id = cfi_read_query(map, base + ofs_factor); cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); switch (cfi->device_type) { case CFI_DEVICETYPE_X16: cfi->addr_unlock1 = 0x5555; cfi->addr_unlock2 = 0x2AAA; break; default: printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0701 device type %d\n", cfi->device_type); return NULL; } } /* CFI mode */ for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; } map->fldrv = &cfi_sststd_chipdrv; MOD_INC_USE_COUNT; cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL); return cfi_sststd_setup(map); }