ichspi: Split ICH7 init out

The original, ICH7 init only shared about three lines with the newer,
ever growing ICH9+ init. That's not worth an indentation level in an
endlessly long function, so split it out.

We introduce a kind of "breakpoint" into the `ich_chipset' enum:

  SPI_ENGINE_ICH9

This marks all chipset entries below it as supporting this code path
and should help to avoid long `case' lists.

Tested read/erase/write on ThinkPad T60 (ICH7).

Change-Id: I41e46d12e02c1343e636b47b2378db86e76af95e
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/173
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/chipset_enable.c b/chipset_enable.c
index 2d958e3..1200005 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -807,7 +807,11 @@
 	void *spibar = rcrb + spibar_offset;
 
 	/* This adds BUS_SPI */
-	int ret_spi = ich_init_spi(spibar, ich_generation);
+	int ret_spi;
+	if (ich_generation < SPI_ENGINE_ICH9)
+		ret_spi = ich7_init_spi(spibar, ich_generation);
+	else
+		ret_spi = ich9_init_spi(spibar, ich_generation);
 	if (ret_spi == ERROR_FATAL)
 		return ret_spi;
 
@@ -951,7 +955,7 @@
 	msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " (phys = 0x%08x)\n", PRIxPTR_WIDTH, (uintptr_t)spibar, phys_spibar);
 
 	/* This adds BUS_SPI */
-	const int ret_spi = ich_init_spi(spibar, pch_generation);
+	const int ret_spi = ich9_init_spi(spibar, pch_generation);
 	if (ret_spi != ERROR_FATAL) {
 		if (ret_bc || ret_spi)
 			ret = ERROR_NONFATAL;
@@ -1055,7 +1059,7 @@
 	 */
 	enable_flash_ich_bios_cntl_memmapped(ich_generation, spibar + 0xFC);
 
-	int ret_spi = ich_init_spi(spibar, ich_generation);
+	int ret_spi = ich9_init_spi(spibar, ich_generation);
 	if (ret_spi == ERROR_FATAL)
 		return ret_spi;
 
diff --git a/ichspi.c b/ichspi.c
index 65c357d..617eba9 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -1710,6 +1710,41 @@
 	.probe_opcode	= ich_spi_probe_opcode,
 };
 
+int ich7_init_spi(void *spibar, enum ich_chipset ich_gen)
+{
+	unsigned int i;
+
+	ich_generation = ich_gen;
+	ich_spibar = spibar;
+
+	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));
+
+	ichspi_bbar = mmio_readl(ich_spibar + 0x50);
+	msg_pdbg("0x50: 0x%08x (BBAR)\n",	ichspi_bbar);
+	msg_pdbg("0x54: 0x%04x     (PREOP)\n",	mmio_readw(ich_spibar + 0x54));
+	msg_pdbg("0x56: 0x%04x     (OPTYPE)\n",	mmio_readw(ich_spibar + 0x56));
+	msg_pdbg("0x58: 0x%08x (OPMENU)\n",	mmio_readl(ich_spibar + 0x58));
+	msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n",	mmio_readl(ich_spibar + 0x5c));
+
+	for (i = 0; i < 3; i++) {
+		const int offs = 0x60 + (i * 4);
+		msg_pdbg("0x%02x: 0x%08x (PBR%u)\n", offs,
+			 mmio_readl(ich_spibar + offs), i);
+	}
+
+	if (mmio_readw(ich_spibar) & (1 << 15)) {
+		msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
+		ichspi_lock = true;
+	}
+
+	ich_init_opcodes();
+	ich_set_bbar(0);
+
+	return register_spi_master(&spi_master_ich7, 0, NULL);
+}
+
 static const struct spi_master spi_master_ich9 = {
 	.max_data_read	= 64,
 	.max_data_write	= 64,
@@ -1729,7 +1764,7 @@
 	.erase		= ich_hwseq_block_erase,
 };
 
