On Fri, Aug 1, 2014 at 6:39 PM, Stefan Tauner stefan.tauner@alumni.tuwien.ac.at wrote:
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@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
flashrom mailing list flashrom@flashrom.org http://www.flashrom.org/mailman/listinfo/flashrom
I tested this branch on CC2: https://github.com/stefanct/flashrom/tree/intel
See attached logs.
Flashrom views both chips as a single flash space. What is the correct method for only updating a single descriptor area? Note that the descriptor allows r/w everything. I have not tried locking down regions.
LGTM Acked-By:Tested-by: Marc Jones marcj303@gmail.com