uboot/board/sc520_spunk/flash.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002, 2003
   3 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
   4 *
   5 * (C) Copyright 2002
   6 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   7 * Alex Zuepke <azu@sysgo.de>
   8 *
   9 * See file CREDITS for list of people who contributed to this
  10 * project.
  11 *
  12 * This program is free software; you can redistribute it and/or
  13 * modify it under the terms of the GNU General Public License as
  14 * published by the Free Software Foundation; either version 2 of
  15 * the License, or (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  25 * MA 02111-1307 USA
  26 */
  27
  28#include <common.h>
  29#include <asm/io.h>
  30#include <pci.h>
  31#include <asm/ic/sc520.h>
  32
  33#define PROBE_BUFFER_SIZE 1024
  34static unsigned char buffer[PROBE_BUFFER_SIZE];
  35
  36#define SC520_MAX_FLASH_BANKS  1
  37#define SC520_FLASH_BANK0_BASE 0x38000000  /* BOOTCS */
  38#define SC520_FLASH_BANKSIZE   0x8000000
  39
  40#define A29LV641DH_SIZE        0x800000
  41#define A29LV641DH_SECTORS     128
  42
  43#define A29LV641MH_SIZE        0x800000
  44#define A29LV641MH_SECTORS     128
  45
  46#define I28F320J3A_SIZE        0x400000
  47#define I28F320J3A_SECTORS     32
  48
  49#define I28F640J3A_SIZE        0x800000
  50#define I28F640J3A_SECTORS     64
  51
  52#define I28F128J3A_SIZE        0x1000000
  53#define I28F128J3A_SECTORS     128
  54
  55flash_info_t    flash_info[SC520_MAX_FLASH_BANKS];
  56
  57#define READY 1
  58#define ERR   2
  59#define TMO   4
  60
  61/*-----------------------------------------------------------------------
  62 */
  63
  64static u32 _probe_flash(u32 addr, u32 bw, int il)
  65{
  66        u32 result=0;
  67
  68        /* First do an unlock cycle for the benefit of
  69         * devices that need it */
  70
  71        switch (bw) {
  72
  73        case 1:
  74                *(volatile u8*)(addr+0x5555) = 0xaa;
  75                *(volatile u8*)(addr+0x2aaa) = 0x55;
  76                *(volatile u8*)(addr+0x5555) = 0x90;
  77
  78                /* Read vendor */
  79                result = *(volatile u8*)addr;
  80                result <<= 16;
  81
  82                /* Read device */
  83                result |= *(volatile u8*)(addr+2);
  84
  85                /* Return device to data mode */
  86                *(volatile u8*)addr = 0xff;
  87                *(volatile u8*)(addr+0x5555), 0xf0;
  88                break;
  89
  90        case 2:
  91                *(volatile u16*)(addr+0xaaaa) = 0xaaaa;
  92                *(volatile u16*)(addr+0x5554) = 0x5555;
  93
  94                /* Issue identification command */
  95                if (il == 2) {
  96                        *(volatile u16*)(addr+0xaaaa) = 0x9090;
  97
  98                        /* Read vendor */
  99                        result = *(volatile u8*)addr;
 100                        result <<= 16;
 101
 102                        /* Read device */
 103                        result |= *(volatile u8*)(addr+2);
 104
 105                        /* Return device to data mode */
 106                        *(volatile u16*)addr =  0xffff;
 107                        *(volatile u16*)(addr+0xaaaa), 0xf0f0;
 108
 109                } else {
 110                        *(volatile u8*)(addr+0xaaaa) = 0x90;
 111                        /* Read vendor */
 112                        result = *(volatile u16*)addr;
 113                        result <<= 16;
 114
 115                        /* Read device */
 116                        result |= *(volatile u16*)(addr+2);
 117
 118                        /* Return device to data mode */
 119                        *(volatile u8*)addr = 0xff;
 120                        *(volatile u8*)(addr+0xaaaa), 0xf0;
 121                }
 122
 123                break;
 124
 125         case 4:
 126                *(volatile u32*)(addr+0x5554) = 0xaaaaaaaa;
 127                *(volatile u32*)(addr+0xaaa8) = 0x55555555;
 128
 129                switch (il) {
 130                case 1:
 131                        /* Issue identification command */
 132                        *(volatile u8*)(addr+0x5554) = 0x90;
 133
 134                        /* Read vendor */
 135                        result = *(volatile u16*)addr;
 136                        result <<= 16;
 137
 138                        /* Read device */
 139                        result |= *(volatile u16*)(addr+4);
 140
 141                        /* Return device to data mode */
 142                        *(volatile u8*)addr =  0xff;
 143                        *(volatile u8*)(addr+0x5554), 0xf0;
 144                        break;
 145
 146                case 2:
 147                        /* Issue identification command */
 148                        *(volatile u32*)(addr + 0x5554) = 0x00900090;
 149
 150                        /* Read vendor */
 151                        result = *(volatile u16*)addr;
 152                        result <<= 16;
 153
 154                        /* Read device */
 155                        result |= *(volatile u16*)(addr+4);
 156
 157                        /* Return device to data mode */
 158                        *(volatile u32*)addr =  0x00ff00ff;
 159                        *(volatile u32*)(addr+0x5554), 0x00f000f0;
 160                        break;
 161
 162                case 4:
 163                        /* Issue identification command */
 164                        *(volatile u32*)(addr+0x5554) = 0x90909090;
 165
 166                        /* Read vendor */
 167                        result = *(volatile u8*)addr;
 168                        result <<= 16;
 169
 170                        /* Read device */
 171                        result |= *(volatile u8*)(addr+4);
 172
 173                        /* Return device to data mode */
 174                        *(volatile u32*)addr =  0xffffffff;
 175                        *(volatile u32*)(addr+0x5554), 0xf0f0f0f0;
 176                        break;
 177                }
 178                break;
 179        }
 180
 181        return result;
 182}
 183
 184extern int _probe_flash_end;
 185asm ("_probe_flash_end:\n"
 186     ".long 0\n");
 187
 188static int identify_flash(unsigned address, int width)
 189{
 190        int is;
 191        int device;
 192        int vendor;
 193        int size;
 194        unsigned res;
 195
 196        u32 (*_probe_flash_ptr)(u32 a, u32 bw, int il);
 197
 198        size = (unsigned)&_probe_flash_end - (unsigned)_probe_flash;
 199
 200        if (size > PROBE_BUFFER_SIZE) {
 201                printf("_probe_flash() routine too large (%d) %p - %p\n",
 202                       size, &_probe_flash_end, _probe_flash);
 203                return 0;
 204        }
 205
 206        memcpy(buffer, _probe_flash, size);
 207        _probe_flash_ptr = (void*)buffer;
 208
 209        is = disable_interrupts();
 210        res = _probe_flash_ptr(address, width, 1);
 211        if (is) {
 212                enable_interrupts();
 213        }
 214
 215        vendor = res >> 16;
 216        device = res & 0xffff;
 217
 218        return res;
 219}
 220
 221ulong flash_init(void)
 222{
 223        int i, j;
 224        ulong size = 0;
 225
 226        for (i = 0; i < SC520_MAX_FLASH_BANKS; i++) {
 227                unsigned id;
 228                ulong flashbase = 0;
 229                int sectsize = 0;
 230
 231                memset(flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT);
 232                switch (i) {
 233                case 0:
 234                        flashbase = SC520_FLASH_BANK0_BASE;
 235                        break;
 236                default:
 237                        panic("configured too many flash banks!\n");
 238                }
 239
 240                id = identify_flash(flashbase, 2);
 241                switch (id) {
 242                case 0x000122d7:
 243                        /* 29LV641DH */
 244                        flash_info[i].flash_id =
 245                                (AMD_MANUFACT & FLASH_VENDMASK) |
 246                                (AMD_ID_LV640U & FLASH_TYPEMASK);
 247
 248                        flash_info[i].size = A29LV641DH_SIZE;
 249                        flash_info[i].sector_count = A29LV641DH_SECTORS;
 250                        sectsize = A29LV641DH_SIZE/A29LV641DH_SECTORS;
 251                        printf("Bank %d: AMD 29LV641DH\n", i);
 252                        break;
 253
 254                case 0x0001227E:
 255                        /* 29LV641MH */
 256                        flash_info[i].flash_id =
 257                                (AMD_MANUFACT & FLASH_VENDMASK) |
 258                                (AMD_ID_DL640 & FLASH_TYPEMASK);
 259
 260                        flash_info[i].size = A29LV641MH_SIZE;
 261                        flash_info[i].sector_count = A29LV641MH_SECTORS;
 262                        sectsize = A29LV641MH_SIZE/A29LV641MH_SECTORS;
 263                        printf("Bank %d: AMD 29LV641MH\n", i);
 264                        break;
 265
 266                case 0x00890016:
 267                        /* 28F320J3A */
 268                        flash_info[i].flash_id =
 269                                (INTEL_MANUFACT & FLASH_VENDMASK) |
 270                                (INTEL_ID_28F320J3A & FLASH_TYPEMASK);
 271
 272                        flash_info[i].size = I28F320J3A_SIZE;
 273                        flash_info[i].sector_count = I28F320J3A_SECTORS;
 274                        sectsize = I28F320J3A_SIZE/I28F320J3A_SECTORS;
 275                        printf("Bank %d: Intel 28F320J3A\n", i);
 276                        break;
 277
 278                case 0x00890017:
 279                        /* 28F640J3A */
 280                        flash_info[i].flash_id =
 281                                (INTEL_MANUFACT & FLASH_VENDMASK) |
 282                                (INTEL_ID_28F640J3A & FLASH_TYPEMASK);
 283
 284                        flash_info[i].size = I28F640J3A_SIZE;
 285                        flash_info[i].sector_count = I28F640J3A_SECTORS;
 286                        sectsize = I28F640J3A_SIZE/I28F640J3A_SECTORS;
 287                        printf("Bank %d: Intel 28F640J3A\n", i);
 288                        break;
 289
 290                case 0x00890018:
 291                        /* 28F128J3A */
 292                        flash_info[i].flash_id =
 293                                (INTEL_MANUFACT & FLASH_VENDMASK) |
 294                                (INTEL_ID_28F128J3A & FLASH_TYPEMASK);
 295
 296                        flash_info[i].size = I28F128J3A_SIZE;
 297                        flash_info[i].sector_count = I28F128J3A_SECTORS;
 298                        sectsize = I28F128J3A_SIZE/I28F128J3A_SECTORS;
 299                        printf("Bank %d: Intel 28F128J3A\n", i);
 300                        break;
 301
 302                default:
 303                        printf("Bank %d have unknown flash %08x\n", i, id);
 304                        flash_info[i].flash_id = FLASH_UNKNOWN;
 305                        continue;
 306                }
 307
 308                for (j = 0; j < flash_info[i].sector_count; j++) {
 309                        flash_info[i].start[j] = flashbase + j * sectsize;
 310                }
 311                size += flash_info[i].size;
 312
 313                flash_protect(FLAG_PROTECT_CLEAR,
 314                              flash_info[i].start[0],
 315                               flash_info[i].start[0] + flash_info[i].size - 1,
 316                              &flash_info[i]);
 317        }
 318
 319        /*
 320         * Protect monitor and environment sectors
 321         */
 322        flash_protect(FLAG_PROTECT_SET,
 323                      i386boot_start,
 324                      i386boot_end,
 325                      &flash_info[0]);
 326#ifdef CONFIG_ENV_ADDR
 327        flash_protect(FLAG_PROTECT_SET,
 328                      CONFIG_ENV_ADDR,
 329                      CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
 330                      &flash_info[0]);
 331#endif
 332        return size;
 333}
 334
 335/*-----------------------------------------------------------------------
 336 */
 337void flash_print_info(flash_info_t *info)
 338{
 339        int i;
 340
 341        switch (info->flash_id & FLASH_VENDMASK) {
 342        case (INTEL_MANUFACT & FLASH_VENDMASK):
 343                printf("INTEL: ");
 344                switch (info->flash_id & FLASH_TYPEMASK) {
 345                case (INTEL_ID_28F320J3A & FLASH_TYPEMASK):
 346                        printf("1x I28F320J3A (32Mbit)\n");
 347                        break;
 348                case (INTEL_ID_28F640J3A & FLASH_TYPEMASK):
 349                        printf("1x I28F640J3A (64Mbit)\n");
 350                        break;
 351                case (INTEL_ID_28F128J3A & FLASH_TYPEMASK):
 352                        printf("1x I28F128J3A (128Mbit)\n");
 353                        break;
 354                default:
 355                        printf("Unknown Chip Type\n");
 356                        goto done;
 357                        break;
 358                }
 359
 360                break;
 361
 362        case (AMD_MANUFACT & FLASH_VENDMASK):
 363                printf("AMD:   ");
 364                switch (info->flash_id & FLASH_TYPEMASK) {
 365                case (AMD_ID_LV640U & FLASH_TYPEMASK):
 366                        printf("1x AMD29LV641DH (64Mbit)\n");
 367                        break;
 368                case (AMD_ID_DL640 & FLASH_TYPEMASK):
 369                        printf("1x AMD29LV641MH (64Mbit)\n");
 370                        break;
 371                default:
 372                        printf("Unknown Chip Type\n");
 373                        goto done;
 374                        break;
 375                }
 376
 377                break;
 378        default:
 379                printf("Unknown Vendor ");
 380                break;
 381        }
 382
 383        printf("  Size: %ld MB in %d Sectors\n",
 384               info->size >> 20, info->sector_count);
 385
 386        printf("  Sector Start Addresses:");
 387        for (i = 0; i < info->sector_count; i++) {
 388                if ((i % 5) == 0) {
 389                        printf ("\n   ");
 390                }
 391                printf (" %08lX%s", info->start[i],
 392                        info->protect[i] ? " (RO)" : "     ");
 393        }
 394        printf ("\n");
 395
 396done:
 397        return;
 398}
 399
 400/*-----------------------------------------------------------------------
 401 */
 402
 403static u32 _amd_erase_flash(u32 addr, u32 sector)
 404{
 405        unsigned elapsed;
 406
 407        /* Issue erase */
 408        *(volatile u16*)(addr + 0xaaaa) = 0x00AA;
 409        *(volatile u16*)(addr + 0x5554) = 0x0055;
 410        *(volatile u16*)(addr + 0xaaaa) = 0x0080;
 411        /* And one unlock */
 412        *(volatile u16*)(addr + 0xaaaa) = 0x00AA;
 413        *(volatile u16*)(addr + 0x5554) = 0x0055;
 414        /* Sector erase command comes last */
 415        *(volatile u16*)(addr + sector) = 0x0030;
 416
 417        elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
 418        elapsed = 0;
 419        while (((*(volatile u16*)(addr + sector)) & 0x0080) != 0x0080) {
 420
 421                elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
 422                if (elapsed > ((CONFIG_SYS_FLASH_ERASE_TOUT/CONFIG_SYS_HZ) * 1000)) {
 423                        *(volatile u16*)(addr) = 0x00f0;
 424                        return 1;
 425                }
 426        }
 427
 428        *(volatile u16*)(addr) = 0x00f0;
 429
 430        return 0;
 431}
 432
 433extern int _amd_erase_flash_end;
 434asm ("_amd_erase_flash_end:\n"
 435     ".long 0\n");
 436
 437/* this needs to be inlined, the SWTMRMMILLI register is reset by each read */
 438#define __udelay(delay) \
 439{       \
 440        unsigned micro; \
 441        unsigned milli=0; \
 442        \
 443        micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
 444         \
 445        for (;;) { \
 446                \
 447                milli += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
 448                micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMICRO); \
 449                \
 450                if ((delay) <= (micro + (milli * 1000))) { \
 451                        break; \
 452                } \
 453        } \
 454} while (0)
 455
 456static u32 _intel_erase_flash(u32 addr, u32 sector)
 457{
 458        unsigned elapsed;
 459
 460        *(volatile u16*)(addr + sector) = 0x0050;   /* clear status register */
 461        *(volatile u16*)(addr + sector) = 0x0020;   /* erase setup */
 462        *(volatile u16*)(addr + sector) = 0x00D0;   /* erase confirm */
 463
 464        /* Wait at least 80us - let's wait 1 ms */
 465        __udelay(1000);
 466
 467        elapsed = 0;
 468        while (((*(volatile u16*)(addr + sector)) & 0x0080) != 0x0080) {
 469                elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
 470                if (elapsed > ((CONFIG_SYS_FLASH_ERASE_TOUT/CONFIG_SYS_HZ) * 1000)) {
 471                        *(volatile u16*)(addr + sector) = 0x00B0;  /* suspend erase      */
 472                        *(volatile u16*)(addr + sector) = 0x00FF;  /* reset to read mode */
 473                        return 1;
 474                }
 475        }
 476
 477        *(volatile u16*)(addr + sector) = 0x00FF;  /* reset to read mode */
 478
 479        return 0;
 480}
 481
 482extern int _intel_erase_flash_end;
 483asm ("_intel_erase_flash_end:\n"
 484     ".long 0\n");
 485
 486int flash_erase(flash_info_t *info, int s_first, int s_last)
 487{
 488        u32 (*_erase_flash_ptr)(u32 a, u32 so);
 489        int prot;
 490        int sect;
 491        unsigned size;
 492
 493        if ((s_first < 0) || (s_first > s_last)) {
 494                if (info->flash_id == FLASH_UNKNOWN) {
 495                        printf("- missing\n");
 496                } else {
 497                        printf("- no sectors to erase\n");
 498                }
 499                return 1;
 500        }
 501
 502        if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
 503                size = (unsigned)&_amd_erase_flash_end - (unsigned)_amd_erase_flash;
 504
 505                if (size > PROBE_BUFFER_SIZE) {
 506                        printf("_amd_erase_flash() routine too large (%d) %p - %p\n",
 507                               size, &_amd_erase_flash_end, _amd_erase_flash);
 508                        return 0;
 509                }
 510
 511                memcpy(buffer, _amd_erase_flash, size);
 512                _erase_flash_ptr = (void*)buffer;
 513
 514        } else if ((info->flash_id & FLASH_VENDMASK) == (INTEL_MANUFACT & FLASH_VENDMASK)) {
 515                size = (unsigned)&_intel_erase_flash_end - (unsigned)_intel_erase_flash;
 516
 517                if (size > PROBE_BUFFER_SIZE) {
 518                        printf("_intel_erase_flash() routine too large (%d) %p - %p\n",
 519                               size, &_intel_erase_flash_end, _intel_erase_flash);
 520                        return 0;
 521                }
 522
 523                memcpy(buffer, _intel_erase_flash, size);
 524                _erase_flash_ptr = (void*)buffer;
 525        } else {
 526                printf ("Can't erase unknown flash type - aborted\n");
 527                return 1;
 528        }
 529
 530        prot = 0;
 531        for (sect=s_first; sect<=s_last; ++sect) {
 532                if (info->protect[sect]) {
 533                        prot++;
 534                }
 535        }
 536
 537        if (prot) {
 538                printf ("- Warning: %d protected sectors will not be erased!\n", prot);
 539        } else {
 540                printf ("\n");
 541        }
 542
 543        /* Start erase on unprotected sectors */
 544        for (sect = s_first; sect<=s_last; sect++) {
 545
 546                if (info->protect[sect] == 0) { /* not protected */
 547                        int res;
 548                        int flag;
 549
 550                        /* Disable interrupts which might cause a timeout here */
 551                        flag = disable_interrupts();
 552
 553                        res = _erase_flash_ptr(info->start[0], info->start[sect]-info->start[0]);
 554
 555                        /* re-enable interrupts if necessary */
 556                        if (flag) {
 557                                enable_interrupts();
 558                        }
 559
 560                        if (res) {
 561                                printf("Erase timed out, sector %d\n", sect);
 562                                return res;
 563                        }
 564
 565                        putc('.');
 566                }
 567        }
 568
 569        return 0;
 570}
 571
 572/*-----------------------------------------------------------------------
 573 * Write a word to Flash, returns:
 574 * 0 - OK
 575 * 1 - write timeout
 576 * 2 - Flash not erased
 577 */
 578static int _amd_write_word(unsigned start, unsigned dest, u16 data)
 579{
 580        volatile u16 *addr2 = (volatile u16*)start;
 581        volatile u16 *dest2 = (volatile u16*)dest;
 582        volatile u16 *data2 = (volatile u16*)&data;
 583        int i;
 584        unsigned elapsed;
 585
 586        /* Check if Flash is (sufficiently) erased */
 587        if ((*((volatile u16*)dest) & (u16)data) != (u16)data) {
 588                return 2;
 589        }
 590
 591        for (i = 0; i < 2; i++) {
 592
 593                addr2[0x5555] = 0x00AA;
 594                addr2[0x2aaa] = 0x0055;
 595                addr2[0x5555] = 0x00A0;
 596
 597                dest2[i] = (data >> (i*16)) & 0xffff;
 598
 599                elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
 600                elapsed = 0;
 601
 602                /* data polling for D7 */
 603                while ((dest2[i] & 0x0080) != (data2[i] & 0x0080)) {
 604                        elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
 605                        if (elapsed > ((CONFIG_SYS_FLASH_WRITE_TOUT/CONFIG_SYS_HZ) * 1000)) {
 606                                addr2[i] = 0x00f0;
 607                                return 1;
 608                        }
 609                }
 610        }
 611
 612        addr2[i] = 0x00f0;
 613
 614        return 0;
 615}
 616
 617extern int _amd_write_word_end;
 618asm ("_amd_write_word_end:\n"
 619     ".long 0\n");
 620
 621static int _intel_write_word(unsigned start, unsigned dest, unsigned data)
 622{
 623        int i;
 624        unsigned elapsed;
 625
 626        /* Check if Flash is (sufficiently) erased */
 627        if ((*((volatile u16*)dest) & (u16)data) != (u16)data) {
 628                return 2;
 629        }
 630
 631        for (i = 0; i < 2; i++) {
 632
 633                *(volatile u16*)(dest+2*i) = 0x0040; /* write setup */
 634                *(volatile u16*)(dest+2*i) = (data >> (i*16)) & 0xffff;
 635
 636                elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
 637                elapsed = 0;
 638
 639                /* data polling for D7 */
 640                while ((*(volatile u16*)dest & 0x0080) != 0x0080) {
 641                        elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
 642                        if (elapsed > ((CONFIG_SYS_FLASH_WRITE_TOUT/CONFIG_SYS_HZ) * 1000)) {
 643                                *(volatile u16*)dest = 0x00ff;
 644                                return 1;
 645                        }
 646                }
 647        }
 648
 649        *(volatile u16*)dest = 0x00ff;
 650
 651
 652        return 0;
 653}
 654
 655extern int _intel_write_word_end;
 656asm ("_intel_write_word_end:\n"
 657     ".long 0\n");
 658
 659/*-----------------------------------------------------------------------
 660 * Copy memory to flash, returns:
 661 * 0 - OK
 662 * 1 - write timeout
 663 * 2 - Flash not erased
 664 * 3 - Unsupported flash type
 665 */
 666
 667int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 668{
 669        ulong cp, wp, data;
 670        int i, l, rc;
 671        int flag;
 672        u32 (*_write_word_ptr)(unsigned start, unsigned dest, unsigned data);
 673        unsigned size;
 674
 675        if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
 676                size = (unsigned)&_amd_write_word_end - (unsigned)_amd_write_word;
 677
 678                if (size > PROBE_BUFFER_SIZE) {
 679                        printf("_amd_write_word() routine too large (%d) %p - %p\n",
 680                               size, &_amd_write_word_end, _amd_write_word);
 681                        return 0;
 682                }
 683
 684                memcpy(buffer, _amd_write_word, size);
 685                _write_word_ptr = (void*)buffer;
 686
 687        } else if ((info->flash_id & FLASH_VENDMASK) == (INTEL_MANUFACT & FLASH_VENDMASK)) {
 688                size = (unsigned)&_intel_write_word_end - (unsigned)_intel_write_word;
 689
 690                if (size > PROBE_BUFFER_SIZE) {
 691                        printf("_intel_write_word() routine too large (%d) %p - %p\n",
 692                               size, &_intel_write_word_end, _intel_write_word);
 693                        return 0;
 694                }
 695
 696                memcpy(buffer, _intel_write_word, size);
 697                _write_word_ptr = (void*)buffer;
 698        } else {
 699                printf ("Can't program unknown flash type - aborted\n");
 700                return 3;
 701        }
 702
 703        wp = (addr & ~3);       /* get lower word aligned address */
 704
 705        /*
 706         * handle unaligned start bytes
 707         */
 708        if ((l = addr - wp) != 0) {
 709                data = 0;
 710                for (i=0, cp=wp; i<l; ++i, ++cp) {
 711                        data |= (*(uchar *)cp) << (8*i);
 712                }
 713                for (; i<4 && cnt>0; ++i) {
 714                        data |= *src++ << (8*i);
 715                        --cnt;
 716                        ++cp;
 717                }
 718                for (; cnt==0 && i<4; ++i, ++cp) {
 719                        data |= (*(uchar *)cp)  << (8*i);
 720                }
 721
 722                /* Disable interrupts which might cause a timeout here */
 723                flag = disable_interrupts();
 724
 725                rc = _write_word_ptr(info->start[0], wp, data);
 726
 727                /* re-enable interrupts if necessary */
 728                if (flag) {
 729                        enable_interrupts();
 730                }
 731                if (rc != 0) {
 732                        return rc;
 733                }
 734                wp += 4;
 735        }
 736
 737        /*
 738         * handle word aligned part
 739         */
 740        while (cnt >= 4) {
 741                data = 0;
 742
 743                for (i=0; i<4; ++i) {
 744                        data |= *src++ << (8*i);
 745                }
 746
 747                /* Disable interrupts which might cause a timeout here */
 748                flag = disable_interrupts();
 749
 750                rc = _write_word_ptr(info->start[0], wp, data);
 751
 752                /* re-enable interrupts if necessary */
 753                if (flag) {
 754                        enable_interrupts();
 755                }
 756                if (rc != 0) {
 757                        return rc;
 758                }
 759                wp  += 4;
 760                cnt -= 4;
 761        }
 762
 763        if (cnt == 0) {
 764                return 0;
 765        }
 766
 767        /*
 768         * handle unaligned tail bytes
 769         */
 770        data = 0;
 771        for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
 772                data |= *src++ << (8*i);
 773                --cnt;
 774        }
 775
 776        for (; i<4; ++i, ++cp) {
 777                data |= (*(uchar *)cp) << (8*i);
 778        }
 779
 780        /* Disable interrupts which might cause a timeout here */
 781        flag = disable_interrupts();
 782
 783        rc = _write_word_ptr(info->start[0], wp, data);
 784
 785        /* re-enable interrupts if necessary */
 786        if (flag) {
 787                enable_interrupts();
 788        }
 789
 790        return rc;
 791}
 792