]> git.sur5r.net Git - u-boot/blobdiff - board/alaska/flash.c
i.MX6: mx6qsabrelite: indent with tabs
[u-boot] / board / alaska / flash.c
index 48c94727e07961cc41b3ac7d8ee79eb03b8ba4e1..977822ac51e10b562d9af76f54bbf6bb66a2bea4 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/byteorder/swab.h>
 
 
-flash_info_t flash_info[CFG_MAX_FLASH_BANKS];  /* info for FLASH chips    */
+flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];   /* info for FLASH chips    */
 
 /* Board support for 1 or 2 flash devices */
 #define FLASH_PORT_WIDTH8
@@ -64,7 +64,6 @@ typedef volatile unsigned char FLASH_PORT_WIDTHV;
 #define FLASH_CYCLE2    0x02aa
 
 #define WR_BLOCK        0x20
-
 /*-----------------------------------------------------------------------
  * Functions
  */
@@ -74,6 +73,9 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest);
 static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data);
 static void flash_get_offsets (ulong base, flash_info_t * info);
 void inline spin_wheel (void);
+static void flash_sync_real_protect (flash_info_t * info);
+static unsigned char intel_sector_protected (flash_info_t *info, ushort sector);
+static unsigned char same_chip_banks (int bank1, int bank2);
 
 /*-----------------------------------------------------------------------
  */
@@ -84,30 +86,30 @@ unsigned long flash_init (void)
        ulong size = 0;
        ulong fsize = 0;
 
-       for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+       for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
                memset (&flash_info[i], 0, sizeof (flash_info_t));
 
                switch (i) {
                case 0:
-                       flash_get_size ((FPW *) CFG_FLASH1_BASE,
+                       flash_get_size ((FPW *) CONFIG_SYS_FLASH1_BASE,
                                        &flash_info[i]);
-                       flash_get_offsets (CFG_FLASH1_BASE, &flash_info[i]);
+                       flash_get_offsets (CONFIG_SYS_FLASH1_BASE, &flash_info[i]);
                        break;
                case 1:
-                       flash_get_size ((FPW *) CFG_FLASH1_BASE,
+                       flash_get_size ((FPW *) CONFIG_SYS_FLASH1_BASE,
                                        &flash_info[i]);
-                       fsize = CFG_FLASH1_BASE + flash_info[i - 1].size;
+                       fsize = CONFIG_SYS_FLASH1_BASE + flash_info[i - 1].size;
                        flash_get_offsets (fsize, &flash_info[i]);
                        break;
                case 2:
-                       flash_get_size ((FPW *) CFG_FLASH0_BASE,
+                       flash_get_size ((FPW *) CONFIG_SYS_FLASH0_BASE,
                                        &flash_info[i]);
-                       flash_get_offsets (CFG_FLASH0_BASE, &flash_info[i]);
+                       flash_get_offsets (CONFIG_SYS_FLASH0_BASE, &flash_info[i]);
                        break;
                case 3:
-                       flash_get_size ((FPW *) CFG_FLASH0_BASE,
+                       flash_get_size ((FPW *) CONFIG_SYS_FLASH0_BASE,
                                        &flash_info[i]);
-                       fsize = CFG_FLASH0_BASE + flash_info[i - 1].size;
+                       fsize = CONFIG_SYS_FLASH0_BASE + flash_info[i - 1].size;
                        flash_get_offsets (fsize, &flash_info[i]);
                        break;
                default:
@@ -115,35 +117,38 @@ unsigned long flash_init (void)
                        break;
                }
                size += flash_info[i].size;
+
+               /* get the h/w and s/w protection status in sync */
+               flash_sync_real_protect(&flash_info[i]);
        }
 
        /* Protect monitor and environment sectors
         */
-#if defined (CFG_AMD_BOOT)
+#if defined (CONFIG_SYS_AMD_BOOT)
        flash_protect (FLAG_PROTECT_SET,
-                      CFG_MONITOR_BASE,
-                      CFG_MONITOR_BASE + monitor_flash_len - 1,
+                      CONFIG_SYS_MONITOR_BASE,
+                      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
                       &flash_info[2]);
        flash_protect (FLAG_PROTECT_SET,
-                      CFG_INTEL_BASE,
-                      CFG_INTEL_BASE + monitor_flash_len - 1,
+                      CONFIG_SYS_INTEL_BASE,
+                      CONFIG_SYS_INTEL_BASE + monitor_flash_len - 1,
                       &flash_info[1]);
 #else
        flash_protect (FLAG_PROTECT_SET,
-                      CFG_MONITOR_BASE,
-                      CFG_MONITOR_BASE + monitor_flash_len - 1,
+                      CONFIG_SYS_MONITOR_BASE,
+                      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
                       &flash_info[3]);
        flash_protect (FLAG_PROTECT_SET,
-                      CFG_AMD_BASE,
-                      CFG_AMD_BASE + monitor_flash_len - 1, &flash_info[0]);
+                      CONFIG_SYS_AMD_BASE,
+                      CONFIG_SYS_AMD_BASE + monitor_flash_len - 1, &flash_info[0]);
 #endif
 
        flash_protect (FLAG_PROTECT_SET,
-                      CFG_ENV1_ADDR,
-                      CFG_ENV1_ADDR + CFG_ENV1_SIZE - 1, &flash_info[1]);
+                      CONFIG_ENV1_ADDR,
+                      CONFIG_ENV1_ADDR + CONFIG_ENV1_SIZE - 1, &flash_info[1]);
        flash_protect (FLAG_PROTECT_SET,
-                      CFG_ENV_ADDR,
-                      CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[3]);
+                      CONFIG_ENV_ADDR,
+                      CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[3]);
 
        return size;
 }
