uboot/drivers/mtd/jedec_flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007
   3 * Michael Schwingen, <michael@schwingen.org>
   4 *
   5 * based in great part on jedec_probe.c from linux kernel:
   6 * (C) 2000 Red Hat. GPL'd.
   7 * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
   8 *
   9 * SPDX-License-Identifier:     GPL-2.0+
  10 */
  11
  12/* The DEBUG define must be before common to enable debugging */
  13/*#define DEBUG*/
  14
  15#include <common.h>
  16#include <asm/processor.h>
  17#include <asm/io.h>
  18#include <asm/byteorder.h>
  19#include <environment.h>
  20
  21#define P_ID_AMD_STD CFI_CMDSET_AMD_LEGACY
  22
  23/* AMD */
  24#define AM29DL800BB     0x22CB
  25#define AM29DL800BT     0x224A
  26
  27#define AM29F400BB      0x22AB
  28#define AM29F800BB      0x2258
  29#define AM29F800BT      0x22D6
  30#define AM29LV400BB     0x22BA
  31#define AM29LV400BT     0x22B9
  32#define AM29LV800BB     0x225B
  33#define AM29LV800BT     0x22DA
  34#define AM29LV160DT     0x22C4
  35#define AM29LV160DB     0x2249
  36#define AM29F017D       0x003D
  37#define AM29F016D       0x00AD
  38#define AM29F080        0x00D5
  39#define AM29F040        0x00A4
  40#define AM29LV040B      0x004F
  41#define AM29F032B       0x0041
  42#define AM29F002T       0x00B0
  43
  44/* SST */
  45#define SST39LF800      0x2781
  46#define SST39LF160      0x2782
  47#define SST39VF1601     0x234b
  48#define SST39LF512      0x00D4
  49#define SST39LF010      0x00D5
  50#define SST39LF020      0x00D6
  51#define SST39LF040      0x00D7
  52#define SST39SF010A     0x00B5
  53#define SST39SF020A     0x00B6
  54
  55/* STM */
  56#define STM29F400BB     0x00D6
  57
  58/* MXIC */
  59#define MX29LV040       0x004F
  60
  61/* WINBOND */
  62#define W39L040A        0x00D6
  63
  64/* AMIC */
  65#define A29L040         0x0092
  66
  67/* EON */
  68#define EN29LV040A      0x004F
  69
  70/*
  71 * Unlock address sets for AMD command sets.
  72 * Intel command sets use the MTD_UADDR_UNNECESSARY.
  73 * Each identifier, except MTD_UADDR_UNNECESSARY, and
  74 * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[].
  75 * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure
  76 * initialization need not require initializing all of the
  77 * unlock addresses for all bit widths.
  78 */
  79enum uaddr {
  80        MTD_UADDR_NOT_SUPPORTED = 0,    /* data width not supported */
  81        MTD_UADDR_0x0555_0x02AA,
  82        MTD_UADDR_0x0555_0x0AAA,
  83        MTD_UADDR_0x5555_0x2AAA,
  84        MTD_UADDR_0x0AAA_0x0555,
  85        MTD_UADDR_DONT_CARE,            /* Requires an arbitrary address */
  86        MTD_UADDR_UNNECESSARY,          /* Does not require any address */
  87};
  88
  89
  90struct unlock_addr {
  91        u32 addr1;
  92        u32 addr2;
  93};
  94
  95
  96/*
  97 * I don't like the fact that the first entry in unlock_addrs[]
  98 * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
  99 * should not be used.  The  problem is that structures with
 100 * initializers have extra fields initialized to 0.  It is _very_
 101 * desireable to have the unlock address entries for unsupported
 102 * data widths automatically initialized - that means that
 103 * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
 104 * must go unused.
 105 */
 106static const struct unlock_addr  unlock_addrs[] = {
 107        [MTD_UADDR_NOT_SUPPORTED] = {
 108                .addr1 = 0xffff,
 109                .addr2 = 0xffff
 110        },
 111
 112        [MTD_UADDR_0x0555_0x02AA] = {
 113                .addr1 = 0x0555,
 114                .addr2 = 0x02aa
 115        },
 116
 117        [MTD_UADDR_0x0555_0x0AAA] = {
 118                .addr1 = 0x0555,
 119                .addr2 = 0x0aaa
 120        },
 121
 122        [MTD_UADDR_0x5555_0x2AAA] = {
 123                .addr1 = 0x5555,
 124                .addr2 = 0x2aaa
 125        },
 126
 127        [MTD_UADDR_0x0AAA_0x0555] = {
 128                .addr1 = 0x0AAA,
 129                .addr2 = 0x0555
 130        },
 131
 132        [MTD_UADDR_DONT_CARE] = {
 133                .addr1 = 0x0000,      /* Doesn't matter which address */
 134                .addr2 = 0x0000       /* is used - must be last entry */
 135        },
 136
 137        [MTD_UADDR_UNNECESSARY] = {
 138                .addr1 = 0x0000,
 139                .addr2 = 0x0000
 140        }
 141};
 142
 143
 144struct amd_flash_info {
 145        const __u16 mfr_id;
 146        const __u16 dev_id;
 147        const char *name;
 148        const int DevSize;
 149        const int NumEraseRegions;
 150        const int CmdSet;
 151        const __u8 uaddr[4];            /* unlock addrs for 8, 16, 32, 64 */
 152        const ulong regions[6];
 153};
 154
 155#define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
 156
 157#define SIZE_64KiB  16
 158#define SIZE_128KiB 17
 159#define SIZE_256KiB 18
 160#define SIZE_512KiB 19
 161#define SIZE_1MiB   20
 162#define SIZE_2MiB   21
 163#define SIZE_4MiB   22
 164#define SIZE_8MiB   23
 165
 166static const struct amd_flash_info jedec_table[] = {
 167#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8
 168        {
 169                .mfr_id         = (u16)SST_MANUFACT,
 170                .dev_id         = SST39LF020,
 171                .name           = "SST 39LF020",
 172                .uaddr          = {
 173                        [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
 174                },
 175                .DevSize        = SIZE_256KiB,
 176                .CmdSet         = P_ID_AMD_STD,
 177                .NumEraseRegions= 1,
 178                .regions        = {
 179                        ERASEINFO(0x01000,64),
 180                }
 181        },
 182#endif
 183#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx8
 184        {
 185                .mfr_id         = (u16)AMD_MANUFACT,
 186                .dev_id         = AM29LV040B,
 187                .name           = "AMD AM29LV040B",
 188                .uaddr          = {
 189                        [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
 190                },
 191                .DevSize        = SIZE_512KiB,
 192                .CmdSet         = P_ID_AMD_STD,
 193                .NumEraseRegions= 1,
 194                .regions        = {
 195                        ERASEINFO(0x10000,8),
 196                }
 197        },
 198        {
 199                .mfr_id         = (u16)SST_MANUFACT,
 200                .dev_id         = SST39LF040,
 201                .name           = "SST 39LF040",
 202                .uaddr          = {
 203                        [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
 204                },
 205                .DevSize        = SIZE_512KiB,
 206                .CmdSet         = P_ID_AMD_STD,
 207                .NumEraseRegions= 1,
 208                .regions        = {
 209                        ERASEINFO(0x01000,128),
 210                }
 211        },
 212        {
 213                .mfr_id         = (u16)STM_MANUFACT,
 214                .dev_id         = STM_ID_M29W040B,
 215                .name           = "ST Micro M29W040B",
 216                .uaddr          = {
 217                        [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
 218                },
 219                .DevSize        = SIZE_512KiB,
 220                .CmdSet         = P_ID_AMD_STD,
 221                .NumEraseRegions= 1,
 222                .regions        = {
 223                        ERASEINFO(0x10000,8),
 224                }
 225        },
 226        {
 227                .mfr_id         = (u16)MX_MANUFACT,
 228                .dev_id         = MX29LV040,
 229                .name           = "MXIC MX29LV040",
 230                .uaddr          = {
 231                        [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
 232                },
 233                .DevSize        = SIZE_512KiB,
 234                .CmdSet         = P_ID_AMD_STD,
 235                .NumEraseRegions= 1,
 236                .regions        = {
 237                        ERASEINFO(0x10000, 8),
 238                }
 239        },
 240        {
 241                .mfr_id         = (u16)WINB_MANUFACT,
 242                .dev_id         = W39L040A,
 243                .name           = "WINBOND W39L040A",
 244                .uaddr          = {
 245                        [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
 246                },
 247                .DevSize        = SIZE_512KiB,
 248                .CmdSet         = P_ID_AMD_STD,
 249                .NumEraseRegions= 1,
 250                .regions        = {
 251                        ERASEINFO(0x10000, 8),
 252                }
 253        },
 254        {
 255                .mfr_id         = (u16)AMIC_MANUFACT,
 256                .dev_id         = A29L040,
 257                .name           = "AMIC A29L040",
 258                .uaddr          = {
 259                        [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
 260                },
 261                .DevSize        = SIZE_512KiB,
 262                .CmdSet         = P_ID_AMD_STD,
 263                .NumEraseRegions= 1,
 264                .regions        = {
 265                        ERASEINFO(0x10000, 8),
 266                }
 267        },
 268        {
 269                .mfr_id         = (u16)EON_MANUFACT,
 270                .dev_id         = EN29LV040A,
 271                .name           = "EON EN29LV040A",
 272                .uaddr          = {
 273                        [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
 274                },
 275                .DevSize        = SIZE_512KiB,
 276                .CmdSet         = P_ID_AMD_STD,
 277                .NumEraseRegions= 1,
 278                .regions        = {
 279                        ERASEINFO(0x10000, 8),
 280                }
 281        },
 282#endif
 283#ifdef CONFIG_SYS_FLASH_LEGACY_512Kx16
 284        {
 285                .mfr_id         = (u16)AMD_MANUFACT,
 286                .dev_id         = AM29F400BB,
 287                .name           = "AMD AM29F400BB",
 288                .uaddr          = {
 289                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 290                },
 291                .DevSize        = SIZE_512KiB,
 292                .CmdSet         = CFI_CMDSET_AMD_LEGACY,
 293                .NumEraseRegions= 4,
 294                .regions        = {
 295                        ERASEINFO(0x04000, 1),
 296                        ERASEINFO(0x02000, 2),
 297                        ERASEINFO(0x08000, 1),
 298                        ERASEINFO(0x10000, 7),
 299                }
 300        },
 301        {
 302                .mfr_id         = (u16)AMD_MANUFACT,
 303                .dev_id         = AM29LV400BB,
 304                .name           = "AMD AM29LV400BB",
 305                .uaddr          = {
 306                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 307                },
 308                .DevSize        = SIZE_512KiB,
 309                .CmdSet         = CFI_CMDSET_AMD_LEGACY,
 310                .NumEraseRegions= 4,
 311                .regions        = {
 312                        ERASEINFO(0x04000,1),
 313                        ERASEINFO(0x02000,2),
 314                        ERASEINFO(0x08000,1),
 315                        ERASEINFO(0x10000,7),
 316                }
 317        },
 318        {
 319                .mfr_id         = (u16)AMD_MANUFACT,
 320                .dev_id         = AM29LV800BB,
 321                .name           = "AMD AM29LV800BB",
 322                .uaddr          = {
 323                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 324                },
 325                .DevSize        = SIZE_1MiB,
 326                .CmdSet         = CFI_CMDSET_AMD_LEGACY,
 327                .NumEraseRegions= 4,
 328                .regions        = {
 329                        ERASEINFO(0x04000, 1),
 330                        ERASEINFO(0x02000, 2),
 331                        ERASEINFO(0x08000, 1),
 332                        ERASEINFO(0x10000, 15),
 333                }
 334        },
 335        {
 336                .mfr_id         = (u16)STM_MANUFACT,
 337                .dev_id         = STM29F400BB,
 338                .name           = "ST Micro M29F400BB",
 339                .uaddr          = {
 340                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 341                },
 342                .DevSize                = SIZE_512KiB,
 343                .CmdSet                 = CFI_CMDSET_AMD_LEGACY,
 344                .NumEraseRegions        = 4,
 345                .regions                = {
 346                        ERASEINFO(0x04000, 1),
 347                        ERASEINFO(0x02000, 2),
 348                        ERASEINFO(0x08000, 1),
 349                        ERASEINFO(0x10000, 7),
 350                }
 351        },
 352#endif
 353};
 354
 355static inline void fill_info(flash_info_t *info, const struct amd_flash_info *jedec_entry, ulong base)
 356{
 357        int i,j;
 358        int sect_cnt;
 359        int size_ratio;
 360        int total_size;
 361        enum uaddr uaddr_idx;
 362
 363        size_ratio = info->portwidth / info->chipwidth;
 364
 365        debug("Found JEDEC Flash: %s\n", jedec_entry->name);
 366        info->vendor = jedec_entry->CmdSet;
 367        /* Todo: do we need device-specific timeouts? */
 368        info->erase_blk_tout = 30000;
 369        info->buffer_write_tout = 1000;
 370        info->write_tout = 100;
 371        info->name = jedec_entry->name;
 372
 373        /* copy unlock addresses from device table to CFI info struct. This
 374           is just here because the addresses are in the table anyway - if
 375           the flash is not detected due to wrong unlock addresses,
 376           flash_detect_legacy would have to try all of them before we even
 377           get here. */
 378        switch(info->chipwidth) {
 379        case FLASH_CFI_8BIT:
 380                uaddr_idx = jedec_entry->uaddr[0];
 381                break;
 382        case FLASH_CFI_16BIT:
 383                uaddr_idx = jedec_entry->uaddr[1];
 384                break;
 385        case FLASH_CFI_32BIT:
 386                uaddr_idx = jedec_entry->uaddr[2];
 387                break;
 388        default:
 389                uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
 390                break;
 391        }
 392
 393        debug("unlock address index %d\n", uaddr_idx);
 394        info->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
 395        info->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
 396        debug("unlock addresses are 0x%lx/0x%lx\n",
 397                info->addr_unlock1, info->addr_unlock2);
 398
 399        sect_cnt = 0;
 400        total_size = 0;
 401        for (i = 0; i < jedec_entry->NumEraseRegions; i++) {
 402                ulong erase_region_size = jedec_entry->regions[i] >> 8;
 403                ulong erase_region_count = (jedec_entry->regions[i] & 0xff) + 1;
 404
 405                total_size += erase_region_size * erase_region_count;
 406                debug("erase_region_count = %ld erase_region_size = %ld\n",
 407                       erase_region_count, erase_region_size);
 408                for (j = 0; j < erase_region_count; j++) {
 409                        if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
 410                                printf("ERROR: too many flash sectors\n");
 411                                break;
 412                        }
 413                        info->start[sect_cnt] = base;
 414                        base += (erase_region_size * size_ratio);
 415                        sect_cnt++;
 416                }
 417        }
 418        info->sector_count = sect_cnt;
 419        info->size = total_size * size_ratio;
 420}
 421
 422/*-----------------------------------------------------------------------
 423 * match jedec ids against table. If a match is found, fill flash_info entry
 424 */
 425int jedec_flash_match(flash_info_t *info, ulong base)
 426{
 427        int ret = 0;
 428        int i;
 429        ulong mask = 0xFFFF;
 430        if (info->chipwidth == 1)
 431                mask = 0xFF;
 432
 433        for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
 434                if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
 435                    (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
 436                        fill_info(info, &jedec_table[i], base);
 437                        ret = 1;
 438                        break;
 439                }
 440        }
 441        return ret;
 442}
 443