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