diff options
Diffstat (limited to 'drivers/mtd/cfi_flash.c')
-rw-r--r-- | drivers/mtd/cfi_flash.c | 176 |
1 files changed, 90 insertions, 86 deletions
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 6c18252..14c2061 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -171,6 +171,38 @@ flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* FLASH chips info */ typedef unsigned long flash_sect_t; +/* CFI standard query structure */ +struct cfi_qry { + u8 qry[3]; + u16 p_id; + u16 p_adr; + u16 a_id; + u16 a_adr; + u8 vcc_min; + u8 vcc_max; + u8 vpp_min; + u8 vpp_max; + u8 word_write_timeout_typ; + u8 buf_write_timeout_typ; + u8 block_erase_timeout_typ; + u8 chip_erase_timeout_typ; + u8 word_write_timeout_max; + u8 buf_write_timeout_max; + u8 block_erase_timeout_max; + u8 chip_erase_timeout_max; + u8 dev_size; + u16 interface_desc; + u16 max_buf_write_size; + u8 num_erase_regions; + u32 erase_region_info[NUM_ERASE_REGIONS]; +} __attribute__((packed)); + +struct cfi_pri_hdr { + u8 pri[3]; + u8 major_version; + u8 minor_version; +} __attribute__((packed)); + static void flash_write8(u8 value, void *addr) { __raw_writeb(value, addr); @@ -291,28 +323,24 @@ static void print_longlong (char *str, unsigned long long data) sprintf (&str[i * 2], "%2.2x", *cp++); } -static void flash_printqry (flash_info_t * info, flash_sect_t sect) +static void flash_printqry (struct cfi_qry *qry) { - void *addr; + u8 *p = (u8 *)qry; int x, y; - for (x = 0; x < 0x40; x += 16U / info->portwidth) { - addr = flash_map(info, sect, x + FLASH_OFFSET_CFI_RESP); - debug ("%p : ", addr); - for (y = 0; y < 16; y++) { - debug ("%2.2x ", flash_read8(addr + y)); - } - debug (" "); + for (x = 0; x < sizeof(struct cfi_qry); x += 16) { + debug("%02x : ", x); + for (y = 0; y < 16; y++) + debug("%2.2x ", p[x + y]); + debug(" "); for (y = 0; y < 16; y++) { - unsigned char c = flash_read8(addr + y); - if (c >= 0x20 && c <= 0x7e) { - debug ("%c", c); - } else { - debug ("."); - } + unsigned char c = p[x + y]; + if (c >= 0x20 && c <= 0x7e) + debug("%c", c); + else + debug("."); } - debug ("\n"); - flash_unmap(info, sect, x + FLASH_OFFSET_CFI_RESP, addr); + debug("\n"); } } #endif @@ -337,41 +365,6 @@ static inline uchar flash_read_uchar (flash_info_t * info, uint offset) } /*----------------------------------------------------------------------- - * read a short word by swapping for ppc format. - */ -static ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, - uint offset) -{ - uchar *addr; - ushort retval; - -#ifdef DEBUG - int x; -#endif - addr = flash_map (info, sect, offset); - -#ifdef DEBUG - debug ("ushort addr is at %p info->portwidth = %d\n", addr, - info->portwidth); - for (x = 0; x < 2 * info->portwidth; x++) { - debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x)); - } -#endif -#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) - retval = ((flash_read8(addr + info->portwidth) << 8) | - flash_read8(addr)); -#else - retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 8) | - flash_read8(addr + info->portwidth - 1)); -#endif - - debug ("retval = 0x%x\n", retval); - flash_unmap (info, sect, offset, addr); - - return retval; -} - -/*----------------------------------------------------------------------- * read a long word by picking the least significant byte of each maximum * port size word. Swap for ppc format. */ @@ -1427,7 +1420,17 @@ static inline int flash_detect_legacy(ulong base, int banknum) * detect if flash is compatible with the Common Flash Interface (CFI) * http://www.jedec.org/download/search/jesd68.pdf */ -static int __flash_detect_cfi (flash_info_t * info) +static void flash_read_cfi (flash_info_t *info, void *buf, + unsigned int start, size_t len) +{ + u8 *p = buf; + unsigned int i; + + for (i = 0; i < len; i++) + p[i] = flash_read_uchar(info, start + i); +} + +static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) { int cfi_offset; @@ -1440,8 +1443,10 @@ static int __flash_detect_cfi (flash_info_t * info) if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { - info->interface = flash_read_ushort (info, 0, - FLASH_OFFSET_INTERFACE); + flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, + sizeof(struct cfi_qry)); + info->interface = le16_to_cpu(qry->interface_desc); + info->cfi_offset = flash_offset_cfi[cfi_offset]; debug ("device interface is %d\n", info->interface); @@ -1478,7 +1483,7 @@ static int __flash_detect_cfi (flash_info_t * info) return 0; } -static int flash_detect_cfi (flash_info_t * info) +static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) { debug ("flash detect cfi\n"); @@ -1487,7 +1492,7 @@ static int flash_detect_cfi (flash_info_t * info) for (info->chipwidth = FLASH_CFI_BY8; info->chipwidth <= info->portwidth; info->chipwidth <<= 1) - if (__flash_detect_cfi(info)) + if (__flash_detect_cfi(info, qry)) return 1; } debug ("not found\n"); @@ -1510,6 +1515,7 @@ ulong flash_get_size (ulong base, int banknum) int erase_region_size; int erase_region_count; int geometry_reversed = 0; + struct cfi_qry qry; info->ext_addr = 0; info->cfi_version = 0; @@ -1519,15 +1525,14 @@ ulong flash_get_size (ulong base, int banknum) info->start[0] = base; - if (flash_detect_cfi (info)) { - info->vendor = flash_read_ushort (info, 0, - FLASH_OFFSET_PRIMARY_VENDOR); + if (flash_detect_cfi (info, &qry)) { + info->vendor = le16_to_cpu(qry.p_id); + info->ext_addr = le16_to_cpu(qry.p_adr); + num_erase_regions = qry.num_erase_regions; + flash_read_jedec_ids (info); flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI); - num_erase_regions = flash_read_uchar (info, - FLASH_OFFSET_NUM_ERASE_REGIONS); - info->ext_addr = flash_read_ushort (info, 0, - FLASH_OFFSET_EXT_QUERY_T_P_ADDR); + if (info->ext_addr) { info->cfi_version = (ushort) flash_read_uchar (info, info->ext_addr + 3) << 8; @@ -1535,7 +1540,7 @@ ulong flash_get_size (ulong base, int banknum) info->ext_addr + 4); } #ifdef DEBUG - flash_printqry (info, 0); + flash_printqry (&qry); #endif switch (info->vendor) { case CFI_CMDSET_INTEL_STANDARD: @@ -1591,23 +1596,23 @@ ulong flash_get_size (ulong base, int banknum) sect_cnt = 0; sector = base; for (i = 0; i < num_erase_regions; i++) { + unsigned int region = i; + if (i > NUM_ERASE_REGIONS) { printf ("%d erase regions found, only %d used\n", num_erase_regions, NUM_ERASE_REGIONS); break; } if (geometry_reversed) - tmp = flash_read_long (info, 0, - FLASH_OFFSET_ERASE_REGIONS + - (num_erase_regions - 1 - i) * 4); - else - tmp = flash_read_long (info, 0, - FLASH_OFFSET_ERASE_REGIONS + - i * 4); + region = num_erase_regions - 1 - i; + + tmp = le32_to_cpu(qry.erase_region_info[region]); + debug("erase region %u: 0x%08lx\n", region, tmp); + + erase_region_count = (tmp & 0xffff) + 1; + tmp >>= 16; erase_region_size = (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; - tmp >>= 16; - erase_region_count = (tmp & 0xffff) + 1; debug ("erase_region_count = %d erase_region_size = %d\n", erase_region_count, erase_region_size); for (j = 0; j < erase_region_count; j++) { @@ -1640,23 +1645,22 @@ ulong flash_get_size (ulong base, int banknum) } info->sector_count = sect_cnt; - info->size = 1 << flash_read_uchar (info, FLASH_OFFSET_SIZE); + info->size = 1 << qry.dev_size; /* multiply the size by the number of chips */ info->size *= size_ratio; - info->buffer_size = 1 << flash_read_ushort (info, 0, - FLASH_OFFSET_BUFFER_SIZE); - tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT); + info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); + tmp = 1 << qry.block_erase_timeout_typ; info->erase_blk_tout = tmp * - (1 << flash_read_uchar ( - info, FLASH_OFFSET_EMAX_TOUT)); - tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) * - (1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)); + (1 << qry.block_erase_timeout_max); + tmp = (1 << qry.buf_write_timeout_typ) * + (1 << qry.buf_write_timeout_max); + /* round up when converting to ms */ - info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); - tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) * - (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT)); + info->buffer_write_tout = (tmp + 999) / 1000; + tmp = (1 << qry.word_write_timeout_typ) * + (1 << qry.word_write_timeout_max); /* round up when converting to ms */ - info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); + info->write_tout = (tmp + 999) / 1000; info->flash_id = FLASH_MAN_CFI; if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { |