Add Elkhart Lake support

Elkhart Lake has a chipset called Mule Creek Canyon which is quite
compatible with 300 series chipsets. There are a few differences though,
e.g. different encoding for the SPI clock values for read and write in
the FLCOMP register. In addition Elkhart Lake has a new PCI device ID
for the SPI controller which is added, too.

Tested: Read and flash complete flash on Siemens MC EHL1

Change-Id: I711e39a3ec9cd7098389231eaa1cb864d615a475
Signed-off-by: Werner Zeh <werner.zeh@siemens.com>
Original-Reviewed-on: https://review.coreboot.org/c/flashrom/+/60711
Original-Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/flashrom-stable/+/71443
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/chipset_enable.c b/chipset_enable.c
index 9bb24e0..7bd12e7 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -600,6 +600,7 @@
 	case CHIPSET_C620_SERIES_LEWISBURG:
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
+	case CHIPSET_ELKHART_LAKE:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
 		reg_name = "BIOS_SPI_BC";
@@ -706,6 +707,7 @@
 		break;
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		boot_straps = boot_straps_apl;
 		break;
 	case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet
@@ -734,6 +736,7 @@
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		bbs = (gcs >> 6) & 0x1;
 		break;
 	default:
@@ -979,6 +982,11 @@
 	return enable_flash_pch100_or_c620(dev, name, 0x1f, 5, CHIPSET_500_SERIES_TIGER_POINT);
 }
 
+static int enable_flash_mcc(struct pci_dev *const dev, const char *const name)
+{
+	return enable_flash_pch100_or_c620(dev, name, 0x1f, 5, CHIPSET_ELKHART_LAKE);
+}
+
 static int enable_flash_apl(struct pci_dev *const dev, const char *const name)
 {
 	return enable_flash_pch100_or_c620(dev, name, 0x0d, 2, CHIPSET_APOLLO_LAKE);
@@ -2093,6 +2101,7 @@
 	{0x8086, 0x5af0, B_S,    DEP, "Intel", "Apollo Lake",			enable_flash_apl},
 	{0x8086, 0x3197, B_S,    NT,  "Intel", "Gemini Lake",			enable_flash_glk},
 	{0x8086, 0x31e8, B_S,    DEP, "Intel", "Gemini Lake",			enable_flash_glk},
+	{0x8086, 0x4b24, B_S,    DEP, "Intel", "Elkhart Lake",			enable_flash_mcc},
 	{0x8086, 0xa303, B_S,    NT,  "Intel", "H310",				enable_flash_pch300},
 	{0x8086, 0xa304, B_S,    NT,  "Intel", "H370",				enable_flash_pch300},
 	{0x8086, 0xa305, B_S,    DEP, "Intel", "Z390",				enable_flash_pch300},
diff --git a/ich_descriptors.c b/ich_descriptors.c
index ac3602b..8ea0ac2 100644
--- a/ich_descriptors.c
+++ b/ich_descriptors.c
@@ -45,6 +45,7 @@
 	case CHIPSET_C620_SERIES_LEWISBURG:
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
+	case CHIPSET_ELKHART_LAKE:
 		return 16;
 	case CHIPSET_100_SERIES_SUNRISE_POINT:
 		return 10;
@@ -71,6 +72,7 @@
 	case CHIPSET_C620_SERIES_LEWISBURG:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		if (cont->NM <= MAX_NUM_MASTERS)
 			return cont->NM;
 		break;
@@ -108,7 +110,7 @@
 		"8 series Lynx Point", "Baytrail", "8 series Lynx Point LP", "8 series Wellsburg",
 		"9 series Wildcat Point", "9 series Wildcat Point LP", "100 series Sunrise Point",
 		"C620 series Lewisburg", "300/400 series Cannon/Comet Point",
-		"500 series Tiger Point", "Apollo Lake", "Gemini Lake",
+		"500 series Tiger Point", "Apollo Lake", "Gemini Lake", "Elkhart Lake",
 	};
 	if (cs < CHIPSET_ICH8 || cs - CHIPSET_ICH8 + 1 >= ARRAY_SIZE(chipset_names))
 		cs = 0;
