uboot/board/etin/debris/flash.c
<<
>>
Prefs
   1/*
   2 * board/eva/flash.c
   3 *
   4 * (C) Copyright 2002
   5 * Sangmoon Kim, Etin Systems, dogoil@etinsys.com.
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26#include <common.h>
  27#include <asm/processor.h>
  28#include <asm/pci_io.h>
  29#include <mpc824x.h>
  30#include <asm/mmu.h>
  31
  32int (*do_flash_erase)(flash_info_t*, uint32_t, uint32_t);
  33int (*write_dword)(flash_info_t*, ulong, uint64_t);
  34
  35typedef uint64_t cfi_word;
  36
  37#define cfi_read(flash, addr) *((volatile cfi_word*)(flash->start[0] + addr))
  38
  39#define cfi_write(flash, val, addr) \
  40        move64((cfi_word*)&val, \
  41                        (cfi_word*)(flash->start[0] + addr))
  42
  43#define CMD(x) ((((cfi_word)x)<<48)|(((cfi_word)x)<<32)|(((cfi_word)x)<<16)|(((cfi_word)x)))
  44
  45static void write32(unsigned long addr, uint32_t value)
  46{
  47        *(volatile uint32_t*)(addr) = value;
  48        asm volatile("sync");
  49}
  50
  51static uint32_t read32(unsigned long addr)
  52{
  53        uint32_t value;
  54        value = *(volatile uint32_t*)addr;
  55        asm volatile("sync");
  56        return value;
  57}
  58
  59static cfi_word cfi_cmd(flash_info_t *flash, uint8_t cmd, uint32_t addr)
  60{
  61        uint32_t base = flash->start[0];
  62        uint32_t val=(cmd << 16) | cmd;
  63        addr <<= 3;
  64        write32(base + addr, val);
  65        return addr;
  66}
  67
  68static uint16_t cfi_read_query(flash_info_t *flash, uint32_t addr)
  69{
  70        uint32_t base = flash->start[0];
  71        addr <<= 3;
  72        return (uint16_t)read32(base + addr);
  73}
  74
  75flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
  76
  77static void move64(uint64_t *src, uint64_t *dest)
  78{
  79        asm volatile("lfd  0, 0(3)\n\t" /* fpr0   =  *scr       */
  80         "stfd 0, 0(4)"         /* *dest  =  fpr0       */
  81         : : : "fr0" );         /* Clobbers fr0         */
  82        return;
  83}
  84
  85static int cfi_write_dword(flash_info_t *flash, ulong dest, cfi_word data)
  86{
  87        unsigned long start;
  88        cfi_word status = 0;
  89
  90        status = cfi_read(flash, dest);
  91        data &= status;
  92
  93        cfi_cmd(flash, 0x40, 0);
  94        cfi_write(flash, data, dest);
  95
  96        udelay(10);
  97        start = get_timer (0);
  98        for(;;) {
  99                status = cfi_read(flash, dest);
 100                status &= CMD(0x80);
 101                if(status == CMD(0x80))
 102                        break;
 103                if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
 104                        cfi_cmd(flash, 0xff, 0);
 105                        return 1;
 106                }
 107                udelay(1);
 108        }
 109        cfi_cmd(flash, 0xff, 0);
 110
 111        return 0;
 112}
 113
 114static int jedec_write_dword (flash_info_t *flash, ulong dest, cfi_word data)
 115{
 116        ulong start;
 117        cfi_word status = 0;
 118
 119        status = cfi_read(flash, dest);
 120        if(status != CMD(0xffff)) return 2;
 121
 122        cfi_cmd(flash, 0xaa, 0x555);
 123        cfi_cmd(flash, 0x55, 0x2aa);
 124        cfi_cmd(flash, 0xa0, 0x555);
 125
 126        cfi_write(flash, data, dest);
 127
 128        udelay(10);
 129        start = get_timer (0);
 130        status = ~data;
 131        while(status != data) {
 132                if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT)
 133                        return 1;
 134                status = cfi_read(flash, dest);
 135                udelay(1);
 136        }
 137        return 0;
 138}
 139
 140static __inline__ unsigned long get_msr(void)
 141{
 142        unsigned long msr;
 143        __asm__ __volatile__ ("mfmsr %0" : "=r" (msr) :);
 144        return msr;
 145}
 146
 147static __inline__ void set_msr(unsigned long msr)
 148{
 149        __asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
 150}
 151
 152int write_buff (flash_info_t *flash, uchar *src, ulong addr, ulong cnt)
 153{
 154        ulong wp;
 155        int i, s, l, rc;
 156        cfi_word data;
 157        uint8_t *t = (uint8_t*)&data;
 158        unsigned long base = flash->start[0];
 159        uint32_t msr;
 160
 161        if (flash->flash_id == FLASH_UNKNOWN)
 162                return 4;
 163
 164        if (cnt == 0)
 165                return 0;
 166
 167        addr -= base;
 168
 169        msr = get_msr();
 170        set_msr(msr|MSR_FP);
 171
 172        wp = (addr & ~7);   /* get lower word aligned address */
 173
 174        if((addr-wp) != 0) {
 175                data = cfi_read(flash, wp);
 176                s = addr & 7;
 177                l = ( cnt < (8-s) ) ? cnt : (8-s);
 178                for(i = 0; i < l; i++)
 179                        t[s+i] = *src++;
 180                if ((rc = write_dword(flash, wp, data)) != 0)
 181                        goto DONE;
 182                wp += 8;
 183                cnt -= l;
 184        }
 185
 186        while (cnt >= 8) {
 187                for (i = 0; i < 8; i++)
 188                        t[i] = *src++;
 189                if ((rc = write_dword(flash, wp, data)) != 0)
 190                        goto DONE;
 191                wp  += 8;
 192                cnt -= 8;
 193        }
 194
 195        if (cnt == 0) {
 196                rc = 0;
 197                goto DONE;
 198        }
 199
 200        data = cfi_read(flash, wp);
 201        for(i = 0; i < cnt; i++)
 202                t[i] = *src++;
 203        rc = write_dword(flash, wp, data);
 204DONE:
 205        set_msr(msr);
 206        return rc;
 207}
 208
 209static int cfi_erase_oneblock(flash_info_t *flash, uint32_t sect)
 210{
 211        int sa;
 212        int flag;
 213        ulong start, last, now;
 214        cfi_word status;
 215
 216        flag = disable_interrupts();
 217
 218        sa = (flash->start[sect] - flash->start[0]);
 219        write32(flash->start[sect], 0x00200020);
 220        write32(flash->start[sect], 0x00d000d0);
 221
 222        if (flag)
 223                enable_interrupts();
 224
 225        udelay(1000);
 226        start = get_timer (0);
 227        last  = start;
 228
 229        for (;;) {
 230                status = cfi_read(flash, sa);
 231                status &= CMD(0x80);
 232                if (status == CMD(0x80))
 233                        break;
 234                if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 235                        cfi_cmd(flash, 0xff, 0);
 236                        printf ("Timeout\n");
 237                        return ERR_TIMOUT;
 238                }
 239
 240                if ((now - last) > 1000) {
 241                        serial_putc ('.');
 242                        last = now;
 243                }
 244                udelay(10);
 245        }
 246        cfi_cmd(flash, 0xff, 0);
 247        return ERR_OK;
 248}
 249
 250static int cfi_erase(flash_info_t *flash, uint32_t s_first, uint32_t s_last)
 251{
 252        int sect;
 253        int rc = ERR_OK;
 254
 255        for (sect = s_first; sect <= s_last; sect++) {
 256                if (flash->protect[sect] == 0) {
 257                        rc = cfi_erase_oneblock(flash, sect);
 258                        if (rc != ERR_OK) break;
 259                }
 260        }
 261        printf (" done\n");
 262        return rc;
 263}
 264
 265static int jedec_erase(flash_info_t *flash, uint32_t s_first, uint32_t s_last)
 266{
 267        int sect;
 268        cfi_word status;
 269        int sa = -1;
 270        int flag;
 271        ulong start, last, now;
 272
 273        flag = disable_interrupts();
 274
 275        cfi_cmd(flash, 0xaa, 0x555);
 276        cfi_cmd(flash, 0x55, 0x2aa);
 277        cfi_cmd(flash, 0x80, 0x555);
 278        cfi_cmd(flash, 0xaa, 0x555);
 279        cfi_cmd(flash, 0x55, 0x2aa);
 280        for ( sect = s_first; sect <= s_last; sect++) {
 281                if (flash->protect[sect] == 0) {
 282                        sa = flash->start[sect] - flash->start[0];
 283                        write32(flash->start[sect], 0x00300030);
 284                }
 285        }
 286        if (flag)
 287                enable_interrupts();
 288
 289        if (sa < 0)
 290                goto DONE;
 291
 292        udelay (1000);
 293        start = get_timer (0);
 294        last  = start;
 295        for(;;) {
 296                status = cfi_read(flash, sa);
 297                if (status == CMD(0xffff))
 298                        break;
 299
 300                if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
 301                        printf ("Timeout\n");
 302                        return ERR_TIMOUT;
 303                }
 304
 305                if ((now - last) > 1000) {
 306                        serial_putc ('.');
 307                        last = now;
 308                }
 309                udelay(10);
 310        }
 311DONE:
 312        cfi_cmd(flash, 0xf0, 0);
 313
 314        printf (" done\n");
 315
 316        return ERR_OK;
 317}
 318
 319int flash_erase (flash_info_t *flash, int s_first, int s_last)
 320{
 321        int sect;
 322        int prot;
 323
 324        if ((s_first < 0) || (s_first > s_last)) {
 325                if (flash->flash_id == FLASH_UNKNOWN)
 326                        printf ("- missing\n");
 327                else
 328                        printf ("- no sectors to erase\n");
 329                return ERR_NOT_ERASED;
 330        }
 331        if (flash->flash_id == FLASH_UNKNOWN) {
 332                printf ("Can't erase unknown flash type - aborted\n");
 333                return ERR_NOT_ERASED;
 334        }
 335
 336        prot = 0;
 337        for (sect = s_first; sect <= s_last; sect++)
 338                if (flash->protect[sect]) prot++;
 339
 340        if (prot)
 341                printf ("- Warning: %d protected sectors will not be erased!\n",
 342                                                                prot);
 343        else
 344                printf ("\n");
 345
 346        return do_flash_erase(flash, s_first, s_last);
 347}
 348
 349struct jedec_flash_info {
 350        const uint16_t mfr_id;
 351        const uint16_t dev_id;
 352        const char *name;
 353        const int DevSize;
 354        const int InterfaceDesc;
 355        const int NumEraseRegions;
 356        const ulong regions[4];
 357};
 358
 359#define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
 360
 361#define SIZE_1MiB 20
 362#define SIZE_2MiB 21
 363#define SIZE_4MiB 22
 364
 365static const struct jedec_flash_info jedec_table[] = {
 366        {
 367                mfr_id: (uint16_t)AMD_MANUFACT,
 368                dev_id: (uint16_t)AMD_ID_LV800T,
 369                name: "AMD AM29LV800T",
 370                DevSize: SIZE_1MiB,
 371                NumEraseRegions: 4,
 372                regions: {ERASEINFO(0x10000,15),
 373                          ERASEINFO(0x08000,1),
 374                          ERASEINFO(0x02000,2),
 375                          ERASEINFO(0x04000,1)
 376                }
 377        }, {
 378                mfr_id: (uint16_t)AMD_MANUFACT,
 379                dev_id: (uint16_t)AMD_ID_LV800B,
 380                name: "AMD AM29LV800B",
 381                DevSize: SIZE_1MiB,
 382                NumEraseRegions: 4,
 383                regions: {ERASEINFO(0x10000,15),
 384                          ERASEINFO(0x08000,1),
 385                          ERASEINFO(0x02000,2),
 386                          ERASEINFO(0x04000,1)
 387                }
 388        }, {
 389                mfr_id: (uint16_t)AMD_MANUFACT,
 390                dev_id: (uint16_t)AMD_ID_LV160T,
 391                name: "AMD AM29LV160T",
 392                DevSize: SIZE_2MiB,
 393                NumEraseRegions: 4,
 394                regions: {ERASEINFO(0x10000,31),
 395                          ERASEINFO(0x08000,1),
 396                          ERASEINFO(0x02000,2),
 397                          ERASEINFO(0x04000,1)
 398                }
 399        }, {
 400                mfr_id: (uint16_t)AMD_MANUFACT,
 401                dev_id: (uint16_t)AMD_ID_LV160B,
 402                name: "AMD AM29LV160B",
 403                DevSize: SIZE_2MiB,
 404                NumEraseRegions: 4,
 405                regions: {ERASEINFO(0x04000,1),
 406                          ERASEINFO(0x02000,2),
 407                          ERASEINFO(0x08000,1),
 408                          ERASEINFO(0x10000,31)
 409                }
 410        }, {
 411                mfr_id: (uint16_t)AMD_MANUFACT,
 412                dev_id: (uint16_t)AMD_ID_LV320T,
 413                name: "AMD AM29LV320T",
 414                DevSize: SIZE_4MiB,
 415                NumEraseRegions: 2,
 416                regions: {ERASEINFO(0x10000,63),
 417                          ERASEINFO(0x02000,8)
 418                }
 419
 420        }, {
 421                mfr_id: (uint16_t)AMD_MANUFACT,
 422                dev_id: (uint16_t)AMD_ID_LV320B,
 423                name: "AMD AM29LV320B",
 424                DevSize: SIZE_4MiB,
 425                NumEraseRegions: 2,
 426                regions: {ERASEINFO(0x02000,8),
 427                          ERASEINFO(0x10000,63)
 428                }
 429        }
 430};
 431
 432static ulong cfi_init(uint32_t base,  flash_info_t *flash)
 433{
 434        int sector;
 435        int block;
 436        int block_count;
 437        int offset = 0;
 438        int reverse = 0;
 439        int primary;
 440        int mfr_id;
 441        int dev_id;
 442
 443        flash->start[0] = base;
 444        cfi_cmd(flash, 0xF0, 0);
 445        cfi_cmd(flash, 0x98, 0);
 446        if ( !( cfi_read_query(flash, 0x10) == 'Q' &&
 447                cfi_read_query(flash, 0x11) == 'R' &&
 448                cfi_read_query(flash, 0x12) == 'Y' )) {
 449                cfi_cmd(flash, 0xff, 0);
 450                return 0;
 451        }
 452
 453        flash->size = 1 << cfi_read_query(flash, 0x27);
 454        flash->size *= 4;
 455        block_count = cfi_read_query(flash, 0x2c);
 456        primary = cfi_read_query(flash, 0x15);
 457        if ( cfi_read_query(flash, primary + 4) == 0x30)
 458                reverse = (cfi_read_query(flash, 0x1) & 0x01);
 459        else
 460                reverse = (cfi_read_query(flash, primary+15) == 3);
 461
 462        flash->sector_count = 0;
 463
 464        for ( block = reverse ? block_count - 1 : 0;
 465                      reverse ? block >= 0      : block < block_count;
 466                      reverse ? block--         : block ++) {
 467                int sector_size =
 468                        (cfi_read_query(flash, 0x2d + block*4+2) |
 469                        (cfi_read_query(flash, 0x2d + block*4+3) << 8)) << 8;
 470                int sector_count =
 471                        (cfi_read_query(flash, 0x2d + block*4+0) |
 472                        (cfi_read_query(flash, 0x2d + block*4+1) << 8)) + 1;
 473                for(sector = 0; sector < sector_count; sector++) {
 474                        flash->start[flash->sector_count++] = base + offset;
 475                        offset += sector_size * 4;
 476                }
 477        }
 478        mfr_id = cfi_read_query(flash, 0x00);
 479        dev_id = cfi_read_query(flash, 0x01);
 480
 481        cfi_cmd(flash, 0xff, 0);
 482
 483        flash->flash_id = (mfr_id << 16) | dev_id;
 484
 485        for (sector = 0; sector < flash->sector_count; sector++) {
 486                write32(flash->start[sector], 0x00600060);
 487                write32(flash->start[sector], 0x00d000d0);
 488        }
 489        cfi_cmd(flash, 0xff, 0);
 490
 491        for (sector = 0; sector < flash->sector_count; sector++)
 492                flash->protect[sector] = 0;
 493
 494        do_flash_erase = cfi_erase;
 495        write_dword = cfi_write_dword;
 496
 497        return flash->size;
 498}
 499
 500static ulong jedec_init(unsigned long base, flash_info_t *flash)
 501{
 502        int i;
 503        int block, block_count;
 504        int sector, offset;
 505        int mfr_id, dev_id;
 506        flash->start[0] = base;
 507        cfi_cmd(flash, 0xF0, 0x000);
 508        cfi_cmd(flash, 0xAA, 0x555);
 509        cfi_cmd(flash, 0x55, 0x2AA);
 510        cfi_cmd(flash, 0x90, 0x555);
 511        mfr_id = cfi_read_query(flash, 0x000);
 512        dev_id = cfi_read_query(flash, 0x0001);
 513        cfi_cmd(flash, 0xf0, 0x000);
 514
 515        for(i=0; i<sizeof(jedec_table)/sizeof(struct jedec_flash_info); i++) {
 516                if((jedec_table[i].mfr_id == mfr_id) &&
 517                        (jedec_table[i].dev_id == dev_id)) {
 518
 519                        flash->flash_id = (mfr_id << 16) | dev_id;
 520                        flash->size = 1 << jedec_table[0].DevSize;
 521                        flash->size *= 4;
 522                        block_count = jedec_table[i].NumEraseRegions;
 523                        offset = 0;
 524                        flash->sector_count = 0;
 525                        for (block = 0; block < block_count; block++) {
 526                                int sector_size = jedec_table[i].regions[block];
 527                                int sector_count = (sector_size & 0xff) + 1;
 528                                sector_size >>= 8;
 529                                for (sector=0; sector<sector_count; sector++) {
 530                                        flash->start[flash->sector_count++] =
 531                                                base + offset;
 532                                        offset += sector_size * 4;
 533                                }
 534                        }
 535                        break;
 536                }
 537        }
 538
 539        for (sector = 0; sector < flash->sector_count; sector++)
 540                flash->protect[sector] = 0;
 541
 542        do_flash_erase = jedec_erase;
 543        write_dword = jedec_write_dword;
 544
 545        return flash->size;
 546}
 547
 548inline void mtibat1u(unsigned int x)
 549{
 550        __asm__ __volatile__ ("mtspr   530, %0" :: "r" (x));
 551}
 552
 553inline void mtibat1l(unsigned int x)
 554{
 555        __asm__ __volatile__ ("mtspr   531, %0" :: "r" (x));
 556}
 557
 558inline void mtdbat1u(unsigned int x)
 559{
 560        __asm__ __volatile__ ("mtspr   538, %0" :: "r" (x));
 561}
 562
 563inline void mtdbat1l(unsigned int x)
 564{
 565        __asm__ __volatile__ ("mtspr   539, %0" :: "r" (x));
 566}
 567
 568unsigned long flash_init (void)
 569{
 570        unsigned long size = 0;
 571        int i;
 572        unsigned int msr;
 573
 574        /* BAT1 */
 575        CONFIG_WRITE_WORD(ERCR3, 0x0C00000C);
 576        CONFIG_WRITE_WORD(ERCR4, 0x0800000C);
 577        msr = get_msr();
 578        set_msr(msr & ~(MSR_IR | MSR_DR));
 579        mtibat1l(0x70000000 | BATL_PP_10 | BATL_CACHEINHIBIT);
 580        mtibat1u(0x70000000 | BATU_BL_256M | BATU_VS | BATU_VP);
 581        mtdbat1l(0x70000000 | BATL_PP_10 | BATL_CACHEINHIBIT);
 582        mtdbat1u(0x70000000 | BATU_BL_256M | BATU_VS | BATU_VP);
 583        set_msr(msr);
 584
 585        for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++)
 586                flash_info[i].flash_id = FLASH_UNKNOWN;
 587        size = cfi_init(FLASH_BASE0_PRELIM, &flash_info[0]);
 588        if (!size)
 589                size = jedec_init(FLASH_BASE0_PRELIM, &flash_info[0]);
 590
 591        if (flash_info[0].flash_id == FLASH_UNKNOWN)
 592                printf ("# Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n",
 593                        size, size<<20);
 594
 595        return size;
 596}
 597
 598void flash_print_info  (flash_info_t *flash)
 599{
 600        int i;
 601        int k;
 602        int size;
 603        int erased;
 604        volatile unsigned long *p;
 605
 606        if (flash->flash_id == FLASH_UNKNOWN) {
 607                printf ("missing or unknown FLASH type\n");
 608                flash_init();
 609        }
 610
 611        if (flash->flash_id == FLASH_UNKNOWN) {
 612                printf ("missing or unknown FLASH type\n");
 613                return;
 614        }
 615
 616        switch (((flash->flash_id) >> 16) & 0xff) {
 617        case 0x01:
 618                printf ("AMD ");
 619                break;
 620        case 0x04:
 621                printf("FUJITSU ");
 622                break;
 623        case 0x20:
 624                printf("STM ");
 625                break;
 626        case 0xBF:
 627                printf("SST ");
 628                break;
 629        case 0x89:
 630        case 0xB0:
 631                printf("INTEL ");
 632                break;
 633        default:
 634                printf ("Unknown Vendor ");
 635                break;
 636        }
 637
 638        switch ((flash->flash_id) & 0xffff) {
 639        case (uint16_t)AMD_ID_LV800T:
 640                printf ("AM29LV800T\n");
 641                break;
 642        case (uint16_t)AMD_ID_LV800B:
 643                printf ("AM29LV800B\n");
 644                break;
 645        case (uint16_t)AMD_ID_LV160T:
 646                printf ("AM29LV160T\n");
 647                break;
 648        case (uint16_t)AMD_ID_LV160B:
 649                printf ("AM29LV160B\n");
 650                break;
 651        case (uint16_t)AMD_ID_LV320T:
 652                printf ("AM29LV320T\n");
 653                break;
 654        case (uint16_t)AMD_ID_LV320B:
 655                printf ("AM29LV320B\n");
 656                break;
 657        case (uint16_t)INTEL_ID_28F800C3T:
 658                printf ("28F800C3T\n");
 659                break;
 660        case (uint16_t)INTEL_ID_28F800C3B:
 661                printf ("28F800C3B\n");
 662                break;
 663        case (uint16_t)INTEL_ID_28F160C3T:
 664                printf ("28F160C3T\n");
 665                break;
 666        case (uint16_t)INTEL_ID_28F160C3B:
 667                printf ("28F160C3B\n");
 668                break;
 669        case (uint16_t)INTEL_ID_28F320C3T:
 670                printf ("28F320C3T\n");
 671                break;
 672        case (uint16_t)INTEL_ID_28F320C3B:
 673                printf ("28F320C3B\n");
 674                break;
 675        case (uint16_t)INTEL_ID_28F640C3T:
 676                printf ("28F640C3T\n");
 677                break;
 678        case (uint16_t)INTEL_ID_28F640C3B:
 679                printf ("28F640C3B\n");
 680                break;
 681        default:
 682                printf ("Unknown Chip Type\n");
 683                break;
 684        }
 685
 686        if (flash->size >= (1 << 20)) {
 687                printf ("  Size: %ld MB in %d Sectors\n",
 688                                flash->size >> 20, flash->sector_count);
 689        } else {
 690                printf ("  Size: %ld kB in %d Sectors\n",
 691                                flash->size >> 10, flash->sector_count);
 692        }
 693
 694        printf ("  Sector Start Addresses:");
 695        for (i = 0; i < flash->sector_count; ++i) {
 696                /* Check if whole sector is erased*/
 697                if (i != (flash->sector_count-1))
 698                        size = flash->start[i+1] - flash->start[i];
 699                else
 700                        size = flash->start[0] + flash->size - flash->start[i];
 701
 702                erased = 1;
 703                p = (volatile unsigned long *)flash->start[i];
 704                size = size >> 2;        /* divide by 4 for longword access */
 705                for (k=0; k<size; k++) {
 706                        if (*p++ != 0xffffffff) {
 707                                erased = 0;
 708                                break;
 709                        }
 710                }
 711
 712                if ((i % 5) == 0)
 713                        printf ("\n   ");
 714
 715                printf (" %08lX%s%s",
 716                        flash->start[i],
 717                        erased ? " E" : "  ",
 718                        flash->protect[i] ? "RO " : "   ");
 719        }
 720        printf ("\n");
 721}
 722