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