85xx: remove dummy board_early_init_f
[platform/kernel/u-boot.git] / board / pm520 / flash.c
index 4ea8b36..4301b8c 100644 (file)
@@ -35,36 +35,36 @@ flash_info_t flash_info[CFG_MAX_FLASH_BANKS];       /* info for FLASH chips    */
 #undef FLASH_PORT_WIDTH16
 
 #ifdef FLASH_PORT_WIDTH16
-#define FLASH_PORT_WIDTH               ushort
-#define FLASH_PORT_WIDTHV              vu_short
-#define SWAP(x)                        (x)
+#define FLASH_PORT_WIDTH       ushort
+#define FLASH_PORT_WIDTHV      vu_short
+#define SWAP(x)                        (x)
 #else
-#define FLASH_PORT_WIDTH               ulong
-#define FLASH_PORT_WIDTHV              vu_long
-#define SWAP(x)                        (x)
+#define FLASH_PORT_WIDTH       ulong
+#define FLASH_PORT_WIDTHV      vu_long
+#define SWAP(x)                        (x)
 #endif
 
 /* Intel-compatible flash ID */
-#define INTEL_COMPAT  0x00890089
-#define INTEL_ALT     0x00B000B0
+#define INTEL_COMPAT           0x00890089
+#define INTEL_ALT              0x00B000B0
 
 /* Intel-compatible flash commands */
-#define INTEL_PROGRAM 0x00100010
-#define INTEL_ERASE   0x00200020
-#define INTEL_CLEAR   0x00500050
-#define INTEL_LOCKBIT 0x00600060
-#define INTEL_PROTECT 0x00010001
-#define INTEL_STATUS  0x00700070
-#define INTEL_READID  0x00900090
-#define INTEL_CONFIRM 0x00D000D0
-#define INTEL_RESET   0xFFFFFFFF
+#define INTEL_PROGRAM          0x00100010
+#define INTEL_ERASE            0x00200020
+#define INTEL_CLEAR            0x00500050
+#define INTEL_LOCKBIT          0x00600060
+#define INTEL_PROTECT          0x00010001
+#define INTEL_STATUS           0x00700070
+#define INTEL_READID           0x00900090
+#define INTEL_CONFIRM          0x00D000D0
+#define INTEL_RESET            0xFFFFFFFF
 
 /* Intel-compatible flash status bits */
-#define INTEL_FINISHED 0x00800080
-#define INTEL_OK       0x00800080
+#define INTEL_FINISHED         0x00800080
+#define INTEL_OK               0x00800080
 
-#define FPW       FLASH_PORT_WIDTH
-#define FPWV   FLASH_PORT_WIDTHV
+#define FPW    FLASH_PORT_WIDTH
+#define FPWV   FLASH_PORT_WIDTHV
 
 #define mb() __asm__ __volatile__ ("" : : : "memory")
 
@@ -75,6 +75,8 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info);
 static int write_data (flash_info_t *info, ulong 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);
 
 /*-----------------------------------------------------------------------
  */
@@ -83,30 +85,47 @@ unsigned long flash_init (void)
 {
        int i;
        ulong size = 0;
+       extern void flash_preinit(void);
+       extern void flash_afterinit(ulong, ulong);
+       ulong flashbase = CFG_FLASH_BASE;
+
+       flash_preinit();
 
        for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
                switch (i) {
                case 0:
-                       flash_get_size ((FPW *) CFG_FLASH_BASE, &flash_info[i]);
-                       flash_get_offsets (CFG_FLASH_BASE, &flash_info[i]);
+                       memset(&flash_info[i], 0, sizeof(flash_info_t));
+                       flash_get_size ((FPW *) flashbase, &flash_info[i]);
+                       flash_get_offsets (flash_info[i].start[0], &flash_info[i]);
                        break;
                default:
                        panic ("configured to many flash banks!\n");
                        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 CFG_MONITOR_BASE >= CFG_FLASH_BASE
+#ifndef CONFIG_BOOT_ROM
        flash_protect ( FLAG_PROTECT_SET,
                        CFG_MONITOR_BASE,
                        CFG_MONITOR_BASE + monitor_flash_len - 1,
                        &flash_info[0] );
+#endif
+#endif
 
+#ifdef CFG_ENV_IS_IN_FLASH
        flash_protect ( FLAG_PROTECT_SET,
                        CFG_ENV_ADDR,
                        CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0] );
+#endif
+
+       flash_afterinit(flash_info[0].start[0], flash_info[0].size);
 
        return size;
 }
