uboot/board/esd/pf5200/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
  26flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];    /* info for FLASH chips */
  27
  28typedef unsigned short FLASH_PORT_WIDTH;
  29typedef volatile unsigned short FLASH_PORT_WIDTHV;
  30
  31#define FLASH_ID_MASK           0x00FF
  32
  33#define FPW                     FLASH_PORT_WIDTH
  34#define FPWV                    FLASH_PORT_WIDTHV
  35
  36#define FLASH_CYCLE1            0x0555
  37#define FLASH_CYCLE2            0x0aaa
  38#define FLASH_ID1               0x00
  39#define FLASH_ID2               0x01
  40#define FLASH_ID3               0x0E
  41#define FLASH_ID4               0x0F
  42
  43/*-----------------------------------------------------------------------
  44 * Functions
  45 */
  46static ulong flash_get_size(FPWV * addr, flash_info_t * info);
  47static void flash_reset(flash_info_t * info);
  48static int write_word_amd(flash_info_t * info, FPWV * dest, FPW data);
  49static flash_info_t *flash_get_info(ulong base);
  50
  51/*-----------------------------------------------------------------------
  52 * flash_init()
  53 *
  54 * sets up flash_info and returns size of FLASH (bytes)
  55 */
  56unsigned long flash_init(void)
  57{
  58        unsigned long size = 0;
  59        int i = 0;
  60        extern void flash_preinit(void);
  61        extern void flash_afterinit(uint, ulong, ulong);
  62
  63        ulong flashbase = CONFIG_SYS_FLASH_BASE;
  64
  65        flash_preinit();
  66
  67        /* There is only ONE FLASH device */
  68        memset(&flash_info[i], 0, sizeof(flash_info_t));
  69        flash_info[i].size = flash_get_size((FPW *) flashbase, &flash_info[i]);
  70        size += flash_info[i].size;
  71
  72#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
  73        /* monitor protection ON by default */
  74        flash_protect(FLAG_PROTECT_SET, CONFIG_SYS_MONITOR_BASE,
  75                      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
  76                      flash_get_info(CONFIG_SYS_MONITOR_BASE));
  77#endif
  78
  79#ifdef  CONFIG_ENV_IS_IN_FLASH
  80        /* ENV protection ON by default */
  81        flash_protect(FLAG_PROTECT_SET, CONFIG_ENV_ADDR,
  82                      CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
  83                      flash_get_info(CONFIG_ENV_ADDR));
  84#endif
  85
  86        flash_afterinit(i, flash_info[i].start[0], flash_info[i].size);
  87        return size ? size : 1;
  88}
  89
  90/*-----------------------------------------------------------------------
  91 */
  92static void flash_reset(flash_info_t * info) {
  93        FPWV *base = (FPWV *) (info->start[0]);
  94
  95        /* Put FLASH back in read mode */
  96        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
  97                *base = (FPW) 0x00FF00FF;       /* Intel Read Mode */
  98        } else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) {
  99                *base = (FPW) 0x00F000F0;       /* AMD Read Mode */
 100        }
 101}
 102
 103/*-----------------------------------------------------------------------
 104 */
 105
 106static flash_info_t *flash_get_info(ulong base) {
 107        int i;
 108        flash_info_t *info;
 109
 110        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
 111                info = &flash_info[i];
 112                if ((info->size) && (info->start[0] <= base)
 113                    && (base <= info->start[0] + info->size - 1)) {
 114                        break;
 115                }
 116        }
 117        return (i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info);
 118}
 119
 120/*-----------------------------------------------------------------------
 121 */
 122
 123void flash_print_info(flash_info_t * info) {
 124        int i;
 125        char *fmt;
 126
 127        if (info->flash_id == FLASH_UNKNOWN) {
 128                printf("missing or unknown FLASH type\n");
 129                return;
 130        }
 131
 132        switch (info->flash_id & FLASH_VENDMASK) {
 133        case FLASH_MAN_AMD:
 134                printf("AMD ");
 135                break;
 136        default:
 137                printf("Unknown Vendor ");
 138                break;
 139        }
 140
 141        switch (info->flash_id & FLASH_TYPEMASK) {
 142        case FLASH_AMLV256U:
 143                fmt = "29LV256M (256 Mbit)\n";
 144                break;
 145        default:
 146                fmt = "Unknown Chip Type\n";
 147                break;
 148        }
 149
 150        printf(fmt);
 151        printf("  Size: %ld MB in %d Sectors\n", info->size >> 20,
 152               info->sector_count);
 153        printf("  Sector Start Addresses:");
 154
 155        for (i = 0; i < info->sector_count; ++i) {
 156                ulong size;
 157                int erased;
 158                ulong *flash = (unsigned long *)info->start[i];
 159
 160                if ((i % 5) == 0) {
 161                        printf("\n   ");
 162                }
 163
 164                /*
 165                 * Check if whole sector is erased
 166                 */
 167                size =
 168                    (i !=
 169                     (info->sector_count - 1)) ? (info->start[i + 1] -
 170                                                  info->start[i]) >> 2 : (info->
 171                                                                          start
 172                                                                          [0] +
 173                                                                          info->
 174                                                                          size -
 175                                                                          info->
 176                                                                          start
 177                                                                          [i])
 178                    >> 2;
 179
 180                for (flash = (unsigned long *)info->start[i], erased = 1;
 181                     (flash != (unsigned long *)info->start[i] + size)
 182                     && erased; flash++) {
 183                        erased = *flash == ~0x0UL;
 184                }
 185                printf(" %08lX %s %s", info->start[i], erased ? "E" : " ",
 186                       info->protect[i] ? "(RO)" : "    ");
 187        }
 188
 189        printf("\n");
 190}
 191
 192/*-----------------------------------------------------------------------
 193 */
 194
 195/*
 196 * The following code cannot be run from FLASH!
 197 */
 198
 199ulong flash_get_size(FPWV * addr, flash_info_t * info) {
 200        int i;
 201
 202        /* Write auto select command: read Manufacturer ID                     */
 203        /* Write auto select command sequence and test FLASH answer            */
 204        addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* for AMD, Intel ignores this */
 205        addr[FLASH_CYCLE2] = (FPW) 0x00550055;  /* for AMD, Intel ignores this */
 206        addr[FLASH_CYCLE1] = (FPW) 0x00900090;  /* selects Intel or AMD        */
 207
 208        /* The manufacturer codes are only 1 byte, so just use 1 byte.         */
 209        /* This works for any bus width and any FLASH device width.            */
 210        udelay(100);
 211        switch (addr[FLASH_ID1] & 0x00ff) {
 212        case (uchar) AMD_MANUFACT:
 213                info->flash_id = FLASH_MAN_AMD;
 214                break;
 215        default:
 216                printf("unknown vendor=%x ", addr[FLASH_ID1] & 0xff);
 217                info->flash_id = FLASH_UNKNOWN;
 218                info->sector_count = 0;
 219                info->size = 0;
 220                break;
 221        }
 222
 223        /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus.     */
 224        if (info->flash_id != FLASH_UNKNOWN) {
 225                switch ((FPW) addr[FLASH_ID2]) {
 226                case (FPW) AMD_ID_MIRROR:
 227                        /* MIRROR BIT FLASH, read more ID bytes */
 228                        if ((FPW) addr[FLASH_ID3] == (FPW) AMD_ID_LV256U_2
 229                            && (FPW) addr[FLASH_ID4] == (FPW) AMD_ID_LV256U_3) {
 230                                /* attention: only the first 16 MB will be used in u-boot */
 231                                info->flash_id += FLASH_AMLV256U;
 232                                info->sector_count = 512;
 233                                info->size = 0x02000000;
 234                                for (i = 0; i < info->sector_count; i++) {
 235                                        info->start[i] =
 236                                            (ulong) addr + 0x10000 * i;
 237                                }
 238                                break;
 239                        }
 240                        /* fall thru to here ! */
 241                default:
 242                        printf("unknown AMD device=%x %x %x",
 243                               (FPW) addr[FLASH_ID2], (FPW) addr[FLASH_ID3],
 244                               (FPW) addr[FLASH_ID4]);
 245                        info->flash_id = FLASH_UNKNOWN;
 246                        info->sector_count = 0;
 247                        info->size = 0x800000;
 248                        break;
 249                }
 250
 251                /* Put FLASH back in read mode */
 252                flash_reset(info);
 253        }
 254        return (info->size);
 255}
 256
 257/*-----------------------------------------------------------------------
 258 */
 259
 260int flash_erase(flash_info_t * info, int s_first, int s_last) {
 261        FPWV *addr;
 262        int flag, prot, sect;
 263        int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
 264        ulong start, now, last;
 265        int rcode = 0;
 266
 267        if ((s_first < 0) || (s_first > s_last)) {
 268                if (info->flash_id == FLASH_UNKNOWN) {
 269                        printf("- missing\n");
 270                } else {
 271                        printf("- no sectors to erase\n");
 272                }
 273                return 1;
 274        }
 275
 276        switch (info->flash_id & FLASH_TYPEMASK) {
 277        case FLASH_AMLV256U:
 278                break;
 279        case FLASH_UNKNOWN:
 280        default:
 281                printf("Can't erase unknown flash type %08lx - aborted\n",
 282                       info->flash_id);
 283                return 1;
 284        }
 285
 286        prot = 0;
 287        for (sect = s_first; sect <= s_last; ++sect) {
 288                if (info->protect[sect]) {
 289                        prot++;
 290                }
 291        }
 292
 293        if (prot) {
 294                printf("- Warning: %d protected sectors will not be erased!\n",
 295                       prot);
 296        } else {
 297                printf("\n");
 298        }
 299
 300        last = get_timer(0);
 301
 302        /* Start erase on unprotected sectors */
 303        for (sect = s_first; sect <= s_last && rcode == 0; sect++) {
 304                if (info->protect[sect] != 0) { /* protected, skip it */
 305                        continue;
 306                }
 307                /* Disable interrupts which might cause a timeout here */
 308                flag = disable_interrupts();
 309
 310                addr = (FPWV *) (info->start[sect]);
 311                if (intel) {
 312                        *addr = (FPW) 0x00500050;       /* clear status register */
 313                        *addr = (FPW) 0x00200020;       /* erase setup */
 314                        *addr = (FPW) 0x00D000D0;       /* erase confirm */
 315                } else {
 316                        /* must be AMD style if not Intel */
 317                        FPWV *base;     /* first address in bank */
 318
 319                        base = (FPWV *) (info->start[0]);
 320                        base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
 321                        base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
 322                        base[FLASH_CYCLE1] = (FPW) 0x00800080;  /* erase mode */
 323                        base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
 324                        base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
 325                        *addr = (FPW) 0x00300030;       /* erase sector */
 326                }
 327
 328                /* re-enable interrupts if necessary */
 329                if (flag) {
 330                        enable_interrupts();
 331                }
 332                start = get_timer(0);
 333
 334                /* wait at least 50us for AMD, 80us for Intel. */
 335                /* Let's wait 1 ms.                            */
 336                udelay(1000);
 337
 338                while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) {
 339                        if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 340                                printf("Timeout\n");
 341                                if (intel) {
 342                                        /* suspend erase        */
 343                                        *addr = (FPW) 0x00B000B0;
 344                                }
 345                                flash_reset(info);      /* reset to read mode */
 346                                rcode = 1;      /* failed */
 347                                break;
 348                        }
 349                        /* show that we're waiting */
 350                        if ((get_timer(last)) > CONFIG_SYS_HZ) {
 351                                /* every second */
 352                                putc('.');
 353                                last = get_timer(0);
 354                        }
 355                }
 356                /* show that we're waiting */
 357                if ((get_timer(last)) > CONFIG_SYS_HZ) {
 358                        /* every second */
 359                        putc('.');
 360                        last = get_timer(0);
 361                }
 362                flash_reset(info);      /* reset to read mode */
 363        }
 364        printf(" done\n");
 365        return (rcode);
 366}
 367
 368/*-----------------------------------------------------------------------
 369 * Copy memory to flash, returns:
 370 * 0 - OK
 371 * 1 - write timeout
 372 * 2 - Flash not erased
 373 */
 374int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 375{
 376        FPW data = 0;           /* 16 or 32 bit word, matches flash bus width on MPC8XX */
 377        int bytes;              /* number of bytes to program in current word         */
 378        int left;               /* number of bytes left to program                    */
 379        int i, res;
 380
 381        for (left = cnt, res = 0;
 382             left > 0 && res == 0;
 383             addr += sizeof(data), left -= sizeof(data) - bytes) {
 384
 385                bytes = addr & (sizeof(data) - 1);
 386                addr &= ~(sizeof(data) - 1);
 387
 388                /* combine source and destination data so can program
 389                 * an entire word of 16 or 32 bits
 390                 */
 391                for (i = 0; i < sizeof(data); i++) {
 392                        data <<= 8;
 393                        if (i < bytes || i - bytes >= left)
 394                                data += *((uchar *) addr + i);
 395                        else
 396                                data += *src++;
 397                }
 398
 399                /* write one word to the flash */
 400                switch (info->flash_id & FLASH_VENDMASK) {
 401                case FLASH_MAN_AMD:
 402                        res = write_word_amd(info, (FPWV *) addr, data);
 403                        break;
 404                default:
 405                        /* unknown flash type, error! */
 406                        printf("missing or unknown FLASH type\n");
 407                        res = 1;        /* not really a timeout, but gives error */
 408                        break;
 409                }
 410        }
 411        return (res);
 412}
 413
 414/*-----------------------------------------------------------------------
 415 * Write a word to Flash for AMD FLASH
 416 * A word is 16 or 32 bits, whichever the bus width of the flash bank
 417 * (not an individual chip) is.
 418 *
 419 * returns:
 420 * 0 - OK
 421 * 1 - write timeout
 422 * 2 - Flash not erased
 423 */
 424static int write_word_amd(flash_info_t * info, FPWV * dest, FPW data) {
 425        ulong start;
 426        int flag;
 427        int res = 0;            /* result, assume success       */
 428        FPWV *base;             /* first address in flash bank  */
 429
 430        /* Check if Flash is (sufficiently) erased */
 431        if ((*dest & data) != data) {
 432                return (2);
 433        }
 434
 435        base = (FPWV *) (info->start[0]);
 436
 437        /* Disable interrupts which might cause a timeout here */
 438        flag = disable_interrupts();
 439
 440        base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
 441        base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
 442        base[FLASH_CYCLE1] = (FPW) 0x00A000A0;  /* selects program mode */
 443
 444        *dest = data;           /* start programming the data   */
 445
 446        /* re-enable interrupts if necessary */
 447        if (flag) {
 448                enable_interrupts();
 449        }
 450        start = get_timer(0);
 451
 452        /* data polling for D7 */
 453        while (res == 0
 454               && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) {
 455                if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 456                        *dest = (FPW) 0x00F000F0;       /* reset bank */
 457                        res = 1;
 458                }
 459        }
 460        return (res);
 461}
 462