From 2ba9f6ebe56b208a1fb0b0ce5edf81097a0158be Mon Sep 17 00:00:00 2001 From: Stefan Tauner Date: Wed, 20 Aug 2014 15:39:19 +0000 Subject: Refine Flash Component descriptor handling 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. Corresponding to flashrom svn r1843. Signed-off-by: Stefan Tauner Acked-by: Stefan Tauner --- ich_descriptors.c | 192 +++++++++++++++++------ ich_descriptors.h | 41 ++++- ichspi.c | 30 ++-- util/ich_descriptors_tool/ich_descriptors_tool.c | 6 +- 4 files changed, 204 insertions(+), 65 deletions(-) diff --git a/ich_descriptors.c b/ich_descriptors.c index 528717b2..b1e081f2 100644 --- a/ich_descriptors.c +++ b/ich_descriptors.c @@ -45,14 +45,16 @@ #define min(a, b) (a < b) ? a : b #endif -void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity) +void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl) { print(verbosity, "BES=0x%x, ", (reg_val & VSCC_BES) >> VSCC_BES_OFF); print(verbosity, "WG=%d, ", (reg_val & VSCC_WG) >> VSCC_WG_OFF); print(verbosity, "WSR=%d, ", (reg_val & VSCC_WSR) >> VSCC_WSR_OFF); print(verbosity, "WEWS=%d, ", (reg_val & VSCC_WEWS) >> VSCC_WEWS_OFF); - print(verbosity, "EO=0x%x, ", (reg_val & VSCC_EO) >> VSCC_EO_OFF); - print(verbosity, "VCL=%d\n", (reg_val & VSCC_VCL) >> VSCC_VCL_OFF); + print(verbosity, "EO=0x%x", (reg_val & VSCC_EO) >> VSCC_EO_OFF); + if (print_vcl) + print(verbosity, ", VCL=%d", (reg_val & VSCC_VCL) >> VSCC_VCL_OFF); + print(verbosity, "\n"); } #define getFCBA(cont) (((cont)->FLMAP0 << 4) & 0x00000ff0) @@ -64,7 +66,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 +100,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 +198,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 +341,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; @@ -630,7 +698,7 @@ void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap) msg_pdbg2(" "); /* indention */ prettyprint_rdid(jid); msg_pdbg2(" "); /* indention */ - prettyprint_ich_reg_vscc(vscc, 0); + prettyprint_ich_reg_vscc(vscc, 0, false); } msg_pdbg2("\n"); } @@ -723,29 +791,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 3a44740b..208e640c 100644 --- a/ich_descriptors.h +++ b/ich_descriptors.h @@ -64,7 +64,7 @@ #define ICH_FREG_BASE(flreg) (((flreg) << 12) & 0x01fff000) #define ICH_FREG_LIMIT(flreg) (((flreg) >> 4) & 0x01fff000) -void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity); +void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl); struct ich_desc_content { uint32_t FLVALSIG; /* 0x00 */ @@ -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 5d37d061..7c068e10 100644 --- a/ichspi.c +++ b/ichspi.c @@ -1737,7 +1737,7 @@ int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen) tmp = mmio_readl(ich_spibar + ICH8_REG_VSCC); msg_pdbg("0xC1: 0x%08x (VSCC)\n", tmp); msg_pdbg("VSCC: "); - prettyprint_ich_reg_vscc(tmp, MSG_DEBUG); + prettyprint_ich_reg_vscc(tmp, MSG_DEBUG, true); } else { ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR); msg_pdbg("0xA0: 0x%08x (BBAR)\n", @@ -1747,12 +1747,12 @@ int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen) tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC); msg_pdbg("0xC4: 0x%08x (LVSCC)\n", tmp); msg_pdbg("LVSCC: "); - prettyprint_ich_reg_vscc(tmp, MSG_DEBUG); + prettyprint_ich_reg_vscc(tmp, MSG_DEBUG, true); tmp = mmio_readl(ich_spibar + ICH9_REG_UVSCC); msg_pdbg("0xC8: 0x%08x (UVSCC)\n", tmp); msg_pdbg("UVSCC: "); - prettyprint_ich_reg_vscc(tmp, MSG_DEBUG); + prettyprint_ich_reg_vscc(tmp, MSG_DEBUG, false); tmp = mmio_readl(ich_spibar + ICH9_REG_FPB); msg_pdbg("0xD0: 0x%08x (FPB)\n", tmp); @@ -1762,10 +1762,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. @@ -1791,8 +1790,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 00ad1f39..e77593e1 100644 --- a/util/ich_descriptors_tool/ich_descriptors_tool.c +++ b/util/ich_descriptors_tool/ich_descriptors_tool.c @@ -113,7 +113,7 @@ static void usage(char *argv[], char *error) "where points to an image of the contents of the SPI flash.\n" "In case the image is really in descriptor mode %s\n" "will pretty print some of the contained information.\n" -"To also print the data stored in the descriptor strap you have to indicate\n" +"To also print the data stored in the descriptor straps you have to indicate\n" "the chipset series with the '-c' parameter and one of the possible arguments:\n" "\t- \"ich8\",\n" "\t- \"ich9\",\n" @@ -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); -- cgit v1.2.3