]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/mtd/cfi_flash.c
Merge branch 'master' of git://git.denx.de/u-boot-arm
[karo-tx-uboot.git] / drivers / mtd / cfi_flash.c
index cf10b0d4ca4af366ab2576aae41c77bf4a258225..50983b837b2238b781477f13b559502047b1ad6e 100644 (file)
  * Copyright (C) 2006
  * Tolunay Orkun <listmember@orkun.us>
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 /* The DEBUG define must be before common to enable debugging */
@@ -38,6 +21,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 #include <environment.h>
 #include <mtd/cfi_flash.h>
 #include <watchdog.h>
@@ -79,6 +63,12 @@ flash_info_t flash_info[CFI_MAX_FLASH_BANKS];        /* FLASH chips info */
 #define CONFIG_SYS_FLASH_CFI_WIDTH     FLASH_CFI_8BIT
 #endif
 
+#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
+#define __maybe_weak __weak
+#else
+#define __maybe_weak static
+#endif
+
 /*
  * 0xffff is an undefined value for the configuration register. When
  * this value is returned, the configuration register shall not be
@@ -97,14 +87,12 @@ static u16 cfi_flash_config_reg(int i)
 int cfi_flash_num_flash_banks = CONFIG_SYS_MAX_FLASH_BANKS_DETECT;
 #endif
 
-static phys_addr_t __cfi_flash_bank_addr(int i)
+__weak phys_addr_t cfi_flash_bank_addr(int i)
 {
        return ((phys_addr_t [])CONFIG_SYS_FLASH_BANKS_LIST)[i];
 }
-phys_addr_t cfi_flash_bank_addr(int i)
-       __attribute__((weak, alias("__cfi_flash_bank_addr")));
 
-static unsigned long __cfi_flash_bank_size(int i)
+__weak unsigned long cfi_flash_bank_size(int i)
 {
 #ifdef CONFIG_SYS_FLASH_BANKS_SIZES
        return ((unsigned long [])CONFIG_SYS_FLASH_BANKS_SIZES)[i];
@@ -112,87 +100,65 @@ static unsigned long __cfi_flash_bank_size(int i)
        return 0;
 #endif
 }
-unsigned long cfi_flash_bank_size(int i)
-       __attribute__((weak, alias("__cfi_flash_bank_size")));
 
-static void __flash_write8(u8 value, void *addr)
+__maybe_weak void flash_write8(u8 value, void *addr)
 {
        __raw_writeb(value, addr);
 }
 
-static void __flash_write16(u16 value, void *addr)
+__maybe_weak void flash_write16(u16 value, void *addr)
 {
        __raw_writew(value, addr);
 }
 
-static void __flash_write32(u32 value, void *addr)
+__maybe_weak void flash_write32(u32 value, void *addr)
 {
        __raw_writel(value, addr);
 }
 
-static void __flash_write64(u64 value, void *addr)
+__maybe_weak void flash_write64(u64 value, void *addr)
 {
        /* No architectures currently implement __raw_writeq() */
        *(volatile u64 *)addr = value;
 }
 
-static u8 __flash_read8(void *addr)
+__maybe_weak u8 flash_read8(void *addr)
 {
        return __raw_readb(addr);
 }
 
-static u16 __flash_read16(void *addr)
+__maybe_weak u16 flash_read16(void *addr)
 {
        return __raw_readw(addr);
 }
 
-static u32 __flash_read32(void *addr)
+__maybe_weak u32 flash_read32(void *addr)
 {
        return __raw_readl(addr);
 }
 
-static u64 __flash_read64(void *addr)
+__maybe_weak u64 flash_read64(void *addr)
 {
        /* No architectures currently implement __raw_readq() */
        return *(volatile u64 *)addr;
 }
 
-#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
-void flash_write8(u8 value, void *addr)__attribute__((weak, alias("__flash_write8")));
-void flash_write16(u16 value, void *addr)__attribute__((weak, alias("__flash_write16")));
-void flash_write32(u32 value, void *addr)__attribute__((weak, alias("__flash_write32")));
-void flash_write64(u64 value, void *addr)__attribute__((weak, alias("__flash_write64")));
-u8 flash_read8(void *addr)__attribute__((weak, alias("__flash_read8")));
-u16 flash_read16(void *addr)__attribute__((weak, alias("__flash_read16")));
-u32 flash_read32(void *addr)__attribute__((weak, alias("__flash_read32")));
-u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
-#else
-#define flash_write8   __flash_write8
-#define flash_write16  __flash_write16
-#define flash_write32  __flash_write32
-#define flash_write64  __flash_write64
-#define flash_read8    __flash_read8
-#define flash_read16   __flash_read16
-#define flash_read32   __flash_read32
-#define flash_read64   __flash_read64
-#endif
-
 /*-----------------------------------------------------------------------
  */
 #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
 flash_info_t *flash_get_info(ulong base)
 {
        int i;
-       flash_info_t *info = NULL;
+       flash_info_t *info;
 
        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
-               info = & flash_info[i];
+               info = &flash_info[i];
                if (info->size && info->start[0] <= base &&
                    base <= info->start[0] + info->size - 1)
-                       break;
+                       return info;
        }
 
-       return info;
+       return NULL;
 }
 #endif
 
@@ -210,11 +176,9 @@ 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 / info->chipwidth;
-       unsigned int addr = (info->start[sect] + byte_offset);
-       unsigned int mask = 0xffffffff << (info->portwidth - 1);
+       unsigned int byte_offset = offset * info->portwidth;
 
-       return (void *)(uintptr_t)(addr & mask);
+       return (void *)(info->start[sect] + byte_offset);
 }
 
 static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