@@ -124,7 +143,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_FLASH_SECT_SIZE);
-                       info->protect[i] = 0;
                }
        }
 }
@@ -150,6 +168,10 @@ void flash_print_info (flash_info_t *info)
        }
 
        switch (info->flash_id & FLASH_TYPEMASK) {
+       case FLASH_28F256J3A:
+               printf ("28F256J3A\n");
+               break;
+
        case FLASH_28F128J3A:
                printf ("28F128J3A\n");
                break;
@@ -195,6 +217,8 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info)
        addr[0x5555] = (FPW) 0x00900090;
 
        mb ();
+       udelay(100);
+
        value = addr[0];
 
        switch (value) {
@@ -216,22 +240,33 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info)
 
        switch (value) {
 
+       case (FPW) INTEL_ID_28F256J3A:
+               info->flash_id += FLASH_28F256J3A;
+               /* In U-Boot we support only 32 MB (no bank-switching) */
+               info->sector_count = 256 / 2;
+               info->size =  0x04000000 / 2;
+               info->start[0] = CFG_FLASH_BASE + 0x02000000;
+               break;                          /* => 32 MB     */
+
        case (FPW) INTEL_ID_28F128J3A:
                info->flash_id += FLASH_28F128J3A;
                info->sector_count = 128;
                info->size = 0x02000000;
+               info->start[0] = CFG_FLASH_BASE + 0x02000000;
                break;                          /* => 32 MB     */
 
        case (FPW) INTEL_ID_28F640J3A:
                info->flash_id += FLASH_28F640J3A;
                info->sector_count = 64;
                info->size = 0x01000000;
+               info->start[0] = CFG_FLASH_BASE + 0x03000000;
                break;                          /* => 16 MB     */
 
        case (FPW) INTEL_ID_28F320J3A:
                info->flash_id += FLASH_28F320J3A;
                info->sector_count = 32;
-               info->size = 0x00800000;
+               info->size = 0x800000;
+               info->start[0] = CFG_FLASH_BASE + 0x03800000;
                break;                          /* => 8 MB     */
 
        default:
@@ -251,6 +286,84 @@ 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_28F256J3A:
+       case FLASH_28F128J3A:
+       case FLASH_28F640J3A:
+       case FLASH_28F320J3A:
+               for (i = 0; i < info->sector_count; ++i) {
+                       info->protect[i] = intel_sector_protected(info, i);
+               }
+               break;
+       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
+        * CFG_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) > CFG_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 2 for 16 bit flash */
+       lock_conf_addr = (FPWV *) info->start[sector] + 2;
+       ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0;
+
+       /* put flash back in read mode */
+       *addr = (FPW) INTEL_RESET;
+
+       return ret;
+}
+
 /*-----------------------------------------------------------------------
  */
 
@@ -472,7 +585,7 @@ void inline spin_wheel (void)
  * 0 - OK
  * 1 - Error (timeout, voltage problems, etc.)
  */
-int flash_real_protect(flash_info_t *info, long sector, int prot)
+int flash_real_protect (flash_info_t *info, long sector, int prot)
 {
        ulong start;
        int i;
@@ -512,6 +625,11 @@ int flash_real_protect(flash_info_t *info, long sector, int prot)
        /*
         * Clear lock bit command clears all sectors lock bits, so
         * we have to restore lock bits of protected sectors.
+        * WARNING: code below re-locks sectors only for one bank (info).
+        * This causes problems on boards where several banks share
+        * the same chip, as sectors in othere banks will be unlocked
+        * but not re-locked. It works fine on pm520 though, as there
+        * is only one chip and one bank.
         */
        if (!prot)
        {
@@ -534,6 +652,11 @@ int flash_real_protect(flash_info_t *info, long sector, int prot)
                                }
                        }
                }
+               /*
+                * 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)