@@ -167,7 +172,6 @@ static void flash_get_offsets (ulong base, flash_info_t * info)
        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
                for (i = 0; i < info->sector_count; i++) {
                        info->start[i] = base + (i * PHYS_INTEL_SECT_SIZE);
-                       info->protect[i] = 0;
                }
        }
 }
@@ -290,10 +294,10 @@ static ulong flash_get_size (FPW * addr, flash_info_t * info)
                break;
        }
 
-       if (info->sector_count > CFG_MAX_FLASH_SECT) {
+       if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
                printf ("** ERROR: sector count %d > max (%d) **\n",
-                       info->sector_count, CFG_MAX_FLASH_SECT);
-               info->sector_count = CFG_MAX_FLASH_SECT;
+                       info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
+               info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
        }
 
        if (value == (FPW) INTEL_ID_28F128J3A)
@@ -305,12 +309,104 @@ static ulong flash_get_size (FPW * addr, flash_info_t * info)
 }
 
 
+/*
+ * This function gets the u-boot flash sector protection status
+ * (flash_info_t.protect[]) in sync with the sector protection
+ * status stored in hardware.
+ */
+static void flash_sync_real_protect (flash_info_t * info)
+{
+       int i;
+
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F128J3A:
+               for (i = 0; i < info->sector_count; ++i) {
+                       info->protect[i] = intel_sector_protected(info, i);
+               }
+               break;
+       case FLASH_AM040:
+       default:
+               /* no h/w protect support */
+               break;
+       }
+}
+
+
+/*
+ * checks if "sector" in bank "info" is protected. Should work on intel
+ * strata flash chips 28FxxxJ3x in 8-bit mode.
+ * Returns 1 if sector is protected (or timed-out while trying to read
+ * protection status), 0 if it is not.
+ */
+static unsigned char intel_sector_protected (flash_info_t *info, ushort sector)
+{
+       FPWV *addr;
+       FPWV *lock_conf_addr;
+       ulong start;
+       unsigned char ret;
+
+       /*
+        * first, wait for the WSM to be finished. The rationale for
+        * waiting for the WSM to become idle for at most
+        * CONFIG_SYS_FLASH_ERASE_TOUT is as follows. The WSM can be busy
+        * because of: (1) erase, (2) program or (3) lock bit
+        * configuration. So we just wait for the longest timeout of
+        * the (1)-(3), i.e. the erase timeout.
+        */
+
+       /* wait at least 35ns (W12) before issuing Read Status Register */
+       udelay(1);
+       addr = (FPWV *) info->start[sector];
+       *addr = (FPW) INTEL_STATUS;
+
+       start = get_timer (0);
+       while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) {
+               if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
+                       *addr = (FPW) INTEL_RESET; /* restore read mode */
+                       printf("WSM busy too long, can't get prot status\n");
+                       return 1;
+               }
+       }
+
+       /* issue the Read Identifier Codes command */
+       *addr = (FPW) INTEL_READID;
+
+       /* wait at least 35ns (W12) before reading */
+       udelay(1);
+
+       /* Intel example code uses offset of 4 for 8-bit flash */
+       lock_conf_addr = (FPWV *) info->start[sector] + 4;
+       ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0;
+
+       /* put flash back in read mode */
+       *addr = (FPW) INTEL_RESET;
+
+       return ret;
+}
+
+
+/*
+ * Checks if "bank1" and "bank2" are on the same chip.  Returns 1 if they
+ * are and 0 otherwise.
+ */
+static unsigned char same_chip_banks (int bank1, int bank2)
+{
+       unsigned char same_chip[CONFIG_SYS_MAX_FLASH_BANKS][CONFIG_SYS_MAX_FLASH_BANKS] = {
+               {1, 1, 0, 0},
+               {1, 1, 0, 0},
+               {0, 0, 1, 1},
+               {0, 0, 1, 1}
+       };
+       return same_chip[bank1][bank2];
+}
+
+
 /*-----------------------------------------------------------------------
  */
 int flash_erase (flash_info_t * info, int s_first, int s_last)
 {
        int flag, prot, sect;
-       ulong type, start, last;
+       ulong type, start;
        int rcode = 0, intel = 0;
 
        if ((s_first < 0) || (s_first > s_last)) {
@@ -348,7 +444,6 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
        }
 
        start = get_timer (0);
-       last = start;
 
        /* Disable interrupts which might cause a timeout here */
        flag = disable_interrupts ();
@@ -371,7 +466,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
                        } else {
                                FPWV *base;     /* first address in bank */
 
-                               base = (FPWV *) (CFG_AMD_BASE);
+                               base = (FPWV *) (CONFIG_SYS_AMD_BASE);
                                base[FLASH_CYCLE1] = (FPW) 0x00AA00AA;  /* unlock */
                                base[FLASH_CYCLE2] = (FPW) 0x00550055;  /* unlock */
                                base[FLASH_CYCLE1] = (FPW) 0x00800080;  /* erase mode */
@@ -383,7 +478,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
                        while (((status =
                                 *addr) & (FPW) 0x00800080) !=
                               (FPW) 0x00800080) {
-                               if (get_timer (start) > CFG_FLASH_ERASE_TOUT) {
+                               if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
                                        printf ("Timeout\n");
                                        if (intel) {
                                                *addr = (FPW) 0x00B000B0;       /* suspend erase     */
@@ -405,6 +500,9 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
                        printf (" done\n");
                }
        }
+       if (flag)
+               enable_interrupts();
+
        return rcode;
 }
 
@@ -570,11 +668,11 @@ static int write_data (flash_info_t * info, ulong dest, FPW data)
 {
        FPWV *addr = (FPWV *) dest;
        ulong start;
-       int flag;
+       int flag, rc = 0;
 
        /* Check if Flash is (sufficiently) erased */
        if ((*addr & data) != data) {
-               printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr);
+               printf ("not erased at %08lx (%lx)\n", (ulong)addr, (ulong)*addr);
                return (2);
        }
        /* Disable interrupts which might cause a timeout here */
@@ -588,15 +686,19 @@ static int write_data (flash_info_t * info, ulong dest, FPW data)
 
        /* wait while polling the status register */
        while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) {
-               if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
-                       *addr = (FPW) 0x00FF00FF;       /* restore read mode */
-                       return (1);
+               if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
+                       rc = 1;
+                       goto OUT;
                }
        }
 
