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; }
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); }
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; } }
__xipram 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; if (!adr) goto out; printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr); extp = kmalloc(size, GFP_KERNEL); if (!extp) { printk(KERN_ERR "Failed to allocate memory\n"); goto out; } #ifdef CONFIG_MTD_XIP local_irq_disable(); #endif /* Switch it into Query Mode */ cfi_qry_mode_on(base, map, cfi); /* 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)); } /* Make sure it returns to read mode */ cfi_qry_mode_off(base, map, cfi); #ifdef CONFIG_MTD_XIP (void) map_read(map, base); xip_iprefetch(); local_irq_enable(); #endif out: return extp; }
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); }