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