-       *addr = (FPW) 0x00FF00FF;       /* restore read mode */
+OUT:
+       *addr = (FPW)0x00FF00FF;        /* restore read mode */
 
-       return (0);
+       if (flag)
+               enable_interrupts();
+
+       return rc;
 }
 
 /*-----------------------------------------------------------------------
@@ -610,13 +712,13 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest)
        FPWV *srcaddr = (FPWV *) src;
        FPWV *dstaddr = (FPWV *) dest;
        ulong start;
-       int flag, i;
+       int flag, i, rc = 0;
 
        /* Check if Flash is (sufficiently) erased */
        for (i = 0; i < WR_BLOCK; i++)
                if ((*dstaddr++ & 0xff) != 0xff) {
                        printf ("not erased at %08lx (%lx)\n",
-                               (ulong) dstaddr, *dstaddr);
+                               (ulong)dstaddr, (ulong)*dstaddr);
                        return (2);
                }
 
@@ -631,10 +733,10 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest)
        start = get_timer (0);
 
        /* wait while polling the status register */
-       while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) {
-               if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
-                       *dstaddr = (FPW) 0x00FF00FF;    /* restore read mode */
-                       return (1);
+       while ((*dstaddr & (FPW)0x00800080) != (FPW)0x00800080) {
+               if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
+                       rc = 1;
+                       goto OUT;
                }
        }
 
@@ -650,15 +752,18 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest)
 
        /* wait while polling the status register */
        while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) {
-               if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+               if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
                        *dstaddr = (FPW) 0x00FF00FF;    /* restore read mode */
                        return (1);
                }
        }
 
