O2DNT: added hardware flash protect support, macros cleanup.
author <m8@hekate.semihalf.com> <>
Thu, 11 Aug 2005 08:10:30 +0000 (10:10 +0200)
committer <m8@hekate.semihalf.com> <>
Thu, 11 Aug 2005 08:10:30 +0000 (10:10 +0200)
board/o2dnt/flash.c
include/configs/o2dnt.h

index 64574f45d7068fe0dea82651c5e6cadb58cf91a3..186e0d29386dd7ccb6a92289944dbd444cdb279b 100644 (file)
@@ -2,6 +2,10 @@
  * (C) Copyright 2005
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  *
+ * flash_real_protect() routine based on boards/alaska/flash.c
+ * (C) Copyright 2001
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
 
 #include <common.h>
 
-flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips  */
+/* Intel-compatible flash commands */
+#define INTEL_ERASE    0x20
+#define INTEL_PROGRAM  0x40
+#define INTEL_CLEAR    0x50
+#define INTEL_LOCKBIT  0x60
+#define INTEL_PROTECT  0x01
+#define INTEL_STATUS   0x70
+#define INTEL_READID   0x90
+#define INTEL_READID   0x90
+#define INTEL_SUSPEND  0xB0
+#define INTEL_CONFIRM  0xD0
+#define INTEL_RESET    0xFF
+
+/* Intel-compatible flash status bits */
+#define INTEL_FINISHED 0x80
+#define INTEL_OK       0x80
 
-/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
- *        has nothing to do with the flash chip being 8-bit or 16-bit.
- */
-#ifdef CONFIG_FLASH_16BIT
-typedef unsigned short FLASH_PORT_WIDTH;
-typedef volatile unsigned short FLASH_PORT_WIDTHV;
-#define        FLASH_ID_MASK   0xFFFF
-#else
 typedef unsigned char FLASH_PORT_WIDTH;
 typedef volatile unsigned char FLASH_PORT_WIDTHV;
+#define FPW            FLASH_PORT_WIDTH
+#define FPWV           FLASH_PORT_WIDTHV
 #define        FLASH_ID_MASK   0xFF
-#endif
-
-#define FPW    FLASH_PORT_WIDTH
-#define FPWV   FLASH_PORT_WIDTHV
 
 #define ORMASK(size) ((-size) & OR_AM_MSK)
 
 #define FLASH_CYCLE1   0x0555
 #define FLASH_CYCLE2   0x02aa
 
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
 /*-----------------------------------------------------------------------
  * Functions
  */
@@ -53,6 +64,8 @@ static ulong flash_get_size(FPWV *addr, flash_info_t *info);
 static void flash_reset(flash_info_t *info);
 static flash_info_t *flash_get_info(ulong base);
 static int write_data (flash_info_t *info, FPWV *dest, FPW data); /* O2D */
+static void flash_sync_real_protect (flash_info_t * info);
+static unsigned char intel_sector_protected (flash_info_t *info, ushort sector);
 
 /*-----------------------------------------------------------------------
  * flash_init()
@@ -79,6 +92,9 @@ unsigned long flash_init (void)
                flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);
        size += flash_info[0].size;
 
+       /* get the h/w and s/w protection status in sync */
+       flash_sync_real_protect(&flash_info[0]);
+
 #if CFG_MONITOR_BASE >= CFG_FLASH_BASE
        /* monitor protection ON by default */
        flash_protect(FLAG_PROTECT_SET,
@@ -108,7 +124,7 @@ static void flash_reset(flash_info_t *info)
 
        /* Put FLASH back in read mode */
        if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
-               *base = (FPW)0x00FF00FF;        /* Intel Read Mode */
+               *base = (FPW) INTEL_RESET;      /* Intel Read Mode */
 }
 
 /*-----------------------------------------------------------------------
@@ -204,7 +220,7 @@ ulong flash_get_size (FPWV *addr, flash_info_t *info)
 
        /* Write auto select command: read Manufacturer ID */
        /* Write auto select command sequence and test FLASH answer */
