diff options
author | Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at> | 2013-10-25 00:33:37 +0000 |
---|---|---|
committer | Stefan Tauner <stefan.tauner@alumni.tuwien.ac.at> | 2013-10-25 00:33:37 +0000 |
commit | 92d6a861ce0e4727c911fd8d6aeba312b805f765 (patch) | |
tree | ae9e39df5b092aea28d5193054cc66a53525f233 | |
parent | 8d7ec2a209073ce4a403378fa6c828397f5011e9 (diff) | |
download | ast2050-flashrom-92d6a861ce0e4727c911fd8d6aeba312b805f765.zip ast2050-flashrom-92d6a861ce0e4727c911fd8d6aeba312b805f765.tar.gz |
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>
-rw-r--r-- | chipset_enable.c | 412 | ||||
-rw-r--r-- | ichspi.c | 61 | ||||
-rw-r--r-- | programmer.h | 12 |
3 files changed, 214 insertions, 271 deletions
diff --git a/chipset_enable.c b/chipset_enable.c index c85db73..3fd06fb 100644 --- a/chipset_enable.c +++ b/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); + + /* Tunnel Creek has a cache disable at bit 2 of the lowest BIOS_CNTL byte. */ + if (ich_generation == CHIPSET_TUNNEL_CREEK) + wanted |= (1 << 2); - /* Set BIOS Write Enable */ - wanted |= (1 << 0); + 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) -{ - 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) +static int enable_flash_ich_fwh_decode(struct pci_dev *dev, 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) -{ - return enable_flash_ich_4e(dev, name, CHIPSET_ICH2); -} - -static int enable_flash_ich3(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) +static int enable_flash_ich0(struct pci_dev *dev, const char *name) { - return enable_flash_ich_4e(dev, name, CHIPSET_ICH4); + return enable_flash_ich_fwh(dev, CHIPSET_ICH, 0x4e); } -static int enable_flash_ich5(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_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"); + } + + /* 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; - /* 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; - } + /* 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}, @@ -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); @@ -529,7 +531,7 @@ static int program_opcodes(OPCODES *op, int enable_undo) opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8); } - /*Program Allowable Opcodes 4 - 7 */ + /* Program Allowable Opcodes 4 - 7 */ opmenu[1] = 0; for (a = 4; a < 8; a++) { opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8); @@ -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; } diff --git a/programmer.h b/programmer.h index ef96c9e..0c51f58 100644 --- a/programmer.h +++ b/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 */ |