@@ -400,8 +364,6 @@ 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 */
@@ -589,6 +551,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 */
@@ -612,7 +575,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
        case CFI_CMDSET_INTEL_PROG_REGIONS:
        case CFI_CMDSET_INTEL_EXTENDED:
        case CFI_CMDSET_INTEL_STANDARD:
-               if ((retcode != ERR_OK)
+               if ((retcode == ERR_OK)
                    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
                        retcode = ERR_INVAL;
                        printf ("Flash %s error at address %lx\n", prompt,
@@ -756,8 +719,12 @@ 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++;
@@ -769,6 +736,7 @@ static flash_sect_t find_sector (flash_info_t * info, ulong addr)
                sector--;
 
        saved_sector = sector;
+       saved_info = info;
        return sector;
 }
 
@@ -785,15 +753,12 @@ 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:
@@ -1054,8 +1019,6 @@ 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;
@@ -1165,9 +1128,6 @@ 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]);
                }
        }
 
@@ -1646,9 +1606,10 @@ static void cfi_reverse_geometry(struct cfi_qry *qry)
        u32 tmp;
 
        for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
-               tmp = qry->erase_region_info[i];
-               qry->erase_region_info[i] = qry->erase_region_info[j];
-               qry->erase_region_info[j] = tmp;
+               tmp = get_unaligned(&(qry->erase_region_info[i]));
+               put_unaligned(get_unaligned(&(qry->erase_region_info[j])),
+                             &(qry->erase_region_info[i]));
+               put_unaligned(tmp, &(qry->erase_region_info[j]));
        }
 }
 
@@ -1801,7 +1762,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
                        };
                        int i;
 
-                       for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
+                       for (i = 0; i < ARRAY_SIZE(modes); i++) {
                                info->vendor = modes[i];
                                info->start[0] =
                                        (ulong)map_physmem(base,
@@ -1824,7 +1785,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
                                        break;
                                else
                                        unmap_physmem((void *)info->start[0],
-                                                     MAP_NOCACHE);
+                                                     info->portwidth);
                        }
                }
 
@@ -1863,7 +1824,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 * 2));
+               p[i] = flash_read_uchar(info, start + i);
 }
 
 static void __flash_cmd_reset(flash_info_t *info)
@@ -1884,40 +1845,20 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
 {
        int cfi_offset;
 
-       for (cfi_offset=0;
-            cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
+       /* Issue FLASH reset command */
+       flash_cmd_reset(info);
+
+       for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi);
             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 + 2, 'R') &&
-                       flash_isequal(info, 0,
-                                       FLASH_OFFSET_CFI_RESP + 4, 'Y')) {
+               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_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);
@@ -1928,8 +1869,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 = 0xaaa;
-                       info->addr_unlock2 = 0x555;
+                       info->addr_unlock1 = 0x555;
+                       info->addr_unlock2 = 0x2aa;
 
                        /*
                         * modify the unlock address if we are
@@ -1963,12 +1904,8 @@ 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)) {
-                               debug("Found CFI flash, portwidth %d,"
-                                       " chipwidth %d\n",
-                                       info->portwidth, info->chipwidth);
+                       if (__flash_detect_cfi(info, qry))
                                return 1;
-                       }
        }
        debug ("not found\n");
        return 0;
@@ -1987,7 +1924,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 + 0x1e) == 3) {
+               } else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
                        /* CFI >= 1.1, deduct from top/bottom flag */
                        /* note: ext_addr is valid since cfi_version > 0 */
                        cfi_reverse_geometry(qry);
@@ -2102,16 +2039,15 @@ ulong flash_get_size (phys_addr_t base, int banknum)
        info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
 
        if (flash_detect_cfi (info, &qry)) {
-               info->vendor = le16_to_cpu(qry.p_id);
-               info->ext_addr = le16_to_cpu(qry.p_adr) * 2;
-               debug("extended address is 0x%x\n", info->ext_addr);
+               info->vendor = le16_to_cpu(get_unaligned(&(qry.p_id)));
+               info->ext_addr = le16_to_cpu(get_unaligned(&(qry.p_adr)));
                num_erase_regions = qry.num_erase_regions;
 
                if (info->ext_addr) {
                        info->cfi_version = (ushort) flash_read_uchar (info,
-                                               info->ext_addr + 6) << 8;
+                                               info->ext_addr + 3) << 8;
                        info->cfi_version |= (ushort) flash_read_uchar (info,
-                                               info->ext_addr + 8);
+                                               info->ext_addr + 4);
                }
 
 #ifdef DEBUG
@@ -2165,8 +2101,6 @@ 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 */
@@ -2195,7 +2129,8 @@ ulong flash_get_size (phys_addr_t base, int banknum)
                                break;
                        }
 
-                       tmp = le32_to_cpu(qry.erase_region_info[i]);
+                       tmp = le32_to_cpu(get_unaligned(
+                                               &(qry.erase_region_info[i])));
                        debug("erase region %u: 0x%08lx\n", i, tmp);
 
                        erase_region_count = (tmp & 0xffff) + 1;
@@ -2365,7 +2300,7 @@ void flash_protect_default(void)
 #endif
 
 #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
-       for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) {
+       for (i = 0; i < ARRAY_SIZE(apl); i++) {
                debug("autoprotecting from %08lx to %08lx\n",
                      apl[i].start, apl[i].start + apl[i].size - 1);
                flash_protect(FLAG_PROTECT_SET,
@@ -2407,7 +2342,7 @@ unsigned long flash_init (void)
 #endif /* CONFIG_SYS_FLASH_QUIET_TEST */
                }
 #ifdef CONFIG_SYS_FLASH_PROTECTION
-               else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
+               else if (strcmp(s, "yes") == 0) {
                        /*
                         * Only the U-Boot image and it's environment
                         * is protected, all other sectors are