-int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
+int ich9_init_spi(void *spibar, enum ich_chipset ich_gen)
 {
 	unsigned int i;
 	uint16_t tmp2;
@@ -1798,90 +1833,130 @@
 		break;
 	}
 
-	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));
-		ichspi_bbar = mmio_readl(ich_spibar + 0x50);
-		msg_pdbg("0x50: 0x%08x (BBAR)\n",
-			     ichspi_bbar);
-		msg_pdbg("0x54: 0x%04x     (PREOP)\n",
-			     mmio_readw(ich_spibar + 0x54));
-		msg_pdbg("0x56: 0x%04x     (OPTYPE)\n",
-			     mmio_readw(ich_spibar + 0x56));
-		msg_pdbg("0x58: 0x%08x (OPMENU)\n",
-			     mmio_readl(ich_spibar + 0x58));
-		msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n",
-			     mmio_readl(ich_spibar + 0x5c));
-		for (i = 0; i < 3; i++) {
-			int offs;
-			offs = 0x60 + (i * 4);
-			msg_pdbg("0x%02x: 0x%08x (PBR%u)\n", offs,
-				     mmio_readl(ich_spibar + offs), i);
-		}
-		if (mmio_readw(ich_spibar) & (1 << 15)) {
-			msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
-			ichspi_lock = true;
-		}
-		ich_init_opcodes();
-		ich_set_bbar(0);
-		register_spi_master(&spi_master_ich7, 0, NULL);
-		break;
-	case CHIPSET_ICH8:
-	default:		/* Future version might behave the same */
-		arg = extract_programmer_param("ich_spi_mode");
-		if (arg && !strcmp(arg, "hwseq")) {
-			ich_spi_mode = ich_hwseq;
-			msg_pspew("user selected hwseq\n");
-		} else if (arg && !strcmp(arg, "swseq")) {
-			ich_spi_mode = ich_swseq;
-			msg_pspew("user selected swseq\n");
-		} else if (arg && !strcmp(arg, "auto")) {
-			msg_pspew("user selected auto\n");
-			ich_spi_mode = ich_auto;
-		} else if (arg && !strlen(arg)) {
-			msg_perr("Missing argument for ich_spi_mode.\n");
-			free(arg);
-			return ERROR_FATAL;
-		} else if (arg) {
-			msg_perr("Unknown argument for ich_spi_mode: %s\n",
-				 arg);
-			free(arg);
-			return ERROR_FATAL;
-		}
+	arg = extract_programmer_param("ich_spi_mode");
+	if (arg && !strcmp(arg, "hwseq")) {
+		ich_spi_mode = ich_hwseq;
+		msg_pspew("user selected hwseq\n");
+	} else if (arg && !strcmp(arg, "swseq")) {
+		ich_spi_mode = ich_swseq;
+		msg_pspew("user selected swseq\n");
+	} else if (arg && !strcmp(arg, "auto")) {
+		msg_pspew("user selected auto\n");
+		ich_spi_mode = ich_auto;
+	} else if (arg && !strlen(arg)) {
+		msg_perr("Missing argument for ich_spi_mode.\n");
 		free(arg);
+		return ERROR_FATAL;
+	} else if (arg) {
+		msg_perr("Unknown argument for ich_spi_mode: %s\n",
+			 arg);
+		free(arg);
+		return ERROR_FATAL;
+	}
+	free(arg);
 
