]> git.sur5r.net Git - u-boot/blobdiff - drivers/mtd/cfi_flash.c
spi: Remove spi_setup_slave_fdt
[u-boot] / drivers / mtd / cfi_flash.c
index 50983b837b2238b781477f13b559502047b1ad6e..f096e039cbcbdcd03c066e6975561ac3ba787ea4 100644 (file)
 /* #define DEBUG       */
 
 #include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdt_support.h>
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
@@ -47,6 +51,8 @@
  * reading and writing ... (yes there is such a Hardware).
  */
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
 #ifdef CONFIG_FLASH_CFI_MTD
 static uint flash_verbose = 1;
@@ -87,10 +93,34 @@ static u16 cfi_flash_config_reg(int i)
 int cfi_flash_num_flash_banks = CONFIG_SYS_MAX_FLASH_BANKS_DETECT;
 #endif
 
+#ifdef CONFIG_CFI_FLASH /* for driver model */
+static void cfi_flash_init_dm(void)
+{
+       struct udevice *dev;
+
+       cfi_flash_num_flash_banks = 0;
+       /*
+        * The uclass_first_device() will probe the first device and
+        * uclass_next_device() will probe the rest if they exist. So
+        * that cfi_flash_probe() will get called assigning the base
+        * addresses that are available.
+        */
+       for (uclass_first_device(UCLASS_MTD, &dev);
+            dev;
+            uclass_next_device(&dev)) {
+       }
+}
+
+phys_addr_t cfi_flash_bank_addr(int i)
+{
+       return flash_info[i].base;
+}
+#else
 __weak phys_addr_t cfi_flash_bank_addr(int i)
 {
        return ((phys_addr_t [])CONFIG_SYS_FLASH_BANKS_LIST)[i];
 }
