Implement h/w sector protection status synchronization at boot.
The code is provided for, and was tested on, the Yukon/Alaska
and PM520 boards only.

A bug in flash_real_protect() for the Yukon board was fixed by adding
a function that tells if two banks are on one flash chip.
diff --git a/board/alaska/flash.c b/board/alaska/flash.c
index 48c9472..383491f 100644
--- a/board/alaska/flash.c
+++ b/board/alaska/flash.c
@@ -64,7 +64,6 @@
 #define FLASH_CYCLE2    0x02aa
 
 #define WR_BLOCK        0x20
-
 /*-----------------------------------------------------------------------
  * Functions
  */
@@ -74,6 +73,9 @@
 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);
 
 /*-----------------------------------------------------------------------
  */
@@ -115,6 +117,9 @@
 			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
@@ -167,7 +172,6 @@
 	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;
 		}
 	}
 }
@@ -305,6 +309,98 @@
 }
 
 
+/*
+ * 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
+	 * 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;
+}
+
+
+/*
+ * 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[CFG_MAX_FLASH_BANKS][CFG_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)
@@ -729,7 +825,9 @@
 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 ();
@@ -779,23 +877,54 @@
 	 * 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 = CFG_MAX_FLASH_BANKS + 1;
+		for (j = 0; j < CFG_MAX_FLASH_BANKS; ++j) {
+			if (&flash_info[j] == info) {
+				curr_bank = j;
+			}
+		}
+		if (curr_bank == CFG_MAX_FLASH_BANKS + 1) {
+			printf("Error: can't determine bank number!\n");
+		}
+
+		for (bank = 0; bank < CFG_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) >
+						    CFG_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)