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