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 <flash.h>
  16#include <log.h>
  17#include <asm/processor.h>
  18#include <asm/io.h>
  19#include <asm/byteorder.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)AMD_MANUFACT,
 337                .dev_id         = AM29LV800BT,
 338                .name           = "AMD AM29LV800BT",
 339                .uaddr          = {
 340                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 341                },
 342                .DevSize        = SIZE_1MiB,
 343                .CmdSet         = CFI_CMDSET_AMD_LEGACY,
 344                .NumEraseRegions= 4,
 345                .regions        = {
 346                        ERASEINFO(0x10000, 15),
 347                        ERASEINFO(0x08000, 1),
 348                        ERASEINFO(0x02000, 2),
 349                        ERASEINFO(0x04000, 1),
 350                }
 351        },
 352        {
 353                .mfr_id         = (u16)MX_MANUFACT,
 354                .dev_id         = AM29LV800BT,
 355                .name           = "MXIC MX29LV800BT",
 356                .uaddr          = {
 357                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 358                },
 359                .DevSize        = SIZE_1MiB,
 360                .CmdSet         = CFI_CMDSET_AMD_LEGACY,
 361                .NumEraseRegions= 4,
 362                .regions        = {
 363                        ERASEINFO(0x10000, 15),
 364                        ERASEINFO(0x08000, 1),
 365                        ERASEINFO(0x02000, 2),
 366                        ERASEINFO(0x04000, 1),
 367                }
 368        },
 369        {
 370                .mfr_id         = (u16)EON_ALT_MANU,
 371                .dev_id         = AM29LV800BT,
 372                .name           = "EON EN29LV800BT",
 373                .uaddr          = {
 374                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 375                },
 376                .DevSize        = SIZE_1MiB,
 377                .CmdSet         = CFI_CMDSET_AMD_LEGACY,
 378                .NumEraseRegions= 4,
 379                .regions        = {
 380                        ERASEINFO(0x10000, 15),
 381                        ERASEINFO(0x08000, 1),
 382                        ERASEINFO(0x02000, 2),
 383                        ERASEINFO(0x04000, 1),
 384                }
 385        },
 386        {
 387                .mfr_id         = (u16)STM_MANUFACT,
 388                .dev_id         = STM29F400BB,
 389                .name           = "ST Micro M29F400BB",
 390                .uaddr          = {
 391                        [1] = MTD_UADDR_0x0555_0x02AA /* x16 */
 392                },
 393                .DevSize                = SIZE_512KiB,
 394                .CmdSet                 = CFI_CMDSET_AMD_LEGACY,
 395                .NumEraseRegions        = 4,
 396                .regions                = {
 397                        ERASEINFO(0x04000, 1),
 398                        ERASEINFO(0x02000, 2),
 399                        ERASEINFO(0x08000, 1),
 400                        ERASEINFO(0x10000, 7),
 401                }
 402        },
 403#endif
 404};
 405
 406static inline void fill_info(flash_info_t *info, const struct amd_flash_info *jedec_entry, ulong base)
 407{
 408        int i,j;
 409        int sect_cnt;
 410        int size_ratio;
 411        int total_size;
 412        enum uaddr uaddr_idx;
 413
 414        size_ratio = info->portwidth / info->chipwidth;
 415
 416        debug("Found JEDEC Flash: %s\n", jedec_entry->name);
 417        info->vendor = jedec_entry->CmdSet;
 418        /* Todo: do we need device-specific timeouts? */
 419        info->erase_blk_tout = 30000;
 420        info->buffer_write_tout = 1000;
 421        info->write_tout = 100;
 422        info->name = jedec_entry->name;
 423
 424        /* copy unlock addresses from device table to CFI info struct. This
 425           is just here because the addresses are in the table anyway - if
 426           the flash is not detected due to wrong unlock addresses,
 427           flash_detect_legacy would have to try all of them before we even
 428           get here. */
 429        switch(info->chipwidth) {
 430        case FLASH_CFI_8BIT:
 431                uaddr_idx = jedec_entry->uaddr[0];
 432                break;
 433        case FLASH_CFI_16BIT:
 434                uaddr_idx = jedec_entry->uaddr[1];
 435                break;
 436        case FLASH_CFI_32BIT:
 437                uaddr_idx = jedec_entry->uaddr[2];
 438                break;
 439        default:
 440                uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
 441                break;
 442        }
 443
 444        debug("unlock address index %d\n", uaddr_idx);
 445        info->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
 446        info->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
 447        debug("unlock addresses are 0x%lx/0x%lx\n",
 448                info->addr_unlock1, info->addr_unlock2);
 449
 450        sect_cnt = 0;
 451        total_size = 0;
 452        for (i = 0; i < jedec_entry->NumEraseRegions; i++) {
 453                ulong erase_region_size = jedec_entry->regions[i] >> 8;
 454                ulong erase_region_count = (jedec_entry->regions[i] & 0xff) + 1;
 455
 456                total_size += erase_region_size * erase_region_count;
 457                debug("erase_region_count = %ld erase_region_size = %ld\n",
 458                       erase_region_count, erase_region_size);
 459                for (j = 0; j < erase_region_count; j++) {
 460                        if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {
 461                                printf("ERROR: too many flash sectors\n");
 462                                break;
 463                        }
 464                        info->start[sect_cnt] = base;
 465                        base += (erase_region_size * size_ratio);
 466                        sect_cnt++;
 467                }
 468        }
 469        info->sector_count = sect_cnt;
 470        info->size = total_size * size_ratio;
 471}
 472
 473/*-----------------------------------------------------------------------
 474 * match jedec ids against table. If a match is found, fill flash_info entry
 475 */
 476int jedec_flash_match(flash_info_t *info, ulong base)
 477{
 478        int ret = 0;
 479        int i;
 480        ulong mask = 0xFFFF;
 481        if (info->chipwidth == 1)
 482                mask = 0xFF;
 483
 484        for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
 485                if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
 486                    (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
 487                        fill_info(info, &jedec_table[i], base);
 488                        ret = 1;
 489                        break;
 490                }
 491        }
 492        return ret;
 493}
 494