[flashrom] [PATCH] Refactor Intel Chipset Enables.

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Sat Sep 21 05:15:35 CEST 2013


 - Combine enable_flash_ich_4e() and enable_flash_ich_dc() to
   enable_flash_ich_fwh().
 - Remove unjustified (chipset) name parameters from various
   enable_flash_ich* functions.
 - Make Poulsbo and Tunnel Creek use generic enables by refining existing
   functions to work with them, including everything in ichspi.c.
 - Refactor enable_flash_ich_fwh_decode() to be called unconditionally for
   all chipsets.
 - Add support for Intel Atom Centerton (S12x0).
 - Recombine ICH2/3/4/5 to CHIPSET_ICH2345 because we treat them equally
   anyway.
 - Move spibar handling out of ich_init_spi() into enable_flash_ich_spi()
 - Various small cleanups.

Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
---
Think of the previous patch as a small teaser ;)
I had this for long on my todo list because the atom support was rather
hacky and the whole organization lacked sanity. Kyösti started the
cleanup actually with his IDSEL patches, but there was a myriad of
other things to enhance.

Call graphs
old: http://postimg.org/image/5s0egfdx7/full/
new: http://postimg.org/image/xtefu4j7f/full/

 chipset_enable.c | 412 ++++++++++++++++++++++++++-----------------------------
 ichspi.c         |  61 ++------
 programmer.h     |  12 +-
 3 files changed, 214 insertions(+), 271 deletions(-)

diff --git a/chipset_enable.c b/chipset_enable.c
index c85db73..3fd06fb 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -260,20 +260,44 @@ static int enable_flash_piix4(struct pci_dev *dev, const char *name)
 	return 0;
 }
 
-/*
- * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet"
- * http://download.intel.com/design/chipsets/datashts/30701303.pdf
- */
-static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_cntl)
+/* Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Poulsbo, Tunnel Creek and other Atom
+ * chipsets/SoCs it is even 32b, but just treating it as 8 bit wide seems to work fine in practice. */
+static int enable_flash_ich_bios_cntl(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
 {
 	uint8_t old, new, wanted;
 
-	/*
-	 * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Tunnel Creek it is even 32b, but
-	 * just treating it as 8 bit wide seems to work fine in practice.
-	 */
-	wanted = old = pci_read_byte(dev, bios_cntl);
+	switch (ich_generation) {
+	case CHIPSET_ICH_UNKNOWN:
+		return ERROR_FATAL;
+	/* Non-SPI-capable */
+	case CHIPSET_ICH:
+	case CHIPSET_ICH2345:
+		break;
+	/* Atom chipsets are special: The second byte of BIOS_CNTL (D9h) contains a prefetch bit similar to what
+	 * other SPI-capable chipsets have at DCh.
+	 * The Tunnel Creek datasheet contains a lot of details about the SPI controller, among other things it
+	 * mentions that the prefetching and caching does only happen for direct memory reads.
+	 * Therefore - at least for Tunnel Creek - it should not matter to flashrom because we use the
+	 * programmed access only and not memory mapping. */
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_POULSBO:
+	case CHIPSET_CENTERTON:
+		old = pci_read_byte(dev, bios_cntl + 1);
+		msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis");
+		break;
+	case CHIPSET_ICH7:
+	default: /* Future version might behave the same */
+		old = (pci_read_byte(dev, bios_cntl) >> 2) & 0x3;
+		msg_pdbg("SPI Read Configuration: ");
+		if (old == 3)
+			msg_pdbg("invalid prefetching/caching settings, ");
+		else
+			msg_pdbg("prefetching %sabled, caching %sabled, ",
+				     (old & 0x2) ? "en" : "dis",
+				     (old & 0x1) ? "dis" : "en");
+	}
 
+	wanted = old = pci_read_byte(dev, bios_cntl);
 	/*
 	 * Quote from the 6 Series datasheet (Document Number: 324645-004):
 	 * "Bit 5: SMM BIOS Write Protect Disable (SMM_BWP)
@@ -283,11 +307,23 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_
 	 *
 	 * Try to unset it in any case.
 	 * It won't hurt and makes sense in some cases according to Stefan Reinauer.
+	 *
+	 * At least in Centerton aforementioned bit is located at bit 7. It is unspecified in all other Atom
+	 * and Desktop chipsets before Ibex Peak/5 Series, but we reset bit 5 anyway.
 	 */
-	wanted &= ~(1 << 5);
+	int smm_bwp_bit;
+	if (ich_generation == CHIPSET_CENTERTON)
+		smm_bwp_bit = 7;
+	else
+		smm_bwp_bit = 5;
+	wanted &= ~(1 << smm_bwp_bit);
+
+	/* Tunnel Creek has a cache disable at bit 2 of the lowest BIOS_CNTL byte. */
+	if (ich_generation == CHIPSET_TUNNEL_CREEK)
+		wanted |= (1 << 2);
 
-	/* Set BIOS Write Enable */
-	wanted |= (1 << 0);
+	wanted |= (1 << 0); /* Set BIOS Write Enable */
+	wanted &= ~(1 << 1); /* Disable lock (futile) */
 
 	/* Only write the register if it's necessary */
 	if (wanted != old) {
@@ -299,76 +335,77 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_
 	msg_pdbg("\nBIOS_CNTL = 0x%02x: ", new);
 	msg_pdbg("BIOS Lock Enable: %sabled, ", (new & (1 << 1)) ? "en" : "dis");
 	msg_pdbg("BIOS Write Enable: %sabled\n", (new & (1 << 0)) ? "en" : "dis");
-	if (new & (1 << 5))
+	if (new & (1 << smm_bwp_bit))
 		msg_pwarn("Warning: BIOS region SMM protection is enabled!\n");
 
-
 	if (new != wanted)
-		msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x on %s failed.\n"
-			  "New value is 0x%02x.\n", bios_cntl, old, wanted, name, new);
+		msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n"
+			  "New value is 0x%02x.\n", bios_cntl, old, wanted, new);
 
-	/* Return an error if we could not set the write enable */
+	/* Return an error if we could not set the write enable only. */
 	if (!(new & (1 << 0)))
 		return -1;
 
 	return 0;
 }
 
