>From 640fc0400b5be71ef9976d19533f2f0664e9ee71 Mon Sep 17 00:00:00 2001
From: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
Date: Thu, 16 Jun 2011 16:42:22 +0200
Subject: [PATCH] fixup! add support for Intel Hardware Sequencing


Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
---
 ichspi.c |  160 +++++++++++++++++++++++++++++---------------------------------
 1 files changed, 74 insertions(+), 86 deletions(-)

diff --git a/ichspi.c b/ichspi.c
index 7865dfb..f6b1bbe 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -1138,6 +1138,44 @@ static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
 	return dec_berase[enc_berase];
 }
 
+/* Polls for Cycle Done Status, Flash Cycle Error or timeout in 10 us intervals.
+   Resets all error flags in HSFS.
+   Returns 0 if the cycle completes successfully without errors within
+   timeout us, 1 on errors. */
+static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
+					     unsigned int len)
+{
+	uint16_t hsfs;
+	uint32_t addr;
+
+	while ((((hsfs = REGREAD16(ICH9_REG_HSFS)) &
+		 (HSFS_FDONE | HSFS_FCERR)) == 0) &&
+	       --timeout) {
+		programmer_delay(10);
+	}
+	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+	if (!timeout) {
+		addr = REGREAD32(ICH9_REG_FADDR);
+		msg_perr("Timeout error between offset 0x%06x and "
+			 "0x%06x + %d (=0x%06x)!\n",
+			 addr, addr, len - 1, addr + len - 1);
+		prettyprint_ich9_reg_hsfs(hsfs);
+		prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC));
+		return 1;
+	}
+
+	if (hsfs & HSFS_FCERR) {
+		addr = REGREAD32(ICH9_REG_FADDR);
+		msg_perr("Transaction error between offset 0x%06x and "
+			 "0x%06x + %d (=0x%06x)!\n",
+			 addr, addr, len - 1, addr + len - 1);
+		prettyprint_ich9_reg_hsfs(hsfs);
+		prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC));
+		return 1;
+	}
+	return 0;
+}
+
 int ich_hwseq_probe(struct flashchip *flash)
 {
 	uint32_t total_size, boundary;
@@ -1224,7 +1262,6 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 {
 	uint32_t erase_block;
 	uint32_t hsfc;
-	uint32_t hsfs;
 	uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */
 
 	if (flash->manufacture_id != INTEL_ID ||
@@ -1238,10 +1275,7 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 	if (len != erase_block) {
 		msg_cerr("Erase block size for address 0x%06x is %d B, "
 			 "but requested erase block size is %d B. "
-			 "Not erasing anything.\n",
-			 addr,
-			 erase_block,
-			 len);
+			 "Not erasing anything.\n", addr, erase_block, len);
 		return -1;
 	}
 
@@ -1250,53 +1284,37 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 	if (addr % erase_block != 0) {
 		msg_cerr("Erase address 0x%06x is not aligned to the erase "
 			 "block boundary (any multiple of %d). "
-			 "Not erasing anything.\n",
-			 addr,
-			 erase_block);
+			 "Not erasing anything.\n", addr, erase_block);
 		return -1;
 	}
 
-	msg_pdbg("Erasing %d bytes starting at 0x%06x\n", len, addr);
+	if (addr < 0 || addr + len > 0x00FFFFFF) {
+		msg_perr("Request to erase some inaccessible memory address(es)"
+			 " (addr=0x%x, len=%d). "
+			 "Not erasing anything.\n", addr, len);
+		return -1;
+	}
+
+	msg_pdbg("Erasing %d bytes starting at 0x%06x.\n", len, addr);
 
-	hsfc = REGREAD16(ICH9_REG_HSFC);
 	/* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
-	REGWRITE16(ICH9_REG_HSFC, hsfc);
+	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+
+	hsfc = REGREAD16(ICH9_REG_HSFC);
 	hsfc &= ~HSFC_FCYCLE; /* clear operation */
 	hsfc = (0x11 << HSFC_FCYCLE_OFF); /* set erase operation */
 	hsfc |= HSFC_FGO; /* start */
 	REGWRITE16(ICH9_REG_HSFC, hsfc);
 
-	/* Wait for Cycle Done Status or Flash Cycle Error. */
-	while (((REGREAD16(ICH9_REG_HSFS) &
-		(HSFS_FDONE | HSFS_FCERR)) == 0) &&
-	       --timeout) {
-		programmer_delay(10);
-	}
-	hsfs = REGREAD16(ICH9_REG_HSFS);
-	if (!timeout) {
-		msg_perr("timeout!\n");
-		prettyprint_ich9_reg_hsfs(hsfs);
-		prettyprint_ich9_reg_hsfc(hsfs);
-		return 1;
-	}
-
-	REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */
-	if (hsfs & HSFS_FCERR) {
-		msg_perr("Transaction error between offset 0x%06x and 0x%06x + "
-			 "%d (=0x%06x)!\n",
-			 addr, addr, len, addr+len);
-		prettyprint_ich9_reg_hsfs(hsfs);
-		prettyprint_ich9_reg_hsfc(hsfs);
+	if (ich_hwseq_wait_for_cycle_complete(timeout, len))
 		return 1;
-	}
 	return 0;
 }
 
 int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len)
 {
 	uint32_t *buf32 = (uint32_t *)buf;
-	uint16_t hsfc = REGREAD16(ICH9_REG_HSFC);
-	uint16_t hsfs;
+	uint16_t hsfc;
 	uint16_t timeout = 100 * 60;
 	int i;
 
@@ -1313,11 +1331,18 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len)
 		return -1;
 	}
 
