uboot/board/pcippc2/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2001
   3 * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
   4 *
   5 * (C) Copyright 2002
   6 * Wolfgang Denk, DENX Software Engineering, wd@denx.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 <config.h>
  28#include <common.h>
  29#include <flash.h>
  30#include <asm/io.h>
  31
  32/*---------------------------------------------------------------------*/
  33#undef DEBUG_FLASH
  34
  35#ifdef DEBUG_FLASH
  36#define DEBUGF(fmt,args...) printf(fmt ,##args)
  37#else
  38#define DEBUGF(fmt,args...)
  39#endif
  40/*---------------------------------------------------------------------*/
  41
  42flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
  43
  44static ulong flash_get_size (ulong addr, flash_info_t *info);
  45static int flash_get_offsets (ulong base, flash_info_t *info);
  46static int write_word (flash_info_t *info, ulong dest, ulong data);
  47static void flash_reset (ulong addr);
  48
  49unsigned long flash_init (void)
  50{
  51        unsigned int i;
  52        unsigned long flash_size = 0;
  53
  54        /* Init: no FLASHes known */
  55        for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
  56                flash_info[i].flash_id = FLASH_UNKNOWN;
  57                flash_info[i].sector_count = 0;
  58                flash_info[i].size = 0;
  59        }
  60
  61        DEBUGF("\n## Get flash size @ 0x%08x\n", CONFIG_SYS_FLASH_BASE);
  62
  63        flash_size = flash_get_size (CONFIG_SYS_FLASH_BASE, flash_info);
  64
  65        DEBUGF("## Flash bank size: %08lx\n", flash_size);
  66
  67        if (flash_size) {
  68#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE && \
  69    CONFIG_SYS_MONITOR_BASE < CONFIG_SYS_FLASH_BASE + CONFIG_SYS_FLASH_MAX_SIZE
  70                /* monitor protection ON by default */
  71                flash_protect(FLAG_PROTECT_SET,
  72                              CONFIG_SYS_MONITOR_BASE,
  73                              CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
  74                              &flash_info[0]);
  75#endif
  76
  77#ifdef CONFIG_ENV_IS_IN_FLASH
  78                /* ENV protection ON by default */
  79                flash_protect(FLAG_PROTECT_SET,
  80                              CONFIG_ENV_ADDR,
  81                              CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
  82                              &flash_info[0]);
  83#endif
  84
  85        } else {
  86                puts ("Warning: the BOOT Flash is not initialised !");
  87        }
  88
  89        return flash_size;
  90}
  91
  92/*
  93 * The following code cannot be run from FLASH!
  94 */
  95static ulong flash_get_size (ulong addr, flash_info_t *info)
  96{
  97        short i;
  98        uchar value;
  99
 100        /* Write auto select command: read Manufacturer ID */
 101        out8(addr + 0x0555, 0xAA);
 102        iobarrier_rw();
 103        out8(addr + 0x02AA, 0x55);
 104        iobarrier_rw();
 105        out8(addr + 0x0555, 0x90);
 106        iobarrier_rw();
 107
 108        value = in8(addr);
 109        iobarrier_rw();
 110
 111        DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
 112
 113        switch (value | (value << 16)) {
 114                case AMD_MANUFACT:
 115                        info->flash_id = FLASH_MAN_AMD;
 116                        break;
 117
 118                case FUJ_MANUFACT:
 119                        info->flash_id = FLASH_MAN_FUJ;
 120                        break;
 121
 122                case STM_MANUFACT:
 123                        info->flash_id = FLASH_MAN_STM;
 124                        break;
 125
 126                default:
 127                        info->flash_id = FLASH_UNKNOWN;
 128                        info->sector_count = 0;
 129                        info->size = 0;
 130                        flash_reset (addr);
 131                        return 0;
 132        }
 133
 134        value = in8(addr + 1);                  /* device ID            */
 135        iobarrier_rw();
 136
 137        DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
 138
 139        switch ((ulong)value) {
 140                case AMD_ID_F040B:
 141                        DEBUGF("Am29F040B\n");
 142                        info->flash_id += FLASH_AM040;
 143                        info->sector_count = 8;
 144                        info->size = 0x00080000;
 145                        break;                  /* => 512 kB            */
 146
 147                case AMD_ID_LV040B:
 148                        DEBUGF("Am29LV040B\n");
 149                        info->flash_id += FLASH_AM040;
 150                        info->sector_count = 8;
 151                        info->size = 0x00080000;
 152                        break;                  /* => 512 kB            */
 153
 154                case AMD_ID_LV400T:
 155                        DEBUGF("Am29LV400T\n");
 156                        info->flash_id += FLASH_AM400T;
 157                        info->sector_count = 11;
 158                        info->size = 0x00100000;
 159                        break;                  /* => 1 MB              */
 160
 161                case AMD_ID_LV400B:
 162                        DEBUGF("Am29LV400B\n");
 163                        info->flash_id += FLASH_AM400B;
 164                        info->sector_count = 11;
 165                        info->size = 0x00100000;
 166                        break;                  /* => 1 MB              */
 167
 168                case AMD_ID_LV800T:
 169                        DEBUGF("Am29LV800T\n");
 170                        info->flash_id += FLASH_AM800T;
 171                        info->sector_count = 19;
 172                        info->size = 0x00200000;
 173                        break;                  /* => 2 MB              */
 174
 175                case AMD_ID_LV800B:
 176                        DEBUGF("Am29LV400B\n");
 177                        info->flash_id += FLASH_AM800B;
 178                        info->sector_count = 19;
 179                        info->size = 0x00200000;
 180                        break;                  /* => 2 MB              */
 181
 182                case AMD_ID_LV160T:
 183                        DEBUGF("Am29LV160T\n");
 184                        info->flash_id += FLASH_AM160T;
 185                        info->sector_count = 35;
 186                        info->size = 0x00400000;
 187                        break;                  /* => 4 MB              */
 188
 189                case AMD_ID_LV160B:
 190                        DEBUGF("Am29LV160B\n");
 191                        info->flash_id += FLASH_AM160B;
 192                        info->sector_count = 35;
 193                        info->size = 0x00400000;
 194                        break;                  /* => 4 MB              */
 195
 196                case AMD_ID_LV320T:
 197                        DEBUGF("Am29LV320T\n");
 198                        info->flash_id += FLASH_AM320T;
 199                        info->sector_count = 67;
 200                        info->size = 0x00800000;
 201                        break;                  /* => 8 MB              */
 202
 203#if 0
 204                /* Has the same ID as AMD_ID_LV320T, to be fixed */
 205                case AMD_ID_LV320B:
 206                        DEBUGF("Am29LV320B\n");
 207                        info->flash_id += FLASH_AM320B;
 208                        info->sector_count = 67;
 209                        info->size = 0x00800000;
 210                        break;                  /* => 8 MB              */
 211#endif
 212
 213                case AMD_ID_LV033C:
 214                        DEBUGF("Am29LV033C\n");
 215                        info->flash_id += FLASH_AM033C;
 216                        info->sector_count = 64;
 217                        info->size = 0x01000000;
 218                        break;                  /* => 16Mb              */
 219
 220                case STM_ID_F040B:
 221                        DEBUGF("M29F040B\n");
 222                        info->flash_id += FLASH_AM040;
 223                        info->sector_count = 8;
 224                        info->size = 0x00080000;
 225                        break;                  /* => 512 kB            */
 226
 227                default:
 228                        info->flash_id = FLASH_UNKNOWN;
 229                        flash_reset (addr);
 230                        return (0);             /* => no or unknown flash */
 231
 232        }
 233
 234        if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
 235                printf ("** ERROR: sector count %d > max (%d) **\n",
 236                        info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
 237                info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
 238        }
 239
 240        if (! flash_get_offsets (addr, info)) {
 241                flash_reset (addr);
 242                return 0;
 243        }
 244
 245        /* check for protected sectors */
 246        for (i = 0; i < info->sector_count; i++) {
 247                /* read sector protection at sector address, (A7 .. A0) = 0x02 */
 248                /* D0 = 1 if protected */
 249                value = in8(info->start[i] + 2);
 250                iobarrier_rw();
 251                info->protect[i] = (value & 1) != 0;
 252        }
 253
 254        /*
 255         * Reset bank to read mode
 256         */
 257        flash_reset (addr);
 258
 259        return (info->size);
 260}
 261
 262static int flash_get_offsets (ulong base, flash_info_t *info)
 263{
 264        unsigned int i;
 265
 266        switch (info->flash_id & FLASH_TYPEMASK) {
 267                case FLASH_AM040:
 268                        /* set sector offsets for uniform sector type   */
 269                        for (i = 0; i < info->sector_count; i++) {
 270                                info->start[i] = base + i * info->size /
 271                                                            info->sector_count;
 272                        }
 273                        break;
 274                default:
 275                        return 0;
 276        }
 277
 278        return 1;
 279}
 280
 281int flash_erase (flash_info_t *info, int s_first, int s_last)
 282{
 283        volatile ulong addr = info->start[0];
 284        int flag, prot, sect, l_sect;
 285        ulong start, now, last;
 286
 287        if (s_first < 0 || s_first > s_last) {
 288                if (info->flash_id == FLASH_UNKNOWN) {
 289                        printf ("- missing\n");
 290                } else {
 291                        printf ("- no sectors to erase\n");
 292                }
 293                return 1;
 294        }
 295
 296        if (info->flash_id == FLASH_UNKNOWN) {
 297                printf ("Can't erase unknown flash type %08lx - aborted\n",
 298                        info->flash_id);
 299                return 1;
 300        }
 301
 302        prot = 0;
 303        for (sect=s_first; sect<=s_last; ++sect) {
 304                if (info->protect[sect]) {
 305                        prot++;
 306                }
 307        }
 308
 309        if (prot) {
 310                printf ("- Warning: %d protected sectors will not be erased!\n",
 311                        prot);
 312        } else {
 313                printf ("\n");
 314        }
 315
 316        l_sect = -1;
 317
 318        /* Disable interrupts which might cause a timeout here */
 319        flag = disable_interrupts();
 320
 321        out8(addr + 0x555, 0xAA);
 322        iobarrier_rw();
 323        out8(addr + 0x2AA, 0x55);
 324        iobarrier_rw();
 325        out8(addr + 0x555, 0x80);
 326        iobarrier_rw();
 327        out8(addr + 0x555, 0xAA);
 328        iobarrier_rw();
 329        out8(addr + 0x2AA, 0x55);
 330        iobarrier_rw();
 331
 332        /* Start erase on unprotected sectors */
 333        for (sect = s_first; sect<=s_last; sect++) {
 334                if (info->protect[sect] == 0) { /* not protected */
 335                        addr = info->start[sect];
 336                        out8(addr, 0x30);
 337                        iobarrier_rw();
 338                        l_sect = sect;
 339                }
 340        }
 341
 342        /* re-enable interrupts if necessary */
 343        if (flag)
 344                enable_interrupts();
 345
 346        /* wait at least 80us - let's wait 1 ms */
 347        udelay (1000);
 348
 349        /*
 350         * We wait for the last triggered sector
 351         */
 352        if (l_sect < 0)
 353                goto DONE;
 354
 355        start = get_timer (0);
 356        last  = start;
 357        addr = info->start[l_sect];
 358
 359        DEBUGF ("Start erase timeout: %d\n", CONFIG_SYS_FLASH_ERASE_TOUT);
 360
 361        while ((in8(addr) & 0x80) != 0x80) {
 362                if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 363                        printf ("Timeout\n");
 364                        flash_reset (info->start[0]);
 365                        return 1;
 366                }
 367                /* show that we're waiting */
 368                if ((now - last) > 1000) {      /* every second */
 369                        putc ('.');
 370                        last = now;
 371                }
 372                iobarrier_rw();
 373        }
 374
 375DONE:
 376        /* reset to read mode */
 377        flash_reset (info->start[0]);
 378
 379        printf (" done\n");
 380        return 0;
 381}
 382
 383/*
 384 * Copy memory to flash, returns:
 385 * 0 - OK
 386 * 1 - write timeout
 387 * 2 - Flash not erased
 388 */
 389int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 390{
 391        ulong cp, wp, data;
 392        int i, l, rc;
 393
 394        wp = (addr & ~3);       /* get lower word aligned address */
 395
 396        /*
 397         * handle unaligned start bytes
 398         */
 399        if ((l = addr - wp) != 0) {
 400                data = 0;
 401                for (i=0, cp=wp; i<l; ++i, ++cp) {
 402                        data = (data << 8) | (*(uchar *)cp);
 403                }
 404                for (; i<4 && cnt>0; ++i) {
 405                        data = (data << 8) | *src++;
 406                        --cnt;
 407                        ++cp;
 408                }
 409                for (; cnt==0 && i<4; ++i, ++cp) {
 410                        data = (data << 8) | (*(uchar *)cp);
 411                }
 412
 413                if ((rc = write_word(info, wp, data)) != 0) {
 414                        return (rc);
 415                }
 416                wp += 4;
 417        }
 418
 419        /*
 420         * handle word aligned part
 421         */
 422        while (cnt >= 4) {
 423                data = 0;
 424                for (i=0; i<4; ++i) {
 425                        data = (data << 8) | *src++;
 426                }
 427                if ((rc = write_word(info, wp, data)) != 0) {
 428                        return (rc);
 429                }
 430                wp  += 4;
 431                cnt -= 4;
 432        }
 433
 434        if (cnt == 0) {
 435                return (0);
 436        }
 437
 438        /*
 439         * handle unaligned tail bytes
 440         */
 441        data = 0;
 442        for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
 443                data = (data << 8) | *src++;
 444                --cnt;
 445        }
 446        for (; i<4; ++i, ++cp) {
 447                data = (data << 8) | (*(uchar *)cp);
 448        }
 449
 450        return (write_word(info, wp, data));
 451}
 452
 453/*
 454 * Write a word to Flash, returns:
 455 * 0 - OK
 456 * 1 - write timeout
 457 * 2 - Flash not erased
 458 */
 459static int write_word (flash_info_t *info, ulong dest, ulong data)
 460{
 461        volatile ulong addr = info->start[0];
 462        ulong start;
 463        int i;
 464
 465        /* Check if Flash is (sufficiently) erased */
 466        if ((in32(dest) & data) != data) {
 467                return (2);
 468        }
 469
 470        /* write each byte out */
 471        for (i = 0; i < 4; i++) {
 472                char *data_ch = (char *)&data;
 473                int flag = disable_interrupts();
 474
 475                out8(addr + 0x555, 0xAA);
 476                iobarrier_rw();
 477                out8(addr + 0x2AA, 0x55);
 478                iobarrier_rw();
 479                out8(addr + 0x555, 0xA0);
 480                iobarrier_rw();
 481                out8(dest+i, data_ch[i]);
 482                iobarrier_rw();
 483
 484                /* re-enable interrupts if necessary */
 485                if (flag)
 486                        enable_interrupts();
 487
 488                /* data polling for D7 */
 489                start = get_timer (0);
 490                while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
 491                        if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 492                                flash_reset (addr);
 493                                return (1);
 494                        }
 495                        iobarrier_rw();
 496                }
 497        }
 498
 499        flash_reset (addr);
 500        return (0);
 501}
 502
 503/*
 504 * Reset bank to read mode
 505 */
 506static void flash_reset (ulong addr)
 507{
 508        out8(addr, 0xF0);       /* reset bank */
 509        iobarrier_rw();
 510}
 511
 512void flash_print_info (flash_info_t *info)
 513{
 514        int i;
 515
 516        if (info->flash_id == FLASH_UNKNOWN) {
 517                printf ("missing or unknown FLASH type\n");
 518                return;
 519        }
 520
 521        switch (info->flash_id & FLASH_VENDMASK) {
 522        case FLASH_MAN_AMD:     printf ("AMD ");                break;
 523        case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
 524        case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
 525        case FLASH_MAN_STM:     printf ("SGS THOMSON ");        break;
 526        default:                printf ("Unknown Vendor ");     break;
 527        }
 528
 529        switch (info->flash_id & FLASH_TYPEMASK) {
 530        case FLASH_AM040:       printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
 531                                break;
 532        case FLASH_AM400B:      printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
 533                                break;
 534        case FLASH_AM400T:      printf ("AM29LV400T (4 Mbit, top boot sector)\n");
 535                                break;
 536        case FLASH_AM800B:      printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
 537                                break;
 538        case FLASH_AM800T:      printf ("AM29LV800T (8 Mbit, top boot sector)\n");
 539                                break;
 540        case FLASH_AM160B:      printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
 541                                break;
 542        case FLASH_AM160T:      printf ("AM29LV160T (16 Mbit, top boot sector)\n");
 543                                break;
 544        case FLASH_AM320B:      printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
 545                                break;
 546        case FLASH_AM320T:      printf ("AM29LV320T (32 Mbit, top boot sector)\n");
 547                                break;
 548        default:                printf ("Unknown Chip Type\n");
 549                                break;
 550        }
 551
 552        if (info->size % 0x100000 == 0) {
 553                printf ("  Size: %ld MB in %d Sectors\n",
 554                        info->size / 0x100000, info->sector_count);
 555        } else if (info->size % 0x400 == 0) {
 556                printf ("  Size: %ld KB in %d Sectors\n",
 557                        info->size / 0x400, info->sector_count);
 558        } else {
 559                printf ("  Size: %ld B in %d Sectors\n",
 560                        info->size, info->sector_count);
 561        }
 562
 563        printf ("  Sector Start Addresses:");
 564        for (i=0; i<info->sector_count; ++i) {
 565                if ((i % 5) == 0)
 566                        printf ("\n   ");
 567                printf (" %08lX%s",
 568                        info->start[i],
 569                        info->protect[i] ? " (RO)" : "     "
 570                );
 571        }
 572        printf ("\n");
 573}
 574