-static int enable_flash_ich0(struct pci_dev *dev, const char *name)
-{
-	internal_buses_supported = BUS_FWH;
-	/* FIXME: Make this use enable_flash_ich_4e() too and add IDSEL support. Unlike later chipsets,
-	 * ICH and ICH-0 do only support mapping of the top-most 4MB and therefore do only feature
-	 * FWH_DEC_EN (E3h, different default too) and FWH_SEL (E8h). */
-	return enable_flash_ich(dev, name, 0x4e);
-}
-
-static int enable_flash_ich_fwh_decode(struct pci_dev *dev, const char *name, enum ich_chipset ich_generation)
+static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich_generation)
 {
-	uint32_t fwh_conf;
-	uint8_t fwh_sel1, fwh_sel2, fwh_dec_en_lo, fwh_dec_en_hi;
-	int i, tmp;
-	char *idsel = NULL;
-	int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0;
-	int contiguous = 1;
-
-	if (ich_generation >= CHIPSET_ICH6) {
-		fwh_sel1 = 0xd0;
-		fwh_sel2 = 0xd4;
-		fwh_dec_en_lo = 0xd8;
-		fwh_dec_en_hi = 0xd9;
-	} else if (ich_generation >= CHIPSET_ICH2) {
+	uint8_t fwh_sel1 = 0, fwh_sel2 = 0, fwh_dec_en_lo = 0, fwh_dec_en_hi = 0; /* silence compilers */
+	bool implemented = 0;
+	switch (ich_generation) {
+	case CHIPSET_ICH:
+		/* FIXME: Unlike later chipsets, ICH and ICH-0 do only support mapping of the top-most 4MB
+		 * and therefore do only feature FWH_DEC_EN (E3h, different default too) and FWH_SEL (E8h). */
+		break;
+	case CHIPSET_ICH2345:
 		fwh_sel1 = 0xe8;
 		fwh_sel2 = 0xee;
 		fwh_dec_en_lo = 0xf0;
 		fwh_dec_en_hi = 0xe3;
-	} else {
-		msg_perr("Error: FWH decode setting not implemented.\n");
-		return ERROR_FATAL;
+		implemented = 1;
+		break;
+	case CHIPSET_POULSBO:
+	case CHIPSET_TUNNEL_CREEK:
+		/* FIXME: Similar to ICH and ICH-0, Tunnel Creek and Poulsbo do only feature one register each,
+		 * FWH_DEC_EN (D7h) and FWH_SEL (D0h). */
+		break;
+	case CHIPSET_CENTERTON:
+		/* FIXME: Similar to above FWH_DEC_EN (D4h) and FWH_SEL (D0h). */
+		break;
+	case CHIPSET_ICH6:
+	case CHIPSET_ICH7:
+	default: /* Future version might behave the same */
+		fwh_sel1 = 0xd0;
+		fwh_sel2 = 0xd4;
+		fwh_dec_en_lo = 0xd8;
+		fwh_dec_en_hi = 0xd9;
+		implemented = 1;
+		break;
 	}
 
-	idsel = extract_programmer_param("fwh_idsel");
+	char *idsel = extract_programmer_param("fwh_idsel");
 	if (idsel && strlen(idsel)) {
-		uint64_t fwh_idsel_old, fwh_idsel;
+		if (!implemented) {
+			msg_perr("Error: fwh_idsel= specified, but (yet) unsupported on this chipset.\n");
+			goto idsel_garbage_out;
+		}
 		errno = 0;
 		/* Base 16, nothing else makes sense. */
-		fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16);
+		uint64_t fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16);
 		if (errno) {
-			msg_perr("Error: fwh_idsel= specified, but value could "
-				 "not be converted.\n");
+			msg_perr("Error: fwh_idsel= specified, but value could not be converted.\n");
 			goto idsel_garbage_out;
 		}
 		if (fwh_idsel & 0xffff000000000000ULL) {
-			msg_perr("Error: fwh_idsel= specified, but value had "
-				 "unused bits set.\n");
+			msg_perr("Error: fwh_idsel= specified, but value had unused bits set.\n");
 			goto idsel_garbage_out;
 		}
-		fwh_idsel_old = pci_read_long(dev, fwh_sel1);
+		uint64_t fwh_idsel_old = pci_read_long(dev, fwh_sel1);
 		fwh_idsel_old <<= 16;
 		fwh_idsel_old |= pci_read_word(dev, fwh_sel2);
-		msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to "
-			 "0x%012" PRIx64 " for top 16 MB.", fwh_idsel_old,
-			 fwh_idsel);
+		msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to 0x%012" PRIx64 " for top 16 MB.",
+			 fwh_idsel_old, fwh_idsel);
 		rpci_write_long(dev, fwh_sel1, (fwh_idsel >> 16) & 0xffffffff);
 		rpci_write_word(dev, fwh_sel2, fwh_idsel & 0xffff);
 		/* FIXME: Decode settings are not changed. */
