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.

-Aaron Williams


Signed-off-by: Aaron Williams <aaron.willi...@caviumnetworks.com>
---
 drivers/mtd/cfi_flash.c |   93 ++++++++++++++++++++++++++++++++++-------------
 include/mtd/cfi_flash.h |   40 ++++++++++----------
 2 files changed, 87 insertions(+), 46 deletions(-)

diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 0909fe7..eab1fbe 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -10,6 +10,9 @@
  *
  * Copyright (C) 2006
  * Tolunay Orkun <listmem...@orkun.us>
+ * 
+ * Copyright (C) 2011 Cavium Networks, Inc.
+ * Aaron Williams <aaron.willi...@caviumnetworks.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -32,7 +35,6 @@
  */
 
 /* The DEBUG define must be before common to enable debugging */
-/* #define DEBUG       */
 
 #include <common.h>
 #include <asm/processor.h>
@@ -209,9 +211,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;
-
-       return (void *)(info->start[sect] + byte_offset);
+       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 *)(addr & mask);
 }
 
 static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
@@ -397,6 +401,8 @@ void flash_write_cmd (flash_info_t * info, flash_sect_t 
sect,
 #endif
                flash_write64(cword.ll, addr);
                break;
+       default:
+               debug ("fwc: Unknown port width %d\n", info->portwidth);
        }
 
        /* Ensure all the instructions are fully finished */
@@ -581,6 +587,7 @@ 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 */
@@ -628,6 +635,7 @@ static int flash_full_status_check (flash_info_t * info, 
flash_sect_t sector,
                                puts ("Vpp Low Error.\n");
                }
                flash_write_cmd (info, sector, 0, info->cmd_reset);
+               udelay(1);
                break;
        default:
                break;
@@ -744,12 +752,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 = 0; /* previously found sector */
-       static flash_info_t *saved_info = 0; /* 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++;
@@ -761,7 +765,6 @@ static flash_sect_t find_sector (flash_info_t * info, ulong 
addr)
                sector--;
 
        saved_sector = sector;
-       saved_info = info;
        return sector;
 }
 
@@ -825,12 +828,15 @@ static int flash_write_cfiword (flash_info_t * info, 
ulong dest,
 
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
+               debug("%s: 8-bit 0x%02x\n", __func__, cword.c);
                flash_write8(cword.c, dstaddr);
                break;
        case FLASH_CFI_16BIT:
+               debug("%s: 16-bit 0x%04x\n", __func__, cword.w);
                flash_write16(cword.w, dstaddr);
                break;
        case FLASH_CFI_32BIT:
+               debug("%s: 32-bit 0x%08lx\n", __func__, cword.l);
                flash_write32(cword.l, dstaddr);
                break;
        case FLASH_CFI_64BIT:
@@ -1043,6 +1049,8 @@ int flash_erase (flash_info_t * info, int s_first, int 
s_last)
        int prot;
        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");
@@ -1082,6 +1090,7 @@ int flash_erase (flash_info_t * info, int s_first, int 
s_last)
                                break;
                        case CFI_CMDSET_AMD_STANDARD:
                        case CFI_CMDSET_AMD_EXTENDED:
+                               flash_write_cmd (info, 0, 0, AMD_CMD_RESET);
                                flash_unlock_seq (info, sect);
                                flash_write_cmd (info, sect,
                                                info->addr_unlock1,
@@ -1121,6 +1130,8 @@ 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", sect);
                }
        }
 
@@ -1490,6 +1501,7 @@ void flash_read_user_serial (flash_info_t * info, void 
*buffer, int offset,
        flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
        memcpy (dst, src + offset, len);
        flash_write_cmd (info, 0, 0, info->cmd_reset);
+       udelay(1);
        flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
 }
 
@@ -1505,6 +1517,7 @@ void flash_read_factory_serial (flash_info_t * info, void 
*buffer, int offset,
        flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
        memcpy (buffer, src + offset, len);
        flash_write_cmd (info, 0, 0, info->cmd_reset);
+       udelay(1);
        flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
 }
 
@@ -1536,6 +1549,7 @@ static void cfi_reverse_geometry(struct cfi_qry *qry)
 static void cmdset_intel_read_jedec_ids(flash_info_t *info)
 {
        flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
+       udelay(1);
        flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
        udelay(1000); /* some flash are slow to respond */
        info->manufacturer_id = flash_read_uchar (info,
@@ -1573,8 +1587,7 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info)
        flash_unlock_seq(info, 0);
        flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
        udelay(1000); /* some flash are slow to respond */
-
-       manuId = flash_read_uchar (info, FLASH_OFFSET_MANUFACTURER_ID);
+       manuId = flash_read_uchar(info, FLASH_OFFSET_MANUFACTURER_ID);
        /* JEDEC JEP106Z specifies ID codes up to bank 7 */
        while (manuId == FLASH_CONTINUATION_CODE && bankId < 0x800) {
                bankId += 0x100;
@@ -1604,6 +1617,7 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info)
                break;
        }
        flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