-		tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFS);
-		msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
-		prettyprint_ich9_reg_hsfs(tmp2);
-		if (tmp2 & HSFS_FLOCKDN) {
-			msg_pinfo("SPI Configuration is locked down.\n");
-			ichspi_lock = true;
-		}
-		if (tmp2 & HSFS_FDV)
-			desc_valid = true;
-		if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
-			msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
-				  "the Master Section of the flash descriptor are NOT in effect. Please note\n"
-				  "that Protected Range (PR) restrictions still apply.\n");
-		ich_init_opcodes();
+	tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFS);
+	msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
+	prettyprint_ich9_reg_hsfs(tmp2);
+	if (tmp2 & HSFS_FLOCKDN) {
+		msg_pinfo("SPI Configuration is locked down.\n");
+		ichspi_lock = true;
+	}
+	if (tmp2 & HSFS_FDV)
+		desc_valid = true;
+	if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
+		msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
+			  "the Master Section of the flash descriptor are NOT in effect. Please note\n"
+			  "that Protected Range (PR) restrictions still apply.\n");
+	ich_init_opcodes();
 
-		if (desc_valid) {
-			tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFC);
-			msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2);
-			prettyprint_ich9_reg_hsfc(tmp2);
-		}
+	if (desc_valid) {
+		tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFC);
+		msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2);
+		prettyprint_ich9_reg_hsfc(tmp2);
+	}
 
-		tmp = mmio_readl(ich_spibar + ICH9_REG_FADDR);
-		msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp);
+	tmp = mmio_readl(ich_spibar + ICH9_REG_FADDR);
+	msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp);
 
