uboot/board/emk/common/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2003
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * (C) Copyright 2003
   6 * Reinhard Meyer, EMK Elektronik GmbH, r.meyer@emk-elektronik.de
   7 *
   8 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27#include <common.h>
  28
  29flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
  30
  31#if defined (CONFIG_TOP860)
  32  typedef unsigned short FLASH_PORT_WIDTH;
  33  typedef volatile unsigned short FLASH_PORT_WIDTHV;
  34  #define       FLASH_ID_MASK   0xFF
  35
  36  #define FPW   FLASH_PORT_WIDTH
  37  #define FPWV  FLASH_PORT_WIDTHV
  38
  39  #define FLASH_CYCLE1  0x0555
  40  #define FLASH_CYCLE2  0x02aa
  41  #define FLASH_ID1             0
  42  #define FLASH_ID2             1
  43  #define FLASH_ID3             0x0e
  44  #define FLASH_ID4             0x0F
  45#endif
  46
  47#if defined (CONFIG_TOP5200) && !defined (CONFIG_LITE5200)
  48  typedef unsigned char FLASH_PORT_WIDTH;
  49  typedef volatile unsigned char FLASH_PORT_WIDTHV;
  50  #define       FLASH_ID_MASK   0xFF
  51
  52  #define FPW   FLASH_PORT_WIDTH
  53  #define FPWV  FLASH_PORT_WIDTHV
  54
  55  #define FLASH_CYCLE1  0x0aaa
  56  #define FLASH_CYCLE2  0x0555
  57  #define FLASH_ID1             0
  58  #define FLASH_ID2             2
  59  #define FLASH_ID3             0x1c
  60  #define FLASH_ID4             0x1E
  61#endif
  62
  63#if defined (CONFIG_TOP5200) && defined (CONFIG_LITE5200)
  64  typedef unsigned char FLASH_PORT_WIDTH;
  65  typedef volatile unsigned char FLASH_PORT_WIDTHV;
  66  #define       FLASH_ID_MASK   0xFF
  67
  68  #define FPW   FLASH_PORT_WIDTH
  69  #define FPWV  FLASH_PORT_WIDTHV
  70
  71  #define FLASH_CYCLE1  0x0555
  72  #define FLASH_CYCLE2  0x02aa
  73  #define FLASH_ID1             0
  74  #define FLASH_ID2             1
  75  #define FLASH_ID3             0x0E
  76  #define FLASH_ID4             0x0F
  77#endif
  78
  79/*-----------------------------------------------------------------------
  80 * Functions
  81 */
  82static ulong flash_get_size(FPWV *addr, flash_info_t *info);
  83static void flash_reset(flash_info_t *info);
  84static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
  85flash_info_t *flash_get_info(ulong base);
  86
  87/*-----------------------------------------------------------------------
  88 * flash_init()
  89 *
  90 * sets up flash_info and returns size of FLASH (bytes)
  91 */
  92unsigned long flash_init (void)
  93{
  94        unsigned long size = 0;
  95        int i = 0;
  96        extern void flash_preinit(void);
  97        extern void flash_afterinit(uint, ulong, ulong);
  98        ulong flashbase = CONFIG_SYS_FLASH_BASE;
  99
 100        flash_preinit();
 101
 102        /* There is only ONE FLASH device */
 103        memset(&flash_info[i], 0, sizeof(flash_info_t));
 104        flash_info[i].size =
 105                        flash_get_size((FPW *)flashbase, &flash_info[i]);
 106        size += flash_info[i].size;
 107
 108#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
 109        /* monitor protection ON by default */
 110        flash_protect(FLAG_PROTECT_SET,
 111                      CONFIG_SYS_MONITOR_BASE,
 112                      CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
 113                      flash_get_info(CONFIG_SYS_MONITOR_BASE));
 114#endif
 115
 116#ifdef  CONFIG_ENV_IS_IN_FLASH
 117        /* ENV protection ON by default */
 118        flash_protect(FLAG_PROTECT_SET,
 119                      CONFIG_ENV_ADDR,
 120                      CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
 121                      flash_get_info(CONFIG_ENV_ADDR));
 122#endif
 123
 124
 125        flash_afterinit(i, flash_info[i].start[0], flash_info[i].size);
 126        return size ? size : 1;
 127}
 128
 129/*-----------------------------------------------------------------------
 130 */
 131static void flash_reset(flash_info_t *info)
 132{
 133        FPWV *base = (FPWV *)(info->start[0]);
 134
 135        /* Put FLASH back in read mode */
 136        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
 137                *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
 138        else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
 139                *base = (FPW)0x00F000F0;        /* AMD Read Mode */
 140}
 141
 142/*-----------------------------------------------------------------------
 143 */
 144
 145flash_info_t *flash_get_info(ulong base)
 146{
 147        int i;
 148        flash_info_t * info;
 149
 150        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
 151                info = & flash_info[i];
 152                if (info->size &&
 153                        info->start[0] <= base && base <= info->start[0] + info->size - 1)
 154                        break;
 155        }
 156
 157        return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
 158}
 159
 160/*-----------------------------------------------------------------------
 161 */
 162
 163void flash_print_info (flash_info_t *info)
 164{
 165        int i;
 166        uchar *boottype;
 167        uchar *bootletter;
 168        char *fmt;
 169        uchar botbootletter[] = "B";
 170        uchar topbootletter[] = "T";
 171        uchar botboottype[] = "bottom boot sector";
 172        uchar topboottype[] = "top boot sector";
 173
 174        if (info->flash_id == FLASH_UNKNOWN) {
 175                printf ("missing or unknown FLASH type\n");
 176                return;
 177        }
 178
 179        switch (info->flash_id & FLASH_VENDMASK) {
 180        case FLASH_MAN_AMD:     printf ("AMD ");                break;
 181#if 0
 182        case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
 183        case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
 184        case FLASH_MAN_SST:     printf ("SST ");                break;
 185        case FLASH_MAN_STM:     printf ("STM ");                break;
 186        case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
 187#endif
 188        default:                printf ("Unknown Vendor ");     break;
 189        }
 190
 191        /* check for top or bottom boot, if it applies */
 192        if (info->flash_id & FLASH_BTYPE) {
 193                boottype = botboottype;
 194                bootletter = botbootletter;
 195        }
 196        else {
 197                boottype = topboottype;
 198                bootletter = topbootletter;
 199        }
 200
 201        switch (info->flash_id & FLASH_TYPEMASK) {
 202        case FLASH_AM160T:
 203        case FLASH_AM160B:
 204                fmt = "29LV160%s (16 Mbit, %s)\n";
 205                break;
 206        case FLASH_AMLV640U:
 207                fmt = "29LV640M (64 Mbit)\n";
 208                break;
 209        case FLASH_AMDLV065D:
 210                fmt = "29LV065D (64 Mbit)\n";
 211                break;
 212        case FLASH_AMLV256U:
 213                fmt = "29LV256M (256 Mbit)\n";
 214                break;
 215        default:
 216                fmt = "Unknown Chip Type\n";
 217                break;
 218        }
 219
 220        printf (fmt, bootletter, boottype);
 221
 222        printf ("  Size: %ld MB in %d Sectors\n",
 223                info->size >> 20,
 224                info->sector_count);
 225
 226        printf ("  Sector Start Addresses:");
 227
 228        for (i=0; i<info->sector_count; ++i) {
 229                ulong   size;
 230                int             erased;
 231                ulong   *flash = (unsigned long *) info->start[i];
 232
 233                if ((i % 5) == 0) {
 234                        printf ("\n   ");
 235                }
 236
 237                /*
 238                 * Check if whole sector is erased
 239                 */
 240                size =
 241                        (i != (info->sector_count - 1)) ?
 242                        (info->start[i + 1] - info->start[i]) >> 2 :
 243                (info->start[0] + info->size - info->start[i]) >> 2;
 244
 245                for (
 246                        flash = (unsigned long *) info->start[i], erased = 1;
 247                                (flash != (unsigned long *) info->start[i] + size) && erased;
 248                                        flash++
 249                        )
 250                        erased = *flash == ~0x0UL;
 251
 252                printf (" %08lX %s %s",
 253                        info->start[i],
 254                        erased ? "E": " ",
 255                        info->protect[i] ? "(RO)" : "    ");
 256        }
 257
 258        printf ("\n");
 259}
 260
 261/*-----------------------------------------------------------------------
 262 */
 263
 264/*
 265 * The following code cannot be run from FLASH!
 266 */
 267
 268ulong flash_get_size (FPWV *addr, flash_info_t *info)
 269{
 270        int             i;
 271
 272        /* Write auto select command: read Manufacturer ID */
 273        /* Write auto select command sequence and test FLASH answer */
 274        addr[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* for AMD, Intel ignores this */
 275        addr[FLASH_CYCLE2] = (FPW)0x00550055;   /* for AMD, Intel ignores this */
 276        addr[FLASH_CYCLE1] = (FPW)0x00900090;   /* selects Intel or AMD */
 277
 278        /* The manufacturer codes are only 1 byte, so just use 1 byte.
 279         * This works for any bus width and any FLASH device width.
 280         */
 281        udelay(100);
 282        switch (addr[FLASH_ID1] & 0xff) {
 283
 284        case (uchar)AMD_MANUFACT:
 285                info->flash_id = FLASH_MAN_AMD;
 286                break;
 287
 288#if 0
 289        case (uchar)INTEL_MANUFACT:
 290                info->flash_id = FLASH_MAN_INTEL;
 291                break;
 292#endif
 293
 294        default:
 295                printf ("unknown vendor=%x ", addr[FLASH_ID1] & 0xff);
 296                info->flash_id = FLASH_UNKNOWN;
 297                info->sector_count = 0;
 298                info->size = 0;
 299                break;
 300        }
 301
 302        /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
 303        if (info->flash_id != FLASH_UNKNOWN) switch ((FPW)addr[FLASH_ID2]) {
 304
 305        case (FPW)AMD_ID_LV160B:
 306                info->flash_id += FLASH_AM160B;
 307                info->sector_count = 35;
 308                info->size = 0x00200000;
 309                info->start[0] = (ulong)addr;
 310                info->start[1] = (ulong)addr + 0x4000;
 311                info->start[2] = (ulong)addr + 0x6000;
 312                info->start[3] = (ulong)addr + 0x8000;
 313                for (i = 4; i < info->sector_count; i++)
 314                {
 315                        info->start[i] = (ulong)addr + 0x10000 * (i-3);
 316                }
 317                break;
 318
 319        case (FPW)AMD_ID_LV065D:
 320                info->flash_id += FLASH_AMDLV065D;
 321                info->sector_count = 128;
 322                info->size = 0x00800000;
 323                for (i = 0; i < info->sector_count; i++)
 324                {
 325                        info->start[i] = (ulong)addr + 0x10000 * i;
 326                }
 327                break;
 328
 329        case (FPW)AMD_ID_MIRROR:
 330                /* MIRROR BIT FLASH, read more ID bytes */
 331                if ((FPW)addr[FLASH_ID3] == (FPW)AMD_ID_LV640U_2 &&
 332                        (FPW)addr[FLASH_ID4] == (FPW)AMD_ID_LV640U_3)
 333                {
 334                        info->flash_id += FLASH_AMLV640U;
 335                        info->sector_count = 128;
 336                        info->size = 0x00800000;
 337                        for (i = 0; i < info->sector_count; i++)
 338                        {
 339                                info->start[i] = (ulong)addr + 0x10000 * i;
 340                        }
 341                        break;
 342                }
 343                if ((FPW)addr[FLASH_ID3] == (FPW)AMD_ID_LV256U_2 &&
 344                        (FPW)addr[FLASH_ID4] == (FPW)AMD_ID_LV256U_3)
 345                {
 346                        /* attention: only the first 16 MB will be used in u-boot */
 347                        info->flash_id += FLASH_AMLV256U;
 348                        info->sector_count = 256;
 349                        info->size = 0x01000000;
 350                        for (i = 0; i < info->sector_count; i++)
 351                        {
 352                                info->start[i] = (ulong)addr + 0x10000 * i;
 353                        }
 354                        break;
 355                }
 356
 357                /* fall thru to here ! */
 358        default:
 359                printf ("unknown AMD device=%x %x %x",
 360                        (FPW)addr[FLASH_ID2],
 361                        (FPW)addr[FLASH_ID3],
 362                        (FPW)addr[FLASH_ID4]);
 363                info->flash_id = FLASH_UNKNOWN;
 364                info->sector_count = 0;
 365                info->size = 0x800000;
 366                break;
 367        }
 368
 369        /* Put FLASH back in read mode */
 370        flash_reset(info);
 371
 372        return (info->size);
 373}
 374
 375/*-----------------------------------------------------------------------
 376 */
 377
 378int     flash_erase (flash_info_t *info, int s_first, int s_last)
 379{
 380        FPWV *addr;
 381        int flag, prot, sect;
 382        int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
 383        ulong start, now, last;
 384        int rcode = 0;
 385
 386        if ((s_first < 0) || (s_first > s_last)) {
 387                if (info->flash_id == FLASH_UNKNOWN) {
 388                        printf ("- missing\n");
 389                } else {
 390                        printf ("- no sectors to erase\n");
 391                }
 392                return 1;
 393        }
 394
 395        switch (info->flash_id & FLASH_TYPEMASK) {
 396        case FLASH_AM160B:
 397        case FLASH_AMLV640U:
 398                break;
 399        case FLASH_UNKNOWN:
 400        default:
 401                printf ("Can't erase unknown flash type %08lx - aborted\n",
 402                        info->flash_id);
 403                return 1;
 404        }
 405
 406        prot = 0;
 407        for (sect=s_first; sect<=s_last; ++sect) {
 408                if (info->protect[sect]) {
 409                        prot++;
 410                }
 411        }
 412
 413        if (prot) {
 414                printf ("- Warning: %d protected sectors will not be erased!\n",
 415                        prot);
 416        } else {
 417                printf ("\n");
 418        }
 419
 420        last  = get_timer(0);
 421
 422        /* Start erase on unprotected sectors */
 423        for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
 424
 425                if (info->protect[sect] != 0)   /* protected, skip it */
 426                        continue;
 427
 428                /* Disable interrupts which might cause a timeout here */
 429                flag = disable_interrupts();
 430
 431                addr = (FPWV *)(info->start[sect]);
 432                if (intel) {
 433                        *addr = (FPW)0x00500050; /* clear status register */
 434                        *addr = (FPW)0x00200020; /* erase setup */
 435                        *addr = (FPW)0x00D000D0; /* erase confirm */
 436                }
 437                else {
 438                        /* must be AMD style if not Intel */
 439                        FPWV *base;             /* first address in bank */
 440
 441                        base = (FPWV *)(info->start[0]);
 442                        base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
 443                        base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
 444                        base[FLASH_CYCLE1] = (FPW)0x00800080;   /* erase mode */
 445                        base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
 446                        base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
 447                        *addr = (FPW)0x00300030;        /* erase sector */
 448                }
 449
 450                /* re-enable interrupts if necessary */
 451                if (flag)
 452                        enable_interrupts();
 453
 454                start = get_timer(0);
 455
 456                /* wait at least 50us for AMD, 80us for Intel.
 457                 * Let's wait 1 ms.
 458                 */
 459                udelay (1000);
 460
 461                while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
 462                        if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 463                                printf ("Timeout\n");
 464
 465                                if (intel) {
 466                                        /* suspend erase        */
 467                                        *addr = (FPW)0x00B000B0;
 468                                }
 469
 470                                flash_reset(info);      /* reset to read mode */
 471                                rcode = 1;              /* failed */
 472                                break;
 473                        }
 474
 475                        /* show that we're waiting */
 476                        if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */
 477                                putc ('.');
 478                                last = get_timer(0);
 479                        }
 480                }
 481
 482                /* show that we're waiting */
 483                if ((get_timer(last)) > CONFIG_SYS_HZ) {        /* every second */
 484                        putc ('.');
 485                        last = get_timer(0);
 486                }
 487
 488                flash_reset(info);      /* reset to read mode */
 489        }
 490
 491        printf (" done\n");
 492        return rcode;
 493}
 494
 495/*-----------------------------------------------------------------------
 496 * Copy memory to flash, returns:
 497 * 0 - OK
 498 * 1 - write timeout
 499 * 2 - Flash not erased
 500 */
 501int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 502{
 503        FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
 504        int bytes;        /* number of bytes to program in current word         */
 505        int left;         /* number of bytes left to program                    */
 506        int i, res;
 507
 508        for (left = cnt, res = 0;
 509                 left > 0 && res == 0;
 510                 addr += sizeof(data), left -= sizeof(data) - bytes) {
 511
 512                bytes = addr & (sizeof(data) - 1);
 513                addr &= ~(sizeof(data) - 1);
 514
 515                /* combine source and destination data so can program
 516                 * an entire word of 16 or 32 bits
 517                 */
 518                for (i = 0; i < sizeof(data); i++) {
 519                        data <<= 8;
 520                        if (i < bytes || i - bytes >= left )
 521                                data += *((uchar *)addr + i);
 522                        else
 523                                data += *src++;
 524                }
 525
 526                /* write one word to the flash */
 527                switch (info->flash_id & FLASH_VENDMASK) {
 528                case FLASH_MAN_AMD:
 529                        res = write_word_amd(info, (FPWV *)addr, data);
 530                        break;
 531                default:
 532                        /* unknown flash type, error! */
 533                        printf ("missing or unknown FLASH type\n");
 534                        res = 1;        /* not really a timeout, but gives error */
 535                        break;
 536                }
 537        }
 538
 539        return (res);
 540}
 541
 542/*-----------------------------------------------------------------------
 543 * Write a word to Flash for AMD FLASH
 544 * A word is 16 or 32 bits, whichever the bus width of the flash bank
 545 * (not an individual chip) is.
 546 *
 547 * returns:
 548 * 0 - OK
 549 * 1 - write timeout
 550 * 2 - Flash not erased
 551 */
 552static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
 553{
 554        ulong start;
 555        int flag;
 556        int res = 0;    /* result, assume success       */
 557        FPWV *base;             /* first address in flash bank  */
 558
 559        /* Check if Flash is (sufficiently) erased */
 560        if ((*dest & data) != data) {
 561                return (2);
 562        }
 563
 564
 565        base = (FPWV *)(info->start[0]);
 566
 567        /* Disable interrupts which might cause a timeout here */
 568        flag = disable_interrupts();
 569
 570        base[FLASH_CYCLE1] = (FPW)0x00AA00AA;   /* unlock */
 571        base[FLASH_CYCLE2] = (FPW)0x00550055;   /* unlock */
 572        base[FLASH_CYCLE1] = (FPW)0x00A000A0;   /* selects program mode */
 573
 574        *dest = data;           /* start programming the data   */
 575
 576        /* re-enable interrupts if necessary */
 577        if (flag)
 578                enable_interrupts();
 579
 580        start = get_timer (0);
 581
 582        /* data polling for D7 */
 583        while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
 584                if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 585                        *dest = (FPW)0x00F000F0;        /* reset bank */
 586                        res = 1;
 587                }
 588        }
 589
 590        return (res);
 591}
 592