rename CFG_ENV_IS_IN_FLASH in CONFIG_ENV_IS_IN_FLASH
[platform/kernel/u-boot.git] / board / cmc_pu2 / flash.c
index 5220fcf..0419d76 100644 (file)
@@ -1,11 +1,12 @@
 /*
- * (C) Copyright 2002
- * Lineo, Inc. <www.lineo.com>
- * Bernhard Kuhn <bkuhn@lineo.com>
+ * (C) Copyright 2003-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  *
- * (C) Copyright 2002
- * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
- * Alex Zuepke <azu@sysgo.de>
+ * (C) Copyright 2004
+ * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de
+ *
+ * Modified for the CMC PU2 by (C) Copyright 2004 Gary Jennejohn
+ * garyj@denx.de
  *
  * See file CREDITS for list of people who contributed to this
  * project.
 
 #include <common.h>
 
-ulong myflush(void);
-
-
-/* Flash Organization Structure */
-typedef struct OrgDef
-{
-       unsigned int sector_number;
-       unsigned int sector_size;
-} OrgDef;
-
-
-/* Flash Organizations */
-OrgDef OrgAT49BV16x4[] =
-{
-       {  8,  8*1024 },        /*   8 *  8 kBytes sectors */
-       {  2, 32*1024 },        /*   2 * 32 kBytes sectors */
-       { 30, 64*1024 },        /*  30 * 64 kBytes sectors */
-};
-
-OrgDef OrgAT49BV16x4A[] =
-{
-       {  8,  8*1024 },        /*   8 *  8 kBytes sectors */
-       { 31, 64*1024 },        /*  31 * 64 kBytes sectors */
-};
-
-OrgDef OrgAT49BV6416[] =
-{
-       {   8,  8*1024 },       /*   8 *  8 kBytes sectors */
-       { 127, 64*1024 },       /* 127 * 64 kBytes sectors */
-};
-
-flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
-
-/* AT49BV1614A Codes */
-#define FLASH_CODE1            0xAA
-#define FLASH_CODE2            0x55
-#define ID_IN_CODE             0x90
-#define ID_OUT_CODE            0xF0
-
-
-#define CMD_READ_ARRAY         0x00F0
-#define CMD_UNLOCK1            0x00AA
-#define CMD_UNLOCK2            0x0055
-#define CMD_ERASE_SETUP                0x0080
-#define CMD_ERASE_CONFIRM      0x0030
-#define CMD_PROGRAM            0x00A0
-#define CMD_UNLOCK_BYPASS      0x0020
-#define CMD_SECTOR_UNLOCK      0x0070
+#ifndef        CFG_ENV_ADDR
+#define CFG_ENV_ADDR   (CFG_FLASH_BASE + CFG_ENV_OFFSET)
+#endif
 
-#define MEM_FLASH_ADDR1                (*(volatile u16 *)(CFG_FLASH_BASE + (0x00005555<<1)))
-#define MEM_FLASH_ADDR2                (*(volatile u16 *)(CFG_FLASH_BASE + (0x00002AAA<<1)))
+flash_info_t   flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
 
-#define BIT_ERASE_DONE         0x0080
-#define BIT_RDY_MASK           0x0080
-#define BIT_PROGRAM_ERROR      0x0020
-#define BIT_TIMEOUT            0x80000000 /* our flag */
+#define FLASH_CYCLE1   0x0555
+#define FLASH_CYCLE2   0x02AA
 
-#define READY 1
-#define ERR   2
-#define TMO   4
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size(vu_short *addr, flash_info_t *info);
+static void flash_reset(flash_info_t *info);
+static int write_word_amd(flash_info_t *info, vu_short *dest, ushort data);
+static flash_info_t *flash_get_info(ulong base);
 
 /*-----------------------------------------------------------------------
+ * flash_init()
+ *
+ * sets up flash_info and returns size of FLASH (bytes)
  */
