From 239cb9d904cfa8ab50d840a47b3306189d695c75 Mon Sep 17 00:00:00 2001 From: "aaron.williams@caviumnetworks.com" Date: Sun, 3 Mar 2013 16:45:05 +0530 Subject: mtd: cfi_flash: Fix CFI flash driver for 8-bit bus support This commit is based on that patch from aaron.williams@caviumnetworks.com with same commit title. pulled the same code changes into current u-boot tree. http://patchwork.ozlabs.org/patch/140863/ http://lists.denx.de/pipermail/u-boot/2011-April/089606.html This patch corrects the addresses used when working with Spansion/AMD FLASH chips. Addressing for 8 and 16 bits is almost identical except in the 16-bit case the LSB of the address is always 0. The confusion arose because the addresses in the datasheet for 16-bit mode are word addresses but this code assumed it was byte addresses. I have only been able to test this on our Octeon boards which use either an 8-bit or 16-bit bus. I have not tested the case where there's an 8-bit part on a 16-bit bus. This patch also adds some delays as suggested by Spansion. If a part can be both 8 and 16-bits, it forces it to work in 8-bit mode if an 8-bit bus is detected. Apart from the pulled changes, fixed few minor code cleanups and tested on 256M29EW, 512M29EW flashes. Before this fix: --------------- Bank # 1: CFI conformant flash (8 x 8) Size: 64 MB in 512 Sectors AMD Standard command set, Manufacturer ID: 0xFF, Device ID: 0xFF Erase timeout: 4096 ms, write timeout: 2 ms Buffer write timeout: 5 ms, buffer size: 1024 bytes After this fix: -------------- Bank # 1: CFI conformant flash (8 x 8) Size: 64 MB in 512 Sectors AMD Standard command set, Manufacturer ID: 0x89, Device ID: 0x7E2301 Erase timeout: 4096 ms, write timeout: 2 ms Buffer write timeout: 5 ms, buffer size: 1024 bytes Signed-off-by: Aaron Williams Signed-off-by: Jagannadha Sutradharudu Teki Tested-by: Jagannadha Sutradharudu Teki --- drivers/mtd/cfi_flash.c | 78 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 23 deletions(-) (limited to 'drivers/mtd/cfi_flash.c') diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 60dbb7864f..6b9fc1a12d 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -210,9 +210,11 @@ unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) static inline void * flash_map (flash_info_t * info, flash_sect_t sect, uint offset) { - unsigned int byte_offset = offset * info->portwidth; + unsigned int byte_offset = offset * info->portwidth / info->chipwidth; + unsigned int addr = (info->start[sect] + byte_offset); + unsigned int mask = 0xffffffff << (info->portwidth - 1); - return (void *)(info->start[sect] + byte_offset); + return (void *)(addr & mask); } static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, @@ -398,6 +400,8 @@ void flash_write_cmd (flash_info_t * info, flash_sect_t sect, #endif flash_write64(cword.ll, addr); break; + default: + printf("fwc: Unknown port width %d\n", info->portwidth); } /* Ensure all the instructions are fully finished */ @@ -585,7 +589,6 @@ static int flash_status_check (flash_info_t * info, flash_sect_t sector, prompt, info->start[sector], flash_read_long (info, sector, 0)); flash_write_cmd (info, sector, 0, info->cmd_reset); - udelay(1); return ERR_TIMOUT; } udelay (1); /* also triggers watchdog */ @@ -753,12 +756,8 @@ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) static flash_sect_t find_sector (flash_info_t * info, ulong addr) { static flash_sect_t saved_sector; /* previously found sector */ - static flash_info_t *saved_info; /* previously used flash bank */ flash_sect_t sector = saved_sector; - if ((info != saved_info) || (sector >= info->sector_count)) - sector = 0; - while ((info->start[sector] < addr) && (sector < info->sector_count - 1)) sector++; @@ -770,7 +769,6 @@ static flash_sect_t find_sector (flash_info_t * info, ulong addr) sector--; saved_sector = sector; - saved_info = info; return sector; } @@ -787,12 +785,15 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest, /* Check if Flash is (sufficiently) erased */ switch (info->portwidth) { case FLASH_CFI_8BIT: + debug("%s: 8-bit 0x%02x\n", __func__, cword.c); flag = ((flash_read8(dstaddr) & cword.c) == cword.c); break; case FLASH_CFI_16BIT: + debug("%s: 16-bit 0x%04x\n", __func__, cword.w); flag = ((flash_read16(dstaddr) & cword.w) == cword.w); break; case FLASH_CFI_32BIT: + debug("%s: 32-bit 0x%08lx\n", __func__, cword.l); flag = ((flash_read32(dstaddr) & cword.l) == cword.l); break; case FLASH_CFI_64BIT: @@ -1053,6 +1054,8 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) flash_sect_t sect; int st; + debug("%s: erasing sectors %d to %d\n", __func__, s_first, s_last); + if (info->flash_id != FLASH_MAN_CFI) { puts ("Can't erase unknown flash type - aborted\n"); return 1; @@ -1162,6 +1165,9 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) rcode = 1; else if (flash_verbose) putc ('.'); + } else { + debug("\nSector %d is protected.\n", + info->protect[sect]); } } @@ -1857,7 +1863,7 @@ static void flash_read_cfi (flash_info_t *info, void *buf, unsigned int i; for (i = 0; i < len; i++) - p[i] = flash_read_uchar(info, start + i); + p[i] = flash_read_uchar(info, start + (i * 2)); } static void __flash_cmd_reset(flash_info_t *info) @@ -1878,21 +1884,40 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) { int cfi_offset; - /* Issue FLASH reset command */ - flash_cmd_reset(info); - for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); cfi_offset++) { + /* Issue FLASH reset command */ + flash_cmd_reset(info); flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); - 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')) { + if (flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP, 'Q') && + flash_isequal(info, 0, + FLASH_OFFSET_CFI_RESP + 2, 'R') && + flash_isequal(info, 0, + FLASH_OFFSET_CFI_RESP + 4, 'Y')) { flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, sizeof(struct cfi_qry)); +#ifdef CONFIG_SYS_FLASH_INTERFACE_WIDTH + info->interface = CONFIG_SYS_FLASH_INTERFACE_WIDTH; +#else info->interface = le16_to_cpu(qry->interface_desc); - + /* Some flash chips can support multiple bus widths. + * In this case, override the interface width and + * limit it to the port width. + */ + if ((info->interface == FLASH_CFI_X8X16) && + (info->portwidth == FLASH_CFI_8BIT)) { + debug("Overriding 16-bit interface" + " width to 8-bit port width.\n"); + info->interface = FLASH_CFI_X8; + } else if ((info->interface == FLASH_CFI_X16X32) && + (info->portwidth == FLASH_CFI_16BIT)) { + debug("Overriding 16-bit interface" + " width to 16-bit port width.\n"); + info->interface = FLASH_CFI_X16; + } +#endif info->cfi_offset = flash_offset_cfi[cfi_offset]; debug ("device interface is %d\n", info->interface); @@ -1903,8 +1928,8 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) info->chipwidth << CFI_FLASH_SHIFT_WIDTH); /* calculate command offsets as in the Linux driver */ - info->addr_unlock1 = 0x555; - info->addr_unlock2 = 0x2aa; + info->addr_unlock1 = 0xaaa; + info->addr_unlock2 = 0x555; /* * modify the unlock address if we are @@ -1938,8 +1963,12 @@ static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) for (info->chipwidth = FLASH_CFI_BY8; info->chipwidth <= info->portwidth; info->chipwidth <<= 1) - if (__flash_detect_cfi(info, qry)) + if (__flash_detect_cfi(info, qry)) { + debug("Found CFI flash, portwidth %d," + " chipwidth %d\n", + info->portwidth, info->chipwidth); return 1; + } } debug ("not found\n"); return 0; @@ -1958,7 +1987,7 @@ static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) /* CFI < 1.1, try to guess from device id */ if ((info->device_id & 0x80) != 0) cfi_reverse_geometry(qry); - } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { + } else if (flash_read_uchar(info, info->ext_addr + 0x1e) == 3) { /* CFI >= 1.1, deduct from top/bottom flag */ /* note: ext_addr is valid since cfi_version > 0 */ cfi_reverse_geometry(qry); @@ -2054,14 +2083,15 @@ ulong flash_get_size (phys_addr_t base, int banknum) if (flash_detect_cfi (info, &qry)) { info->vendor = le16_to_cpu(qry.p_id); - info->ext_addr = le16_to_cpu(qry.p_adr); + info->ext_addr = le16_to_cpu(qry.p_adr) * 2; + debug("extended address is 0x%x\n", info->ext_addr); num_erase_regions = qry.num_erase_regions; if (info->ext_addr) { info->cfi_version = (ushort) flash_read_uchar (info, - info->ext_addr + 3) << 8; + info->ext_addr + 6) << 8; info->cfi_version |= (ushort) flash_read_uchar (info, - info->ext_addr + 4); + info->ext_addr + 8); } #ifdef DEBUG @@ -2112,6 +2142,8 @@ ulong flash_get_size (phys_addr_t base, int banknum) debug ("device id is 0x%x\n", info->device_id); debug ("device id2 is 0x%x\n", info->device_id2); debug ("cfi version is 0x%04x\n", info->cfi_version); + debug("port width: %d, chipwidth: %d, interface: %d\n", + info->portwidth, info->chipwidth, info->interface); size_ratio = info->portwidth / info->chipwidth; /* if the chip is x8/x16 reduce the ratio by half */ -- cgit v1.2.1