From adac376ef2fc3d44764dd32c205cb4ad03dfbe9e Mon Sep 17 00:00:00 2001
From:  <m8@hekate.semihalf.com>
Date: Thu, 11 Aug 2005 10:10:30 +0200
Subject: [PATCH] O2DNT: added hardware flash protect support, macros cleanup.

---
 board/o2dnt/flash.c     | 213 +++++++++++++++++++++++++++++++++++-----
 include/configs/o2dnt.h |   5 +-
 2 files changed, 191 insertions(+), 27 deletions(-)

diff --git a/board/o2dnt/flash.c b/board/o2dnt/flash.c
index 64574f45d7..186e0d2938 100644
--- a/board/o2dnt/flash.c
+++ b/board/o2dnt/flash.c
@@ -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.
  *
@@ -23,29 +27,36 @@
 
 #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;
+}
+
diff --git a/include/configs/o2dnt.h b/include/configs/o2dnt.h
index fa15d85958..6d388f3f64 100644
--- a/include/configs/o2dnt.h
+++ b/include/configs/o2dnt.h
@@ -169,9 +169,8 @@
 
 #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
-- 
2.39.5