-void flash_identification (flash_info_t * info)
+unsigned long flash_init (void)
 {
-       volatile u16 manuf_code, device_code, add_device_code;
+       unsigned long size = 0;
+       ulong flashbase = CFG_FLASH_BASE;
 
-       MEM_FLASH_ADDR1 = FLASH_CODE1;
-       MEM_FLASH_ADDR2 = FLASH_CODE2;
-       MEM_FLASH_ADDR1 = ID_IN_CODE;
+       /* Init: no FLASHes known */
+       memset(&flash_info[0], 0, sizeof(flash_info_t));
 
-       manuf_code = *(volatile u16 *) CFG_FLASH_BASE;
-       device_code = *(volatile u16 *) (CFG_FLASH_BASE + 2);
-       add_device_code = *(volatile u16 *) (CFG_FLASH_BASE + (3 << 1));
+       flash_info[0].size = flash_get_size((vu_short *)flashbase, &flash_info[0]);
 
-       MEM_FLASH_ADDR1 = FLASH_CODE1;
-       MEM_FLASH_ADDR2 = FLASH_CODE2;
-       MEM_FLASH_ADDR1 = ID_OUT_CODE;
+       size = flash_info[0].size;
 
-       /* Vendor type */
-       info->flash_id = ATM_MANUFACT & FLASH_VENDMASK;
-       printf ("Atmel: ");
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
+       /* monitor protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_MONITOR_BASE,
+                     CFG_MONITOR_BASE+monitor_flash_len-1,
+                     flash_get_info(CFG_MONITOR_BASE));
+#endif
 
-       if ((device_code & FLASH_TYPEMASK) == (ATM_ID_BV1614 & FLASH_TYPEMASK)) {
-
-               if ((add_device_code & FLASH_TYPEMASK) ==
-                       (ATM_ID_BV1614A & FLASH_TYPEMASK)) {
-                       info->flash_id |= ATM_ID_BV1614A & FLASH_TYPEMASK;
-                       printf ("AT49BV1614A (16Mbit)\n");
-               } else {                                /* AT49BV1614 Flash */
-                       info->flash_id |= ATM_ID_BV1614 & FLASH_TYPEMASK;
-                       printf ("AT49BV1614 (16Mbit)\n");
-               }
+#ifdef CONFIG_ENV_IS_IN_FLASH
+       /* ENV protection ON by default */
+       flash_protect(FLAG_PROTECT_SET,
+                     CFG_ENV_ADDR,
+                     CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+                     flash_get_info(CFG_ENV_ADDR));
+#endif
 
-       } else if ((device_code & FLASH_TYPEMASK) == (ATM_ID_BV6416 & FLASH_TYPEMASK)) {
-               info->flash_id |= ATM_ID_BV6416 & FLASH_TYPEMASK;
-               printf ("AT49BV6416 (64Mbit)\n");
-       }
-}
-
-ushort flash_number_sector(OrgDef *pOrgDef, unsigned int nb_blocks)
-{
-       int i, nb_sectors = 0;
-
-       for (i=0; i<nb_blocks; i++){
-               nb_sectors += pOrgDef[i].sector_number;
-       }
-
-       return nb_sectors;
+       return size ? size : 1;
 }
 
-void flash_unlock_sector(flash_info_t * info, unsigned int sector)
+/*-----------------------------------------------------------------------
+ */
+static void flash_reset(flash_info_t *info)
 {
-       volatile u16 *addr = (volatile u16 *) (info->start[sector]);
+       vu_short *base = (vu_short *)(info->start[0]);
 
-       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-       *addr = CMD_SECTOR_UNLOCK;
+       /* Put FLASH back in read mode */
+       if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+               *base = 0x00FF; /* Intel Read Mode */
+       else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD)
+               *base = 0x00F0; /* AMD Read Mode */
 }
 
+/*-----------------------------------------------------------------------
+ */
 