@@ -380,15 +417,23 @@ idsel_garbage_out:
 	}
 	free(idsel);
 
+	if (!implemented) {
+		msg_pdbg2("FWH IDSEL handling is not implemented on this chipset.");
+		return 0;
+	}
+
 	/* Ignore all legacy ranges below 1 MB.
 	 * We currently only support flashing the chip which responds to
 	 * IDSEL=0. To support IDSEL!=0, flashbase and decode size calculations
 	 * have to be adjusted.
 	 */
+	int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0;
+	bool contiguous = 1;
+	uint32_t fwh_conf = pci_read_long(dev, fwh_sel1);
+	int i;
 	/* FWH_SEL1 */
-	fwh_conf = pci_read_long(dev, fwh_sel1);
 	for (i = 7; i >= 0; i--) {
-		tmp = (fwh_conf >> (i * 4)) & 0xf;
+		int tmp = (fwh_conf >> (i * 4)) & 0xf;
 		msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
 			 (0x1ff8 + i) * 0x80000,
 			 (0x1ff0 + i) * 0x80000,
@@ -402,7 +447,7 @@ idsel_garbage_out:
 	/* FWH_SEL2 */
 	fwh_conf = pci_read_word(dev, fwh_sel2);
 	for (i = 3; i >= 0; i--) {
-		tmp = (fwh_conf >> (i * 4)) & 0xf;
+		int tmp = (fwh_conf >> (i * 4)) & 0xf;
 		msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
 			 (0xff4 + i) * 0x100000,
 			 (0xff0 + i) * 0x100000,
@@ -419,7 +464,7 @@ idsel_garbage_out:
 	fwh_conf <<= 8;
 	fwh_conf |= pci_read_byte(dev, fwh_dec_en_lo);
 	for (i = 7; i >= 0; i--) {
-		tmp = (fwh_conf >> (i + 0x8)) & 0x1;
+		int tmp = (fwh_conf >> (i + 0x8)) & 0x1;
 		msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled",
 			 (0x1ff8 + i) * 0x80000,
 			 (0x1ff0 + i) * 0x80000,
@@ -431,7 +476,7 @@ idsel_garbage_out:
 		}
 	}
 	for (i = 3; i >= 0; i--) {
-		tmp = (fwh_conf >> i) & 0x1;
+		int tmp = (fwh_conf >> i) & 0x1;
 		msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled",
 			 (0xff4 + i) * 0x100000,
 			 (0xff0 + i) * 0x100000,
@@ -448,146 +493,56 @@ idsel_garbage_out:
 	return 0;
 }
 
-static int enable_flash_ich_4e(struct pci_dev *dev, const char *name, enum ich_chipset ich_generation)
+static int enable_flash_ich_fwh(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
 {
 	int err;
 
 	/* Configure FWH IDSEL decoder maps. */
-	if ((err = enable_flash_ich_fwh_decode(dev, name, ich_generation)) != 0)
+	if ((err = enable_flash_ich_fwh_decode(dev, ich_generation)) != 0)
 		return err;
 
 	internal_buses_supported = BUS_FWH;
-	return enable_flash_ich(dev, name, 0x4e);
+	return enable_flash_ich_bios_cntl(dev, ich_generation, bios_cntl);
 }
 
-static int enable_flash_ich2(struct pci_dev *dev, const char *name)
-{
-	return enable_flash_ich_4e(dev, name, CHIPSET_ICH2);
-}
-
-static int enable_flash_ich3(struct pci_dev *dev, const char *name)
-{
-	return enable_flash_ich_4e(dev, name, CHIPSET_ICH3);
-}
-
-static int enable_flash_ich4(struct pci_dev *dev, const char *name)
+static int enable_flash_ich0(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_4e(dev, name, CHIPSET_ICH4);
+	return enable_flash_ich_fwh(dev, CHIPSET_ICH, 0x4e);
 }
 
-static int enable_flash_ich5(struct pci_dev *dev, const char *name)
+static int enable_flash_ich2345(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_4e(dev, name, CHIPSET_ICH5);
-}
-
-static int enable_flash_ich_dc(struct pci_dev *dev, const char *name, enum ich_chipset ich_generation)
-{
-	int err;
-
-	/* Configure FWH IDSEL decoder maps. */
-	if ((err = enable_flash_ich_fwh_decode(dev, name, ich_generation)) != 0)
-		return err;
-
-	/* If we're called by enable_flash_ich_dc_spi, it will override
-	 * internal_buses_supported anyway.
-	 */
-	internal_buses_supported = BUS_FWH;
-	return enable_flash_ich(dev, name, 0xdc);
+	return enable_flash_ich_fwh(dev, CHIPSET_ICH2345, 0x4e);
 }
 
 static int enable_flash_ich6(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc(dev, name, CHIPSET_ICH6);
+	return enable_flash_ich_fwh(dev, CHIPSET_ICH6, 0xdc);
 }
 
 static int enable_flash_poulsbo(struct pci_dev *dev, const char *name)
 {
-	uint16_t old, new;
-	int err;
-
-	if ((err = enable_flash_ich(dev, name, 0xd8)) != 0)
-		return err;
-
-	old = pci_read_byte(dev, 0xd9);
-	msg_pdbg("BIOS Prefetch Enable: %sabled, ",
-		 (old & 1) ? "en" : "dis");
-	new = old & ~1;
-
-	if (new != old)
-		rpci_write_byte(dev, 0xd9, new);
-
-	internal_buses_supported = BUS_FWH;
-	return 0;
+	return enable_flash_ich_fwh(dev, CHIPSET_POULSBO, 0xd8);
 }
 
-static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name)
+static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
 {
-	uint16_t old, new;
-	uint32_t tmp, bnt;
-	void *rcrb;
-	int ret;
-
-	/* Enable Flash Writes */
-	ret = enable_flash_ich(dev, name, 0xd8);
-	if (ret == ERROR_FATAL)
-		return ret;
-
-	/* Make sure BIOS prefetch mechanism is disabled */
-	old = pci_read_byte(dev, 0xd9);
-	msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis");
-	new = old & ~1;
-	if (new != old)
-		rpci_write_byte(dev, 0xd9, new);
-
-	/* Get physical address of Root Complex Register Block */
-	tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
-	msg_pdbg("\nRoot Complex Register Block address = 0x%x\n", tmp);
-
-	/* Map RCBA to virtual memory */
-	rcrb = rphysmap("ICH RCRB", tmp, 0x4000);
-	if (rcrb == ERROR_PTR)
-		return ERROR_FATAL;
-
-	/* Test Boot BIOS Strap Status */
-	bnt = mmio_readl(rcrb + 0x3410);
-	if (bnt & 0x02) {
-		/* If strapped to LPC, no SPI initialization is required */
-		internal_buses_supported = BUS_FWH;
-		return 0;
-	}
-
-	/* This adds BUS_SPI */
-	if (ich_init_spi(dev, tmp, rcrb, 7) != 0) {
-		if (!ret)
-			ret = ERROR_NONFATAL;
-	}
-
-	return ret;
-}
-
-static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
-				   enum ich_chipset ich_generation)
-{
-	int ret, ret_spi;
-	uint8_t bbs, buc;
-	uint32_t tmp, gcs;
-	void *rcrb;
-	const char *const *straps_names;
-
 	static const char *const straps_names_EP80579[] = { "SPI", "reserved", "reserved", "LPC" };
 	static const char *const straps_names_ich7_nm10[] = { "reserved", "SPI", "PCI", "LPC" };
+	static const char *const straps_names_tunnel_creek[] = { "SPI", "LPC" };
 	static const char *const straps_names_ich8910[] = { "SPI", "SPI", "PCI", "LPC" };
 	static const char *const straps_names_pch567[] = { "LPC", "reserved", "PCI", "SPI" };
 	static const char *const straps_names_pch8[] = { "LPC", "reserved", "reserved", "SPI" };
-	static const char *const straps_names_pch8_lp[] = { "SPI", "LPC", "unknown", "unknown" };
+	static const char *const straps_names_pch8_lp[] = { "SPI", "LPC" };
 	static const char *const straps_names_unknown[] = { "unknown", "unknown", "unknown", "unknown" };
 
+	const char *const *straps_names;
 	switch (ich_generation) {
 	case CHIPSET_ICH7:
 		/* EP80579 may need further changes, but this is the least
 		 * intrusive way to get correct BOOT Strap printing without
 		 * changing the rest of its code path). */
-		if (strcmp(name, "EP80579") == 0)
+		if (dev->device_id == 0x5031)
 			straps_names = straps_names_EP80579;
 		else
 			straps_names = straps_names_ich7_nm10;
@@ -597,6 +552,9 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
 	case CHIPSET_ICH10:
 		straps_names = straps_names_ich8910;
 		break;
+	case CHIPSET_TUNNEL_CREEK:
+		straps_names = straps_names_tunnel_creek;
+		break;
 	case CHIPSET_5_SERIES_IBEX_PEAK:
 	case CHIPSET_6_SERIES_COUGAR_POINT:
 	case CHIPSET_7_SERIES_PANTHER_POINT:
@@ -609,35 +567,33 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
 		straps_names = straps_names_pch8_lp;
 		break;
 	case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet
+	case CHIPSET_CENTERTON: // FIXME: Datasheet does not mention GCS at all
 		straps_names = straps_names_unknown;
 		break;
 	default:
-		msg_gerr("%s: unknown ICH generation. Please report!\n",
-			 __func__);
+		msg_gerr("%s: unknown ICH generation. Please report!\n", __func__);
 		straps_names = straps_names_unknown;
 		break;
 	}
 
-	/* Enable Flash Writes */
-	ret = enable_flash_ich_dc(dev, name, ich_generation);
-	if (ret == ERROR_FATAL)
-		return ret;
-
 	/* Get physical address of Root Complex Register Block */
-	tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
-	msg_pdbg("Root Complex Register Block address = 0x%x\n", tmp);
+	uint32_t rcra = pci_read_long(dev, 0xf0) & 0xffffc000;
+	msg_pdbg("Root Complex Register Block address = 0x%x\n", rcra);
 
 	/* Map RCBA to virtual memory */
-	rcrb = rphysmap("ICH RCRB", tmp, 0x4000);
+	void *rcrb = rphysmap("ICH RCRB", rcra, 0x4000);
 	if (rcrb == ERROR_PTR)
 		return ERROR_FATAL;
 
-	gcs = mmio_readl(rcrb + 0x3410);
+	uint32_t gcs = mmio_readl(rcrb + 0x3410);
 	msg_pdbg("GCS = 0x%x: ", gcs);
-	msg_pdbg("BIOS Interface Lock-Down: %sabled, ",
-		 (gcs & 0x1) ? "en" : "dis");
+	msg_pdbg("BIOS Interface Lock-Down: %sabled, ", (gcs & 0x1) ? "en" : "dis");
 
+	uint8_t bbs;
 	switch (ich_generation) {
+	case CHIPSET_TUNNEL_CREEK:
+		bbs = (gcs >> 1) & 0x1;
+		break;
 	case CHIPSET_8_SERIES_LYNX_POINT_LP:
 	case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet
 		/* Lynx Point LP uses a single bit for GCS */
@@ -650,91 +606,110 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
 	}
 	msg_pdbg("Boot BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]);
 
-	buc = mmio_readb(rcrb + 0x3414);
-	msg_pdbg("Top Swap : %s\n",
-		 (buc & 1) ? "enabled (A16 inverted)" : "not enabled");
+	if (ich_generation != CHIPSET_TUNNEL_CREEK && ich_generation != CHIPSET_CENTERTON) {
+		uint8_t buc = mmio_readb(rcrb + 0x3414);
+		msg_pdbg("Top Swap : %s\n", (buc & 1) ? "enabled (A16(+) inverted)" : "not enabled");
+	}
+
+	/* Handle FWH-related parameters and initialization */
+	int ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl);
+	if (ret_fwh == ERROR_FATAL)
+		return ret_fwh;
 
-	/* It seems the ICH7 does not support SPI and LPC chips at the same
-	 * time. At least not with our current code. So we prevent searching
-	 * on ICH7 when the southbridge is strapped to LPC
-	 */
-	internal_buses_supported = BUS_FWH;
-	if (ich_generation == CHIPSET_ICH7) {
-		if (bbs == 0x03) {
-			/* If strapped to LPC, no further SPI initialization is
-			 * required. */
-			return ret;
-		} else {
-			/* Disable LPC/FWH if strapped to PCI or SPI */
-			internal_buses_supported = BUS_NONE;
-		}
+	/* SPIBAR is at RCRB+0x3020 for ICH[78], Tunnel Creek and Centerton, and RCRB+0x3800 for ICH9. */
+	uint16_t spibar_offset;
+	switch (ich_generation) {
+	case CHIPSET_ICH_UNKNOWN:
+		return ERROR_FATAL;
+	case CHIPSET_ICH7:
+	case CHIPSET_ICH8:
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_CENTERTON:
+		spibar_offset = 0x3020;
+		break;
+	case CHIPSET_ICH9:
+	default:		/* Future version might behave the same */
+		spibar_offset = 0x3800;
+		break;
 	}
+	msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " + 0x%04x\n", PRIxPTR_WIDTH, (uintptr_t)rcrb, spibar_offset);
+	void *spibar = rcrb + spibar_offset;
 
 	/* This adds BUS_SPI */
-	ret_spi = ich_init_spi(dev, tmp, rcrb, ich_generation);
+	int ret_spi = ich_init_spi(dev, spibar, ich_generation);
 	if (ret_spi == ERROR_FATAL)
 		return ret_spi;
 	
-	if (ret || ret_spi)
-		ret = ERROR_NONFATAL;
+	if (ret_fwh || ret_spi)
+		return ERROR_NONFATAL;
 
-	return ret;
+	return 0;
+}
+
+static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_ich_spi(dev, CHIPSET_TUNNEL_CREEK, 0xd8);
+}
+
+static int enable_flash_s12x0(struct pci_dev *dev, const char *name)
+{
+	return enable_flash_ich_spi(dev, CHIPSET_CENTERTON, 0xd8);
 }
 
 static int enable_flash_ich7(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH7);