+	switch (ich_gen) {
+	case CHIPSET_100_SERIES_SUNRISE_POINT:
+	case CHIPSET_C620_SERIES_LEWISBURG:
+	case CHIPSET_300_SERIES_CANNON_POINT:
+	case CHIPSET_500_SERIES_TIGER_POINT:
+	case CHIPSET_APOLLO_LAKE:
+	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
+		tmp = mmio_readl(ich_spibar + PCH100_REG_DLOCK);
+		msg_pdbg("0x0c: 0x%08x (DLOCK)\n", tmp);
+		prettyprint_pch100_reg_dlock(tmp);
+		break;
+	default:
+		break;
+	}
+
+	if (desc_valid) {
+		tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP);
+		msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp);
+		msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp));
+		msg_pdbg("BMRAG 0x%02x, ", ICH_BMRAG(tmp));
+		msg_pdbg("BRWA 0x%02x, ", ICH_BRWA(tmp));
+		msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
+
+		/* Handle FREGx and FRAP registers */
+		for (i = 0; i < num_freg; i++)
+			ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
+		if (ich_spi_rw_restricted)
+			msg_pinfo("Not all flash regions are freely accessible by flashprog. This is "
+				  "most likely\ndue to an active ME. Please see "
+				  "https://flashprog.org/ME for details.\n");
+	}
+
+	/* Handle PR registers */
+	for (i = 0; i < num_pr; i++) {
+		/* if not locked down try to disable PR locks first */
+		if (!ichspi_lock)
+			ich9_set_pr(reg_pr0, i, 0, 0);
+		ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
+	}
+
+	switch (ich_spi_rw_restricted) {
+	case WRITE_PROT:
+		msg_pwarn("At least some flash regions are write protected. For write operations,\n"
+			  "you should use a flash layout and include only writable regions. See\n"
+			  "manpage for more details.\n");
+		break;
+	case READ_PROT:
+	case LOCKED:
+		msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
+			  "layout and include only accessible regions. For write operations, you'll\n"
+			  "additionally need the --noverify-all switch. See manpage for more details.\n"
+			  );
+		break;
+	}
+
+	tmp = mmio_readl(ich_spibar + swseq_data.reg_ssfsc);
+	msg_pdbg("0x%zx: 0x%02x (SSFS)\n", swseq_data.reg_ssfsc, tmp & 0xff);
+	prettyprint_ich9_reg_ssfs(tmp);
+	if (tmp & SSFS_FCERR) {
+		msg_pdbg("Clearing SSFS.FCERR\n");
+		mmio_writeb(SSFS_FCERR, ich_spibar + swseq_data.reg_ssfsc);
+	}
+	msg_pdbg("0x%zx: 0x%06x (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
+	prettyprint_ich9_reg_ssfc(tmp);
+
+	msg_pdbg("0x%zx: 0x%04x     (PREOP)\n",
+		 swseq_data.reg_preop, mmio_readw(ich_spibar + swseq_data.reg_preop));
+	msg_pdbg("0x%zx: 0x%04x     (OPTYPE)\n",
+		 swseq_data.reg_optype, mmio_readw(ich_spibar + swseq_data.reg_optype));
+	msg_pdbg("0x%zx: 0x%08x (OPMENU)\n",
+		 swseq_data.reg_opmenu, mmio_readl(ich_spibar + swseq_data.reg_opmenu));
+	msg_pdbg("0x%zx: 0x%08x (OPMENU+4)\n",
+		 swseq_data.reg_opmenu + 4, mmio_readl(ich_spibar + swseq_data.reg_opmenu + 4));
+
+	if (desc_valid) {
 		switch (ich_gen) {
+		case CHIPSET_ICH8:
 		case CHIPSET_100_SERIES_SUNRISE_POINT:
 		case CHIPSET_C620_SERIES_LEWISBURG:
 		case CHIPSET_300_SERIES_CANNON_POINT:
@@ -1889,189 +1964,110 @@
 		case CHIPSET_APOLLO_LAKE:
 		case CHIPSET_GEMINI_LAKE:
 		case CHIPSET_ELKHART_LAKE:
-			tmp = mmio_readl(ich_spibar + PCH100_REG_DLOCK);
-			msg_pdbg("0x0c: 0x%08x (DLOCK)\n", tmp);
-			prettyprint_pch100_reg_dlock(tmp);
+		case CHIPSET_BAYTRAIL:
 			break;
 		default:
+			ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR);
+			msg_pdbg("0x%x: 0x%08x (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
+			ich_set_bbar(0);
 			break;
 		}
 
-		if (desc_valid) {
-			tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP);
-			msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp);
-			msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp));
-			msg_pdbg("BMRAG 0x%02x, ", ICH_BMRAG(tmp));
-			msg_pdbg("BRWA 0x%02x, ", ICH_BRWA(tmp));
-			msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
-
-			/* Handle FREGx and FRAP registers */
-			for (i = 0; i < num_freg; i++)
-				ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
-			if (ich_spi_rw_restricted)
-				msg_pinfo("Not all flash regions are freely accessible by flashprog. This is "
-					  "most likely\ndue to an active ME. Please see "
-					  "https://flashprog.org/ME for details.\n");
-		}
-
-		/* Handle PR registers */
-		for (i = 0; i < num_pr; i++) {
-			/* if not locked down try to disable PR locks first */
-			if (!ichspi_lock)
-				ich9_set_pr(reg_pr0, i, 0, 0);
-			ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
-		}
-
-		switch (ich_spi_rw_restricted) {
-		case WRITE_PROT:
-			msg_pwarn("At least some flash regions are write protected. For write operations,\n"
-				  "you should use a flash layout and include only writable regions. See\n"
-				  "manpage for more details.\n");
-			break;
-		case READ_PROT:
-		case LOCKED:
-			msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
-				  "layout and include only accessible regions. For write operations, you'll\n"
-				  "additionally need the --noverify-all switch. See manpage for more details.\n"
-				  );
-			break;
-		}
-
-		tmp = mmio_readl(ich_spibar + swseq_data.reg_ssfsc);
-		msg_pdbg("0x%zx: 0x%02x (SSFS)\n", swseq_data.reg_ssfsc, tmp & 0xff);
-		prettyprint_ich9_reg_ssfs(tmp);
-		if (tmp & SSFS_FCERR) {
-			msg_pdbg("Clearing SSFS.FCERR\n");
-			mmio_writeb(SSFS_FCERR, ich_spibar + swseq_data.reg_ssfsc);
-		}
-		msg_pdbg("0x%zx: 0x%06x (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
-		prettyprint_ich9_reg_ssfc(tmp);
-
-		msg_pdbg("0x%zx: 0x%04x     (PREOP)\n",
-			 swseq_data.reg_preop, mmio_readw(ich_spibar + swseq_data.reg_preop));
-		msg_pdbg("0x%zx: 0x%04x     (OPTYPE)\n",
-			 swseq_data.reg_optype, mmio_readw(ich_spibar + swseq_data.reg_optype));
-		msg_pdbg("0x%zx: 0x%08x (OPMENU)\n",
-			 swseq_data.reg_opmenu, mmio_readl(ich_spibar + swseq_data.reg_opmenu));
-		msg_pdbg("0x%zx: 0x%08x (OPMENU+4)\n",
-			 swseq_data.reg_opmenu + 4, mmio_readl(ich_spibar + swseq_data.reg_opmenu + 4));
-
-		if (desc_valid) {
-			switch (ich_gen) {
-			case CHIPSET_ICH8:
-			case CHIPSET_100_SERIES_SUNRISE_POINT:
-			case CHIPSET_C620_SERIES_LEWISBURG:
-			case CHIPSET_300_SERIES_CANNON_POINT:
-			case CHIPSET_500_SERIES_TIGER_POINT:
-			case CHIPSET_APOLLO_LAKE:
-			case CHIPSET_GEMINI_LAKE:
-			case CHIPSET_ELKHART_LAKE:
-			case CHIPSET_BAYTRAIL:
-				break;
-			default:
-				ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR);
-				msg_pdbg("0x%x: 0x%08x (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
-				ich_set_bbar(0);
-				break;
-			}
-
-			if (ich_gen == CHIPSET_ICH8) {
-				tmp = mmio_readl(ich_spibar + ICH8_REG_VSCC);
-				msg_pdbg("0x%x: 0x%08x (VSCC)\n", ICH8_REG_VSCC, tmp);
-				msg_pdbg("VSCC: ");
-				prettyprint_ich_reg_vscc(tmp, FLASHPROG_MSG_DEBUG, true);
-			} else {
-				tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC);
-				msg_pdbg("0x%x: 0x%08x (LVSCC)\n", ICH9_REG_LVSCC, tmp);
-				msg_pdbg("LVSCC: ");
-				prettyprint_ich_reg_vscc(tmp, FLASHPROG_MSG_DEBUG, true);
-
-				tmp = mmio_readl(ich_spibar + ICH9_REG_UVSCC);
-				msg_pdbg("0x%x: 0x%08x (UVSCC)\n", ICH9_REG_UVSCC, tmp);
-				msg_pdbg("UVSCC: ");
-				prettyprint_ich_reg_vscc(tmp, FLASHPROG_MSG_DEBUG, false);
-			}
-
-			switch (ich_gen) {
-			case CHIPSET_ICH8:
-			case CHIPSET_100_SERIES_SUNRISE_POINT:
-			case CHIPSET_C620_SERIES_LEWISBURG:
-			case CHIPSET_300_SERIES_CANNON_POINT:
-			case CHIPSET_500_SERIES_TIGER_POINT:
-			case CHIPSET_APOLLO_LAKE:
-			case CHIPSET_GEMINI_LAKE:
-			case CHIPSET_ELKHART_LAKE:
-				break;
-			default:
-				tmp = mmio_readl(ich_spibar + ICH9_REG_FPB);
-				msg_pdbg("0x%x: 0x%08x (FPB)\n", ICH9_REG_FPB, tmp);
-				break;
-			}
-
-			if (read_ich_descriptors_via_fdo(ich_gen, ich_spibar, &desc) == ICH_RET_OK)
-				prettyprint_ich_descriptors(ich_gen, &desc);
-
-			/* If the descriptor is valid and indicates multiple
-			 * flash devices we need to use hwseq to be able to
-			 * access the second flash device.
-			 */
-			if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
-				msg_pinfo("Enabling hardware sequencing due to "
-					  "multiple flash chips detected.\n");
-				ich_spi_mode = ich_hwseq;
-			}
-		}
-
-		if (ich_spi_mode == ich_auto && ichspi_lock &&
-		    ich_missing_opcodes()) {
-			msg_pinfo("Enabling hardware sequencing because "
-				  "some important opcode is locked.\n");
-			ich_spi_mode = ich_hwseq;
-		}
-
-		if (ich_spi_mode == ich_auto &&
-		    (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
-		     ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
-		     ich_gen == CHIPSET_500_SERIES_TIGER_POINT)) {
-			msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
-			ich_spi_mode = ich_hwseq;
-		}
-
-		if (ich_spi_mode == ich_auto &&
-		    (ich_gen == CHIPSET_APOLLO_LAKE ||
-		     ich_gen == CHIPSET_GEMINI_LAKE ||
-		     ich_gen == CHIPSET_ELKHART_LAKE)) {
-			msg_pdbg("Enabling hardware sequencing by default for Apollo/Gemini/Elkhart Lake.\n");
-			ich_spi_mode = ich_hwseq;
-		}
-
-		if (ich_spi_mode == ich_hwseq) {
-			if (!desc_valid) {
-				msg_perr("Hardware sequencing was requested "
-					 "but the flash descriptor is not "
-					 "valid. Aborting.\n");
-				return ERROR_FATAL;
-			}
-
-			int tmpi = getFCBA_component_density(ich_generation, &desc, 0);
-			if (tmpi < 0) {
-				msg_perr("Could not determine density of flash component %d.\n", 0);
-				return ERROR_FATAL;
-			}
-			hwseq_data.size_comp0 = tmpi;
-
-			tmpi = getFCBA_component_density(ich_generation, &desc, 1);
-			if (tmpi < 0) {
-				msg_perr("Could not determine density of flash component %d.\n", 1);
-				return ERROR_FATAL;
-			}
-			hwseq_data.size_comp1 = tmpi;
-
-			register_opaque_master(&opaque_master_ich_hwseq, NULL);
+		if (ich_gen == CHIPSET_ICH8) {
+			tmp = mmio_readl(ich_spibar + ICH8_REG_VSCC);
+			msg_pdbg("0x%x: 0x%08x (VSCC)\n", ICH8_REG_VSCC, tmp);
+			msg_pdbg("VSCC: ");
+			prettyprint_ich_reg_vscc(tmp, FLASHPROG_MSG_DEBUG, true);
 		} else {
-			register_spi_master(&spi_master_ich9, 0, NULL);
+			tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC);
+			msg_pdbg("0x%x: 0x%08x (LVSCC)\n", ICH9_REG_LVSCC, tmp);
+			msg_pdbg("LVSCC: ");
+			prettyprint_ich_reg_vscc(tmp, FLASHPROG_MSG_DEBUG, true);
+
+			tmp = mmio_readl(ich_spibar + ICH9_REG_UVSCC);
+			msg_pdbg("0x%x: 0x%08x (UVSCC)\n", ICH9_REG_UVSCC, tmp);
+			msg_pdbg("UVSCC: ");
+			prettyprint_ich_reg_vscc(tmp, FLASHPROG_MSG_DEBUG, false);
 		}