-	msg_pdbg("reading %d bytes starting at 0x%06x\n", len, addr);
+	if (addr < 0 || addr + len > 0x00FFFFFF) {
+		msg_perr("Request to read from inaccessible memory address "
+			 "(addr=0x%x, len=%d).\n", addr, len);
+		return -1;
+	}
+
+	msg_pdbg("Reading %d bytes starting at 0x%06x.\n", len, addr);
 	/* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
-	REGWRITE16(ICH9_REG_HSFC, hsfc);
+	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
 
 	for (i = 0; i < len; i += 4) {
+		/* FIXME: reserved bits */
 		REGWRITE32(ICH9_REG_FADDR, (addr & 0x00FFFFFF));
 		hsfc = REGREAD16(ICH9_REG_HSFC);
 		hsfc &= ~HSFC_FCYCLE; /* set read operation */
@@ -1326,30 +1351,8 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len)
 		hsfc |= HSFC_FGO; /* start */
 		REGWRITE16(ICH9_REG_HSFC, hsfc);
 
-		/* Wait for Cycle Done Status or Flash Cycle Error. */
-		while (((REGREAD16(ICH9_REG_HSFS) &
-		        (HSFS_FDONE | HSFS_FCERR)) == 0) &&
-		       --timeout) {
-			programmer_delay(10);
-		}
-		hsfs = REGREAD16(ICH9_REG_HSFS);
-		if (!timeout) {
-			msg_perr("timeout!\n");
-			prettyprint_ich9_reg_hsfs(hsfs);
-			prettyprint_ich9_reg_hsfc(hsfs);
+		if (ich_hwseq_wait_for_cycle_complete(timeout, 4))
 			return 1;
-		}
-
-		REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */
-		if (hsfs & HSFS_FCERR) {
-			msg_perr("Transaction error between offset 0x%06x and "
-				 "0x%06x + %d (= 0x%06x)!\n",
-				 addr, addr, 4, addr + 4);
-			prettyprint_ich9_reg_hsfs(hsfs);
-			prettyprint_ich9_reg_hsfc(hsfs);
-			return 1;
-		}
-
 		*buf32++ = REGREAD32(ICH9_REG_FDATA0);
 		addr += 4;
 	}
@@ -1359,8 +1362,7 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len)
 int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len)
 {
 	uint32_t *buf32 = (uint32_t *)buf;
-	uint16_t hsfc = REGREAD16(ICH9_REG_HSFC);
-	uint16_t hsfs;
+	uint16_t hsfc;
 	uint16_t timeout = 100 * 60;
 	int i;
 	if (flash->manufacture_id != INTEL_ID ||
@@ -1376,11 +1378,18 @@ int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len
 		return -1;
 	}
 
-	msg_pdbg("writing %d bytes starting at 0x%06x\n", len, addr);
+	if (addr < 0 || addr + len > 0x00FFFFFF) {
+		msg_perr("Request to write to inaccessible memory address "
+			 "(addr=0x%x, len=%d).\n", addr, len);
+		return -1;
+	}
+
+	msg_pdbg("Writing %d bytes starting at 0x%06x.\n", len, addr);
 	/* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
-	REGWRITE16(ICH9_REG_HSFC, hsfc);
+	REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
 
 	for (i = 0; i < len; i += 4) {
+		/* FIXME: reserved bits */
 		REGWRITE32(ICH9_REG_FADDR, (addr & 0x00FFFFFF));
 		REGWRITE32(ICH9_REG_FDATA0, *buf32++);
 		hsfc = REGREAD16(ICH9_REG_HSFC);
@@ -1391,29 +1400,8 @@ int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len
 		hsfc |= HSFC_FGO; /* start */
 		REGWRITE16(ICH9_REG_HSFC, hsfc);
 
-		/* Wait for Cycle Done Status or Flash Cycle Error. */
-		while (((REGREAD16(ICH9_REG_HSFS) &
-		        (HSFS_FDONE | HSFS_FCERR)) == 0) &&
-		       --timeout) {
-			programmer_delay(10);
-		}
-		hsfs = REGREAD16(ICH9_REG_HSFS);
-		if (!timeout) {
-			msg_perr("timeout!\n");
-			prettyprint_ich9_reg_hsfs(hsfs);
-			prettyprint_ich9_reg_hsfc(hsfs);
+		if (ich_hwseq_wait_for_cycle_complete(timeout, 4))
 			return 1;
-		}
-
-		REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */
-		if (hsfs & HSFS_FCERR) {
-			msg_perr("Transaction error between offset 0x%06x and "
-				 "0x%06x + %d (= 0x%06x)!\n",
-				 addr, addr, 4, addr + 4);
-			prettyprint_ich9_reg_hsfs(hsfs);
-			prettyprint_ich9_reg_hsfc(hsfs);
-			return 1;
-		}
 		addr += 4;
 	}
 	return 0;
-- 
1.7.1