+	return enable_flash_ich_spi(dev, CHIPSET_ICH7, 0xdc);
 }
 
 static int enable_flash_ich8(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH8);
+	return enable_flash_ich_spi(dev, CHIPSET_ICH8, 0xdc);
 }
 
 static int enable_flash_ich9(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH9);
+	return enable_flash_ich_spi(dev, CHIPSET_ICH9, 0xdc);
 }
 
 static int enable_flash_ich10(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH10);
+	return enable_flash_ich_spi(dev, CHIPSET_ICH10, 0xdc);
 }
 
 /* Ibex Peak aka. 5 series & 3400 series */
 static int enable_flash_pch5(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_5_SERIES_IBEX_PEAK);
+	return enable_flash_ich_spi(dev, CHIPSET_5_SERIES_IBEX_PEAK, 0xdc);
 }
 
 /* Cougar Point aka. 6 series & c200 series */
 static int enable_flash_pch6(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_6_SERIES_COUGAR_POINT);
+	return enable_flash_ich_spi(dev, CHIPSET_6_SERIES_COUGAR_POINT, 0xdc);
 }
 
 /* Panther Point aka. 7 series */
 static int enable_flash_pch7(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_7_SERIES_PANTHER_POINT);
+	return enable_flash_ich_spi(dev, CHIPSET_7_SERIES_PANTHER_POINT, 0xdc);
 }
 
 /* Lynx Point aka. 8 series */
 static int enable_flash_pch8(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT);
