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(a)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));
+}
--
1.6.5