-       *dstaddr = (FPW) 0x00FF00FF;    /* restore read mode */
+OUT:
+       *dstaddr = (FPW)0x00FF00FF;     /* restore read mode */
+       if (flag)
+               enable_interrupts();
 
-       return (0);
+       return rc;
 }
 
 /*-----------------------------------------------------------------------
@@ -683,7 +788,7 @@ static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data)
                return (2);
        }
 
-       base = (FPWV *) (CFG_AMD_BASE);
+       base = (FPWV *) (CONFIG_SYS_AMD_BASE);
 
        /* Disable interrupts which might cause a timeout here */
        flag = disable_interrupts ();
@@ -703,7 +808,7 @@ static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data)
        /* data polling for D7 */
        while (res == 0
               && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) {
-               if (get_timer (start) > CFG_FLASH_WRITE_TOUT) {
+               if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
                        *dest = (FPW) 0x00F000F0;       /* reset bank */
                        res = 1;
                }
@@ -729,7 +834,9 @@ void inline spin_wheel (void)
 int flash_real_protect (flash_info_t * info, long sector, int prot)
 {
        ulong start;
-       int i;
+       int i, j;
+       int curr_bank;
+       int bank;
        int rc = 0;
        FPWV *addr = (FPWV *) (info->start[sector]);
        int flag = disable_interrupts ();
@@ -758,7 +865,7 @@ int flash_real_protect (flash_info_t * info, long sector, int prot)
        start = get_timer (0);
 
        while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) {
-               if (get_timer (start) > CFG_FLASH_UNLOCK_TOUT) {
+               if (get_timer (start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) {
                        printf ("Flash lock bit operation timed out\n");
                        rc = 1;
                        break;
@@ -779,23 +886,54 @@ int flash_real_protect (flash_info_t * info, long sector, int prot)
         * we have to restore lock bits of protected sectors.
         */
        if (!prot) {
-               for (i = 0; i < info->sector_count; i++) {
-                       if (info->protect[i]) {
-                               start = get_timer (0);
-                               addr = (FPWV *) (info->start[i]);
-                               *addr = INTEL_LOCKBIT;  /* Sector lock bit  */
-                               *addr = INTEL_PROTECT;  /* set              */
-                               while ((*addr & INTEL_FINISHED) !=
-                                      INTEL_FINISHED) {
-                                       if (get_timer (start) >
-                                           CFG_FLASH_UNLOCK_TOUT) {
-                                               printf ("Flash lock bit operation timed out\n");
-                                               rc = 1;
-                                               break;
+               /*
+                * re-locking must be done for all banks that belong on one
+                * FLASH chip, as all the sectors on the chip were unlocked
+                * by INTEL_LOCKBIT/INTEL_CONFIRM commands. (let's hope
+                * that banks never span chips, in particular chips which
+                * support h/w protection differently).
+                */
+
+               /* find the current bank number */
+               curr_bank = CONFIG_SYS_MAX_FLASH_BANKS + 1;
+               for (j = 0; j < CONFIG_SYS_MAX_FLASH_BANKS; ++j) {
+                       if (&flash_info[j] == info) {
+                               curr_bank = j;
+                       }
+               }
+               if (curr_bank == CONFIG_SYS_MAX_FLASH_BANKS + 1) {
+                       printf("Error: can't determine bank number!\n");
+               }
+
+               for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+                       if (!same_chip_banks(curr_bank, bank)) {
+                               continue;
+                       }
+                       info = &flash_info[bank];
+                       for (i = 0; i < info->sector_count; i++) {
+                               if (info->protect[i]) {
+                                       start = get_timer (0);
+                                       addr = (FPWV *) (info->start[i]);
+                                       *addr = INTEL_LOCKBIT;  /* Sector lock bit  */
+                                       *addr = INTEL_PROTECT;  /* set              */
+                                       while ((*addr & INTEL_FINISHED) !=
+                                              INTEL_FINISHED) {
+                                               if (get_timer (start) >
+                                                   CONFIG_SYS_FLASH_UNLOCK_TOUT) {
+                                                       printf ("Flash lock bit operation timed out\n");
+                                                       rc = 1;
+                                                       break;
+                                               }
                                        }
                                }
                        }
                }
+
+               /*
+                * get the s/w sector protection status in sync with the h/w,
+                * in case something went wrong during the re-locking.
+                */
+               flash_sync_real_protect(info); /* resets flash to read  mode */
        }
 
        if (flag)