-ulong flash_init (void)
+static flash_info_t *flash_get_info(ulong base)
 {
-       int i, j, k;
-       unsigned int flash_nb_blocks, sector;
-       unsigned int start_address;
-       OrgDef *pOrgDef;
-
-       ulong size = 0;
-
-       for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
-               ulong flashbase = 0;
-
-               flash_identification (&flash_info[i]);
-
-               if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
-                       (ATM_ID_BV1614 & FLASH_TYPEMASK)) {
-
-                       pOrgDef = OrgAT49BV16x4;
-                       flash_nb_blocks = sizeof (OrgAT49BV16x4) / sizeof (OrgDef);
-               } else if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
-                       (ATM_ID_BV1614A & FLASH_TYPEMASK)){     /* AT49BV1614A Flash */
-
-                       pOrgDef = OrgAT49BV16x4A;
-                       flash_nb_blocks = sizeof (OrgAT49BV16x4A) / sizeof (OrgDef);
-               } else if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
-                       (ATM_ID_BV6416 & FLASH_TYPEMASK)){      /* AT49BV6416 Flash */
-
-                       pOrgDef = OrgAT49BV6416;
-                       flash_nb_blocks = sizeof (OrgAT49BV6416) / sizeof (OrgDef);
-               } else {
-                       flash_nb_blocks = 0;
-                       pOrgDef = OrgAT49BV16x4;
-               }
-
-               flash_info[i].sector_count = flash_number_sector(pOrgDef, flash_nb_blocks);
-               memset (flash_info[i].protect, 0, flash_info[i].sector_count);
-
-               if (i == 0)
-                       flashbase = PHYS_FLASH_1;
-               else
-                       panic ("configured too many flash banks!\n");
-
-               sector = 0;
-               start_address = flashbase;
-               flash_info[i].size = 0;
-
-               for (j = 0; j < flash_nb_blocks; j++) {
-                       for (k = 0; k < pOrgDef[j].sector_number; k++) {
-                               flash_info[i].start[sector++] = start_address;
-                               start_address += pOrgDef[j].sector_size;
-                               flash_info[i].size += pOrgDef[j].sector_size;
-                       }
-               }
-
-               size += flash_info[i].size;
-
-               if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
-                       (ATM_ID_BV6416 & FLASH_TYPEMASK)){      /* AT49BV6416 Flash */
+       int i;
+       flash_info_t * info;
 
-                       /* Unlock all sectors at reset */
-                       for (j=0; j<flash_info[i].sector_count; j++){
-                               flash_unlock_sector(&flash_info[i], j);
-                       }
-               }
+       info = NULL;
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
+               info = & flash_info[i];
+               if (info->size && info->start[0] <= base &&
+                   base <= info->start[0] + info->size - 1)
+                       break;
        }
 
-       /* Protect binary boot image */
-       flash_protect (FLAG_PROTECT_SET,
-                      CFG_FLASH_BASE,
-                      CFG_FLASH_BASE + CFG_BOOT_SIZE - 1, &flash_info[0]);
-
-       /* Protect environment variables */
-       flash_protect (FLAG_PROTECT_SET,
-                      CFG_ENV_ADDR,
-                      CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
-
-       /* Protect U-Boot gzipped image */
-       flash_protect (FLAG_PROTECT_SET,
-                      CFG_U_BOOT_BASE,
-                      CFG_U_BOOT_BASE + CFG_U_BOOT_SIZE - 1, &flash_info[0]);
-
-       return size;
+       return i == CFG_MAX_FLASH_BANKS ? 0 : info;
 }
 
 /*-----------------------------------------------------------------------
  */
-void flash_print_info (flash_info_t * info)
+
+void flash_print_info (flash_info_t *info)
 {
        int i;
 
+       if (info->flash_id == FLASH_UNKNOWN) {
+               printf ("missing or unknown FLASH type\n");
+               return;
+       }
+
        switch (info->flash_id & FLASH_VENDMASK) {
-       case (ATM_MANUFACT & FLASH_VENDMASK):
-               printf ("Atmel: ");
-               break;
-       default:
-               printf ("Unknown Vendor ");
-               break;
+       case FLASH_MAN_AMD:     printf ("AMD ");                break;
+       case FLASH_MAN_BM:      printf ("BRIGHT MICRO ");       break;
+       case FLASH_MAN_FUJ:     printf ("FUJITSU ");            break;
+       case FLASH_MAN_SST:     printf ("SST ");                break;
+       case FLASH_MAN_STM:     printf ("STM ");                break;
+       case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
+       default:                printf ("Unknown Vendor ");     break;
        }
 
        switch (info->flash_id & FLASH_TYPEMASK) {
-       case (ATM_ID_BV1614 & FLASH_TYPEMASK):
-               printf ("AT49BV1614 (16Mbit)\n");
-               break;
-       case (ATM_ID_BV1614A & FLASH_TYPEMASK):
-               printf ("AT49BV1614A (16Mbit)\n");
-               break;
-       case (ATM_ID_BV6416 & FLASH_TYPEMASK):
-               printf ("AT49BV6416 (64Mbit)\n");
+       case FLASH_S29GL064M:
+               printf ("S29GL064M-R6 (64Mbit, uniform sector size)\n");
                break;
        default:
                printf ("Unknown Chip Type\n");
-               goto Done;
                break;
        }
 
        printf ("  Size: %ld MB in %d Sectors\n",
-               info->size >> 20, info->sector_count);
+               info->size >> 20,
+               info->sector_count);
 
        printf ("  Sector Start Addresses:");