@@ -203,7 +205,8 @@
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
-	case CHIPSET_GEMINI_LAKE: {
+	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE: {
 		uint8_t size_enc;
 		if (idx == 0) {
 			size_enc = desc->component.dens_new.comp1_density;
@@ -222,7 +225,7 @@
 
 static const char *pprint_freq(enum ich_chipset cs, uint8_t value)
 {
-	static const char *const freq_str[4][8] = { {
+	static const char *const freq_str[5][8] = { {
 		"20 MHz",
 		"33 MHz",
 		"reserved",
@@ -258,6 +261,15 @@
 		"reserved",
 		"14 MHz",
 		"reserved"
+	}, {
+		"reserved",
+		"50 MHz",
+		"reserved",
+		"reserved",
+		"33 MHz",
+		"20 MHz",
+		"reserved",
+		"reserved",
 	}};
 
 	switch (cs) {
@@ -286,6 +298,8 @@
 		return freq_str[2][value];
 	case CHIPSET_500_SERIES_TIGER_POINT:
 		return freq_str[3][value];
+	case CHIPSET_ELKHART_LAKE:
+		return freq_str[4][value];
 	case CHIPSET_ICH_UNKNOWN:
 	default:
 		return "unknown";
@@ -329,6 +343,7 @@
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		has_flill1 = true;
 		break;
 	default:
@@ -507,7 +522,7 @@
 					  desc->master.mstr[i].write & (1 << j) ? 'w' : ' ');
 			msg_pdbg2("\n");
 		}
-	} else if (cs == CHIPSET_APOLLO_LAKE || cs == CHIPSET_GEMINI_LAKE) {
+	} else if (cs == CHIPSET_APOLLO_LAKE || cs == CHIPSET_GEMINI_LAKE || cs == CHIPSET_ELKHART_LAKE) {
 		const char *const master_names[] = { "BIOS", "TXE", };
 		if (nm > (ssize_t)ARRAY_SIZE(master_names)) {
 			msg_pdbg2("%s: number of masters too high (%d).\n", __func__, desc->content.NM);
@@ -1010,6 +1025,8 @@
 			return CHIPSET_300_SERIES_CANNON_POINT;
 		if (content->CSSL == 0x11)
 			return CHIPSET_500_SERIES_TIGER_POINT;
+		if (content->CSSL == 0x03)
+			return CHIPSET_ELKHART_LAKE;
 		msg_pwarn("Unknown flash descriptor, assuming 500 series compatibility.\n");
 		return CHIPSET_500_SERIES_TIGER_POINT;
 	}
@@ -1031,6 +1048,7 @@
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		/* `freq_read` was repurposed, so can't check on it any more. */
 		break;
 	case CHIPSET_100_SERIES_SUNRISE_POINT:
@@ -1186,6 +1204,7 @@
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		if (idx == 0) {
 			size_enc = desc->component.dens_new.comp1_density;
 		} else {
@@ -1223,6 +1242,7 @@
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		mmio_le_writel(control, spibar + PCH100_REG_FDOC);
 		return mmio_le_readl(spibar + PCH100_REG_FDOD);
 	default:
diff --git a/ichspi.c b/ichspi.c
index 0b00466..21f6d9b 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -400,6 +400,7 @@
 	case CHIPSET_C620_SERIES_LEWISBURG:
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
+	case CHIPSET_ELKHART_LAKE:
 		break;
 	default:
 		pprint_reg(HSFS, BERASE, reg_val, ", ");
@@ -411,6 +412,7 @@
 	case CHIPSET_C620_SERIES_LEWISBURG:
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
+	case CHIPSET_ELKHART_LAKE:
 		pprint_reg(HSFS, PRR34_LOCKDN, reg_val, ", ");
 		pprint_reg(HSFS, WRSDIS, reg_val, ", ");
 		break;
@@ -431,6 +433,7 @@
 	case CHIPSET_C620_SERIES_LEWISBURG:
 	case CHIPSET_300_SERIES_CANNON_POINT:
 	case CHIPSET_500_SERIES_TIGER_POINT:
+	case CHIPSET_ELKHART_LAKE:
 		_pprint_reg(HSFC, PCH100_HSFC_FCYCLE, PCH100_HSFC_FCYCLE_OFF, reg_val, ", ");
 		pprint_reg(HSFC, WET, reg_val, ", ");
 		break;
@@ -1745,6 +1748,7 @@
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		num_pr			= 6;	/* Includes GPR0 */
 		reg_pr0			= PCH100_REG_FPR0;
 		swseq_data.reg_ssfsc	= PCH100_REG_SSFSC;
@@ -1778,6 +1782,7 @@
 	case CHIPSET_500_SERIES_TIGER_POINT:
 	case CHIPSET_APOLLO_LAKE:
 	case CHIPSET_GEMINI_LAKE:
+	case CHIPSET_ELKHART_LAKE:
 		num_freg = 16;
 		break;
 	default:
@@ -1875,6 +1880,7 @@
 		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);
@@ -1951,6 +1957,7 @@
 			case CHIPSET_500_SERIES_TIGER_POINT:
 			case CHIPSET_APOLLO_LAKE:
 			case CHIPSET_GEMINI_LAKE:
+			case CHIPSET_ELKHART_LAKE:
 			case CHIPSET_BAYTRAIL:
 				break;
 			default:
@@ -1985,6 +1992,7 @@
 			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);
@@ -2023,8 +2031,9 @@
 
 		if (ich_spi_mode == ich_auto &&
 		    (ich_gen == CHIPSET_APOLLO_LAKE ||
-		     ich_gen == CHIPSET_GEMINI_LAKE)) {
-			msg_pdbg("Enabling hardware sequencing by default for Apollo/Gemini Lake.\n");
+		     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;
 		}
 
diff --git a/programmer.h b/programmer.h
index 15484c1..dcb5f4b 100644
--- a/programmer.h
+++ b/programmer.h
@@ -357,6 +357,7 @@
 	CHIPSET_500_SERIES_TIGER_POINT,
 	CHIPSET_APOLLO_LAKE,
 	CHIPSET_GEMINI_LAKE,
+	CHIPSET_ELKHART_LAKE,
 };
 
 /* ichspi.c */
diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c
index 890f26c..00c0282 100644
--- a/util/ich_descriptors_tool/ich_descriptors_tool.c
+++ b/util/ich_descriptors_tool/ich_descriptors_tool.c
@@ -237,6 +237,8 @@
 			cs = CHIPSET_APOLLO_LAKE;
 		else if (strcmp(csn, "gemini") == 0)
 			cs = CHIPSET_GEMINI_LAKE;
+		else if (strcmp(csn, "elkhart") == 0)
+			cs = CHIPSET_ELKHART_LAKE;
 	}
 
 	ret = read_ich_descriptors_from_dump(buf, len, &cs, &desc);