mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-26 22:52:34 +02:00
Refactor Intel Chipset Enables
- Combine enable_flash_ich_4e() and enable_flash_ich_dc() to enable_flash_ich_fwh(). - Remove unjustified (chipset) name parameters from various enable_flash_ich* functions. - Make Poulsbo and Tunnel Creek use generic enables by refining existing functions to work with them, including everything in ichspi.c. - Refactor enable_flash_ich_fwh_decode() to be called unconditionally for all chipsets. - Add support for Intel Atom Centerton (S12x0). - Recombine ICH2/3/4/5 to CHIPSET_ICH2345 because we treat them equally anyway. - Move spibar handling out of ich_init_spi() into enable_flash_ich_spi() - Various small cleanups. Corresponding to flashrom svn r1761. Signed-off-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at> Acked-by: Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at>
This commit is contained in:
parent
8d7ec2a209
commit
92d6a861ce
412
chipset_enable.c
412
chipset_enable.c
@ -260,20 +260,44 @@ static int enable_flash_piix4(struct pci_dev *dev, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet"
|
||||
* http://download.intel.com/design/chipsets/datashts/30701303.pdf
|
||||
*/
|
||||
static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_cntl)
|
||||
/* Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Poulsbo, Tunnel Creek and other Atom
|
||||
* chipsets/SoCs it is even 32b, but just treating it as 8 bit wide seems to work fine in practice. */
|
||||
static int enable_flash_ich_bios_cntl(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
|
||||
{
|
||||
uint8_t old, new, wanted;
|
||||
|
||||
/*
|
||||
* Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Tunnel Creek it is even 32b, but
|
||||
* just treating it as 8 bit wide seems to work fine in practice.
|
||||
*/
|
||||
wanted = old = pci_read_byte(dev, bios_cntl);
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH_UNKNOWN:
|
||||
return ERROR_FATAL;
|
||||
/* Non-SPI-capable */
|
||||
case CHIPSET_ICH:
|
||||
case CHIPSET_ICH2345:
|
||||
break;
|
||||
/* Atom chipsets are special: The second byte of BIOS_CNTL (D9h) contains a prefetch bit similar to what
|
||||
* other SPI-capable chipsets have at DCh.
|
||||
* The Tunnel Creek datasheet contains a lot of details about the SPI controller, among other things it
|
||||
* mentions that the prefetching and caching does only happen for direct memory reads.
|
||||
* Therefore - at least for Tunnel Creek - it should not matter to flashrom because we use the
|
||||
* programmed access only and not memory mapping. */
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_POULSBO:
|
||||
case CHIPSET_CENTERTON:
|
||||
old = pci_read_byte(dev, bios_cntl + 1);
|
||||
msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis");
|
||||
break;
|
||||
case CHIPSET_ICH7:
|
||||
default: /* Future version might behave the same */
|
||||
old = (pci_read_byte(dev, bios_cntl) >> 2) & 0x3;
|
||||
msg_pdbg("SPI Read Configuration: ");
|
||||
if (old == 3)
|
||||
msg_pdbg("invalid prefetching/caching settings, ");
|
||||
else
|
||||
msg_pdbg("prefetching %sabled, caching %sabled, ",
|
||||
(old & 0x2) ? "en" : "dis",
|
||||
(old & 0x1) ? "dis" : "en");
|
||||
}
|
||||
|
||||
wanted = old = pci_read_byte(dev, bios_cntl);
|
||||
/*
|
||||
* Quote from the 6 Series datasheet (Document Number: 324645-004):
|
||||
* "Bit 5: SMM BIOS Write Protect Disable (SMM_BWP)
|
||||
@ -283,11 +307,23 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_
|
||||
*
|
||||
* Try to unset it in any case.
|
||||
* It won't hurt and makes sense in some cases according to Stefan Reinauer.
|
||||
*
|
||||
* At least in Centerton aforementioned bit is located at bit 7. It is unspecified in all other Atom
|
||||
* and Desktop chipsets before Ibex Peak/5 Series, but we reset bit 5 anyway.
|
||||
*/
|
||||
wanted &= ~(1 << 5);
|
||||
int smm_bwp_bit;
|
||||
if (ich_generation == CHIPSET_CENTERTON)
|
||||
smm_bwp_bit = 7;
|
||||
else
|
||||
smm_bwp_bit = 5;
|
||||
wanted &= ~(1 << smm_bwp_bit);
|
||||
|
||||
/* Set BIOS Write Enable */
|
||||
wanted |= (1 << 0);
|
||||
/* Tunnel Creek has a cache disable at bit 2 of the lowest BIOS_CNTL byte. */
|
||||
if (ich_generation == CHIPSET_TUNNEL_CREEK)
|
||||
wanted |= (1 << 2);
|
||||
|
||||
wanted |= (1 << 0); /* Set BIOS Write Enable */
|
||||
wanted &= ~(1 << 1); /* Disable lock (futile) */
|
||||
|
||||
/* Only write the register if it's necessary */
|
||||
if (wanted != old) {
|
||||
@ -299,76 +335,77 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_
|
||||
msg_pdbg("\nBIOS_CNTL = 0x%02x: ", new);
|
||||
msg_pdbg("BIOS Lock Enable: %sabled, ", (new & (1 << 1)) ? "en" : "dis");
|
||||
msg_pdbg("BIOS Write Enable: %sabled\n", (new & (1 << 0)) ? "en" : "dis");
|
||||
if (new & (1 << 5))
|
||||
if (new & (1 << smm_bwp_bit))
|
||||
msg_pwarn("Warning: BIOS region SMM protection is enabled!\n");
|
||||
|
||||
|
||||
if (new != wanted)
|
||||
msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x on %s failed.\n"
|
||||
"New value is 0x%02x.\n", bios_cntl, old, wanted, name, new);
|
||||
msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n"
|
||||
"New value is 0x%02x.\n", bios_cntl, old, wanted, new);
|
||||
|
||||
/* Return an error if we could not set the write enable */
|
||||
/* Return an error if we could not set the write enable only. */
|
||||
if (!(new & (1 << 0)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_flash_ich0(struct pci_dev *dev, const char *name)
|
||||
static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich_generation)
|
||||
{
|
||||
internal_buses_supported = BUS_FWH;
|
||||
/* FIXME: Make this use enable_flash_ich_4e() too and add IDSEL support. Unlike later chipsets,
|
||||
* ICH and ICH-0 do only support mapping of the top-most 4MB and therefore do only feature
|
||||
* FWH_DEC_EN (E3h, different default too) and FWH_SEL (E8h). */
|
||||
return enable_flash_ich(dev, name, 0x4e);
|
||||
}
|
||||
|
||||
static int enable_flash_ich_fwh_decode(struct pci_dev *dev, const char *name, enum ich_chipset ich_generation)
|
||||
{
|
||||
uint32_t fwh_conf;
|
||||
uint8_t fwh_sel1, fwh_sel2, fwh_dec_en_lo, fwh_dec_en_hi;
|
||||
int i, tmp;
|
||||
char *idsel = NULL;
|
||||
int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0;
|
||||
int contiguous = 1;
|
||||
|
||||
if (ich_generation >= CHIPSET_ICH6) {
|
||||
fwh_sel1 = 0xd0;
|
||||
fwh_sel2 = 0xd4;
|
||||
fwh_dec_en_lo = 0xd8;
|
||||
fwh_dec_en_hi = 0xd9;
|
||||
} else if (ich_generation >= CHIPSET_ICH2) {
|
||||
uint8_t fwh_sel1 = 0, fwh_sel2 = 0, fwh_dec_en_lo = 0, fwh_dec_en_hi = 0; /* silence compilers */
|
||||
bool implemented = 0;
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH:
|
||||
/* FIXME: Unlike later chipsets, ICH and ICH-0 do only support mapping of the top-most 4MB
|
||||
* and therefore do only feature FWH_DEC_EN (E3h, different default too) and FWH_SEL (E8h). */
|
||||
break;
|
||||
case CHIPSET_ICH2345:
|
||||
fwh_sel1 = 0xe8;
|
||||
fwh_sel2 = 0xee;
|
||||
fwh_dec_en_lo = 0xf0;
|
||||
fwh_dec_en_hi = 0xe3;
|
||||
} else {
|
||||
msg_perr("Error: FWH decode setting not implemented.\n");
|
||||
return ERROR_FATAL;
|
||||
implemented = 1;
|
||||
break;
|
||||
case CHIPSET_POULSBO:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
/* FIXME: Similar to ICH and ICH-0, Tunnel Creek and Poulsbo do only feature one register each,
|
||||
* FWH_DEC_EN (D7h) and FWH_SEL (D0h). */
|
||||
break;
|
||||
case CHIPSET_CENTERTON:
|
||||
/* FIXME: Similar to above FWH_DEC_EN (D4h) and FWH_SEL (D0h). */
|
||||
break;
|
||||
case CHIPSET_ICH6:
|
||||
case CHIPSET_ICH7:
|
||||
default: /* Future version might behave the same */
|
||||
fwh_sel1 = 0xd0;
|
||||
fwh_sel2 = 0xd4;
|
||||
fwh_dec_en_lo = 0xd8;
|
||||
fwh_dec_en_hi = 0xd9;
|
||||
implemented = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
idsel = extract_programmer_param("fwh_idsel");
|
||||
char *idsel = extract_programmer_param("fwh_idsel");
|
||||
if (idsel && strlen(idsel)) {
|
||||
uint64_t fwh_idsel_old, fwh_idsel;
|
||||
if (!implemented) {
|
||||
msg_perr("Error: fwh_idsel= specified, but (yet) unsupported on this chipset.\n");
|
||||
goto idsel_garbage_out;
|
||||
}
|
||||
errno = 0;
|
||||
/* Base 16, nothing else makes sense. */
|
||||
fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16);
|
||||
uint64_t fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16);
|
||||
if (errno) {
|
||||
msg_perr("Error: fwh_idsel= specified, but value could "
|
||||
"not be converted.\n");
|
||||
msg_perr("Error: fwh_idsel= specified, but value could not be converted.\n");
|
||||
goto idsel_garbage_out;
|
||||
}
|
||||
if (fwh_idsel & 0xffff000000000000ULL) {
|
||||
msg_perr("Error: fwh_idsel= specified, but value had "
|
||||
"unused bits set.\n");
|
||||
msg_perr("Error: fwh_idsel= specified, but value had unused bits set.\n");
|
||||
goto idsel_garbage_out;
|
||||
}
|
||||
fwh_idsel_old = pci_read_long(dev, fwh_sel1);
|
||||
uint64_t fwh_idsel_old = pci_read_long(dev, fwh_sel1);
|
||||
fwh_idsel_old <<= 16;
|
||||
fwh_idsel_old |= pci_read_word(dev, fwh_sel2);
|
||||
msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to "
|
||||
"0x%012" PRIx64 " for top 16 MB.", fwh_idsel_old,
|
||||
fwh_idsel);
|
||||
msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to 0x%012" PRIx64 " for top 16 MB.",
|
||||
fwh_idsel_old, fwh_idsel);
|
||||
rpci_write_long(dev, fwh_sel1, (fwh_idsel >> 16) & 0xffffffff);
|
||||
rpci_write_word(dev, fwh_sel2, fwh_idsel & 0xffff);
|
||||
/* FIXME: Decode settings are not changed. */
|
||||
@ -380,15 +417,23 @@ idsel_garbage_out:
|
||||
}
|
||||
free(idsel);
|
||||
|
||||
if (!implemented) {
|
||||
msg_pdbg2("FWH IDSEL handling is not implemented on this chipset.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore all legacy ranges below 1 MB.
|
||||
* We currently only support flashing the chip which responds to
|
||||
* IDSEL=0. To support IDSEL!=0, flashbase and decode size calculations
|
||||
* have to be adjusted.
|
||||
*/
|
||||
int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0;
|
||||
bool contiguous = 1;
|
||||
uint32_t fwh_conf = pci_read_long(dev, fwh_sel1);
|
||||
int i;
|
||||
/* FWH_SEL1 */
|
||||
fwh_conf = pci_read_long(dev, fwh_sel1);
|
||||
for (i = 7; i >= 0; i--) {
|
||||
tmp = (fwh_conf >> (i * 4)) & 0xf;
|
||||
int tmp = (fwh_conf >> (i * 4)) & 0xf;
|
||||
msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
|
||||
(0x1ff8 + i) * 0x80000,
|
||||
(0x1ff0 + i) * 0x80000,
|
||||
@ -402,7 +447,7 @@ idsel_garbage_out:
|
||||
/* FWH_SEL2 */
|
||||
fwh_conf = pci_read_word(dev, fwh_sel2);
|
||||
for (i = 3; i >= 0; i--) {
|
||||
tmp = (fwh_conf >> (i * 4)) & 0xf;
|
||||
int tmp = (fwh_conf >> (i * 4)) & 0xf;
|
||||
msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x",
|
||||
(0xff4 + i) * 0x100000,
|
||||
(0xff0 + i) * 0x100000,
|
||||
@ -419,7 +464,7 @@ idsel_garbage_out:
|
||||
fwh_conf <<= 8;
|
||||
fwh_conf |= pci_read_byte(dev, fwh_dec_en_lo);
|
||||
for (i = 7; i >= 0; i--) {
|
||||
tmp = (fwh_conf >> (i + 0x8)) & 0x1;
|
||||
int tmp = (fwh_conf >> (i + 0x8)) & 0x1;
|
||||
msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled",
|
||||
(0x1ff8 + i) * 0x80000,
|
||||
(0x1ff0 + i) * 0x80000,
|
||||
@ -431,7 +476,7 @@ idsel_garbage_out:
|
||||
}
|
||||
}
|
||||
for (i = 3; i >= 0; i--) {
|
||||
tmp = (fwh_conf >> i) & 0x1;
|
||||
int tmp = (fwh_conf >> i) & 0x1;
|
||||
msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled",
|
||||
(0xff4 + i) * 0x100000,
|
||||
(0xff0 + i) * 0x100000,
|
||||
@ -448,146 +493,56 @@ idsel_garbage_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_flash_ich_4e(struct pci_dev *dev, const char *name, enum ich_chipset ich_generation)
|
||||
static int enable_flash_ich_fwh(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Configure FWH IDSEL decoder maps. */
|
||||
if ((err = enable_flash_ich_fwh_decode(dev, name, ich_generation)) != 0)
|
||||
if ((err = enable_flash_ich_fwh_decode(dev, ich_generation)) != 0)
|
||||
return err;
|
||||
|
||||
internal_buses_supported = BUS_FWH;
|
||||
return enable_flash_ich(dev, name, 0x4e);
|
||||
return enable_flash_ich_bios_cntl(dev, ich_generation, bios_cntl);
|
||||
}
|
||||
|
||||
static int enable_flash_ich2(struct pci_dev *dev, const char *name)
|
||||
static int enable_flash_ich0(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_4e(dev, name, CHIPSET_ICH2);
|
||||
return enable_flash_ich_fwh(dev, CHIPSET_ICH, 0x4e);
|
||||
}
|
||||
|
||||
static int enable_flash_ich3(struct pci_dev *dev, const char *name)
|
||||
static int enable_flash_ich2345(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_4e(dev, name, CHIPSET_ICH3);
|
||||
}
|
||||
|
||||
static int enable_flash_ich4(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_4e(dev, name, CHIPSET_ICH4);
|
||||
}
|
||||
|
||||
static int enable_flash_ich5(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_4e(dev, name, CHIPSET_ICH5);
|
||||
}
|
||||
|
||||
static int enable_flash_ich_dc(struct pci_dev *dev, const char *name, enum ich_chipset ich_generation)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Configure FWH IDSEL decoder maps. */
|
||||
if ((err = enable_flash_ich_fwh_decode(dev, name, ich_generation)) != 0)
|
||||
return err;
|
||||
|
||||
/* If we're called by enable_flash_ich_dc_spi, it will override
|
||||
* internal_buses_supported anyway.
|
||||
*/
|
||||
internal_buses_supported = BUS_FWH;
|
||||
return enable_flash_ich(dev, name, 0xdc);
|
||||
return enable_flash_ich_fwh(dev, CHIPSET_ICH2345, 0x4e);
|
||||
}
|
||||
|
||||
static int enable_flash_ich6(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc(dev, name, CHIPSET_ICH6);
|
||||
return enable_flash_ich_fwh(dev, CHIPSET_ICH6, 0xdc);
|
||||
}
|
||||
|
||||
static int enable_flash_poulsbo(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
uint16_t old, new;
|
||||
int err;
|
||||
|
||||
if ((err = enable_flash_ich(dev, name, 0xd8)) != 0)
|
||||
return err;
|
||||
|
||||
old = pci_read_byte(dev, 0xd9);
|
||||
msg_pdbg("BIOS Prefetch Enable: %sabled, ",
|
||||
(old & 1) ? "en" : "dis");
|
||||
new = old & ~1;
|
||||
|
||||
if (new != old)
|
||||
rpci_write_byte(dev, 0xd9, new);
|
||||
|
||||
internal_buses_supported = BUS_FWH;
|
||||
return 0;
|
||||
return enable_flash_ich_fwh(dev, CHIPSET_POULSBO, 0xd8);
|
||||
}
|
||||
|
||||
static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name)
|
||||
static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
|
||||
{
|
||||
uint16_t old, new;
|
||||
uint32_t tmp, bnt;
|
||||
void *rcrb;
|
||||
int ret;
|
||||
|
||||
/* Enable Flash Writes */
|
||||
ret = enable_flash_ich(dev, name, 0xd8);
|
||||
if (ret == ERROR_FATAL)
|
||||
return ret;
|
||||
|
||||
/* Make sure BIOS prefetch mechanism is disabled */
|
||||
old = pci_read_byte(dev, 0xd9);
|
||||
msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis");
|
||||
new = old & ~1;
|
||||
if (new != old)
|
||||
rpci_write_byte(dev, 0xd9, new);
|
||||
|
||||
/* Get physical address of Root Complex Register Block */
|
||||
tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
|
||||
msg_pdbg("\nRoot Complex Register Block address = 0x%x\n", tmp);
|
||||
|
||||
/* Map RCBA to virtual memory */
|
||||
rcrb = rphysmap("ICH RCRB", tmp, 0x4000);
|
||||
if (rcrb == ERROR_PTR)
|
||||
return ERROR_FATAL;
|
||||
|
||||
/* Test Boot BIOS Strap Status */
|
||||
bnt = mmio_readl(rcrb + 0x3410);
|
||||
if (bnt & 0x02) {
|
||||
/* If strapped to LPC, no SPI initialization is required */
|
||||
internal_buses_supported = BUS_FWH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This adds BUS_SPI */
|
||||
if (ich_init_spi(dev, tmp, rcrb, 7) != 0) {
|
||||
if (!ret)
|
||||
ret = ERROR_NONFATAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
|
||||
enum ich_chipset ich_generation)
|
||||
{
|
||||
int ret, ret_spi;
|
||||
uint8_t bbs, buc;
|
||||
uint32_t tmp, gcs;
|
||||
void *rcrb;
|
||||
const char *const *straps_names;
|
||||
|
||||
static const char *const straps_names_EP80579[] = { "SPI", "reserved", "reserved", "LPC" };
|
||||
static const char *const straps_names_ich7_nm10[] = { "reserved", "SPI", "PCI", "LPC" };
|
||||
static const char *const straps_names_tunnel_creek[] = { "SPI", "LPC" };
|
||||
static const char *const straps_names_ich8910[] = { "SPI", "SPI", "PCI", "LPC" };
|
||||
static const char *const straps_names_pch567[] = { "LPC", "reserved", "PCI", "SPI" };
|
||||
static const char *const straps_names_pch8[] = { "LPC", "reserved", "reserved", "SPI" };
|
||||
static const char *const straps_names_pch8_lp[] = { "SPI", "LPC", "unknown", "unknown" };
|
||||
static const char *const straps_names_pch8_lp[] = { "SPI", "LPC" };
|
||||
static const char *const straps_names_unknown[] = { "unknown", "unknown", "unknown", "unknown" };
|
||||
|
||||
const char *const *straps_names;
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH7:
|
||||
/* EP80579 may need further changes, but this is the least
|
||||
* intrusive way to get correct BOOT Strap printing without
|
||||
* changing the rest of its code path). */
|
||||
if (strcmp(name, "EP80579") == 0)
|
||||
if (dev->device_id == 0x5031)
|
||||
straps_names = straps_names_EP80579;
|
||||
else
|
||||
straps_names = straps_names_ich7_nm10;
|
||||
@ -597,6 +552,9 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
|
||||
case CHIPSET_ICH10:
|
||||
straps_names = straps_names_ich8910;
|
||||
break;
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
straps_names = straps_names_tunnel_creek;
|
||||
break;
|
||||
case CHIPSET_5_SERIES_IBEX_PEAK:
|
||||
case CHIPSET_6_SERIES_COUGAR_POINT:
|
||||
case CHIPSET_7_SERIES_PANTHER_POINT:
|
||||
@ -609,35 +567,33 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
|
||||
straps_names = straps_names_pch8_lp;
|
||||
break;
|
||||
case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet
|
||||
case CHIPSET_CENTERTON: // FIXME: Datasheet does not mention GCS at all
|
||||
straps_names = straps_names_unknown;
|
||||
break;
|
||||
default:
|
||||
msg_gerr("%s: unknown ICH generation. Please report!\n",
|
||||
__func__);
|
||||
msg_gerr("%s: unknown ICH generation. Please report!\n", __func__);
|
||||
straps_names = straps_names_unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable Flash Writes */
|
||||
ret = enable_flash_ich_dc(dev, name, ich_generation);
|
||||
if (ret == ERROR_FATAL)
|
||||
return ret;
|
||||
|
||||
/* Get physical address of Root Complex Register Block */
|
||||
tmp = pci_read_long(dev, 0xf0) & 0xffffc000;
|
||||
msg_pdbg("Root Complex Register Block address = 0x%x\n", tmp);
|
||||
uint32_t rcra = pci_read_long(dev, 0xf0) & 0xffffc000;
|
||||
msg_pdbg("Root Complex Register Block address = 0x%x\n", rcra);
|
||||
|
||||
/* Map RCBA to virtual memory */
|
||||
rcrb = rphysmap("ICH RCRB", tmp, 0x4000);
|
||||
void *rcrb = rphysmap("ICH RCRB", rcra, 0x4000);
|
||||
if (rcrb == ERROR_PTR)
|
||||
return ERROR_FATAL;
|
||||
|
||||
gcs = mmio_readl(rcrb + 0x3410);
|
||||
uint32_t gcs = mmio_readl(rcrb + 0x3410);
|
||||
msg_pdbg("GCS = 0x%x: ", gcs);
|
||||
msg_pdbg("BIOS Interface Lock-Down: %sabled, ",
|
||||
(gcs & 0x1) ? "en" : "dis");
|
||||
msg_pdbg("BIOS Interface Lock-Down: %sabled, ", (gcs & 0x1) ? "en" : "dis");
|
||||
|
||||
uint8_t bbs;
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
bbs = (gcs >> 1) & 0x1;
|
||||
break;
|
||||
case CHIPSET_8_SERIES_LYNX_POINT_LP:
|
||||
case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet
|
||||
/* Lynx Point LP uses a single bit for GCS */
|
||||
@ -650,91 +606,110 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name,
|
||||
}
|
||||
msg_pdbg("Boot BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]);
|
||||
|
||||
buc = mmio_readb(rcrb + 0x3414);
|
||||
msg_pdbg("Top Swap : %s\n",
|
||||
(buc & 1) ? "enabled (A16 inverted)" : "not enabled");
|
||||
if (ich_generation != CHIPSET_TUNNEL_CREEK && ich_generation != CHIPSET_CENTERTON) {
|
||||
uint8_t buc = mmio_readb(rcrb + 0x3414);
|
||||
msg_pdbg("Top Swap : %s\n", (buc & 1) ? "enabled (A16(+) inverted)" : "not enabled");
|
||||
}
|
||||
|
||||
/* It seems the ICH7 does not support SPI and LPC chips at the same
|
||||
* time. At least not with our current code. So we prevent searching
|
||||
* on ICH7 when the southbridge is strapped to LPC
|
||||
*/
|
||||
internal_buses_supported = BUS_FWH;
|
||||
if (ich_generation == CHIPSET_ICH7) {
|
||||
if (bbs == 0x03) {
|
||||
/* If strapped to LPC, no further SPI initialization is
|
||||
* required. */
|
||||
return ret;
|
||||
} else {
|
||||
/* Disable LPC/FWH if strapped to PCI or SPI */
|
||||
internal_buses_supported = BUS_NONE;
|
||||
}
|
||||
/* Handle FWH-related parameters and initialization */
|
||||
int ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl);
|
||||
if (ret_fwh == ERROR_FATAL)
|
||||
return ret_fwh;
|
||||
|
||||
/* SPIBAR is at RCRB+0x3020 for ICH[78], Tunnel Creek and Centerton, and RCRB+0x3800 for ICH9. */
|
||||
uint16_t spibar_offset;
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH_UNKNOWN:
|
||||
return ERROR_FATAL;
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_ICH8:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_CENTERTON:
|
||||
spibar_offset = 0x3020;
|
||||
break;
|
||||
case CHIPSET_ICH9:
|
||||
default: /* Future version might behave the same */
|
||||
spibar_offset = 0x3800;
|
||||
break;
|
||||
}
|
||||
msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " + 0x%04x\n", PRIxPTR_WIDTH, (uintptr_t)rcrb, spibar_offset);
|
||||
void *spibar = rcrb + spibar_offset;
|
||||
|
||||
/* This adds BUS_SPI */
|
||||
ret_spi = ich_init_spi(dev, tmp, rcrb, ich_generation);
|
||||
int ret_spi = ich_init_spi(dev, spibar, ich_generation);
|
||||
if (ret_spi == ERROR_FATAL)
|
||||
return ret_spi;
|
||||
|
||||
if (ret || ret_spi)
|
||||
ret = ERROR_NONFATAL;
|
||||
if (ret_fwh || ret_spi)
|
||||
return ERROR_NONFATAL;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_spi(dev, CHIPSET_TUNNEL_CREEK, 0xd8);
|
||||
}
|
||||
|
||||
static int enable_flash_s12x0(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_spi(dev, CHIPSET_CENTERTON, 0xd8);
|
||||
}
|
||||
|
||||
static int enable_flash_ich7(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH7);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_ICH7, 0xdc);
|
||||
}
|
||||
|
||||
static int enable_flash_ich8(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH8);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_ICH8, 0xdc);
|
||||
}
|
||||
|
||||
static int enable_flash_ich9(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH9);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_ICH9, 0xdc);
|
||||
}
|
||||
|
||||
static int enable_flash_ich10(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH10);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_ICH10, 0xdc);
|
||||
}
|
||||
|
||||
/* Ibex Peak aka. 5 series & 3400 series */
|
||||
static int enable_flash_pch5(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_5_SERIES_IBEX_PEAK);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_5_SERIES_IBEX_PEAK, 0xdc);
|
||||
}
|
||||
|
||||
/* Cougar Point aka. 6 series & c200 series */
|
||||
static int enable_flash_pch6(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_6_SERIES_COUGAR_POINT);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_6_SERIES_COUGAR_POINT, 0xdc);
|
||||
}
|
||||
|
||||
/* Panther Point aka. 7 series */
|
||||
static int enable_flash_pch7(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_7_SERIES_PANTHER_POINT);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_7_SERIES_PANTHER_POINT, 0xdc);
|
||||
}
|
||||
|
||||
/* Lynx Point aka. 8 series */
|
||||
static int enable_flash_pch8(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT, 0xdc);
|
||||
}
|
||||
|
||||
/* Lynx Point aka. 8 series low-power */
|
||||
/* Lynx Point LP aka. 8 series low-power */
|
||||
static int enable_flash_pch8_lp(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT_LP);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT_LP, 0xdc);
|
||||
}
|
||||
|
||||
/* Wellsburg (for Haswell-EP Xeons) */
|
||||
static int enable_flash_pch8_wb(struct pci_dev *dev, const char *name)
|
||||
{
|
||||
return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_WELLSBURG);
|
||||
return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_WELLSBURG, 0xdc);
|
||||
}
|
||||
|
||||
static int via_no_byte_merge(struct pci_dev *dev, const char *name)
|
||||
@ -1503,6 +1478,7 @@ const struct penable chipset_enables[] = {
|
||||
{0x1166, 0x0200, OK, "Broadcom", "OSB4", enable_flash_osb4},
|
||||
{0x1166, 0x0205, OK, "Broadcom", "HT-1000", enable_flash_ht1000},
|
||||
{0x17f3, 0x6030, OK, "RDC", "R8610/R3210", enable_flash_rdc_r8610},
|
||||
{0x8086, 0x0c60, NT, "Intel", "S12x0", enable_flash_s12x0},
|
||||
{0x8086, 0x122e, OK, "Intel", "PIIX", enable_flash_piix4},
|
||||
{0x8086, 0x1234, NT, "Intel", "MPIIX", enable_flash_piix4},
|
||||
{0x8086, 0x1c44, OK, "Intel", "Z68", enable_flash_pch6},
|
||||
@ -1541,15 +1517,15 @@ const struct penable chipset_enables[] = {
|
||||
{0x8086, 0x2390, NT, "Intel", "Coleto Creek", enable_flash_pch7},
|
||||
{0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich0},
|
||||
{0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich0},
|
||||
{0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich2},
|
||||
{0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich2},
|
||||
{0x8086, 0x2450, NT, "Intel", "C-ICH", enable_flash_ich2},
|
||||
{0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich3},
|
||||
{0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich3},
|
||||
{0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich4},
|
||||
{0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich4},
|
||||
{0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich5},
|
||||
{0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich5},
|
||||
{0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich2345},
|
||||
{0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich2345},
|
||||
{0x8086, 0x2450, NT, "Intel", "C-ICH", enable_flash_ich2345},
|
||||
{0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich2345},
|
||||
{0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich2345},
|
||||
{0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich2345},
|
||||
{0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich2345},
|
||||
{0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich2345},
|
||||
{0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich2345},
|
||||
{0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich6},
|
||||
{0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich6},
|
||||
{0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW", enable_flash_ich6},
|
||||
|
59
ichspi.c
59
ichspi.c
@ -466,6 +466,8 @@ static int generate_opcodes(OPCODES * op)
|
||||
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_CENTERTON:
|
||||
preop = REGREAD16(ICH7_REG_PREOP);
|
||||
optype = REGREAD16(ICH7_REG_OPTYPE);
|
||||
opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
|
||||
@ -538,6 +540,8 @@ static int program_opcodes(OPCODES *op, int enable_undo)
|
||||
msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_CENTERTON:
|
||||
/* Register undo only for enable_undo=1, i.e. first call. */
|
||||
if (enable_undo) {
|
||||
rmmio_valw(ich_spibar + ICH7_REG_PREOP);
|
||||
@ -603,6 +607,8 @@ static void ich_set_bbar(uint32_t min_addr)
|
||||
int bbar_off;
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_CENTERTON:
|
||||
bbar_off = 0x50;
|
||||
break;
|
||||
case CHIPSET_ICH8:
|
||||
@ -975,6 +981,8 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
|
||||
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_CENTERTON:
|
||||
return ich7_run_opcode(op, offset, datalength, data, maxlength);
|
||||
case CHIPSET_ICH8:
|
||||
default: /* Future version might behave the same */
|
||||
@ -1545,12 +1553,10 @@ static const struct opaque_programmer opaque_programmer_ich_hwseq = {
|
||||
.erase = ich_hwseq_block_erase,
|
||||
};
|
||||
|
||||
int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
|
||||
enum ich_chipset ich_gen)
|
||||
int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen)
|
||||
{
|
||||
int i;
|
||||
uint8_t old, new;
|
||||
uint16_t spibar_offset, tmp2;
|
||||
uint16_t tmp2;
|
||||
uint32_t tmp;
|
||||
char *arg;
|
||||
int ich_spi_force = 0;
|
||||
@ -1564,42 +1570,18 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
|
||||
} ich_spi_mode = ich_auto;
|
||||
|
||||
ich_generation = ich_gen;
|
||||
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH_UNKNOWN:
|
||||
return ERROR_FATAL;
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_ICH8:
|
||||
spibar_offset = 0x3020;
|
||||
break;
|
||||
case CHIPSET_ICH9:
|
||||
default: /* Future version might behave the same */
|
||||
spibar_offset = 0x3800;
|
||||
break;
|
||||
}
|
||||
|
||||
/* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */
|
||||
msg_pdbg("SPIBAR = 0x%x + 0x%04x\n", base, spibar_offset);
|
||||
|
||||
/* Assign Virtual Address */
|
||||
ich_spibar = rcrb + spibar_offset;
|
||||
ich_spibar = spibar;
|
||||
|
||||
switch (ich_generation) {
|
||||
case CHIPSET_ICH7:
|
||||
case CHIPSET_TUNNEL_CREEK:
|
||||
case CHIPSET_CENTERTON:
|
||||
msg_pdbg("0x00: 0x%04x (SPIS)\n",
|
||||
mmio_readw(ich_spibar + 0));
|
||||
msg_pdbg("0x02: 0x%04x (SPIC)\n",
|
||||
mmio_readw(ich_spibar + 2));
|
||||
msg_pdbg("0x04: 0x%08x (SPIA)\n",
|
||||
mmio_readl(ich_spibar + 4));
|
||||
for (i = 0; i < 8; i++) {
|
||||
int offs;
|
||||
offs = 8 + (i * 8);
|
||||
msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs,
|
||||
mmio_readl(ich_spibar + offs), i);
|
||||
msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
|
||||
mmio_readl(ich_spibar + offs + 4), i);
|
||||
}
|
||||
ichspi_bbar = mmio_readl(ich_spibar + 0x50);
|
||||
msg_pdbg("0x50: 0x%08x (BBAR)\n",
|
||||
ichspi_bbar);
|
||||
@ -1811,21 +1793,6 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
|
||||
break;
|
||||
}
|
||||
|
||||
old = pci_read_byte(dev, 0xdc);
|
||||
msg_pdbg("SPI Read Configuration: ");
|
||||
new = (old >> 2) & 0x3;
|
||||
switch (new) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
msg_pdbg("prefetching %sabled, caching %sabled, ",
|
||||
(new & 0x2) ? "en" : "dis",
|
||||
(new & 0x1) ? "dis" : "en");
|
||||
break;
|
||||
default:
|
||||
msg_pdbg("invalid prefetching/caching settings, ");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
12
programmer.h
12
programmer.h
@ -557,11 +557,12 @@ int register_spi_programmer(const struct spi_programmer *programmer);
|
||||
/* The following enum is needed by ich_descriptor_tool and ich* code as well as in chipset_enable.c. */
|
||||
enum ich_chipset {
|
||||
CHIPSET_ICH_UNKNOWN,
|
||||
CHIPSET_ICH2 = 2,
|
||||
CHIPSET_ICH3,
|
||||
CHIPSET_ICH4,
|
||||
CHIPSET_ICH5,
|
||||
CHIPSET_ICH,
|
||||
CHIPSET_ICH2345,
|
||||
CHIPSET_ICH6,
|
||||
CHIPSET_POULSBO, /* SCH U* */
|
||||
CHIPSET_TUNNEL_CREEK, /* Atom E6xx */
|
||||
CHIPSET_CENTERTON, /* Atom S1220 S1240 S1260 */
|
||||
CHIPSET_ICH7,
|
||||
CHIPSET_ICH8,
|
||||
CHIPSET_ICH9,
|
||||
@ -577,8 +578,7 @@ enum ich_chipset {
|
||||
/* ichspi.c */
|
||||
#if CONFIG_INTERNAL == 1
|
||||
extern uint32_t ichspi_bbar;
|
||||
int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
|
||||
enum ich_chipset ich_generation);
|
||||
int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_generation);
|
||||
int via_init_spi(struct pci_dev *dev, uint32_t mmio_base);
|
||||
|
||||
/* amd_imc.c */
|
||||
|
Loading…
x
Reference in New Issue
Block a user