-       for (i = 0; i < info->sector_count; i++) {
+
+       for (i=0; i<info->sector_count; ++i) {
                if ((i % 5) == 0) {
                        printf ("\n   ");
                }
-               printf (" %08lX%s", info->start[i],
+               printf (" %08lX%s",
+                       info->start[i],
                        info->protect[i] ? " (RO)" : "     ");
        }
        printf ("\n");
-
-Done:  ;
+       return;
 }
 
 /*-----------------------------------------------------------------------
  */
 
-int flash_erase (flash_info_t * info, int s_first, int s_last)
-{
-       ulong result;
-       int iflag, cflag, prot, sect;
-       int rc = ERR_OK;
-       int chip1;
-
-       /* first look for protection bits */
-
-       if (info->flash_id == FLASH_UNKNOWN)
-               return ERR_UNKNOWN_FLASH_TYPE;
-
-       if ((s_first < 0) || (s_first > s_last)) {
-               return ERR_INVAL;
-       }
-
-       if ((info->flash_id & FLASH_VENDMASK) !=
-               (ATM_MANUFACT & FLASH_VENDMASK)) {
-               return ERR_UNKNOWN_FLASH_VENDOR;
-       }
-
-       prot = 0;
-       for (sect = s_first; sect <= s_last; ++sect) {
-               if (info->protect[sect]) {
-                       prot++;
-               }
-       }
-       if (prot)
-               return ERR_PROTECTED;
-
-       /*
-        * Disable interrupts which might cause a timeout
-        * here. Remember that our exception vectors are
-        * at address 0 in the flash, and we don't want a
-        * (ticker) exception to happen while the flash
-        * chip is in programming mode.
-        */
-       cflag = icache_status ();
-       icache_disable ();
-       iflag = disable_interrupts ();
+/*
+ * The following code cannot be run from FLASH!
+ */
 
-       /* Start erase on unprotected sectors */
-       for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
-               printf ("Erasing sector %2d ... ", sect);
+ulong flash_get_size (vu_short *addr, flash_info_t *info)
+{
+       int i;
+       ushort value;
+       ulong base = (ulong)addr;
 
-               /* arm simple, non interrupt dependent timer */
-               reset_timer_masked ();
+       /* Write auto select command sequence */
+       addr[FLASH_CYCLE1] = 0x00AA;    /* for AMD, Intel ignores this */
+       addr[FLASH_CYCLE2] = 0x0055;    /* for AMD, Intel ignores this */
+       addr[FLASH_CYCLE1] = 0x0090;    /* selects Intel or AMD */
 
-               if (info->protect[sect] == 0) { /* not protected */
-                       volatile u16 *addr = (volatile u16 *) (info->start[sect]);
+       /* read Manufacturer ID */
+       udelay(100);
+       value = addr[0];
+       debug ("Manufacturer ID: %04X\n", value);
 
-                       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-                       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-                       MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
+       switch (value) {
 
-                       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-                       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-                       *addr = CMD_ERASE_CONFIRM;
+       case (AMD_MANUFACT & 0xFFFF):
+               debug ("Manufacturer: AMD (Spansion)\n");
+               info->flash_id = FLASH_MAN_AMD;
+               break;
 
-                       /* wait until flash is ready */
-                       chip1 = 0;
+       case (INTEL_MANUFACT & 0xFFFF):
+               debug ("Manufacturer: Intel (not supported yet)\n");
+               info->flash_id = FLASH_MAN_INTEL;
+               break;
 
-                       do {
-                               result = *addr;
+       default:
+               printf ("Unknown Manufacturer ID: %04X\n", value);
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               goto out;
+       }
 
-                               /* check timeout */
-                               if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
-                                       MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
-                                       chip1 = TMO;
-                                       break;
+       value = addr[1];
+       debug ("Device ID: %04X\n", value);
+
+       switch (addr[1]) {
+
+       case (AMD_ID_MIRROR & 0xFFFF):
+               debug ("Mirror Bit flash: addr[14] = %08X  addr[15] = %08X\n",
+                       addr[14], addr[15]);
+
+               switch(addr[14]) {
+               case (AMD_ID_GL064M_2 & 0xFFFF):
+                       if (addr[15] != (AMD_ID_GL064M_3 & 0xffff)) {
+                               printf ("Chip: S29GLxxxM -> unknown\n");
+                               info->flash_id = FLASH_UNKNOWN;
+                               info->sector_count = 0;
+                               info->size = 0;
+                       } else {
+                               debug ("Chip: S29GL064M-R6\n");
+                               info->flash_id += FLASH_S29GL064M;
+                               info->sector_count = 128;
+                               info->size = 0x00800000;
+                               for (i = 0; i < info->sector_count; i++) {
+                                       info->start[i] = base;
+                                       base += 0x10000;
                                }
-
-                               if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
-                                       chip1 = READY;
-
-                       } while (!chip1);
-
-                       MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
-
-                       if (chip1 == ERR) {
-                               rc = ERR_PROG_ERROR;
-                               goto outahere;
-                       }
-                       if (chip1 == TMO) {
-                               rc = ERR_TIMOUT;
-                               goto outahere;
                        }
-
-                       printf ("ok.\n");
-               } else {                        /* it was protected */
-                       printf ("protected!\n");
+                       break;  /* => 16 MB     */
+               default:
+                       printf ("Chip: *** unknown ***\n");
+                       info->flash_id = FLASH_UNKNOWN;
+                       info->sector_count = 0;
+                       info->size = 0;
+                       break;
                }
-       }
-
-       if (ctrlc ())
-               printf ("User Interrupt!\n");
-
-outahere:
-       /* allow flash to settle - wait 10 ms */
-       udelay_masked (10000);
+               break;
 
-       if (iflag)
-               enable_interrupts ();
+       default:
+               printf ("Unknown Device ID: %04X\n", value);
+               info->flash_id = FLASH_UNKNOWN;
+               info->sector_count = 0;
+               info->size = 0;
+               break;
+       }
 
-       if (cflag)
-               icache_enable ();
+out:
+       /* Put FLASH back in read mode */
+       flash_reset(info);
 
-       return rc;
+       return (info->size);
 }
 
 /*-----------------------------------------------------------------------
- * Copy memory to flash
  */
 
-volatile static int write_word (flash_info_t * info, ulong dest,
-                                                               ulong data)
+int    flash_erase (flash_info_t *info, int s_first, int s_last)
 {
-       volatile u16 *addr = (volatile u16 *) dest;
-       ulong result;
-       int rc = ERR_OK;
-       int cflag, iflag;
-       int chip1;
+       vu_short *addr = (vu_short *)(info->start[0]);
+       int flag, prot, sect, ssect, l_sect;
+       ulong now, last;
 
-       /*
-        * Check if Flash is (sufficiently) erased
-        */
-       result = *addr;
-       if ((result & data) != data)
-               return ERR_NOT_ERASED;
+       debug ("flash_erase: first: %d last: %d\n", s_first, s_last);
 
+       if ((s_first < 0) || (s_first > s_last)) {
+               if (info->flash_id == FLASH_UNKNOWN) {
+                       printf ("- missing\n");
+               } else {
+                       printf ("- no sectors to erase\n");
+               }
+               return 1;
+       }
 
-       /*
-        * Disable interrupts which might cause a timeout
-        * here. Remember that our exception vectors are
-        * at address 0 in the flash, and we don't want a
-        * (ticker) exception to happen while the flash
-        * chip is in programming mode.
-        */
-       cflag = icache_status ();
-       icache_disable ();
-       iflag = disable_interrupts ();
+       if ((info->flash_id == FLASH_UNKNOWN) ||
+           (info->flash_id > FLASH_AMD_COMP)) {
+               printf ("Can't erase unknown flash type %08lx - aborted\n",
+                       info->flash_id);
+               return 1;
+       }
 
-       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-       MEM_FLASH_ADDR1 = CMD_PROGRAM;
-       *addr = data;
+       prot = 0;
+       for (sect=s_first; sect<=s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
 
-       /* arm simple, non interrupt dependent timer */
-       reset_timer_masked ();
+       if (prot) {
+               printf ("- Warning: %d protected sectors will not be erased!\n",
+                       prot);
+       } else {
+               printf ("\n");
+       }
 
-       /* wait until flash is ready */
-       chip1 = 0;
-       do {
-               result = *addr;
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
 
-               /* check timeout */
-               if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
-                       chip1 = ERR | TMO;
-                       break;
+       /*
+        * Start erase on unprotected sectors.
+        * Since the flash can erase multiple sectors with one command
+        * we take advantage of that by doing the erase in chunks of
+        * 3 sectors.
+        */
+       for (sect = s_first; sect <= s_last; ) {
+               l_sect = -1;
+
+               addr[FLASH_CYCLE1] = 0x00AA;
+               addr[FLASH_CYCLE2] = 0x0055;
+               addr[FLASH_CYCLE1] = 0x0080;
+               addr[FLASH_CYCLE1] = 0x00AA;
+               addr[FLASH_CYCLE2] = 0x0055;
+
+               /* do the erase in chunks of at most 3 sectors */
+               for (ssect = 0; ssect < 3; ssect++) {
+                       if ((sect + ssect) > s_last)
+                               break;
+                       if (info->protect[sect + ssect] == 0) { /* not protected */
+                               addr = (vu_short *)(info->start[sect + ssect]);
+                               addr[0] = 0x0030;
+                               l_sect = sect + ssect;
+                       }
                }
-               if (!chip1 && ((result & 0x80) == (data & 0x80)))
-                       chip1 = READY;
+               /* wait at least 80us - let's wait 1 ms */
+               udelay (1000);
 
-       } while (!chip1);
+               /*
+                * We wait for the last triggered sector
+                */
+               if (l_sect < 0)
+                       goto DONE;
 
-       *addr = CMD_READ_ARRAY;
-
-       if (chip1 == ERR || *addr != data)
-               rc = ERR_PROG_ERROR;
+               reset_timer_masked ();
+               last  = 0;
+               addr = (vu_short *)(info->start[l_sect]);
+               while ((addr[0] & 0x0080) != 0x0080) {
+                       if ((now = get_timer_masked ()) > CFG_FLASH_ERASE_TOUT) {
+                               printf ("Timeout\n");
+                               return 1;
+                       }
+                       /* show that we're waiting */
+                       if ((now - last) > 1000) {      /* every second */
+                               putc ('.');
+                               last = now;
+                       }
+               }
+               addr = (vu_short *)info->start[0];
+               addr[0] = 0x00F0;       /* reset bank */
+               sect += ssect;
+       }
 
-       if (iflag)
-               enable_interrupts ();
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
 
-       if (cflag)
-               icache_enable ();
+DONE:
+       /* reset to read mode */
+       addr = (vu_short *)info->start[0];
+       addr[0] = 0x00F0;       /* reset bank */
 
-       return rc;
+       printf (" done\n");
+       return 0;
 }
 
 /*-----------------------------------------------------------------------
- * Copy memory to flash.
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
  */
 
-int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
 {
        ulong wp, data;
        int rc;
@@ -483,8 +392,9 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
        wp = addr;
 
        while (cnt >= 2) {
-               data = *((volatile u16 *) src);
-               if ((rc = write_word (info, wp, data)) != 0) {
+               data = *((vu_short *)src);
+               if ((rc = write_word_amd(info, (vu_short *)wp, data)) != 0) {
+printf ("write_buff 1: write_word_amd() rc=%d\n", rc);
                        return (rc);
                }
                src += 2;
@@ -492,16 +402,67 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
                cnt -= 2;
        }
 
+       if (cnt == 0) {
+               return (ERR_OK);
+       }
+
        if (cnt == 1) {
-               data = (*((volatile u8 *) src)) | (*((volatile u8 *) (wp + 1)) <<
-                                                                                  8);
-               if ((rc = write_word (info, wp, data)) != 0) {
+               data = (*((volatile u8 *) src)) | (*((volatile u8 *) (wp + 1)) << 8);
+               if ((rc = write_word_amd(info, (vu_short *)wp, data)) != 0) {
+printf ("write_buff 1: write_word_amd() rc=%d\n", rc);
                        return (rc);
                }
                src += 1;
                wp += 1;
                cnt -= 1;
-       };
+       }
 
        return ERR_OK;
 }
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for AMD FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_amd (flash_info_t *info, vu_short *dest, ushort data)
+{
+       int flag;
+       vu_short *base;         /* first address in flash bank  */
+
+       /* Check if Flash is (sufficiently) erased */
+       if ((*dest & data) != data) {
+               return (2);
+       }
+
+       base = (vu_short *)(info->start[0]);
+
+       /* Disable interrupts which might cause a timeout here */
+       flag = disable_interrupts();
+
+       base[FLASH_CYCLE1] = 0x00AA;    /* unlock */
+       base[FLASH_CYCLE2] = 0x0055;    /* unlock */
+       base[FLASH_CYCLE1] = 0x00A0;    /* selects program mode */
+
+       *dest = data;           /* start programming the data   */
+
+       /* re-enable interrupts if necessary */
+       if (flag)
+               enable_interrupts();
+
+       reset_timer_masked ();
+
+       /* data polling for D7 */
+       while ((*dest & 0x0080) != (data & 0x0080)) {
+               if (get_timer_masked () > CFG_FLASH_WRITE_TOUT) {
+                       *dest = 0x00F0; /* reset bank */
+                       return (1);
+               }
+       }
+       return (0);
+}