[flashrom] [PATCH 1/3] Refine Flash Component descriptor handling.

Stefan Tauner stefan.tauner at alumni.tuwien.ac.at
Sat Aug 2 02:39:31 CEST 2014


Possible values as well as encodings have changed in newer chipsets as follows.
 - Pre-PCH (i.e. ICH) chipsets had a maximum frequency of 33 MHz for all
   operations
 - Since Cougar Point the chipsets support dual output fast reads (encoded
   in bit 30).
 - Flash component density encoding has changed from 3 to 4 bits with Lynx
   Point, currently allowing for up to 64 MB chips.

Signed-off-by: Stefan Tauner <stefan.tauner at alumni.tuwien.ac.at>
---
 ich_descriptors.c                                | 182 +++++++++++++++++------
 ich_descriptors.h                                |  39 ++++-
 ichspi.c                                         |  24 ++-
 util/ich_descriptors_tool/ich_descriptors_tool.c |   4 +
 4 files changed, 193 insertions(+), 56 deletions(-)

diff --git a/ich_descriptors.c b/ich_descriptors.c
index 528717b..3977a4b 100644
--- a/ich_descriptors.c
+++ b/ich_descriptors.c
@@ -64,7 +64,7 @@ void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity)
 void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descriptors *desc)
 {
 	prettyprint_ich_descriptor_content(&desc->content);
-	prettyprint_ich_descriptor_component(desc);
+	prettyprint_ich_descriptor_component(cs, desc);
 	prettyprint_ich_descriptor_region(desc);
 	prettyprint_ich_descriptor_master(&desc->master);
 #ifdef ICH_DESCRIPTORS_FROM_DUMP
@@ -98,28 +98,97 @@ void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont)
 	msg_pdbg2("\n");
 }
 
-void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc)
+static const char *pprint_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx)
+{
+	if (idx > 1) {
+		msg_perr("Only ICH SPI component index 0 or 1 are supported yet.\n");
+		return NULL;
+	}
+
+	if (desc->content.NC == 0 && idx > 0)
+		return "unused";
+
+	static const char * const size_str[] = {
+		"512 kB",	/* 0000 */
+		"1 MB",		/* 0001 */
+		"2 MB",		/* 0010 */
+		"4 MB",		/* 0011 */
+		"8 MB",		/* 0100 */
+		"16 MB",	/* 0101 */ /* Maximum up to Lynx Point (excl.) */
+		"32 MB",	/* 0110 */
+		"64 MB",	/* 0111 */
+	};
+
+	switch (cs) {
+	case CHIPSET_ICH8:
+	case CHIPSET_ICH9:
+	case CHIPSET_ICH10:
+	case CHIPSET_5_SERIES_IBEX_PEAK:
+	case CHIPSET_6_SERIES_COUGAR_POINT:
+	case CHIPSET_7_SERIES_PANTHER_POINT: {
+		uint8_t size_enc;
+		if (idx == 0) {
+			size_enc = desc->component.old.comp1_density;
+		} else {
+			size_enc = desc->component.old.comp2_density;
+		}
+		if (size_enc > 5)
+			return "reserved";
+		return size_str[size_enc];
+	}
+	case CHIPSET_8_SERIES_LYNX_POINT:
+	case CHIPSET_8_SERIES_LYNX_POINT_LP:
+	case CHIPSET_8_SERIES_WELLSBURG: {
+		uint8_t size_enc;
+		if (idx == 0) {
+			size_enc = desc->component.new.comp1_density;
+		} else {
+			size_enc = desc->component.new.comp2_density;
+		}
+		if (size_enc > 7)
+			return "reserved";
+		return size_str[size_enc];
+	}
+	case CHIPSET_ICH_UNKNOWN:
+	default:
+		return "unknown";
+	}
+}
+
+static const char *pprint_freq(enum ich_chipset cs, uint8_t value)
 {
 	static const char * const freq_str[8] = {
 		"20 MHz",	/* 000 */
 		"33 MHz",	/* 001 */
 		"reserved",	/* 010 */
 		"reserved",	/* 011 */
-		"50 MHz",	/* 100 */
+		"50 MHz",	/* 100 */ /* New since Ibex Peak */
 		"reserved",	/* 101 */
 		"reserved",	/* 110 */
 		"reserved"	/* 111 */
 	};
-	static const char * const size_str[8] = {
-		"512 kB",	/* 000 */
-		"  1 MB",	/* 001 */
-		"  2 MB",	/* 010 */
-		"  4 MB",	/* 011 */
-		"  8 MB",	/* 100 */
-		" 16 MB",	/* 101 */
-		"reserved",	/* 110 */
-		"reserved",	/* 111 */
-	};
+
+	switch (cs) {
+	case CHIPSET_ICH8:
+	case CHIPSET_ICH9:
+	case CHIPSET_ICH10:
+		if (value > 1)
+			return "reserved";
+	case CHIPSET_5_SERIES_IBEX_PEAK:
+	case CHIPSET_6_SERIES_COUGAR_POINT:
+	case CHIPSET_7_SERIES_PANTHER_POINT:
+	case CHIPSET_8_SERIES_LYNX_POINT:
+	case CHIPSET_8_SERIES_LYNX_POINT_LP:
+	case CHIPSET_8_SERIES_WELLSBURG:
+		return freq_str[value];
+	case CHIPSET_ICH_UNKNOWN:
+	default:
+		return "unknown";
+	}
+}
+
+void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_descriptors *desc)
+{
 
 	msg_pdbg2("=== Component Section ===\n");
 	msg_pdbg2("FLCOMP   0x%08x\n", desc->component.FLCOMP);
@@ -127,24 +196,21 @@ void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc)
 	msg_pdbg2("\n");
 
 	msg_pdbg2("--- Details ---\n");
