Commit 2ba9f6eb authored by Stefan Tauner's avatar Stefan Tauner
Browse files

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: default avatarStefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
Acked-by: default avatarStefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
parent 9e3a6984
......@@ -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));
}
......
......@@ -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__ */
......
......@@ -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);
......
......@@ -113,7 +113,7 @@ static void usage(char *argv[], char *error)
"where <image file name> 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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment