summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-12-14 15:36:16 +0100
committerStefan Roese <sr@denx.de>2007-12-17 15:48:25 +0100
commite23741f4a6d8047520ef0d4971762749b3587d32 (patch)
tree0b3a75714703dd8d1fc567dcb31f0b6915a17248 /drivers
parent12d30aa79779c2aa7a998bbae4c075f822a53004 (diff)
downloadtalos-obmc-uboot-e23741f4a6d8047520ef0d4971762749b3587d32.tar.gz
talos-obmc-uboot-e23741f4a6d8047520ef0d4971762749b3587d32.zip
cfi_flash: Read whole QRY structure in one go
Read out the whole CFI Standard Query structure after successful cfi identification. This allows subsequent code to access this information directly without having to go through flash_read_uchar() and friends. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/cfi_flash.c176
1 files changed, 90 insertions, 86 deletions
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 6c18252da7..14c20610e5 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)) {
OpenPOWER on IntegriCloud