This mainboard uses external pins for banking the ROM chip, which seems to be impossible to do with the "internal" programmer, yet I had to clone most of the init stuff from internal.c . Hints for a clean implementation will be appreciated. --- Makefile | 2 +- flash.h | 11 ++++++ flashrom.c | 19 ++++++++++ t20.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletions(-) create mode 100644 t20.c
diff --git a/Makefile b/Makefile index 501f65a..cdd45d1 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,7 @@ CONFIG_PRINT_WIKI ?= no
ifeq ($(CONFIG_INTERNAL), yes) FEATURE_CFLAGS += -D'INTERNAL_SUPPORT=1' -PROGRAMMER_OBJS += chipset_enable.o board_enable.o cbtable.o it87spi.o ichspi.o sb600spi.o wbsio_spi.o +PROGRAMMER_OBJS += chipset_enable.o board_enable.o cbtable.o it87spi.o ichspi.o sb600spi.o t20.o wbsio_spi.o NEED_PCI := yes endif
diff --git a/flash.h b/flash.h index 9a25c70..77b0d48 100644 --- a/flash.h +++ b/flash.h @@ -58,6 +58,9 @@ enum programmer { #if INTERNAL_SUPPORT == 1 PROGRAMMER_IT87SPI, #endif +#if INTERNAL_SUPPORT == 1 + PROGRAMMER_TPT20, +#endif #if FT2232_SPI_SUPPORT == 1 PROGRAMMER_FT2232SPI, #endif @@ -435,6 +438,14 @@ uint8_t drkaiser_chip_readb(const chipaddr addr); extern struct pcidev_status drkaiser_pcidev[]; #endif
+/* t20.c */ +#if INTERNAL_SUPPORT == 1 +int t20_init(void); +int t20_shutdown(void); +void t20_chip_writeb(uint8_t val, chipaddr addr); +uint8_t t20_chip_readb(const chipaddr addr); +#endif + /* satasii.c */ #if SATASII_SUPPORT == 1 int satasii_init(void); diff --git a/flashrom.c b/flashrom.c index db44c2f..7f05eeb 100644 --- a/flashrom.c +++ b/flashrom.c @@ -226,6 +226,25 @@ const struct programmer_entry programmer_table[] = { }, #endif
+#if INTERNAL_SUPPORT == 1 + { + .name = "t20", + .init = t20_init, + .shutdown = t20_shutdown, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .chip_readb = t20_chip_readb, + .chip_readw = fallback_chip_readw, + .chip_readl = fallback_chip_readl, + .chip_readn = fallback_chip_readn, + .chip_writeb = t20_chip_writeb, + .chip_writew = fallback_chip_writew, + .chip_writel = fallback_chip_writel, + .chip_writen = fallback_chip_writen, + .delay = internal_delay, + }, +#endif + #if FT2232_SPI_SUPPORT == 1 { .name = "ft2232spi", diff --git a/t20.c b/t20.c new file mode 100644 index 0000000..d6841cc --- /dev/null +++ b/t20.c @@ -0,0 +1,108 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2010 Michael Karcher flashrom@mkarcher.dialup.fu-berlin.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Base address of register IND1 in the Field IMGA in the DSDT */ +#define IMGA1_BASE 0x15EE + +#include "flash.h" + +static uint8_t *t20_base; + +#define MAX_COUNT 20 + +static void imga1_mask(uint8_t index, uint8_t mask, uint8_t value) +{ + uint16_t temp; + int count = 0; + /* Be careful, as ACPI might use these registers too, so check + that the index is still OK. */ + do { + OUTB(index, IMGA1_BASE); + temp = INW(IMGA1_BASE); + } + while ((temp & 0xff) != index && ++count < MAX_COUNT); + if(count == MAX_COUNT) + { + printf("error: IMGA1 index stuck at %02x\n", temp & 0xff); + return; + } + temp &= ~(mask << 8); + temp |= (value & mask) << 8; + OUTW(temp, IMGA1_BASE); +} + +int t20_init(void) +{ + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); /* We want to get the list of devices */ + get_io_perms(); + /* ID of the graphics chip in T20/T21/T22. The mainboards are + identical in these models */ + if (!pci_card_find(0x5333, 0x8c12, 0x1014, 0x017f)) + { + msg_perr("This is not a ThinkPad T20/T21/T22\n"); + return 1; + } + if (chipset_flash_enable() == -2) { + printf("WARNING: No chipset found. Flash detection " + "will most likely fail.\n"); + } + + imga1_mask(0, 4, 4); /* Enable flash writes */ + t20_base = physmap("IBM T20 mainboard flash", 0xFFFE0000, 0x20000); + buses_supported = CHIP_BUSTYPE_PARALLEL; + return 0; +} + +int t20_shutdown(void) +{ + physunmap(t20_base, 0x20000); + imga1_mask(0, 4, 4); /* Disable flash writes */ + release_io_perms(); + pci_cleanup(pacc); + return 0; +} + +static unsigned int currentbank = -1U; + +static void switchtobank(unsigned int banknum) +{ + if (banknum > 3) + { + msg_perr("Bad bank number %d\n", banknum); + return; + } + if(banknum != currentbank) + imga1_mask(0, 3, banknum); + currentbank = banknum; +} + +void t20_chip_writeb(uint8_t val, chipaddr addr) +{ + switchtobank(addr >> 17); + mmio_writeb(val, t20_base + (addr & 0x1FFFF)); +} + +uint8_t t20_chip_readb(chipaddr addr) +{ + switchtobank(addr >> 17); + return mmio_readb(t20_base + (addr & 0x1FFFF)); +}