+	return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT, 0xdc);
 }
 
-/* Lynx Point aka. 8 series low-power */
+/* Lynx Point LP aka. 8 series low-power */
 static int enable_flash_pch8_lp(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT_LP);
+	return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT_LP, 0xdc);
 }
 
 /* Wellsburg (for Haswell-EP Xeons) */
 static int enable_flash_pch8_wb(struct pci_dev *dev, const char *name)
 {
-	return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_WELLSBURG);
+	return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_WELLSBURG, 0xdc);
 }
 
 static int via_no_byte_merge(struct pci_dev *dev, const char *name)
@@ -1503,6 +1478,7 @@ const struct penable chipset_enables[] = {
 	{0x1166, 0x0200, OK, "Broadcom", "OSB4",	enable_flash_osb4},
 	{0x1166, 0x0205, OK, "Broadcom", "HT-1000",	enable_flash_ht1000},
 	{0x17f3, 0x6030, OK, "RDC", "R8610/R3210",	enable_flash_rdc_r8610},
+	{0x8086, 0x0c60, NT, "Intel", "S12x0",		enable_flash_s12x0},
 	{0x8086, 0x122e, OK, "Intel", "PIIX",		enable_flash_piix4},
 	{0x8086, 0x1234, NT, "Intel", "MPIIX",		enable_flash_piix4},
 	{0x8086, 0x1c44, OK, "Intel", "Z68",		enable_flash_pch6},
@@ -1541,15 +1517,15 @@ const struct penable chipset_enables[] = {
 	{0x8086, 0x2390, NT, "Intel", "Coleto Creek",	enable_flash_pch7},
 	{0x8086, 0x2410, OK, "Intel", "ICH",		enable_flash_ich0},
 	{0x8086, 0x2420, OK, "Intel", "ICH0",		enable_flash_ich0},
-	{0x8086, 0x2440, OK, "Intel", "ICH2",		enable_flash_ich2},
-	{0x8086, 0x244c, OK, "Intel", "ICH2-M",		enable_flash_ich2},
-	{0x8086, 0x2450, NT, "Intel", "C-ICH",		enable_flash_ich2},
-	{0x8086, 0x2480, OK, "Intel", "ICH3-S",		enable_flash_ich3},
-	{0x8086, 0x248c, OK, "Intel", "ICH3-M",		enable_flash_ich3},
-	{0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L",	enable_flash_ich4},
-	{0x8086, 0x24cc, OK, "Intel", "ICH4-M",		enable_flash_ich4},
-	{0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R",	enable_flash_ich5},
-	{0x8086, 0x25a1, OK, "Intel", "6300ESB",	enable_flash_ich5},
+	{0x8086, 0x2440, OK, "Intel", "ICH2",		enable_flash_ich2345},
+	{0x8086, 0x244c, OK, "Intel", "ICH2-M",		enable_flash_ich2345},
+	{0x8086, 0x2450, NT, "Intel", "C-ICH",		enable_flash_ich2345},
+	{0x8086, 0x2480, OK, "Intel", "ICH3-S",		enable_flash_ich2345},
+	{0x8086, 0x248c, OK, "Intel", "ICH3-M",		enable_flash_ich2345},
+	{0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L",	enable_flash_ich2345},
+	{0x8086, 0x24cc, OK, "Intel", "ICH4-M",		enable_flash_ich2345},
+	{0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R",	enable_flash_ich2345},
+	{0x8086, 0x25a1, OK, "Intel", "6300ESB",	enable_flash_ich2345},
 	{0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R",	enable_flash_ich6},
 	{0x8086, 0x2641, OK, "Intel", "ICH6-M",		enable_flash_ich6},
 	{0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW",	enable_flash_ich6},
diff --git a/ichspi.c b/ichspi.c
index 1dcff5b..6c394db 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -466,6 +466,8 @@ static int generate_opcodes(OPCODES * op)
 
 	switch (ich_generation) {
 	case CHIPSET_ICH7:
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_CENTERTON:
 		preop = REGREAD16(ICH7_REG_PREOP);
 		optype = REGREAD16(ICH7_REG_OPTYPE);
 		opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
@@ -529,7 +531,7 @@ static int program_opcodes(OPCODES *op, int enable_undo)
 		opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
 	}
 
-	/*Program Allowable Opcodes 4 - 7 */
+	/* Program Allowable Opcodes 4 - 7 */
 	opmenu[1] = 0;
 	for (a = 4; a < 8; a++) {
 		opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
@@ -538,6 +540,8 @@ static int program_opcodes(OPCODES *op, int enable_undo)
 	msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
 	switch (ich_generation) {
 	case CHIPSET_ICH7:
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_CENTERTON:
 		/* Register undo only for enable_undo=1, i.e. first call. */
 		if (enable_undo) {
 			rmmio_valw(ich_spibar + ICH7_REG_PREOP);
@@ -603,6 +607,8 @@ static void ich_set_bbar(uint32_t min_addr)
 	int bbar_off;
 	switch (ich_generation) {
 	case CHIPSET_ICH7:
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_CENTERTON:
 		bbar_off = 0x50;
 		break;
 	case CHIPSET_ICH8:
@@ -975,6 +981,8 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
 
 	switch (ich_generation) {
 	case CHIPSET_ICH7:
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_CENTERTON:
 		return ich7_run_opcode(op, offset, datalength, data, maxlength);
 	case CHIPSET_ICH8:
 	default:		/* Future version might behave the same */
@@ -1545,12 +1553,10 @@ static const struct opaque_programmer opaque_programmer_ich_hwseq = {
 	.erase = ich_hwseq_block_erase,
 };
 
-int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
-		 enum ich_chipset ich_gen)
+int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen)
 {
 	int i;
-	uint8_t old, new;
-	uint16_t spibar_offset, tmp2;
+	uint16_t tmp2;
 	uint32_t tmp;
 	char *arg;
 	int ich_spi_force = 0;
@@ -1564,42 +1570,18 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 	} ich_spi_mode = ich_auto;
 
 	ich_generation = ich_gen;
-
-	switch (ich_generation) {
-	case CHIPSET_ICH_UNKNOWN:
-		return ERROR_FATAL;
-	case CHIPSET_ICH7:
-	case CHIPSET_ICH8:
-		spibar_offset = 0x3020;
-		break;
-	case CHIPSET_ICH9:
-	default:		/* Future version might behave the same */
-		spibar_offset = 0x3800;
-		break;
-	}
-
-	/* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */
-	msg_pdbg("SPIBAR = 0x%x + 0x%04x\n", base, spibar_offset);
-
-	/* Assign Virtual Address */
-	ich_spibar = rcrb + spibar_offset;
+	ich_spibar = spibar;
 
 	switch (ich_generation) {
 	case CHIPSET_ICH7:
+	case CHIPSET_TUNNEL_CREEK:
+	case CHIPSET_CENTERTON:
 		msg_pdbg("0x00: 0x%04x     (SPIS)\n",
 			     mmio_readw(ich_spibar + 0));
 		msg_pdbg("0x02: 0x%04x     (SPIC)\n",
 			     mmio_readw(ich_spibar + 2));
 		msg_pdbg("0x04: 0x%08x (SPIA)\n",
 			     mmio_readl(ich_spibar + 4));
-		for (i = 0; i < 8; i++) {
-			int offs;
-			offs = 8 + (i * 8);
-			msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs,
-				     mmio_readl(ich_spibar + offs), i);
-			msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
-				     mmio_readl(ich_spibar + offs + 4), i);
-		}
 		ichspi_bbar = mmio_readl(ich_spibar + 0x50);
 		msg_pdbg("0x50: 0x%08x (BBAR)\n",
 			     ichspi_bbar);
@@ -1811,21 +1793,6 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 		break;
 	}
 
-	old = pci_read_byte(dev, 0xdc);
-	msg_pdbg("SPI Read Configuration: ");
-	new = (old >> 2) & 0x3;
-	switch (new) {
-	case 0:
-	case 1:
-	case 2:
-		msg_pdbg("prefetching %sabled, caching %sabled, ",
-			     (new & 0x2) ? "en" : "dis",
-			     (new & 0x1) ? "dis" : "en");
-		break;
-	default:
-		msg_pdbg("invalid prefetching/caching settings, ");
-		break;
-	}
 	return 0;
 }
 
diff --git a/programmer.h b/programmer.h
index ef96c9e..0c51f58 100644
--- a/programmer.h
+++ b/programmer.h
@@ -557,11 +557,12 @@ int register_spi_programmer(const struct spi_programmer *programmer);
 /* The following enum is needed by ich_descriptor_tool and ich* code as well as in chipset_enable.c. */
 enum ich_chipset {
 	CHIPSET_ICH_UNKNOWN,
-	CHIPSET_ICH2 = 2,
-	CHIPSET_ICH3,
-	CHIPSET_ICH4,
-	CHIPSET_ICH5,
+	CHIPSET_ICH,
+	CHIPSET_ICH2345,
 	CHIPSET_ICH6,
+	CHIPSET_POULSBO, /* SCH U* */
+	CHIPSET_TUNNEL_CREEK, /* Atom E6xx */
+	CHIPSET_CENTERTON, /* Atom S1220 S1240 S1260 */
 	CHIPSET_ICH7,
 	CHIPSET_ICH8,
 	CHIPSET_ICH9,
@@ -577,8 +578,7 @@ enum ich_chipset {
 /* ichspi.c */
 #if CONFIG_INTERNAL == 1
 extern uint32_t ichspi_bbar;
-int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
-		 enum ich_chipset ich_generation);
+int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_generation);
 int via_init_spi(struct pci_dev *dev, uint32_t mmio_base);
 
 /* amd_imc.c */
-- 
Kind regards, Stefan Tauner





More information about the flashrom mailing list