+#endif
 
 __weak unsigned long cfi_flash_bank_size(int i)
 {
@@ -146,7 +176,7 @@ __maybe_weak u64 flash_read64(void *addr)
 /*-----------------------------------------------------------------------
  */
 #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)
+static flash_info_t *flash_get_info(ulong base)
 {
        int i;
        flash_info_t *info;
@@ -323,8 +353,8 @@ static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
 /*
  * Write a proper sized command to the correct address
  */
-void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
-                     uint offset, u32 cmd)
+static void flash_write_cmd(flash_info_t *info, flash_sect_t sect,
+                           uint offset, u32 cmd)
 {
 
        void *addr;
@@ -335,34 +365,34 @@ void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
                debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
-                      cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-               flash_write8(cword.c, addr);
+                      cword.w8, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
+               flash_write8(cword.w8, addr);
                break;
        case FLASH_CFI_16BIT:
                debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
-                      cmd, cword.w,
+                      cmd, cword.w16,
                       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-               flash_write16(cword.w, addr);
+               flash_write16(cword.w16, addr);
                break;
        case FLASH_CFI_32BIT:
-               debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
-                      cmd, cword.l,
+               debug ("fwc addr %p cmd %x %8.8x 32bit x %d bit\n", addr,
+                      cmd, cword.w32,
                       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-               flash_write32(cword.l, addr);
+               flash_write32(cword.w32, addr);
                break;
        case FLASH_CFI_64BIT:
 #ifdef DEBUG
                {
                        char str[20];
 
-                       print_longlong (str, cword.ll);
+                       print_longlong (str, cword.w64);
 
                        debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
                               addr, cmd, str,
                               info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
                }
 #endif
-               flash_write64(cword.ll, addr);
+               flash_write64(cword.w64, addr);
                break;
        }
 
@@ -393,16 +423,16 @@ static int flash_isequal (flash_info_t * info, flash_sect_t sect,
        debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
-               debug ("is= %x %x\n", flash_read8(addr), cword.c);
-               retval = (flash_read8(addr) == cword.c);
+               debug ("is= %x %x\n", flash_read8(addr), cword.w8);
+               retval = (flash_read8(addr) == cword.w8);
                break;
        case FLASH_CFI_16BIT:
-               debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
-               retval = (flash_read16(addr) == cword.w);
+               debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w16);
+               retval = (flash_read16(addr) == cword.w16);
                break;
        case FLASH_CFI_32BIT:
-               debug ("is= %8.8x %8.8lx\n", flash_read32(addr), cword.l);
-               retval = (flash_read32(addr) == cword.l);
+               debug ("is= %8.8x %8.8x\n", flash_read32(addr), cword.w32);
+               retval = (flash_read32(addr) == cword.w32);
                break;
        case FLASH_CFI_64BIT:
 #ifdef DEBUG
@@ -411,11 +441,11 @@ static int flash_isequal (flash_info_t * info, flash_sect_t sect,
                        char str2[20];
 
                        print_longlong (str1, flash_read64(addr));
-                       print_longlong (str2, cword.ll);
+                       print_longlong (str2, cword.w64);
                        debug ("is= %s %s\n", str1, str2);
                }
 #endif
-               retval = (flash_read64(addr) == cword.ll);
+               retval = (flash_read64(addr) == cword.w64);
                break;
        default:
                retval = 0;
@@ -439,16 +469,16 @@ static int flash_isset (flash_info_t * info, flash_sect_t sect,
        flash_make_cmd (info, cmd, &cword);
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
-               retval = ((flash_read8(addr) & cword.c) == cword.c);
+               retval = ((flash_read8(addr) & cword.w8) == cword.w8);
                break;
        case FLASH_CFI_16BIT:
-               retval = ((flash_read16(addr) & cword.w) == cword.w);
+               retval = ((flash_read16(addr) & cword.w16) == cword.w16);
                break;
        case FLASH_CFI_32BIT:
-               retval = ((flash_read32(addr) & cword.l) == cword.l);
+               retval = ((flash_read32(addr) & cword.w32) == cword.w32);
                break;
        case FLASH_CFI_64BIT:
-               retval = ((flash_read64(addr) & cword.ll) == cword.ll);
+               retval = ((flash_read64(addr) & cword.w64) == cword.w64);
                break;
        default:
                retval = 0;
@@ -514,7 +544,16 @@ static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
 #ifdef CONFIG_FLASH_CFI_LEGACY
        case CFI_CMDSET_AMD_LEGACY:
 #endif
-               retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
+               if (info->sr_supported) {
+                       flash_write_cmd (info, sect, info->addr_unlock1,
+                                        FLASH_CMD_READ_STATUS);
+                       retval = !flash_isset (info, sect, 0,
+                                              FLASH_STATUS_DONE);
+               } else {
+                       retval = flash_toggle (info, sect, 0,
+                                              AMD_STATUS_TOGGLE);
+               }
+
                break;
        default:
                retval = 0;
@@ -576,7 +615,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
        case CFI_CMDSET_INTEL_EXTENDED:
        case CFI_CMDSET_INTEL_STANDARD:
                if ((retcode == ERR_OK)
-                   && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
+                   && !flash_isset(info, sector, 0, FLASH_STATUS_DONE)) {
                        retcode = ERR_INVAL;
                        printf ("Flash %s error at address %lx\n", prompt,
                                info->start[sector]);
@@ -680,33 +719,33 @@ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
 
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
-               cword->c = c;
+               cword->w8 = c;
                break;
        case FLASH_CFI_16BIT:
 #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
                w = c;
                w <<= 8;
-               cword->w = (cword->w >> 8) | w;
+               cword->w16 = (cword->w16 >> 8) | w;
 #else
-               cword->w = (cword->w << 8) | c;
+               cword->w16 = (cword->w16 << 8) | c;
 #endif
                break;
        case FLASH_CFI_32BIT:
 #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
                l = c;
                l <<= 24;
-               cword->l = (cword->l >> 8) | l;
+               cword->w32 = (cword->w32 >> 8) | l;
 #else
-               cword->l = (cword->l << 8) | c;
+               cword->w32 = (cword->w32 << 8) | c;
 #endif
                break;
        case FLASH_CFI_64BIT:
 #if defined(__LITTLE_ENDIAN) && !defined(CONFIG_SYS_WRITE_SWAPPED_DATA)
                ll = c;
                ll <<= 56;
-               cword->ll = (cword->ll >> 8) | ll;
+               cword->w64 = (cword->w64 >> 8) | ll;
 #else
-               cword->ll = (cword->ll << 8) | c;
+               cword->w64 = (cword->w64 << 8) | c;
 #endif
                break;
        }
@@ -753,16 +792,16 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
        /* Check if Flash is (sufficiently) erased */
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
-               flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
+               flag = ((flash_read8(dstaddr) & cword.w8) == cword.w8);
                break;
        case FLASH_CFI_16BIT:
-               flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
+               flag = ((flash_read16(dstaddr) & cword.w16) == cword.w16);
                break;
        case FLASH_CFI_32BIT:
-               flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
+               flag = ((flash_read32(dstaddr) & cword.w32) == cword.w32);
                break;
        case FLASH_CFI_64BIT:
-               flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
+               flag = ((flash_read64(dstaddr) & cword.w64) == cword.w64);
                break;
        default:
                flag = 0;
@@ -800,16 +839,16 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
 
        switch (info->portwidth) {
        case FLASH_CFI_8BIT:
-               flash_write8(cword.c, dstaddr);
+               flash_write8(cword.w8, dstaddr);
                break;
        case FLASH_CFI_16BIT:
-               flash_write16(cword.w, dstaddr);
+               flash_write16(cword.w16, dstaddr);
                break;
        case FLASH_CFI_32BIT:
-               flash_write32(cword.l, dstaddr);
+               flash_write32(cword.w32, dstaddr);
                break;
        case FLASH_CFI_64BIT:
-               flash_write64(cword.ll, dstaddr);
+               flash_write64(cword.w64, dstaddr);
                break;
        }
 
@@ -947,7 +986,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 
        case CFI_CMDSET_AMD_STANDARD:
        case CFI_CMDSET_AMD_EXTENDED:
-               flash_unlock_seq(info,0);
+               flash_unlock_seq(info, sector);
 
 #ifdef CONFIG_FLASH_SPANSION_S29WS_N
                offset = ((unsigned long)dst - info->start[sector]) >> shift;
@@ -1115,7 +1154,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
                        if (use_flash_status_poll(info)) {
                                cfiword_t cword;
                                void *dest;
-                               cword.ll = 0xffffffffffffffffULL;
+                               cword.w64 = 0xffffffffffffffffULL;
                                dest = flash_map(info, sect, 0);
                                st = flash_status_poll(info, &cword, dest,
                                                       info->erase_blk_tout, "erase");
@@ -1305,7 +1344,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 
        /* handle unaligned start */
        if ((aln = addr - wp) != 0) {
-               cword.l = 0;
+               cword.w32 = 0;
                p = (uchar *)wp;
                for (i = 0; i < aln; ++i)
                        flash_add_byte (info, &cword, flash_read8(p + i));
@@ -1332,7 +1371,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
        while (cnt >= info->portwidth) {
                /* prohibit buffer write when buffer_size is 1 */
                if (info->buffer_size == 1) {
-                       cword.l = 0;
+                       cword.w32 = 0;
                        for (i = 0; i < info->portwidth; i++)
                                flash_add_byte (info, &cword, *src++);
                        if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
@@ -1359,7 +1398,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
        }
 #else
        while (cnt >= info->portwidth) {
-               cword.l = 0;
+               cword.w32 = 0;
                for (i = 0; i < info->portwidth; i++) {
                        flash_add_byte (info, &cword, *src++);
                }
@@ -1381,7 +1420,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
        /*
         * handle unaligned tail bytes
         */
-       cword.l = 0;
+       cword.w32 = 0;
        p = (uchar *)wp;
        for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
                flash_add_byte (info, &cword, *src++);
@@ -1424,8 +1463,8 @@ static int cfi_protect_bugfix(flash_info_t *info, long sector, int prot)
                                cmd = FLASH_CMD_PROTECT_SET;
                        else
                                cmd = FLASH_CMD_PROTECT_CLEAR;
-                               flash_write_cmd(info, sector, 0,
-                                         FLASH_CMD_PROTECT);
+
+                       flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT);
                        flash_write_cmd(info, sector, 0, cmd);
                        /* re-enable interrupts if necessary */
                        if (flag)
@@ -1655,6 +1694,7 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info)
 {
        ushort bankId = 0;
        uchar  manuId;
+       uchar  feature;
 
        flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
        flash_unlock_seq(info, 0);
@@ -1670,6 +1710,15 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info)
        }
        info->manufacturer_id = manuId;
 
+       debug("info->ext_addr = 0x%x, cfi_version = 0x%x\n",
+             info->ext_addr, info->cfi_version);
+       if (info->ext_addr && info->cfi_version >= 0x3134) {
+               /* read software feature (at 0x53) */
+               feature = flash_read_uchar(info, info->ext_addr + 0x13);
+               debug("feature = 0x%x\n", feature);
+               info->sr_supported = feature & 0x1;
+       }
+
        switch (info->chipwidth){
        case FLASH_CFI_8BIT:
                info->device_id = flash_read_uchar (info,
@@ -2171,6 +2220,8 @@ ulong flash_get_size (phys_addr_t base, int banknum)
                                                flash_isset (info, sect_cnt,
                                                             FLASH_OFFSET_PROTECT,
                                                             FLASH_STATUS_PROTECT);
+                                       flash_write_cmd(info, sect_cnt, 0,
+                                                       FLASH_CMD_RESET);
                                        break;
                                case CFI_CMDSET_AMD_EXTENDED:
                                case CFI_CMDSET_AMD_STANDARD:
@@ -2264,7 +2315,7 @@ static void cfi_flash_set_config_reg(u32 base, u16 val)
 /*-----------------------------------------------------------------------
  */
 
-void flash_protect_default(void)
+static void flash_protect_default(void)
 {
 #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST)
        int i;
@@ -2319,7 +2370,11 @@ unsigned long flash_init (void)
 #ifdef CONFIG_SYS_FLASH_PROTECTION
        /* read environment from EEPROM */
        char s[64];
-       getenv_f("unlock", s, sizeof(s));
+       env_get_f("unlock", s, sizeof(s));
+#endif
+
+#ifdef CONFIG_CFI_FLASH /* for driver model */
+       cfi_flash_init_dm();
 #endif
 
        /* Init: no FLASHes known */
@@ -2398,3 +2453,48 @@ unsigned long flash_init (void)
 
        return (size);
 }
+
+#ifdef CONFIG_CFI_FLASH /* for driver model */
+static int cfi_flash_probe(struct udevice *dev)
+{
+       void *blob = (void *)gd->fdt_blob;
+       int node = dev_of_offset(dev);
+       const fdt32_t *cell;
+       phys_addr_t addr;
+       int parent, addrc, sizec;
+       int len, idx;
+
+       parent = fdt_parent_offset(blob, node);
+       fdt_support_default_count_cells(blob, parent, &addrc, &sizec);
+       /* decode regs, there may be multiple reg tuples. */
+       cell = fdt_getprop(blob, node, "reg", &len);
+       if (!cell)
+               return -ENOENT;
+       idx = 0;
+       len /= sizeof(fdt32_t);
+       while (idx < len) {
+               addr = fdt_translate_address((void *)blob,
+                                            node, cell + idx);
+               flash_info[cfi_flash_num_flash_banks].dev = dev;
+               flash_info[cfi_flash_num_flash_banks].base = addr;
+               cfi_flash_num_flash_banks++;
+               idx += addrc + sizec;
+       }
+       gd->bd->bi_flashstart = flash_info[0].base;
+
+       return 0;
+}
+
+static const struct udevice_id cfi_flash_ids[] = {
+       { .compatible = "cfi-flash" },
+       { .compatible = "jedec-flash" },
+       {}
+};
+
+U_BOOT_DRIVER(cfi_flash) = {
+       .name   = "cfi_flash",
+       .id     = UCLASS_MTD,
+       .of_match = cfi_flash_ids,
+       .probe = cfi_flash_probe,
+};
+#endif /* CONFIG_CFI_FLASH */