-       addr[FLASH_CYCLE1] = (FPW)0x00900090;   /* selects Intel or AMD */
+       addr[FLASH_CYCLE1] = (FPW) INTEL_READID;        /* selects Intel or AMD */
 
        /* The manufacturer codes are only 1 byte, so just use 1 byte.
         * This works for any bus width and any FLASH device width.
@@ -298,9 +314,9 @@ int flash_erase (flash_info_t *info, int s_first, int s_last)
                flag = disable_interrupts();
 
                addr = (FPWV *)(info->start[sect]);
-               *addr = (FPW)0x00500050; /* clear status register */
-               *addr = (FPW)0x00200020; /* erase setup */
-               *addr = (FPW)0x00D000D0; /* erase confirm */
+               *addr = (FPW) INTEL_CLEAR; /* clear status register */
+               *addr = (FPW) INTEL_ERASE; /* erase setup */
+               *addr = (FPW) INTEL_CONFIRM; /* erase confirm */
 
                /* re-enable interrupts if necessary */
                if (flag)
@@ -311,10 +327,10 @@ int flash_erase (flash_info_t *info, int s_first, int s_last)
                /* wait at least 80us for Intel - let's wait 1 ms */
                udelay (1000);
 
-               while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
+               while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) {
                        if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
                                printf ("Timeout\n");
-                               *addr = (FPW)0x00B000B0;/* suspend erase */
+                               *addr = (FPW) INTEL_SUSPEND;/* suspend erase */
                                flash_reset(info);      /* reset to read mode */
                                rcode = 1;              /* failed */
                                break;
@@ -401,23 +417,172 @@ static int write_data (flash_info_t *info, FPWV *dest, FPW data)
        /* Disable interrupts which might cause a timeout here */
        flag = disable_interrupts ();
 
-       *addr = (FPW) 0x00400040;       /* write setup */
+       *addr = (FPW) INTEL_PROGRAM;    /* write setup */
        *addr = data;
 
        /* arm simple, non interrupt dependent timer */
        start = get_timer(0);
 
        /* wait while polling the status register */
-       while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
+       while (((status = *addr) & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) {
                if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
-                       *addr = (FPW) 0x00FF00FF;       /* restore read mode */
+                       *addr = (FPW) INTEL_RESET;      /* restore read mode */
                        return (1);
                }
        }
 
-       *addr = (FPW) 0x00FF00FF;       /* restore read mode */
+       *addr = (FPW) INTEL_RESET;      /* restore read mode */
        if (flag)
                enable_interrupts();
 
        return (0);
 }
+
+
+/*-----------------------------------------------------------------------
+ * Set/Clear sector's lock bit, returns:
+ * 0 - OK
+ * 1 - Error (timeout, voltage problems, etc.)
+ */
+int flash_real_protect (flash_info_t * info, long sector, int prot)
+{
+       ulong start;
+       int i;
+       int rc = 0;
+       FPWV *addr = (FPWV *) (info->start[sector]);
+       int flag = disable_interrupts ();
+
+       *addr = INTEL_CLEAR;    /* Clear status register    */
+       if (prot) {             /* Set sector lock bit      */
+               *addr = INTEL_LOCKBIT;  /* Sector lock bit          */
+               *addr = INTEL_PROTECT;  /* set                      */
+       } else {                /* Clear sector lock bit    */
+               *addr = INTEL_LOCKBIT;  /* All sectors lock bits    */
+               *addr = INTEL_CONFIRM;  /* clear                    */
+       }
+
+       start = get_timer (0);
+
+       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;
+               }
+       }
+
+       if (*addr != INTEL_OK) {
+               printf ("Flash lock bit operation failed at %08X, CSR=%08X\n",
+                       (uint) addr, (uint) * addr);
+               rc = 1;
+       }
+
+       if (!rc)
+               info->protect[sector] = prot;
+
+       /*
+        * Clear lock bit command clears all sectors lock bits, so
+        * 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;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (flag)
+               enable_interrupts ();
+
+       *addr = INTEL_RESET;    /* Reset to read array mode */
+
+       return rc;
+}
+
+
+/*
+ * 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;
+       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 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;
+}
+
index fa15d859586b549c1ba1cb2fcb352fc4eaeabae0..6d388f3f64ae29c469fdb60b741d2b819712c2ec 100644 (file)
 
 #define CFG_FLASH_ERASE_TOUT   240000  /* Flash Erase Timeout (in ms)  */
 #define CFG_FLASH_WRITE_TOUT   500     /* Flash Write Timeout (in ms)  */
-
-#undef CONFIG_FLASH_16BIT      /* Flash is 8-bit */
-
+#define CFG_FLASH_UNLOCK_TOUT  10000   /* Timeout for Flash Clear Lock Bits (in ms) */
+#define CFG_FLASH_PROTECTION           /* "Real" (hardware) sectors protection */
 
 /*
  * Environment settings