-	msg_pdbg2("Component 1 density:           %s\n",
-		  size_str[desc->component.comp1_density]);
+	msg_pdbg2("Component 1 density:            %s\n", pprint_density(cs, desc, 0));
 	if (desc->content.NC)
-		msg_pdbg2("Component 2 density:           %s\n",
-			  size_str[desc->component.comp2_density]);
+		msg_pdbg2("Component 2 density:            %s\n", pprint_density(cs, desc, 1));
 	else
 		msg_pdbg2("Component 2 is not used.\n");
-	msg_pdbg2("Read Clock Frequency:           %s\n",
-		  freq_str[desc->component.freq_read]);
-	msg_pdbg2("Read ID and Status Clock Freq.: %s\n",
-		  freq_str[desc->component.freq_read_id]);
-	msg_pdbg2("Write and Erase Clock Freq.:    %s\n",
-		  freq_str[desc->component.freq_write]);
-	msg_pdbg2("Fast Read is %ssupported.\n",
-		  desc->component.fastread ? "" : "not ");
-	if (desc->component.fastread)
+	msg_pdbg2("Read Clock Frequency:           %s\n", pprint_freq(cs, desc->component.common.freq_read));
+	msg_pdbg2("Read ID and Status Clock Freq.: %s\n", pprint_freq(cs, desc->component.common.freq_read_id));
+	msg_pdbg2("Write and Erase Clock Freq.:    %s\n", pprint_freq(cs, desc->component.common.freq_write));
+	msg_pdbg2("Fast Read is %ssupported.\n", desc->component.common.fastread ? "" : "not ");
+	if (desc->component.common.fastread)
 		msg_pdbg2("Fast Read Clock Frequency:      %s\n",
-			  freq_str[desc->component.freq_fastread]);
+			  pprint_freq(cs, desc->component.common.freq_fastread));
+	if (cs > CHIPSET_6_SERIES_COUGAR_POINT)
+		msg_pdbg2("Dual Output Fast Read Support:  %sabled\n",
+			  desc->component.new.dual_output ? "dis" : "en");
 	if (desc->component.FLILL == 0)
 		msg_pdbg2("No forbidden opcodes.\n");
 	else {
@@ -273,7 +339,7 @@ static void prettyprint_ich_descriptor_straps_56_pciecs(uint8_t conf, uint8_t of
 	msg_pdbg2("PCI Express Port Configuration Strap %d: ", off+1);
 
 	off *= 4;
-	switch(conf){
+	switch (conf){
 	case 0:
 		msg_pdbg2("4x1 Ports %d-%d (x1)", 1+off, 4+off);
 		break;
@@ -723,29 +789,57 @@ int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struc
 #else /* ICH_DESCRIPTORS_FROM_DUMP */
 
 /** Returns the integer representation of the component density with index
-idx in bytes or 0 if a correct size can not be determined. */
-int getFCBA_component_density(const struct ich_descriptors *desc, uint8_t idx)
+\em idx in bytes or -1 if the correct size can not be determined. */
+int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx)
 {
+	if (idx > 1) {
+		msg_perr("Only ICH SPI component index 0 or 1 are supported yet.\n");
+		return -1;
+	}
+
+	if (desc->content.NC == 0 && idx > 0)
+		return 0;
+
 	uint8_t size_enc;
-	
-	switch(idx) {
-	case 0:
-		size_enc = desc->component.comp1_density;
+	uint8_t size_max;
+
+	switch (cs) {
+	case CHIPSET_ICH8:
+	case CHIPSET_ICH9:
+	case CHIPSET_ICH10:
+	case CHIPSET_5_SERIES_IBEX_PEAK:
+	case CHIPSET_6_SERIES_COUGAR_POINT:
+	case CHIPSET_7_SERIES_PANTHER_POINT:
+		if (idx == 0) {
+			size_enc = desc->component.old.comp1_density;
+		} else {
+			size_enc = desc->component.old.comp2_density;
+		}
+		size_max = 5;
 		break;
-	case 1:
-		if (desc->content.NC == 0)
-			return 0;
-		size_enc = desc->component.comp2_density;
+	case CHIPSET_8_SERIES_LYNX_POINT:
+	case CHIPSET_8_SERIES_LYNX_POINT_LP:
+	case CHIPSET_8_SERIES_WELLSBURG:
+		if (idx == 0) {
+			size_enc = desc->component.new.comp1_density;
+		} else {
+			size_enc = desc->component.new.comp2_density;
+		}
+		size_max = 7;
 		break;
+	case CHIPSET_ICH_UNKNOWN:
 	default:
-		msg_perr("Only ICH SPI component index 0 or 1 are supported yet.\n");
-		return 0;
+		msg_pwarn("Density encoding is unknown on this chipset.\n");
+		return -1;
 	}
-	if (size_enc > 5) {
-		msg_perr("Density of ICH SPI component with index %d is invalid. Encoded density is 0x%x.\n",
-			 idx, size_enc);
-		return 0;
+
+	if (size_enc > size_max) {
+		msg_perr("Density of ICH SPI component with index %d is invalid."
+			 "Encoded density is 0x%x while maximum allowed is 0x%x.\n",
+			 idx, size_enc, size_max);
+		return -1;
 	}
+
 	return (1 << (19 + size_enc));
 }
 
diff --git a/ich_descriptors.h b/ich_descriptors.h
index 3a44740..b9213c8 100644
--- a/ich_descriptors.h
+++ b/ich_descriptors.h
@@ -102,17 +102,44 @@ struct ich_desc_content {
 struct ich_desc_component {
 	union {			/* 0x00 */
 		uint32_t FLCOMP; /* Flash Components Register */
+		/* FLCOMP encoding on various generations:
+		 *
+		 * Chipset/Generation	max_speed	dual_output	density
+		 * 			[MHz]		bits		max.	bits
+		 * ICH8:		33		N/A		5	0:2, 3:5
+		 * ICH9:		33		N/A		5	0:2, 3:5
+		 * ICH10:		33		N/A		5	0:2, 3:5
+		 * Ibex Peak/5:		50		N/A		5	0:2, 3:5
+		 * Cougar Point/6:	50		30		5	0:2, 3:5
+		 * Patsburg:		50		30		5	0:2, 3:5
+		 * Panther Point/7	50		30		5	0:2, 3:5
+		 * Lynx Point/8:	50		30		7	0:3, 4:7
+		 * Wildcat Point/9:	50		?? (multi I/O)	?	?:?, ?:?
+		 */
 		struct {
-			uint32_t comp1_density	:3,
-				 comp2_density	:3,
-						:11,
+			uint32_t 		:17,
 				 freq_read	:3,
 				 fastread	:1,
 				 freq_fastread	:3,
 				 freq_write	:3,
 				 freq_read_id	:3,
 						:2;
-		};
+		} common;
+		struct {
+			uint32_t comp1_density	:3,
+				 comp2_density	:3,
+						:11,
+						:13,
+						:2;
+		} old;
+		struct {
+			uint32_t comp1_density	:4, /* new since Lynx Point/8 */
+				 comp2_density	:4,
+						:9,
+						:13,
+				 dual_output	:1, /* new since Cougar Point/6 */
+						:1;
+		} new;
 	};
 	union {			/* 0x04 */
 		uint32_t FLILL; /* Flash Invalid Instructions Register */
@@ -555,7 +582,7 @@ struct ich_descriptors {
 void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descriptors *desc);
 
 void prettyprint_ich_descriptor_content(const struct ich_desc_content *content);
-void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc);
+void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_descriptors *desc);
 void prettyprint_ich_descriptor_region(const struct ich_descriptors *desc);
 void prettyprint_ich_descriptor_master(const struct ich_desc_master *master);
 
@@ -568,7 +595,7 @@ int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struc
 #else /* ICH_DESCRIPTORS_FROM_DUMP */
 
 int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc);
-int getFCBA_component_density(const struct ich_descriptors *desc, uint8_t idx);
+int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx);
 
 #endif /* ICH_DESCRIPTORS_FROM_DUMP */
 #endif /* __ICH_DESCRIPTORS_H__ */
diff --git a/ichspi.c b/ichspi.c
index 90bb0de..6744bef 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -1754,10 +1754,9 @@ int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen)
 
 		msg_pdbg("\n");
 		if (desc_valid) {
-			if (read_ich_descriptors_via_fdo(ich_spibar, &desc) ==
-			    ICH_RET_OK)
-				prettyprint_ich_descriptors(CHIPSET_ICH_UNKNOWN,
-							    &desc);
+			if (read_ich_descriptors_via_fdo(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.
@@ -1783,8 +1782,21 @@ int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen)
 					 "valid. Aborting.\n");
 				return ERROR_FATAL;
 			}
-			hwseq_data.size_comp0 = getFCBA_component_density(&desc, 0);
-			hwseq_data.size_comp1 = getFCBA_component_density(&desc, 1);
+
+			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);
 		} else {
 			register_spi_master(&spi_master_ich9);
diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c
index 00ad1f3..4c1f05c 100644
--- a/util/ich_descriptors_tool/ich_descriptors_tool.c
+++ b/util/ich_descriptors_tool/ich_descriptors_tool.c
@@ -121,6 +121,7 @@ static void usage(char *argv[], char *error)
 "\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n"
 "\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n"
 "\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n"
+"\t- \"8\" or \"lynx\" for Intel's 8 series chipsets.\n"
 "If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n"
 "the GbE blob that is required to initialize the GbE are also dumped to files.\n",
 	argv[0], argv[0]);
@@ -198,6 +199,9 @@ int main(int argc, char *argv[])
 		else if ((strcmp(csn, "7") == 0) ||
 			 (strcmp(csn, "panther") == 0))
 			cs = CHIPSET_7_SERIES_PANTHER_POINT;
+		else if ((strcmp(csn, "8") == 0) ||
+			 (strcmp(csn, "lynx") == 0))
+			cs = CHIPSET_8_SERIES_LYNX_POINT;
 	}
 
 	ret = read_ich_descriptors_from_dump(buf, len, &desc);
-- 
Kind regards, Stefan Tauner





More information about the flashrom mailing list