uboot/board/purple/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#include <asm/inca-ip.h>
  26
  27flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
  28
  29typedef unsigned long FLASH_PORT_WIDTH;
  30typedef volatile unsigned long FLASH_PORT_WIDTHV;
  31
  32#define FLASH_ID_MASK   0xFFFFFFFF
  33
  34#define FPW     FLASH_PORT_WIDTH
  35#define FPWV    FLASH_PORT_WIDTHV
  36
  37#define ORMASK(size) ((-size) & OR_AM_MSK)
  38
  39#define FLASH29_REG_ADRS(reg) ((FPWV *)PHYS_FLASH_1 + (reg))
  40
  41/* FLASH29 command register addresses */
  42
  43#define FLASH29_REG_FIRST_CYCLE         FLASH29_REG_ADRS (0x1555)
  44#define FLASH29_REG_SECOND_CYCLE        FLASH29_REG_ADRS (0x2aaa)
  45#define FLASH29_REG_THIRD_CYCLE         FLASH29_REG_ADRS (0x3555)
  46#define FLASH29_REG_FOURTH_CYCLE        FLASH29_REG_ADRS (0x4555)
  47#define FLASH29_REG_FIFTH_CYCLE         FLASH29_REG_ADRS (0x5aaa)
  48#define FLASH29_REG_SIXTH_CYCLE         FLASH29_REG_ADRS (0x6555)
  49
  50/* FLASH29 command definitions */
  51
  52#define FLASH29_CMD_FIRST               0xaaaaaaaa
  53#define FLASH29_CMD_SECOND              0x55555555
  54#define FLASH29_CMD_FOURTH              0xaaaaaaaa
  55#define FLASH29_CMD_FIFTH               0x55555555
  56#define FLASH29_CMD_SIXTH               0x10101010
  57
  58#define FLASH29_CMD_SECTOR              0x30303030
  59#define FLASH29_CMD_PROGRAM             0xa0a0a0a0
  60#define FLASH29_CMD_CHIP_ERASE          0x80808080
  61#define FLASH29_CMD_READ_RESET          0xf0f0f0f0
  62#define FLASH29_CMD_AUTOSELECT          0x90909090
  63#define FLASH29_CMD_READ                0x70707070
  64
  65#define IN_RAM_CMD_READ         0x1
  66#define IN_RAM_CMD_WRITE        0x2
  67
  68#define FLASH_WRITE_CMD ((ulong)(flash_write_cmd) & 0x7)+0xbf008000
  69#define FLASH_READ_CMD  ((ulong)(flash_read_cmd) & 0x7)+0xbf008000
  70
  71typedef void (*FUNCPTR_CP)(ulong *source, ulong *destination, ulong nlongs);
  72typedef void (*FUNCPTR_RD)(int cmd, FPWV * pFA, char * string, int strLen);
  73typedef void (*FUNCPTR_WR)(int cmd, FPWV * pFA, FPW value);
  74
  75static ulong flash_get_size(FPWV *addr, flash_info_t *info);
  76static int write_word(flash_info_t *info, FPWV *dest, FPW data);
  77static void flash_get_offsets(ulong base, flash_info_t *info);
  78static flash_info_t *flash_get_info(ulong base);
  79
  80static void load_cmd(ulong cmd);
  81static ulong in_ram_cmd = 0;
  82
  83
  84/******************************************************************************
  85*
  86* Don't change the program architecture
  87* This architecture assure the program
  88* can be relocated to scratch ram
  89*/
  90static void flash_read_cmd(int cmd, FPWV * pFA, char * string, int strLen)
  91{
  92        int i,j;
  93        FPW temp,temp1;
  94        FPWV *str;
  95
  96        str = (FPWV *)string;
  97
  98        j=  strLen/4;
  99
 100        if(cmd == FLASH29_CMD_AUTOSELECT)
 101           {
 102            *(FLASH29_REG_FIRST_CYCLE)  = FLASH29_CMD_FIRST;
 103            *(FLASH29_REG_SECOND_CYCLE) = FLASH29_CMD_SECOND;
 104            *(FLASH29_REG_THIRD_CYCLE)  = FLASH29_CMD_AUTOSELECT;
 105           }
 106
 107        if(cmd == FLASH29_CMD_READ)
 108           {
 109            i = 0;
 110            while(i<j)
 111            {
 112                temp = *pFA++;
 113                temp1 = *(int *)0xa0000000;
 114                *(int *)0xbf0081f8 = temp1 + temp;
 115                *str++ = temp;
 116                i++;
 117            }
 118           }
 119
 120         if(cmd == FLASH29_CMD_READ_RESET)
 121         {
 122            *(FLASH29_REG_FIRST_CYCLE)  = FLASH29_CMD_FIRST;
 123            *(FLASH29_REG_SECOND_CYCLE) = FLASH29_CMD_SECOND;
 124            *(FLASH29_REG_THIRD_CYCLE)  = FLASH29_CMD_READ_RESET;
 125         }
 126
 127        *(int *)0xbf0081f8 = *(int *)0xa0000000;        /* dummy read switch back to sdram interface */
 128}
 129
 130/******************************************************************************
 131*
 132* Don't change the program architecture
 133* This architecture assure the program
 134* can be relocated to scratch ram
 135*/
 136static void flash_write_cmd(int cmd, FPWV * pFA, FPW value)
 137{
 138        *(FLASH29_REG_FIRST_CYCLE)  = FLASH29_CMD_FIRST;
 139        *(FLASH29_REG_SECOND_CYCLE) = FLASH29_CMD_SECOND;
 140
 141        if (cmd == FLASH29_CMD_SECTOR)
 142           {
 143            *(FLASH29_REG_THIRD_CYCLE)  = FLASH29_CMD_CHIP_ERASE;
 144            *(FLASH29_REG_FOURTH_CYCLE) = FLASH29_CMD_FOURTH;
 145            *(FLASH29_REG_FIFTH_CYCLE)  = FLASH29_CMD_FIFTH;
 146            *pFA                        = FLASH29_CMD_SECTOR;
 147           }
 148
 149        if (cmd == FLASH29_CMD_SIXTH)
 150           {
 151            *(FLASH29_REG_THIRD_CYCLE)  = FLASH29_CMD_CHIP_ERASE;
 152            *(FLASH29_REG_FOURTH_CYCLE) = FLASH29_CMD_FOURTH;
 153            *(FLASH29_REG_FIFTH_CYCLE)  = FLASH29_CMD_FIFTH;
 154            *(FLASH29_REG_SIXTH_CYCLE)  = FLASH29_CMD_SIXTH;
 155           }
 156
 157        if (cmd == FLASH29_CMD_PROGRAM)
 158           {
 159            *(FLASH29_REG_THIRD_CYCLE)  = FLASH29_CMD_PROGRAM;
 160            *pFA = value;
 161           }
 162
 163        if (cmd == FLASH29_CMD_READ_RESET)
 164           {
 165            *(FLASH29_REG_THIRD_CYCLE)  = FLASH29_CMD_READ_RESET;
 166           }
 167
 168        *(int *)0xbf0081f8 = *(int *)0xa0000000;        /* dummy read switch back to sdram interface */
 169}
 170
 171static void load_cmd(ulong cmd)
 172{
 173        ulong *src;
 174        ulong *dst;
 175        FUNCPTR_CP absEntry;
 176        ulong func;
 177
 178        if (in_ram_cmd & cmd) return;
 179
 180        if (cmd == IN_RAM_CMD_READ)
 181        {
 182                func = (ulong)flash_read_cmd;
 183        }
 184        else
 185        {
 186                func = (ulong)flash_write_cmd;
 187        }
 188
 189        src = (ulong *)(func & 0xfffffff8);
 190        dst = (ulong *)0xbf008000;
 191        absEntry = (FUNCPTR_CP)(0xbf0081d0);
 192        absEntry(src,dst,0x38);
 193
 194        in_ram_cmd = cmd;
 195}
 196
 197/*-----------------------------------------------------------------------
 198 * flash_init()
 199 *
 200 * sets up flash_info and returns size of FLASH (bytes)
 201 */
 202unsigned long flash_init (void)
 203{
 204        unsigned long size = 0;
 205        int i;
 206
 207        load_cmd(IN_RAM_CMD_READ);
 208
 209        /* Init: no FLASHes known */
 210        for (i=0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
 211                ulong flashbase = PHYS_FLASH_1;
 212                ulong * buscon = (ulong *) INCA_IP_EBU_EBU_BUSCON0;
 213
 214                /* Disable write protection */
 215                *buscon &= ~INCA_IP_EBU_EBU_BUSCON1_WRDIS;
 216
 217#if 1
 218                memset(&flash_info[i], 0, sizeof(flash_info_t));
 219#endif
 220
 221                flash_info[i].size =
 222                        flash_get_size((FPW *)flashbase, &flash_info[i]);
 223
 224                if (flash_info[i].flash_id == FLASH_UNKNOWN) {
 225                        printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx\n",
 226                        i, flash_info[i].size);
 227                }
 228
 229                size += flash_info[i].size;
 230        }
 231
 232#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE
 233        /* monitor protection ON by default */
 234        flash_protect(FLAG_PROTECT_SET,
 235                      CONFIG_SYS_MONITOR_BASE,
 236                      CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
 237                      flash_get_info(CONFIG_SYS_MONITOR_BASE));
 238#endif
 239
 240#ifdef  CONFIG_ENV_IS_IN_FLASH
 241        /* ENV protection ON by default */
 242        flash_protect(FLAG_PROTECT_SET,
 243                      CONFIG_ENV_ADDR,
 244                      CONFIG_ENV_ADDR+CONFIG_ENV_SIZE-1,
 245                      flash_get_info(CONFIG_ENV_ADDR));
 246#endif
 247
 248        return size;
 249}
 250
 251/*-----------------------------------------------------------------------
 252 */
 253static void flash_get_offsets (ulong base, flash_info_t *info)
 254{
 255        int i;
 256
 257        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
 258                 && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM160B) {
 259
 260                int bootsect_size[4];   /* number of bytes/boot sector  */
 261                int sect_size;          /* number of bytes/regular sector */
 262
 263                bootsect_size[0] = 0x00008000;
 264                bootsect_size[1] = 0x00004000;
 265                bootsect_size[2] = 0x00004000;
 266                bootsect_size[3] = 0x00010000;
 267                sect_size =        0x00020000;
 268
 269                /* set sector offsets for bottom boot block type        */
 270                for (i = 0; i < info->sector_count; i++) {
 271                        info->start[i] = base;
 272                        base += i < 4 ? bootsect_size[i] : sect_size;
 273                }
 274        }
 275}
 276
 277/*-----------------------------------------------------------------------
 278 */
 279
 280static flash_info_t *flash_get_info(ulong base)
 281{
 282        int i;
 283        flash_info_t * info;
 284
 285        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i ++) {
 286                info = & flash_info[i];
 287                if (info->start[0] <= base && base < info->start[0] + info->size)
 288                        break;
 289        }
 290
 291        return i == CONFIG_SYS_MAX_FLASH_BANKS ? 0 : info;
 292}
 293
 294/*-----------------------------------------------------------------------
 295 */
 296
 297void flash_print_info (flash_info_t *info)
 298{
 299        int i;
 300        uchar *boottype;
 301        uchar *bootletter;
 302        char *fmt;
 303        uchar botbootletter[] = "B";
 304        uchar topbootletter[] = "T";
 305        uchar botboottype[] = "bottom boot sector";
 306        uchar topboottype[] = "top boot sector";
 307
 308        if (info->flash_id == FLASH_UNKNOWN) {
 309                printf ("missing or unknown FLASH type\n");
 310                return;
 311        }
 312
 313        switch (info->flash_id & FLASH_VENDMASK) {
 314        case FLASH_MAN_AMD:     printf ("AMD ");                break;
 315        case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
 316        case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
 317        case FLASH_MAN_SST:     printf ("SST ");                break;
 318        case FLASH_MAN_STM:     printf ("STM ");                break;
 319        case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
 320        default:                printf ("Unknown Vendor ");     break;
 321        }
 322
 323        /* check for top or bottom boot, if it applies */
 324        if (info->flash_id & FLASH_BTYPE) {
 325                boottype = botboottype;
 326                bootletter = botbootletter;
 327        }
 328        else {
 329                boottype = topboottype;
 330                bootletter = topbootletter;
 331        }
 332
 333        switch (info->flash_id & FLASH_TYPEMASK) {
 334        case FLASH_AM160B:
 335                fmt = "29LV160B%s (16 Mbit, %s)\n";
 336                break;
 337        case FLASH_28F800C3B:
 338        case FLASH_28F800C3T:
 339                fmt = "28F800C3%s (8 Mbit, %s)\n";
 340                break;
 341        case FLASH_INTEL800B:
 342        case FLASH_INTEL800T:
 343                fmt = "28F800B3%s (8 Mbit, %s)\n";
 344                break;
 345        case FLASH_28F160C3B:
 346        case FLASH_28F160C3T:
 347                fmt = "28F160C3%s (16 Mbit, %s)\n";
 348                break;
 349        case FLASH_INTEL160B:
 350        case FLASH_INTEL160T:
 351                fmt = "28F160B3%s (16 Mbit, %s)\n";
 352                break;
 353        case FLASH_28F320C3B:
 354        case FLASH_28F320C3T:
 355                fmt = "28F320C3%s (32 Mbit, %s)\n";
 356                break;
 357        case FLASH_INTEL320B:
 358        case FLASH_INTEL320T:
 359                fmt = "28F320B3%s (32 Mbit, %s)\n";
 360                break;
 361        case FLASH_28F640C3B:
 362        case FLASH_28F640C3T:
 363                fmt = "28F640C3%s (64 Mbit, %s)\n";
 364                break;
 365        case FLASH_INTEL640B:
 366        case FLASH_INTEL640T:
 367                fmt = "28F640B3%s (64 Mbit, %s)\n";
 368                break;
 369        default:
 370                fmt = "Unknown Chip Type\n";
 371                break;
 372        }
 373
 374        printf (fmt, bootletter, boottype);
 375
 376        printf ("  Size: %ld MB in %d Sectors\n",
 377                info->size >> 20,
 378                info->sector_count);
 379
 380        printf ("  Sector Start Addresses:");
 381
 382        for (i=0; i<info->sector_count; ++i) {
 383                if ((i % 5) == 0) {
 384                        printf ("\n   ");
 385                }
 386
 387                printf (" %08lX%s", info->start[i],
 388                        info->protect[i] ? " (RO)" : "     ");
 389        }
 390
 391        printf ("\n");
 392}
 393
 394/*-----------------------------------------------------------------------
 395 */
 396
 397/*
 398 * The following code cannot be run from FLASH!
 399 */
 400
 401ulong flash_get_size (FPWV *addr, flash_info_t *info)
 402{
 403        FUNCPTR_RD absEntry;
 404        FPW retValue;
 405        int flag;
 406
 407        load_cmd(IN_RAM_CMD_READ);
 408        absEntry = (FUNCPTR_RD)FLASH_READ_CMD;
 409
 410        flag = disable_interrupts();
 411        absEntry(FLASH29_CMD_AUTOSELECT,0,0,0);
 412        if (flag) enable_interrupts();
 413
 414        udelay(100);
 415
 416        flag = disable_interrupts();
 417        absEntry(FLASH29_CMD_READ, addr + 1, (char *)&retValue, sizeof(retValue));
 418        absEntry(FLASH29_CMD_READ_RESET,0,0,0);
 419        if (flag) enable_interrupts();
 420
 421        udelay(100);
 422
 423        switch (retValue) {
 424
 425        case (FPW)AMD_ID_LV160B:
 426                info->flash_id += FLASH_AM160B;
 427                info->sector_count = 35;
 428                info->size = 0x00400000;
 429                break;                          /* => 8 or 16 MB        */
 430
 431        default:
 432                info->flash_id = FLASH_UNKNOWN;
 433                info->sector_count = 0;
 434                info->size = 0;
 435                return (0);                     /* => no or unknown flash */
 436        }
 437
 438        flash_get_offsets((ulong)addr, info);
 439
 440        return (info->size);
 441}
 442
 443/*-----------------------------------------------------------------------
 444 */
 445
 446int     flash_erase (flash_info_t *info, int s_first, int s_last)
 447{
 448        FPWV *addr;
 449        int flag, prot, sect;
 450        ulong start, now, last;
 451        FUNCPTR_WR absEntry;
 452
 453        load_cmd(IN_RAM_CMD_WRITE);
 454        absEntry = (FUNCPTR_WR)FLASH_WRITE_CMD;
 455
 456        if ((s_first < 0) || (s_first > s_last)) {
 457                if (info->flash_id == FLASH_UNKNOWN) {
 458                        printf ("- missing\n");
 459                } else {
 460                        printf ("- no sectors to erase\n");
 461                }
 462                return 1;
 463        }
 464
 465        switch (info->flash_id & FLASH_TYPEMASK) {
 466        case FLASH_AM160B:
 467                break;
 468        case FLASH_UNKNOWN:
 469        default:
 470                printf ("Can't erase unknown flash type %08lx - aborted\n",
 471                        info->flash_id);
 472                return 1;
 473        }
 474
 475        prot = 0;
 476        for (sect=s_first; sect<=s_last; ++sect) {
 477                if (info->protect[sect]) {
 478                        prot++;
 479                }
 480        }
 481
 482        if (prot) {
 483                printf ("- Warning: %d protected sectors will not be erased!\n",
 484                        prot);
 485        } else {
 486                printf ("\n");
 487        }
 488
 489        last  = get_timer(0);
 490
 491        /* Start erase on unprotected sectors */
 492        for (sect = s_first; sect<=s_last; sect++) {
 493
 494                if (info->protect[sect] != 0)   /* protected, skip it */
 495                        continue;
 496
 497                /* Disable interrupts which might cause a timeout here */
 498                flag = disable_interrupts();
 499
 500                addr = (FPWV *)(info->start[sect]);
 501                absEntry(FLASH29_CMD_SECTOR, addr, 0);
 502
 503                /* re-enable interrupts if necessary */
 504                if (flag)
 505                        enable_interrupts();
 506
 507                start = get_timer(0);
 508
 509                while ((now = get_timer(start)) <= CONFIG_SYS_FLASH_ERASE_TOUT) {
 510
 511                        /* show that we're waiting */
 512                        if ((get_timer(last)) > CONFIG_SYS_HZ) {/* every second */
 513                                putc ('.');
 514                                last = get_timer(0);
 515                        }
 516                }
 517
 518                flag = disable_interrupts();
 519                absEntry(FLASH29_CMD_READ_RESET,0,0);
 520                if (flag)
 521                        enable_interrupts();
 522        }
 523
 524        printf (" done\n");
 525        return 0;
 526}
 527
 528/*-----------------------------------------------------------------------
 529 * Copy memory to flash, returns:
 530 * 0 - OK
 531 * 1 - write timeout
 532 * 2 - Flash not erased
 533 */
 534int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 535{
 536    FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
 537    int bytes;    /* number of bytes to program in current word         */
 538    int left;     /* number of bytes left to program                    */
 539    int i, res;
 540
 541    for (left = cnt, res = 0;
 542         left > 0 && res == 0;
 543         addr += sizeof(data), left -= sizeof(data) - bytes) {
 544
 545        bytes = addr & (sizeof(data) - 1);
 546        addr &= ~(sizeof(data) - 1);
 547
 548        /* combine source and destination data so can program
 549         * an entire word of 16 or 32 bits
 550         */
 551        for (i = 0; i < sizeof(data); i++) {
 552            data <<= 8;
 553            if (i < bytes || i - bytes >= left )
 554                data += *((uchar *)addr + i);
 555            else
 556                data += *src++;
 557        }
 558
 559        res = write_word(info, (FPWV *)addr, data);
 560    }
 561
 562    return (res);
 563}
 564
 565static int write_word (flash_info_t *info, FPWV *dest, FPW data)
 566{
 567    int res = 0;        /* result, assume success       */
 568    FUNCPTR_WR absEntry;
 569    int flag;
 570
 571    /* Check if Flash is (sufficiently) erased */
 572    if ((*dest & data) != data) {
 573        return (2);
 574    }
 575
 576    if (info->start[0] != PHYS_FLASH_1)
 577    {
 578        return (3);
 579    }
 580
 581    load_cmd(IN_RAM_CMD_WRITE);
 582    absEntry = (FUNCPTR_WR)FLASH_WRITE_CMD;
 583
 584    flag = disable_interrupts();
 585    absEntry(FLASH29_CMD_PROGRAM,dest,data);
 586    if (flag) enable_interrupts();
 587
 588    udelay(100);
 589
 590    flag = disable_interrupts();
 591    absEntry(FLASH29_CMD_READ_RESET,0,0);
 592    if (flag) enable_interrupts();
 593
 594    return (res);
 595}
 596