>From 1f0d8d7b516102d79760ddfdbfeea427afed4d4d Mon Sep 17 00:00:00 2001
From: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
Date: Sun, 5 Jun 2011 03:34:37 +0200
Subject: [PATCH] squash! add support for Intel Hardware Sequencing


Signed-off-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
---
 flashchips.c |   27 ++---------
 flashchips.h |    2 +
 flashrom.c   |    6 +-
 ichspi.c     |  144 ++++++++++++++++++++++++++++++++++++++++-----------------
 4 files changed, 111 insertions(+), 68 deletions(-)

diff --git a/flashchips.c b/flashchips.c
index f912c23..2f0161f 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -8507,44 +8507,27 @@ const struct flashchip flashchips[] = {
 		.write		= write_jedec_1,
 		.read		= read_memmapped,
 	},
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(CONFIG_INTERNAL) && (defined(__i386__) || defined(__x86_64__))
 	{
 		.vendor		= "Intel",
 		.name		= "Hardware Sequencing",
 		.bustype	= CHIP_BUSTYPE_SPI,
 		.manufacture_id	= INTEL_ID,
-		.model_id	= GENERIC_DEVICE_ID,
-		.total_size	= 4,
+		.model_id	= INTEL_HWSEQ,
+		.total_size	= 0,
 		.page_size	= 256,
 		.tested		= TEST_OK_PR,
 		.probe		= ich_hwseq_probe,
 		.block_erasers	=
 		{
-			{
-				.eraseblocks = { {256, 4 * 4} },
+			{ /* erase blocks will be set by the probing function */
 				.block_erase = ich_hwseq_block_erase,
-			//}, {
-			//{
-				//.eraseblocks = { {256, CHIPSIZE * 4} },
-				//.block_erase = ich_hwseq_block_erase,
-			//}, {
-			//{
-				//.eraseblocks = { {4 * 1024, CHIPSIZE / 4} },
-				//.block_erase = ich_hwseq_block_erase,
-			//}, {
-			//{
-				//.eraseblocks = { {8 * 1024, CHIPSIZE / 8} },
-				//.block_erase = ich_hwseq_block_erase,
-			//}, {
-			//{
-				//.eraseblocks = { {64 * 1024, CHIPSIZE / 64} },
-				//.block_erase = ich_hwseq_block_erase,
 			}
 		},
 		.write		= ich_hwseq_write_256,
 		.read		= ich_hwseq_read,
 	},
-#endif // defined(__i386__) || defined(__x86_64__)
+#endif // defined(CONFIG_INTERNAL) && (defined(__i386__) || defined(__x86_64__))
 	{
 		.vendor		= "AMIC",
 		.name		= "unknown AMIC SPI chip",
diff --git a/flashchips.h b/flashchips.h
index 3b2b94f..6b8d574 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -340,6 +340,8 @@
 #define SHARP_LH28F008SA	0xA2	/* Sharp chip, Intel Vendor ID */
 #define SHARP_LH28F008SC	0xA6	/* Sharp chip, Intel Vendor ID */
 
+#define INTEL_HWSEQ		0xFFFE	/* dummy ID for hardware sequencing */
+
 #define ISSI_ID			0xD5	/* ISSI Integrated Silicon Solutions */
 
 /*
diff --git a/flashrom.c b/flashrom.c
index e9e6a77..41f4c26 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1191,7 +1191,7 @@ notfound:
 		programmer_unmap_flash_region((void *)fill_flash->virtual_memory, size);
 	}
 
-	if (!flash || !flash->name)
+	if (!fill_flash || !fill_flash->name)
 		return -1;
 
 #if CONFIG_INTERNAL == 1
@@ -1203,8 +1203,8 @@ notfound:
 
 	msg_cinfo("%s chip \"%s %s\" (%d kB, %s) %s.\n",
 	       force ? "Assuming" : "Found",
-	       flash->vendor, flash->name, flash->total_size,
-	       flashbuses_to_text(flash->bustype), location);
+	       fill_flash->vendor, fill_flash->name, fill_flash->total_size,
+	       flashbuses_to_text(fill_flash->bustype), location);
 
 	/* Flash registers will not be mapped if the chip was forced. Lock info
 	 * may be stored in registers, so avoid lock info printing.
diff --git a/ichspi.c b/ichspi.c
index 8cdcb5c..238c43c 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -35,10 +35,11 @@
  *
  */
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(CONFIG_INTERNAL) && (defined(__i386__) || defined(__x86_64__))
 
 #include <string.h>
 #include "flash.h"
+#include "flashchips.h"
 #include "chipdrivers.h"
 #include "programmer.h"
 #include "spi.h"
@@ -1099,8 +1100,16 @@ static int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt,
 	return result;
 }
 
-uint32_t ich_hwseq_get_erase_block_size(void)
+static uint32_t ich_hwseq_get_flash_boundary(void)
 {
+	return (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12;
+}
+
+/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes
+ * of the block containing this address. */
+static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
+{
+	REGWRITE32(ICH9_REG_FADDR, (addr & 0x00FFFFFF));
 	uint8_t enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >>
 				   HSFS_BERASE_OFF;
 	const uint32_t dec_berase[4] = {
@@ -1114,19 +1123,71 @@ uint32_t ich_hwseq_get_erase_block_size(void)
 
 int ich_hwseq_probe(struct flashchip *flash)
 {
+	uint32_t total_size, boundary;
+	uint32_t erase_size_low, size_low, erase_size_high, size_high;
+	struct block_eraser eraser;
 	extern struct flash_descriptor fdbar;
+
+	if (flash->manufacture_id != INTEL_ID ||
+	    flash->model_id != INTEL_HWSEQ) {
+		msg_cerr("This chip (%s) is not supported in hardware"
+			 "sequencing mode and should never have been probed.\n",
+			 flash->name);
+		msg_cerr("%s: Please report a bug at flashrom@flashrom.org\n",
+			 __func__);
+		return 0;
+	}
+
 	msg_cdbg("Prerequisites for Intel Hardware Sequencing are ");
-	if (spi_programmer->type == SPI_CONTROLLER_ICH_HWSEQ) {
-		msg_cdbg("met.\n");
-		msg_cdbg("Found %d attached SPI flash chips with a "
-			 "combined density of %d kB.\n", fdbar.NC + 1,
-			 (getFCBA_component_density(0) +
-			  getFCBA_component_density(1)) / 1024);
-		return 1;
-	} else {
+	if (spi_programmer->type != SPI_CONTROLLER_ICH_HWSEQ) {
 		msg_cdbg("not met.\n");
 		return 0;
 	}
+
+	msg_cdbg("met.\n");
+	total_size = (getFCBA_component_density(0) +
+		      getFCBA_component_density(1));
+	msg_cdbg("Found %d attached SPI flash chip", fdbar.NC + 1);
+	if (fdbar.NC)
+		msg_cdbg("s with a combined");
+	else
+		msg_cdbg(" with a");
+	msg_cdbg(" density of %d kB.\n", total_size / 1024);
+	flash->total_size = total_size / 1024;
+
+	eraser = flash->block_erasers[0];
+	boundary = ich_hwseq_get_flash_boundary();
+	size_high = total_size - boundary;
+	erase_size_high = ich_hwseq_get_erase_block_size(boundary);
+
+	if (boundary == 0) {
+		msg_cdbg("There is only one partition containting the whole "
+			 "address space (0x%06x - 0x%06x)\n", 0, size_high-1);
+		eraser.eraseblocks[0].size = erase_size_high;
+		eraser.eraseblocks[0].count = size_high / erase_size_high;
+		msg_cdbg("There are %d erase blocks with %d B each.\n",
+			 size_high / erase_size_high, erase_size_high);
+	} else {
+		msg_cdbg("The flash is divided at address 0x%06x in two "
+			 "partitions.\n", boundary);
+		size_low = total_size - size_high;
+		erase_size_low = ich_hwseq_get_erase_block_size(0);
+
+		eraser.eraseblocks[0].size = erase_size_low;
+		eraser.eraseblocks[0].count = size_low / erase_size_low;
+		msg_cdbg("The first partition ranges from 0x%06x to 0x%06x.\n",
+			 0, size_low-1);
+		msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+			 size_low / erase_size_low, erase_size_low);
+
+		eraser.eraseblocks[1].size = erase_size_high;
+		eraser.eraseblocks[1].count = size_high / erase_size_high;
+		msg_cdbg("The second partition ranges from 0x%06x to 0x%06x.\n",
+			 boundary, size_high-1);
+		msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+			 size_high / erase_size_high, erase_size_high);
+	}
+	return 1;
 }
 
 static int ich_hwseq_send_command(unsigned int writecnt,
@@ -1148,14 +1209,14 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 	uint32_t hsfs;
 	uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */
 
-	REGWRITE32(ICH9_REG_FADDR, (addr & 0x00FFFFFF));
-	erase_block = ich_hwseq_get_erase_block_size();
-	if (strcmp(flash->name, "Hardware Sequencing") != 0) {
+	if (flash->manufacture_id != INTEL_ID ||
+	    flash->model_id != INTEL_HWSEQ) {
 		msg_perr("This chip (%s) is not supported in hardware"
 			 "sequencing mode\n", flash->name);
 		return -1;
 	}
 
+	erase_block = ich_hwseq_get_erase_block_size(addr);
 	if (len != erase_block) {
 		msg_cerr("Erase block size for address 0x%06x is %d B, "
 			 "but requested erase block size is %d B. "
@@ -1166,6 +1227,8 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 		return -1;
 	}
 
+	/* Although the hardware supports this (it would erase the whole block
+	 * containing the address) we play safe here. */
 	if (addr % erase_block != 0) {
 		msg_cerr("Erase address 0x%06x is not aligned to the erase "
 			 "block boundary (any multiple of %d). "
@@ -1175,10 +1238,10 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 		return -1;
 	}
 
-	msg_pdbg("erasing %d bytes starting at 0x%06x\n", len, addr);
+	msg_pdbg("Erasing %d bytes starting at 0x%06x\n", len, addr);
 
 	hsfc = REGREAD16(ICH9_REG_HSFC);
-	/* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */
+	/* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
 	REGWRITE16(ICH9_REG_HSFC, hsfc);
 	hsfc &= ~HSFC_FCYCLE; /* clear operation */
 	hsfc = (0x11 << HSFC_FCYCLE_OFF); /* set erase operation */
@@ -1191,17 +1254,18 @@ int ich_hwseq_block_erase(struct flashchip *flash,
 	       --timeout) {
 		programmer_delay(10);
 	}
+	hsfs = REGREAD16(ICH9_REG_HSFS);
 	if (!timeout) {
-		msg_perr("timeout, ICH9_REG_HSFS=0x%04x\n",
-			 REGREAD16(ICH9_REG_HSFS));
+		msg_perr("timeout!\n");
+		prettyprint_ich9_reg_hsfs(hsfs);
+		prettyprint_ich9_reg_hsfc(hsfs);
 		return 1;
 	}
 
-	hsfs = REGREAD16(ICH9_REG_HSFS);
 	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",
+			 "%d (=0x%06x)!\n",
 			 addr, addr, len, addr+len);
 		prettyprint_ich9_reg_hsfs(hsfs);
 		prettyprint_ich9_reg_hsfc(hsfs);
@@ -1218,15 +1282,16 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len)
 	uint16_t timeout = 100 * 60;
 	int i;
 
-	if (strcmp(flash->name, "Hardware Sequencing") != 0) {
+	if (flash->manufacture_id != INTEL_ID ||
+	    flash->model_id != INTEL_HWSEQ) {
 		msg_perr("This chip (%s) is not supported in hardware"
-			 "sequencing mode\n", flash->name);
+			 "sequencing mode.\n", flash->name);
 		return -1;
 	}
 
 	if (len % 4 != 0) {
-		msg_perr("Read size has to be a multiple of 4 in hardware"
-			 "sequencing mode\n");
+		msg_perr("Read size has to be a multiple of 4 for this "
+			 "implementation of hardware sequencing mode.\n");
 		return -1;
 	}
 
@@ -1249,13 +1314,14 @@ int ich_hwseq_read(struct flashchip *flash, uint8_t *buf, int addr, int len)
 		       --timeout) {
 			programmer_delay(10);
 		}
+		hsfs = REGREAD16(ICH9_REG_HSFS);
 		if (!timeout) {
-			msg_perr("timeout, ICH9_REG_HSFS=0x%04x\n",
-				 REGREAD16(ICH9_REG_HSFS));
+			msg_perr("timeout!\n");
+			prettyprint_ich9_reg_hsfs(hsfs);
+			prettyprint_ich9_reg_hsfc(hsfs);
 			return 1;
 		}
 
-		hsfs = REGREAD16(ICH9_REG_HSFS);
 		REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */
 		if (hsfs & HSFS_FCERR) {
 			msg_perr("Transaction error between offset 0x%06x and "
@@ -1279,15 +1345,16 @@ int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len
 	uint16_t hsfs;
 	uint16_t timeout = 100 * 60;
 	int i;
-	if (strcmp(flash->name, "Hardware Sequencing") != 0) {
+	if (flash->manufacture_id != INTEL_ID ||
+	    flash->model_id != INTEL_HWSEQ) {
 		msg_perr("This chip (%s) is not supported in hardware"
 			 "sequencing mode\n", flash->name);
 		return -1;
 	}
 
 	if ((len % 4 != 0)) {
-		msg_perr("Write size has to be a multiple of 4 in hardware "
-			 "sequencing mode\n");
+		msg_perr("Write size has to be a multiple of 4 for this "
+			 "implementation of hardware sequencing mode\n");
 		return -1;
 	}
 
@@ -1312,13 +1379,14 @@ int ich_hwseq_write_256(struct flashchip *flash, uint8_t *buf, int addr, int len
 		       --timeout) {
 			programmer_delay(10);
 		}
+		hsfs = REGREAD16(ICH9_REG_HSFS);
 		if (!timeout) {
-			msg_perr("timeout, ICH9_REG_HSFS=0x%04x\n",
-				 REGREAD16(ICH9_REG_HSFS));
+			msg_perr("timeout!\n");
+			prettyprint_ich9_reg_hsfs(hsfs);
+			prettyprint_ich9_reg_hsfc(hsfs);
 			return 1;
 		}
 
-		hsfs = REGREAD16(ICH9_REG_HSFS);
 		REGWRITE16(ICH9_REG_HSFS, hsfs); /* clear all error bits */
 		if (hsfs & HSFS_FCERR) {
 			msg_perr("Transaction error between offset 0x%06x and "
@@ -1471,8 +1539,6 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 	int ichspi_desc = 0;
 	/* used for hw sequencing detection */
 	extern struct flash_descriptor fdbar;
-	uint32_t size_low;
-	uint32_t size_high;
 
 	switch (ich_generation) {
 	case 7:
@@ -1615,15 +1681,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 			pretty_print_ich_descriptors();
 		}
 
-		/* Fetch erase block sizes for addresses below and above FPBA
-		 * and check if erase blocks are equal for all addresses. */
-		REGWRITE32(ICH9_REG_FADDR, (0 & 0x00FFFFFF));
-		size_low = ich_hwseq_get_erase_block_size();
-		REGWRITE32(ICH9_REG_FADDR,
-			   (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) & 0x00FFFFFF);
-		size_high = ich_hwseq_get_erase_block_size();
-
-		if ((ichspi_lock || fdbar.NC != 0) && (size_low == size_high))
+		if (ichspi_lock || fdbar.NC != 0)
 			register_spi_programmer(&spi_programmer_ich_hwseq);
 		else {
 			register_spi_programmer(&spi_programmer_ich9);
-- 
1.7.1

