uboot/board/amirix/ap1000/flash.c
<<
>>
Prefs
   1/**
   2 * @file flash.c
   3 */
   4
   5/*
   6 * (C) Copyright 2003
   7 * AMIRIX Systems Inc.
   8 *
   9 * Originated from ppcboot-2.0.0/board/esd/cpci440/strataflash.c
  10 *
  11 * (C) Copyright 2002
  12 * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com
  13 *
  14 * See file CREDITS for list of people who contributed to this
  15 * project.
  16 *
  17 * This program is free software; you can redistribute it and/or
  18 * modify it under the terms of the GNU General Public License as
  19 * published by the Free Software Foundation; either version 2 of
  20 * the License, or (at your option) any later version.
  21 *
  22 * This program is distributed in the hope that it will be useful,
  23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25 * GNU General Public License for more details.
  26 *
  27 * You should have received a copy of the GNU General Public License
  28 * along with this program; if not, write to the Free Software
  29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  30 * MA 02111-1307 USA
  31 */
  32
  33#include <common.h>
  34#include <asm/processor.h>
  35
  36#undef  DEBUG_FLASH
  37/*
  38 * This file implements a Common Flash Interface (CFI) driver for ppcboot.
  39 * The width of the port and the width of the chips are determined at initialization.
  40 * These widths are used to calculate the address for access CFI data structures.
  41 * It has been tested on an Intel Strataflash implementation.
  42 *
  43 * References
  44 * JEDEC Standard JESD68 - Common Flash Interface (CFI)
  45 * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes
  46 * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets
  47 * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet
  48 *
  49 * TODO
  50 * Use Primary Extended Query table (PRI) and Alternate Algorithm Query Table (ALT) to determine if protection is available
  51 * Add support for other command sets Use the PRI and ALT to determine command set
  52 * Verify erase and program timeouts.
  53 */
  54
  55#define FLASH_CMD_CFI           0x98
  56#define FLASH_CMD_READ_ID       0x90
  57#define FLASH_CMD_RESET         0xff
  58#define FLASH_CMD_BLOCK_ERASE       0x20
  59#define FLASH_CMD_ERASE_CONFIRM     0xD0
  60#define FLASH_CMD_WRITE         0x40
  61#define FLASH_CMD_PROTECT       0x60
  62#define FLASH_CMD_PROTECT_SET       0x01
  63#define FLASH_CMD_PROTECT_CLEAR     0xD0
  64#define FLASH_CMD_CLEAR_STATUS      0x50
  65#define FLASH_CMD_WRITE_TO_BUFFER       0xE8
  66#define FLASH_CMD_WRITE_BUFFER_CONFIRM  0xD0
  67
  68#define FLASH_STATUS_DONE       0x80
  69#define FLASH_STATUS_ESS        0x40
  70#define FLASH_STATUS_ECLBS      0x20
  71#define FLASH_STATUS_PSLBS      0x10
  72#define FLASH_STATUS_VPENS      0x08
  73#define FLASH_STATUS_PSS        0x04
  74#define FLASH_STATUS_DPS        0x02
  75#define FLASH_STATUS_R          0x01
  76#define FLASH_STATUS_PROTECT        0x01
  77
  78#define FLASH_OFFSET_CFI        0x55
  79#define FLASH_OFFSET_CFI_RESP       0x10
  80#define FLASH_OFFSET_WTOUT      0x1F
  81#define FLASH_OFFSET_WBTOUT             0x20
  82#define FLASH_OFFSET_ETOUT      0x21
  83#define FLASH_OFFSET_CETOUT             0x22
  84#define FLASH_OFFSET_WMAX_TOUT      0x23
  85#define FLASH_OFFSET_WBMAX_TOUT         0x24
  86#define FLASH_OFFSET_EMAX_TOUT      0x25
  87#define FLASH_OFFSET_CEMAX_TOUT         0x26
  88#define FLASH_OFFSET_SIZE       0x27
  89#define FLASH_OFFSET_INTERFACE          0x28
  90#define FLASH_OFFSET_BUFFER_SIZE        0x2A
  91#define FLASH_OFFSET_NUM_ERASE_REGIONS  0x2C
  92#define FLASH_OFFSET_ERASE_REGIONS  0x2D
  93#define FLASH_OFFSET_PROTECT        0x02
  94#define FLASH_OFFSET_USER_PROTECTION    0x85
  95#define FLASH_OFFSET_INTEL_PROTECTION   0x81
  96
  97#define FLASH_MAN_CFI           0x01000000
  98
  99typedef union {
 100        unsigned char c;
 101        unsigned short w;
 102        unsigned long l;
 103} cfiword_t;
 104
 105typedef union {
 106        unsigned char *cp;
 107        unsigned short *wp;
 108        unsigned long *lp;
 109} cfiptr_t;
 110
 111#define NUM_ERASE_REGIONS 4
 112
 113flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];    /* info for FLASH chips    */
 114
 115/*-----------------------------------------------------------------------
 116 * Functions
 117 */
 118
 119static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c);
 120static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf);
 121static void flash_write_cmd (flash_info_t * info, int sect, uchar offset,
 122                             uchar cmd);
 123static int flash_isequal (flash_info_t * info, int sect, uchar offset,
 124                          uchar cmd);
 125static int flash_isset (flash_info_t * info, int sect, uchar offset,
 126                        uchar cmd);
 127static int flash_detect_cfi (flash_info_t * info);
 128static ulong flash_get_size (ulong base, int banknum);
 129static int flash_write_cfiword (flash_info_t * info, ulong dest,
 130                                cfiword_t cword);
 131static int flash_full_status_check (flash_info_t * info, ulong sector,
 132                                    ulong tout, char *prompt);
 133#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
 134static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 135                                  int len);
 136#endif
 137/*-----------------------------------------------------------------------
 138 * create an address based on the offset and the port width
 139 */
 140uchar *flash_make_addr (flash_info_t * info, int sect, int offset)
 141{
 142        return ((uchar *) (info->start[sect] + (offset * info->chipwidth)));
 143}
 144
 145/*-----------------------------------------------------------------------
 146 * read a character at a port width address
 147 */
 148uchar flash_read_uchar (flash_info_t * info, uchar offset)
 149{
 150        if (info->portwidth == FLASH_CFI_8BIT) {
 151                volatile uchar *cp;
 152                uchar c;
 153
 154                cp = flash_make_addr (info, 0, offset);
 155                c = *cp;
 156#ifdef DEBUG_FLASH
 157                printf ("flash_read_uchar offset=%04x ptr=%08x c=%02x\n",
 158                        offset, (unsigned int) cp, c);
 159#endif
 160                return (c);
 161
 162        } else if (info->portwidth == FLASH_CFI_16BIT) {
 163                volatile ushort *sp;
 164                ushort s;
 165                uchar c;
 166
 167                sp = (ushort *) flash_make_addr (info, 0, offset);
 168                s = *sp;
 169                c = (uchar) s;
 170#ifdef DEBUG_FLASH
 171                printf ("flash_read_uchar offset=%04x ptr=%08x s=%04x c=%02x\n", offset, (unsigned int) sp, s, c);
 172#endif
 173                return (c);
 174
 175        }
 176
 177        return 0;
 178}
 179
 180/*-----------------------------------------------------------------------
 181 * read a short word by swapping for ppc format.
 182 */
 183ushort flash_read_ushort (flash_info_t * info, int sect, uchar offset)
 184{
 185        if (info->portwidth == FLASH_CFI_8BIT) {
 186                volatile uchar *cp;
 187                uchar c0, c1;
 188                ushort s;
 189
 190                cp = flash_make_addr (info, 0, offset);
 191                c1 = cp[2];
 192                c0 = cp[0];
 193                s = c1 << 8 | c0;
 194#ifdef DEBUG_FLASH
 195                printf ("flash_read_ushort offset=%04x ptr=%08x c1=%02x c0=%02x s=%04x\n", offset, (unsigned int) cp, c1, c0, s);
 196#endif
 197                return (s);
 198
 199        } else if (info->portwidth == FLASH_CFI_16BIT) {
 200                volatile ushort *sp;
 201                ushort s;
 202                uchar c0, c1;
 203
 204                sp = (ushort *) flash_make_addr (info, 0, offset);
 205                s = *sp;
 206                c1 = (uchar) sp[1];
 207                c0 = (uchar) sp[0];
 208                s = c1 << 8 | c0;
 209#ifdef DEBUG_FLASH
 210                printf ("flash_read_ushort offset=%04x ptr=%08x c1=%02x c0=%02x s=%04x\n", offset, (unsigned int) sp, c1, c0, s);
 211#endif
 212                return (s);
 213
 214        }
 215
 216        return 0;
 217}
 218
 219/*-----------------------------------------------------------------------
 220 * read a long word by picking the least significant byte of each maiximum
 221 * port size word. Swap for ppc format.
 222 */
 223ulong flash_read_long (flash_info_t * info, int sect, uchar offset)
 224{
 225        if (info->portwidth == FLASH_CFI_8BIT) {
 226                volatile uchar *cp;
 227                uchar c0, c1, c2, c3;
 228                ulong l;
 229
 230                cp = flash_make_addr (info, 0, offset);
 231                c3 = cp[6];
 232                c2 = cp[4];
 233                c1 = cp[2];
 234                c0 = cp[0];
 235                l = c3 << 24 | c2 << 16 | c1 << 8 | c0;
 236#ifdef DEBUG_FLASH
 237                printf ("flash_read_long offset=%04x ptr=%08x c3=%02x c2=%02x c1=%02x c0=%02x l=%08x\n", offset, (unsigned int) cp, c3, c2, c1, c0, l);
 238#endif
 239                return (l);
 240
 241        } else if (info->portwidth == FLASH_CFI_16BIT) {
 242                volatile ushort *sp;
 243                uchar c0, c1, c2, c3;
 244                ulong l;
 245
 246                sp = (ushort *) flash_make_addr (info, 0, offset);
 247                c3 = (uchar) sp[3];
 248                c2 = (uchar) sp[2];
 249                c1 = (uchar) sp[1];
 250                c0 = (uchar) sp[0];
 251                l = c3 << 24 | c2 << 16 | c1 << 8 | c0;
 252#ifdef DEBUG_FLASH
 253                printf ("flash_read_long offset=%04x ptr=%08x c3=%02x c2=%02x c1=%02x c0=%02x l=%08x\n", offset, (unsigned int) sp, c3, c2, c1, c0, l);
 254#endif
 255                return (l);
 256
 257        }
 258
 259        return 0;
 260}
 261
 262/*-----------------------------------------------------------------------
 263 */
 264unsigned long flash_init (void)
 265{
 266        unsigned long size;
 267
 268        size = 0;
 269
 270        flash_info[0].flash_id = FLASH_UNKNOWN;
 271        flash_info[0].portwidth = FLASH_CFI_16BIT;
 272        flash_info[0].chipwidth = FLASH_CFI_16BIT;
 273        size += flash_info[0].size = flash_get_size (CONFIG_SYS_PROGFLASH_BASE, 0);
 274        if (flash_info[0].flash_id == FLASH_UNKNOWN) {
 275                printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", 1, flash_info[0].size, flash_info[0].size << 20);
 276        };
 277
 278        flash_info[1].flash_id = FLASH_UNKNOWN;
 279        flash_info[1].portwidth = FLASH_CFI_8BIT;
 280        flash_info[1].chipwidth = FLASH_CFI_16BIT;
 281        size += flash_info[1].size = flash_get_size (CONFIG_SYS_CONFFLASH_BASE, 1);
 282        if (flash_info[1].flash_id == FLASH_UNKNOWN) {
 283                printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", 2, flash_info[1].size, flash_info[1].size << 20);
 284        };
 285
 286        return (size);
 287}
 288
 289/*-----------------------------------------------------------------------
 290 */
 291int flash_erase (flash_info_t * info, int s_first, int s_last)
 292{
 293        int rcode = 0;
 294        int prot;
 295        int sect;
 296
 297        if (info->flash_id != FLASH_MAN_CFI) {
 298                printf ("Can't erase unknown flash type - aborted\n");
 299                return 1;
 300        }
 301        if ((s_first < 0) || (s_first > s_last)) {
 302                printf ("- no sectors to erase\n");
 303                return 1;
 304        }
 305
 306        prot = 0;
 307        for (sect = s_first; sect <= s_last; ++sect) {
 308                if (info->protect[sect]) {
 309                        prot++;
 310                }
 311        }
 312        if (prot) {
 313                printf ("- Warning: %d protected sectors will not be erased!\n", prot);
 314        } else {
 315                printf ("\n");
 316        }
 317
 318        for (sect = s_first; sect <= s_last; sect++) {
 319                if (info->protect[sect] == 0) { /* not protected */
 320                        flash_write_cmd (info, sect, 0,
 321                                         FLASH_CMD_CLEAR_STATUS);
 322                        flash_write_cmd (info, sect, 0,
 323                                         FLASH_CMD_BLOCK_ERASE);
 324                        flash_write_cmd (info, sect, 0,
 325                                         FLASH_CMD_ERASE_CONFIRM);
 326
 327                        if (flash_full_status_check
 328                            (info, sect, info->erase_blk_tout, "erase")) {
 329                                rcode = 1;
 330                        } else
 331                                printf (".");
 332                }
 333        }
 334        printf (" done\n");
 335        return rcode;
 336}
 337
 338/*-----------------------------------------------------------------------
 339 */
 340void flash_print_info (flash_info_t * info)
 341{
 342        int i;
 343
 344        if (info->flash_id != FLASH_MAN_CFI) {
 345                printf ("missing or unknown FLASH type\n");
 346                return;
 347        }
 348
 349        printf ("CFI conformant FLASH (x%d device in x%d mode)",
 350                (info->chipwidth << 3), (info->portwidth << 3));
 351        printf ("  Size: %ld MB in %d Sectors\n",
 352                info->size >> 20, info->sector_count);
 353        printf (" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n", info->erase_blk_tout, info->write_tout, info->buffer_write_tout, info->buffer_size);
 354
 355        printf ("  Sector Start Addresses:");
 356        for (i = 0; i < info->sector_count; ++i) {
 357                if ((i % 5) == 0)
 358                        printf ("\n");
 359                printf (" %08lX%5s",
 360                        info->start[i], info->protect[i] ? " (RO)" : " ");
 361        }
 362        printf ("\n");
 363        return;
 364}
 365
 366/*-----------------------------------------------------------------------
 367 * Copy memory to flash, returns:
 368 * 0 - OK
 369 * 1 - write timeout
 370 * 2 - Flash not erased
 371 */
 372int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 373{
 374        ulong wp;
 375        ulong cp;
 376        int aln;
 377        cfiword_t cword;
 378        int i, rc;
 379
 380        /* get lower aligned address */
 381        wp = (addr & ~(info->portwidth - 1));
 382
 383        /* handle unaligned start */
 384        if ((aln = addr - wp) != 0) {
 385                cword.l = 0;
 386                cp = wp;
 387                for (i = 0; i < aln; ++i, ++cp)
 388                        flash_add_byte (info, &cword, (*(uchar *) cp));
 389
 390                for (; (i < info->portwidth) && (cnt > 0); i++) {
 391                        flash_add_byte (info, &cword, *src++);
 392                        cnt--;
 393                        cp++;
 394                }
 395                for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
 396                        flash_add_byte (info, &cword, (*(uchar *) cp));
 397                if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
 398                        return rc;
 399                wp = cp;
 400        }
 401#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
 402        while (cnt >= info->portwidth) {
 403                i = info->buffer_size > cnt ? cnt : info->buffer_size;
 404                if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
 405                        return rc;
 406                wp += i;
 407                src += i;
 408                cnt -= i;
 409        }
 410#else
 411        /* handle the aligned part */
 412        while (cnt >= info->portwidth) {
 413                cword.l = 0;
 414                for (i = 0; i < info->portwidth; i++) {
 415                        flash_add_byte (info, &cword, *src++);
 416                }
 417                if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
 418                        return rc;
 419                wp += info->portwidth;
 420                cnt -= info->portwidth;
 421        }
 422#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */
 423        if (cnt == 0) {
 424                return (0);
 425        }
 426
 427        /*
 428         * handle unaligned tail bytes
 429         */
 430        cword.l = 0;
 431        for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
 432                flash_add_byte (info, &cword, *src++);
 433                --cnt;
 434        }
 435        for (; i < info->portwidth; ++i, ++cp) {
 436                flash_add_byte (info, &cword, (*(uchar *) cp));
 437        }
 438
 439        return flash_write_cfiword (info, wp, cword);
 440}
 441
 442/*-----------------------------------------------------------------------
 443 */
 444int flash_real_protect (flash_info_t * info, long sector, int prot)
 445{
 446        int retcode = 0;
 447
 448        flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
 449        flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
 450        if (prot)
 451                flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
 452        else
 453                flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
 454
 455        if ((retcode =
 456             flash_full_status_check (info, sector, info->erase_blk_tout,
 457                                      prot ? "protect" : "unprotect")) == 0) {
 458
 459                info->protect[sector] = prot;
 460                /* Intel's unprotect unprotects all locking */
 461                if (prot == 0) {
 462                        int i;
 463
 464                        for (i = 0; i < info->sector_count; i++) {
 465                                if (info->protect[i])
 466                                        flash_real_protect (info, i, 1);
 467                        }
 468                }
 469        }
 470
 471        return retcode;
 472}
 473
 474/*-----------------------------------------------------------------------
 475 *  wait for XSR.7 to be set. Time out with an error if it does not.
 476 *  This routine does not set the flash to read-array mode.
 477 */
 478static int flash_status_check (flash_info_t * info, ulong sector, ulong tout,
 479                               char *prompt)
 480{
 481        ulong start;
 482
 483        /* Wait for command completion */
 484        start = get_timer (0);
 485        while (!flash_isset (info, sector, 0, FLASH_STATUS_DONE)) {
 486                if (get_timer (start) > info->erase_blk_tout) {
 487                        printf ("Flash %s timeout at address %lx\n", prompt,
 488                                info->start[sector]);
 489                        flash_write_cmd (info, sector, 0, FLASH_CMD_RESET);
 490                        return ERR_TIMOUT;
 491                }
 492        }
 493        return ERR_OK;
 494}
 495
 496/*-----------------------------------------------------------------------
 497 * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
 498 * This routine sets the flash to read-array mode.
 499 */
 500static int flash_full_status_check (flash_info_t * info, ulong sector,
 501                                    ulong tout, char *prompt)
 502{
 503        int retcode;
 504
 505        retcode = flash_status_check (info, sector, tout, prompt);
 506        if ((retcode == ERR_OK)
 507            && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
 508                retcode = ERR_INVAL;
 509                printf ("Flash %s error at address %lx\n", prompt,
 510                        info->start[sector]);
 511                if (flash_isset
 512                    (info, sector, 0,
 513                     FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) {
 514                        printf ("Command Sequence Error.\n");
 515                } else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) {
 516                        printf ("Block Erase Error.\n");
 517                        retcode = ERR_NOT_ERASED;
 518                } else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) {
 519                        printf ("Locking Error\n");
 520                }
 521                if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
 522                        printf ("Block locked.\n");
 523                        retcode = ERR_PROTECTED;
 524                }
 525                if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS))
 526                        printf ("Vpp Low Error.\n");
 527        }
 528        flash_write_cmd (info, sector, 0, FLASH_CMD_RESET);
 529        return retcode;
 530}
 531
 532/*-----------------------------------------------------------------------
 533 */
 534static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c)
 535{
 536        switch (info->portwidth) {
 537        case FLASH_CFI_8BIT:
 538                cword->c = c;
 539                break;
 540        case FLASH_CFI_16BIT:
 541                cword->w = (cword->w << 8) | c;
 542                break;
 543        case FLASH_CFI_32BIT:
 544                cword->l = (cword->l << 8) | c;
 545        }
 546}
 547
 548/*-----------------------------------------------------------------------
 549 * make a proper sized command based on the port and chip widths
 550 */
 551static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
 552{
 553        /*int i; */
 554        uchar *cp = (uchar *) cmdbuf;
 555
 556        /* for(i=0; i< info->portwidth; i++) */
 557        /*  *cp++ = ((i+1) % info->chipwidth) ? '\0':cmd; */
 558        if (info->portwidth == FLASH_CFI_8BIT
 559            && info->chipwidth == FLASH_CFI_16BIT) {
 560                cp[0] = cmd;
 561        } else if (info->portwidth == FLASH_CFI_16BIT
 562                   && info->chipwidth == FLASH_CFI_16BIT) {
 563                cp[0] = '\0';
 564                cp[1] = cmd;
 565        };
 566}
 567
 568/*
 569 * Write a proper sized command to the correct address
 570 */
 571static void flash_write_cmd (flash_info_t * info, int sect, uchar offset,
 572                             uchar cmd)
 573{
 574
 575        volatile cfiptr_t addr;
 576        cfiword_t cword;
 577
 578        addr.cp = flash_make_addr (info, sect, offset);
 579        flash_make_cmd (info, cmd, &cword);
 580        switch (info->portwidth) {
 581        case FLASH_CFI_8BIT:
 582                *addr.cp = cword.c;
 583                break;
 584        case FLASH_CFI_16BIT:
 585                *addr.wp = cword.w;
 586                break;
 587        case FLASH_CFI_32BIT:
 588                *addr.lp = cword.l;
 589                break;
 590        }
 591}
 592
 593/*-----------------------------------------------------------------------
 594 */
 595static int flash_isequal (flash_info_t * info, int sect, uchar offset,
 596                          uchar cmd)
 597{
 598        cfiptr_t cptr;
 599        cfiword_t cword;
 600        int retval;
 601
 602        cptr.cp = flash_make_addr (info, sect, offset);
 603        flash_make_cmd (info, cmd, &cword);
 604        switch (info->portwidth) {
 605        case FLASH_CFI_8BIT:
 606                retval = (cptr.cp[0] == cword.c);
 607                break;
 608        case FLASH_CFI_16BIT:
 609                retval = (cptr.wp[0] == cword.w);
 610                break;
 611        case FLASH_CFI_32BIT:
 612                retval = (cptr.lp[0] == cword.l);
 613                break;
 614        default:
 615                retval = 0;
 616                break;
 617        }
 618        return retval;
 619}
 620
 621/*-----------------------------------------------------------------------
 622 */
 623static int flash_isset (flash_info_t * info, int sect, uchar offset,
 624                        uchar cmd)
 625{
 626        cfiptr_t cptr;
 627        cfiword_t cword;
 628        int retval;
 629
 630        cptr.cp = flash_make_addr (info, sect, offset);
 631        flash_make_cmd (info, cmd, &cword);
 632        switch (info->portwidth) {
 633        case FLASH_CFI_8BIT:
 634                retval = ((cptr.cp[0] & cword.c) == cword.c);
 635                break;
 636        case FLASH_CFI_16BIT:
 637                retval = ((cptr.wp[0] & cword.w) == cword.w);
 638                break;
 639        case FLASH_CFI_32BIT:
 640                retval = ((cptr.lp[0] & cword.l) == cword.l);
 641                break;
 642        default:
 643                retval = 0;
 644                break;
 645        }
 646        return retval;
 647}
 648
 649/*-----------------------------------------------------------------------
 650 * detect if flash is compatible with the Common Flash Interface (CFI)
 651 * http://www.jedec.org/download/search/jesd68.pdf
 652 *
 653*/
 654static int flash_detect_cfi (flash_info_t * info)
 655{
 656
 657#if 0
 658        for (info->portwidth = FLASH_CFI_8BIT;
 659             info->portwidth <= FLASH_CFI_32BIT; info->portwidth <<= 1) {
 660                for (info->chipwidth = FLASH_CFI_BY8;
 661                     info->chipwidth <= info->portwidth;
 662                     info->chipwidth <<= 1) {
 663                        flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
 664                        flash_write_cmd (info, 0, FLASH_OFFSET_CFI,
 665                                         FLASH_CMD_CFI);
 666                        if (flash_isequal
 667                            (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
 668                            && flash_isequal (info, 0,
 669                                              FLASH_OFFSET_CFI_RESP + 1, 'R')
 670                            && flash_isequal (info, 0,
 671                                              FLASH_OFFSET_CFI_RESP + 2, 'Y'))
 672                                return 1;
 673                }
 674        }
 675#endif
 676        flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
 677        flash_write_cmd (info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI);
 678        if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') &&
 679            flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') &&
 680            flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
 681                return 1;
 682        } else {
 683                return 0;
 684        };
 685}
 686
 687/*
 688 * The following code cannot be run from FLASH!
 689 *
 690 */
 691static ulong flash_get_size (ulong base, int banknum)
 692{
 693        flash_info_t *info = &flash_info[banknum];
 694        int i, j;
 695        int sect_cnt;
 696        unsigned long sector;
 697        unsigned long tmp;
 698        int size_ratio;
 699        uchar num_erase_regions;
 700        int erase_region_size;
 701        int erase_region_count;
 702
 703        info->start[0] = base;
 704
 705        if (flash_detect_cfi (info)) {
 706#ifdef DEBUG_FLASH
 707                printf ("portwidth=%d chipwidth=%d\n", info->portwidth, info->chipwidth);       /* test-only */
 708#endif
 709                size_ratio = 1; /* info->portwidth / info->chipwidth; */
 710                num_erase_regions =
 711                        flash_read_uchar (info,
 712                                          FLASH_OFFSET_NUM_ERASE_REGIONS);
 713#ifdef DEBUG_FLASH
 714                printf ("found %d erase regions\n", num_erase_regions);
 715#endif
 716                sect_cnt = 0;
 717                sector = base;
 718                for (i = 0; i < num_erase_regions; i++) {
 719                        if (i > NUM_ERASE_REGIONS) {
 720                                printf ("%d erase regions found, only %d used\n", num_erase_regions, NUM_ERASE_REGIONS);
 721                                break;
 722                        }
 723                        tmp = flash_read_long (info, 0,
 724                                               FLASH_OFFSET_ERASE_REGIONS);
 725                        erase_region_count = (tmp & 0xffff) + 1;
 726                        tmp >>= 16;
 727                        erase_region_size =
 728                                (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
 729                        for (j = 0; j < erase_region_count; j++) {
 730                                info->start[sect_cnt] = sector;
 731                                sector += (erase_region_size * size_ratio);
 732                                info->protect[sect_cnt] =
 733                                        flash_isset (info, sect_cnt,
 734                                                     FLASH_OFFSET_PROTECT,
 735                                                     FLASH_STATUS_PROTECT);
 736                                sect_cnt++;
 737                        }
 738                }
 739
 740                info->sector_count = sect_cnt;
 741                /* multiply the size by the number of chips */
 742                info->size =
 743                        (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) *
 744                        size_ratio;
 745                info->buffer_size =
 746                        (1 <<
 747                         flash_read_ushort (info, 0,
 748                                            FLASH_OFFSET_BUFFER_SIZE));
 749                tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
 750                info->erase_blk_tout =
 751                        (tmp *
 752                         (1 <<
 753                          flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
 754                tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT);
 755                info->buffer_write_tout =
 756                        (tmp *
 757                         (1 <<
 758                          flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)));
 759                tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT);
 760                info->write_tout =
 761                        (tmp *
 762                         (1 <<
 763                          flash_read_uchar (info,
 764                                            FLASH_OFFSET_WMAX_TOUT))) / 1000;
 765                info->flash_id = FLASH_MAN_CFI;
 766        }
 767
 768        flash_write_cmd (info, 0, 0, FLASH_CMD_RESET);
 769        return (info->size);
 770}
 771
 772/*-----------------------------------------------------------------------
 773 */
 774static int flash_write_cfiword (flash_info_t * info, ulong dest,
 775                                cfiword_t cword)
 776{
 777        cfiptr_t cptr;
 778        int flag;
 779
 780        cptr.cp = (uchar *) dest;
 781
 782        /* Check if Flash is (sufficiently) erased */
 783        switch (info->portwidth) {
 784        case FLASH_CFI_8BIT:
 785                flag = ((cptr.cp[0] & cword.c) == cword.c);
 786                break;
 787        case FLASH_CFI_16BIT:
 788                flag = ((cptr.wp[0] & cword.w) == cword.w);
 789                break;
 790        case FLASH_CFI_32BIT:
 791                flag = ((cptr.lp[0] & cword.l) == cword.l);
 792                break;
 793        default:
 794                return 2;
 795        }
 796        if (!flag)
 797                return 2;
 798
 799        /* Disable interrupts which might cause a timeout here */
 800        flag = disable_interrupts ();
 801
 802        flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
 803        flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
 804
 805        switch (info->portwidth) {
 806        case FLASH_CFI_8BIT:
 807                cptr.cp[0] = cword.c;
 808                break;
 809        case FLASH_CFI_16BIT:
 810                cptr.wp[0] = cword.w;
 811                break;
 812        case FLASH_CFI_32BIT:
 813                cptr.lp[0] = cword.l;
 814                break;
 815        }
 816
 817        /* re-enable interrupts if necessary */
 818        if (flag)
 819                enable_interrupts ();
 820
 821        return flash_full_status_check (info, 0, info->write_tout, "write");
 822}
 823
 824#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
 825
 826/* loop through the sectors from the highest address
 827 * when the passed address is greater or equal to the sector address
 828 * we have a match
 829 */
 830static int find_sector (flash_info_t * info, ulong addr)
 831{
 832        int sector;
 833
 834        for (sector = info->sector_count - 1; sector >= 0; sector--) {
 835                if (addr >= info->start[sector])
 836                        break;
 837        }
 838        return sector;
 839}
 840
 841static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 842                                  int len)
 843{
 844
 845        int sector;
 846        int cnt;
 847        int retcode;
 848        volatile cfiptr_t src;
 849        volatile cfiptr_t dst;
 850
 851        src.cp = cp;
 852        dst.cp = (uchar *) dest;
 853        sector = find_sector (info, dest);
 854        flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
 855        flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
 856        if ((retcode =
 857             flash_status_check (info, sector, info->buffer_write_tout,
 858                                 "write to buffer")) == ERR_OK) {
 859                switch (info->portwidth) {
 860                case FLASH_CFI_8BIT:
 861                        cnt = len;
 862                        break;
 863                case FLASH_CFI_16BIT:
 864                        cnt = len >> 1;
 865                        break;
 866                case FLASH_CFI_32BIT:
 867                        cnt = len >> 2;
 868                        break;
 869                default:
 870                        return ERR_INVAL;
 871                        break;
 872                }
 873                flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
 874                while (cnt-- > 0) {
 875                        switch (info->portwidth) {
 876                        case FLASH_CFI_8BIT:
 877                                *dst.cp++ = *src.cp++;
 878                                break;
 879                        case FLASH_CFI_16BIT:
 880                                *dst.wp++ = *src.wp++;
 881                                break;
 882                        case FLASH_CFI_32BIT:
 883                                *dst.lp++ = *src.lp++;
 884                                break;
 885                        default:
 886                                return ERR_INVAL;
 887                                break;
 888                        }
 889                }
 890                flash_write_cmd (info, sector, 0,
 891                                 FLASH_CMD_WRITE_BUFFER_CONFIRM);
 892                retcode =
 893                        flash_full_status_check (info, sector,
 894                                                 info->buffer_write_tout,
 895                                                 "buffer write");
 896        }
 897        flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
 898        return retcode;
 899}
 900#endif /* CONFIG_SYS_USE_FLASH_BUFFER_WRITE */
 901