+       udelay(1);
 }
 
 static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
@@ -1719,7 +1733,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));
 }
 
 void __flash_cmd_reset(flash_info_t *info)
@@ -1730,6 +1744,7 @@ void __flash_cmd_reset(flash_info_t *info)
         * that AMD flash roms ignore the Intel command.
         */
        flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
+       udelay(1);
        flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
 }
 void flash_cmd_reset(flash_info_t *info)
@@ -1739,21 +1754,38 @@ 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')) 
{
+                   && 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);
@@ -1764,8 +1796,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
@@ -1799,8 +1831,11 @@ 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;
@@ -1819,7 +1854,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);
@@ -1891,14 +1926,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
@@ -1945,13 +1981,16 @@ 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 0
                /* if the chip is x8/x16 reduce the ratio by half */
                if ((info->interface == FLASH_CFI_X8X16)
                    && (info->chipwidth == FLASH_CFI_BY8)) {
                        size_ratio >>= 1;
                }
+#endif
                debug ("size_ratio %d port %d bits chip %d bits\n",
                       size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH,
                       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
@@ -2023,6 +2062,8 @@ ulong flash_get_size (phys_addr_t base, int banknum)
                                sect_cnt++;
                        }
                }
+               debug ("port width: %d, chipwidth: %d, interface: %d\n",
+                      info->portwidth, info->chipwidth, info->interface);
 
                info->sector_count = sect_cnt;
                info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
diff --git a/include/mtd/cfi_flash.h b/include/mtd/cfi_flash.h
index 3245b44..edcf9be 100644
--- a/include/mtd/cfi_flash.h
+++ b/include/mtd/cfi_flash.h
@@ -71,29 +71,29 @@
 #define FLASH_CONTINUATION_CODE                0x7F
 
 #define FLASH_OFFSET_MANUFACTURER_ID   0x00
-#define FLASH_OFFSET_DEVICE_ID         0x01
-#define FLASH_OFFSET_DEVICE_ID2                0x0E
-#define FLASH_OFFSET_DEVICE_ID3                0x0F
-#define FLASH_OFFSET_CFI               0x55
+#define FLASH_OFFSET_DEVICE_ID         0x02
+#define FLASH_OFFSET_DEVICE_ID2                0x1C
+#define FLASH_OFFSET_DEVICE_ID3                0x1E
+#define FLASH_OFFSET_CFI               0xAA
 #define FLASH_OFFSET_CFI_ALT           0x555
-#define FLASH_OFFSET_CFI_RESP          0x10
-#define FLASH_OFFSET_PRIMARY_VENDOR    0x13
+#define FLASH_OFFSET_CFI_RESP          0x20
+#define FLASH_OFFSET_PRIMARY_VENDOR    0x26
 /* extended query table primary address */
-#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR        0x15
+#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR        0x2A
 #define FLASH_OFFSET_WTOUT             0x1F
-#define FLASH_OFFSET_WBTOUT            0x20
-#define FLASH_OFFSET_ETOUT             0x21
-#define FLASH_OFFSET_CETOUT            0x22
-#define FLASH_OFFSET_WMAX_TOUT         0x23
-#define FLASH_OFFSET_WBMAX_TOUT                0x24
-#define FLASH_OFFSET_EMAX_TOUT         0x25
-#define FLASH_OFFSET_CEMAX_TOUT                0x26
-#define FLASH_OFFSET_SIZE              0x27
-#define FLASH_OFFSET_INTERFACE         0x28
-#define FLASH_OFFSET_BUFFER_SIZE       0x2A
-#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C
-#define FLASH_OFFSET_ERASE_REGIONS     0x2D
-#define FLASH_OFFSET_PROTECT           0x02
+#define FLASH_OFFSET_WBTOUT            0x40
+#define FLASH_OFFSET_ETOUT             0x4A
+#define FLASH_OFFSET_CETOUT            0x44
+#define FLASH_OFFSET_WMAX_TOUT         0x46
+#define FLASH_OFFSET_WBMAX_TOUT                0x48
+#define FLASH_OFFSET_EMAX_TOUT         0x4A
+#define FLASH_OFFSET_CEMAX_TOUT                0x4C
+#define FLASH_OFFSET_SIZE              0x4E
+#define FLASH_OFFSET_INTERFACE         0x50
+#define FLASH_OFFSET_BUFFER_SIZE       0x54
+#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x58
+#define FLASH_OFFSET_ERASE_REGIONS     0x5A
+#define FLASH_OFFSET_PROTECT           0x04
 #define FLASH_OFFSET_USER_PROTECTION   0x85
 #define FLASH_OFFSET_INTEL_PROTECTION  0x81
 
-- 
1.7.3.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to