-		break;
+
+		switch (ich_gen) {
+		case CHIPSET_ICH8:
+		case CHIPSET_100_SERIES_SUNRISE_POINT:
+		case CHIPSET_C620_SERIES_LEWISBURG:
+		case CHIPSET_300_SERIES_CANNON_POINT:
+		case CHIPSET_500_SERIES_TIGER_POINT:
+		case CHIPSET_APOLLO_LAKE:
+		case CHIPSET_GEMINI_LAKE:
+		case CHIPSET_ELKHART_LAKE:
+			break;
+		default:
+			tmp = mmio_readl(ich_spibar + ICH9_REG_FPB);
+			msg_pdbg("0x%x: 0x%08x (FPB)\n", ICH9_REG_FPB, tmp);
+			break;
+		}
+
+		if (read_ich_descriptors_via_fdo(ich_gen, ich_spibar, &desc) == ICH_RET_OK)
+			prettyprint_ich_descriptors(ich_gen, &desc);
+
+		/* If the descriptor is valid and indicates multiple
+		 * flash devices we need to use hwseq to be able to
+		 * access the second flash device.
+		 */
+		if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
+			msg_pinfo("Enabling hardware sequencing due to "
+				  "multiple flash chips detected.\n");
+			ich_spi_mode = ich_hwseq;
+		}
+	}
+
+	if (ich_spi_mode == ich_auto && ichspi_lock &&
+	    ich_missing_opcodes()) {
+		msg_pinfo("Enabling hardware sequencing because "
+			  "some important opcode is locked.\n");
+		ich_spi_mode = ich_hwseq;
+	}
+
+	if (ich_spi_mode == ich_auto &&
+	    (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
+	     ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
+	     ich_gen == CHIPSET_500_SERIES_TIGER_POINT)) {
+		msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
+		ich_spi_mode = ich_hwseq;
+	}
+
+	if (ich_spi_mode == ich_auto &&
+	    (ich_gen == CHIPSET_APOLLO_LAKE ||
+	     ich_gen == CHIPSET_GEMINI_LAKE ||
+	     ich_gen == CHIPSET_ELKHART_LAKE)) {
+		msg_pdbg("Enabling hardware sequencing by default for Apollo/Gemini/Elkhart Lake.\n");
+		ich_spi_mode = ich_hwseq;
+	}
+
+	if (ich_spi_mode == ich_hwseq) {
+		if (!desc_valid) {
+			msg_perr("Hardware sequencing was requested "
+				 "but the flash descriptor is not "
+				 "valid. Aborting.\n");
+			return ERROR_FATAL;
+		}
+
+		int tmpi = getFCBA_component_density(ich_generation, &desc, 0);
+		if (tmpi < 0) {
+			msg_perr("Could not determine density of flash component %d.\n", 0);
+			return ERROR_FATAL;
+		}
+		hwseq_data.size_comp0 = tmpi;
+
+		tmpi = getFCBA_component_density(ich_generation, &desc, 1);
+		if (tmpi < 0) {
+			msg_perr("Could not determine density of flash component %d.\n", 1);
+			return ERROR_FATAL;
+		}
+		hwseq_data.size_comp1 = tmpi;
+
+		register_opaque_master(&opaque_master_ich_hwseq, NULL);
+	} else {
+		register_spi_master(&spi_master_ich9, 0, NULL);
 	}
 
 	return 0;
diff --git a/include/programmer.h b/include/programmer.h
index 2633450..f3e32c6 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -334,7 +334,10 @@
 	CHIPSET_TUNNEL_CREEK, /* Atom E6xx */
 	CHIPSET_CENTERTON, /* Atom S1220 S1240 S1260 */
 	CHIPSET_ICH7,
-	CHIPSET_ICH8,
+
+	SPI_ENGINE_ICH9,	/******** ICH9 compatible from here on ********/
+
+	CHIPSET_ICH8 = SPI_ENGINE_ICH9,
 	CHIPSET_ICH9,
 	CHIPSET_ICH10,
 	CHIPSET_5_SERIES_IBEX_PEAK,
@@ -357,7 +360,8 @@
 
 /* ichspi.c */
 #if CONFIG_INTERNAL == 1
-int ich_init_spi(void *spibar, enum ich_chipset ich_generation);
+int ich7_init_spi(void *spibar, enum ich_chipset);
+int ich9_init_spi(void *spibar, enum ich_chipset);
 int via_init_spi(uint32_t mmio_base);
 
 /* amd_imc.c */