[flashrom] [PATCH] Add VIA VT6421A LPC programmer driver.
Stefan Tauner
stefan.tauner at student.tuwien.ac.at
Wed Sep 5 17:02:07 CEST 2012
Thanks to Idwer Vollering for his iterative testing of this code.
Signed-off-by: Jonathan Kollasch <jakllsch at kollasch.net>
Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
---
Now with less WTF... :)
Makefile | 9 +++
atavia.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
flashrom.c | 10 ++++
print.c | 5 ++
programmer.h | 13 ++++-
5 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 atavia.c
diff --git a/Makefile b/Makefile
index 9309ce5..e4b364d 100644
--- a/Makefile
+++ b/Makefile
@@ -334,6 +334,9 @@ CONFIG_SATASII ?= yes
# IMPORTANT: This code is not yet working!
CONFIG_ATAHPT ?= no
+# VIA VT6421A LPC memory support
+CONFIG_ATAVIA ?= yes
+
# Always enable FT2232 SPI dongles for now.
CONFIG_FT2232_SPI ?= yes
@@ -459,6 +462,12 @@ PROGRAMMER_OBJS += atahpt.o
NEED_PCI := yes
endif
+ifeq ($(CONFIG_ATAVIA), yes)
+FEATURE_CFLAGS += -D'CONFIG_ATAVIA=1'
+PROGRAMMER_OBJS += atavia.o
+NEED_PCI := yes
+endif
+
ifeq ($(CONFIG_FT2232_SPI), yes)
FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb")
# This is a totally ugly hack.
diff --git a/atavia.c b/atavia.c
new file mode 100644
index 0000000..6045e2d
--- /dev/null
+++ b/atavia.c
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2011 Jonathan Kollasch <jakllsch at kollasch.net>
+ * Copyright (C) 2012 Stefan Tauner
+ *
+ * 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
+ */
+
+#include <stdbool.h>
+#include "flash.h"
+#include "programmer.h"
+#include "hwaccess.h"
+
+#define PCI_VENDOR_ID_VIA 0x1106
+
+#define VIA_MAX_RETRIES 300
+#define VT6421A_OFF 0
+
+#define BROM_ADDR 0x60
+
+#define BROM_DATA 0x64
+
+#define BROM_ACCESS 0x68
+#define BROM_TRIGGER 0x80
+#define BROM_WRITE 0x40
+#define BROM_SIZE_MASK 0x30
+#define BROM_SIZE_64K 0x00
+#define BROM_SIZE_32K 0x10
+#define BROM_SIZE_16K 0x20
+#define BROM_SIZE_0K 0x30
+#define BROM_BYTE_ENABLE_MASK 0x0f
+
+#define BROM_STATUS 0x69
+#define BROM_ERROR_STATUS 0x80
+
+/* Select the byte we want to access. This is done by clearing the bit corresponding to the byte we want to
+ * access, leaving the others set (yes, really). */
+#define ENABLE_BYTE(address) ((~(1 << ((address) & 3))) & BROM_BYTE_ENABLE_MASK)
+#define BYTE_OFFSET(address) (((addr) & 3) * 8)
+
+const struct pcidev_status ata_via[] = {
+ {PCI_VENDOR_ID_VIA, 0x3249, NT, "VIA", "VT6421A"},
+
+ {},
+};
+
+static const struct par_programmer lpc_programmer_atavia = {
+ .chip_readb = atavia_chip_readb,
+ .chip_readw = fallback_chip_readw,
+ .chip_readl = fallback_chip_readl,
+ .chip_readn = fallback_chip_readn,
+ .chip_writeb = atavia_chip_writeb,
+ .chip_writew = fallback_chip_writew,
+ .chip_writel = fallback_chip_writel,
+ .chip_writen = fallback_chip_writen,
+};
+
+static void atavia_prettyprint_access(uint8_t access)
+{
+ uint8_t bmask = access & BROM_BYTE_ENABLE_MASK;
+ uint8_t size = access & BROM_SIZE_MASK;
+
+ msg_pspew("Accessing byte(s):%s%s%s%s\n",
+ (bmask & (1<<3)) ? " 3" : "",
+ (bmask & (1<<2)) ? " 2" : "",
+ (bmask & (1<<1)) ? " 1" : "",
+ (bmask & (1<<0)) ? " 0" : "");
+ if (size == BROM_SIZE_0K) {
+ msg_pspew("No ROM device found.\n");
+ } else
+ msg_pspew("ROM device with %s kB attached.\n",
+ (size == BROM_SIZE_64K) ? "64" :
+ (size == BROM_SIZE_32K) ? "32" : "16");
+ msg_pspew("Access is a %s.\n", (access & BROM_WRITE) ? "write" : "read");
+ msg_pspew("Device is %s.\n", (access & BROM_TRIGGER) ? "busy" : "ready");
+}
+
+static bool atavia_ready(void)
+{
+ int try;
+ uint8_t access, status;
+ bool ready = false;
+
+ for (try = 0; try < VIA_MAX_RETRIES; try++) {
+ access = pci_read_byte(pcidev_dev, BROM_ACCESS);
+ status = pci_read_byte(pcidev_dev, BROM_STATUS);
+ if (((access & BROM_TRIGGER) == 0) && (status & BROM_ERROR_STATUS) == 0) {
+ ready = true;
+ break;
+ } else {
+ programmer_delay(1);
+ continue;
+ }
+ }
+
+ msg_pdbg2("%s: %s after %d tries (access=0x%02x, status=0x%02x)\n",
+ __func__, ready ? "suceeded" : "failed", try, access, status);
+ atavia_prettyprint_access(access);
+ return ready;
+}
+
+static int atavia_shutdown(void *data)
+{
+ pci_cleanup(pacc);
+ return 0;
+}
+
+int atavia_init(void)
+{
+ uint32_t tmp;
+ if (rget_io_perms())
+ return 1;
+
+ pcidev_init(PCI_ROM_ADDRESS, ata_via); /* Acutally no BAR setup needed at all. */
+
+ if (register_shutdown(atavia_shutdown, NULL))
+ return 1;
+
+ /* Test if a flash chip is attached. */
+ pci_write_long(pcidev_dev, PCI_ROM_ADDRESS, (uint32_t)PCI_ROM_ADDRESS_MASK);
+ programmer_delay(90);
+ tmp = pci_read_long(pcidev_dev, PCI_ROM_ADDRESS);
+ msg_pdbg2("BROM base=0x%08x\n", tmp);
+ if ((tmp & PCI_ROM_ADDRESS_MASK) == 0) {
+ msg_perr("Controller thinks there is no ROM attached.\n");
+ //return 1;
+ }
+
+ if (!atavia_ready()) {
+ msg_perr("Controller not ready.\n");
+ //return 1;
+ }
+
+ atavia_prettyprint_access(pci_read_byte(pcidev_dev, BROM_ACCESS));
+ register_par_programmer(&lpc_programmer_atavia, BUS_LPC);
+
+ return 0;
+}
+
+void atavia_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ addr += VT6421A_OFF;
+ pci_write_long(pcidev_dev, BROM_ADDR, (addr & ~3));
+ pci_write_long(pcidev_dev, BROM_DATA, val << BYTE_OFFSET(addr));
+ pci_write_byte(pcidev_dev, BROM_ACCESS, BROM_TRIGGER | BROM_WRITE | ENABLE_BYTE(addr));
+
+ if (!atavia_ready()) {
+ msg_perr("not ready after write\n");
+ }
+}
+
+uint8_t atavia_chip_readb(const struct flashctx *flash, chipaddr addr)
+{
+ uint8_t val;
+
+ addr += VT6421A_OFF;
+ pci_write_long(pcidev_dev, BROM_ADDR, (addr & ~3));
+ pci_write_byte(pcidev_dev, BROM_ACCESS, BROM_TRIGGER | ENABLE_BYTE(addr));
+
+ if (!atavia_ready()) {
+ msg_perr("not ready after read\n");
+ }
+
+ val = (pci_read_long(pcidev_dev, BROM_DATA) >> BYTE_OFFSET(addr)) & 0xff;
+
+ return val;
+}
diff --git a/flashrom.c b/flashrom.c
index fdc5412..f5bf45f 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -152,6 +152,16 @@ const struct programmer_entry programmer_table[] = {
},
#endif
+#if CONFIG_ATAVIA == 1
+ {
+ .name = "atavia",
+ .init = atavia_init,
+ .map_flash_region = fallback_map,
+ .unmap_flash_region = fallback_unmap,
+ .delay = internal_delay,
+ },
+#endif
+
#if CONFIG_FT2232_SPI == 1
{
.name = "ft2232_spi",
diff --git a/print.c b/print.c
index 582a49e..724f91c 100644
--- a/print.c
+++ b/print.c
@@ -487,6 +487,11 @@ void print_supported(void)
programmer_table[PROGRAMMER_ATAHPT].name);
print_supported_pcidevs(ata_hpt);
#endif
+#if CONFIG_ATAVIA == 1
+ printf("\nSupported devices for the %s programmer:\n",
+ programmer_table[PROGRAMMER_ATAVIA].name);
+ print_supported_pcidevs(ata_via);
+#endif
#if CONFIG_FT2232_SPI == 1
msg_ginfo("\nSupported devices for the %s programmer:\n",
programmer_table[PROGRAMMER_FT2232_SPI].name);
diff --git a/programmer.h b/programmer.h
index 51b9c40..105613c 100644
--- a/programmer.h
+++ b/programmer.h
@@ -54,6 +54,9 @@ enum programmer {
#if CONFIG_ATAHPT == 1
PROGRAMMER_ATAHPT,
#endif
+#if CONFIG_ATAVIA == 1
+ PROGRAMMER_ATAVIA,
+#endif
#if CONFIG_FT2232_SPI == 1
PROGRAMMER_FT2232_SPI,
#endif
@@ -239,7 +242,7 @@ int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data);
#endif
/* print.c */
-#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_NICINTEL+CONFIG_NICINTEL_SPI+CONFIG_OGP_SPI+CONFIG_SATAMV >= 1
+#if CONFIG_NIC3COM+CONFIG_NICREALTEK+CONFIG_NICNATSEMI+CONFIG_GFXNVIDIA+CONFIG_DRKAISER+CONFIG_SATASII+CONFIG_ATAHPT+CONFIG_ATAVIA+CONFIG_NICINTEL+CONFIG_NICINTEL_SPI+CONFIG_OGP_SPI+CONFIG_SATAMV >= 1
/* Not needed for CONFIG_INTERNAL, but for all other PCI-based programmers. */
void print_supported_pcidevs(const struct pcidev_status *devs);
#endif
@@ -420,6 +423,14 @@ int atahpt_init(void);
extern const struct pcidev_status ata_hpt[];
#endif
+/* atavia.c */
+#if CONFIG_ATAVIA == 1
+int atavia_init(void);
+void atavia_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
+uint8_t atavia_chip_readb(const struct flashctx *flash, const chipaddr addr);
+extern const struct pcidev_status ata_via[];
+#endif
+
/* ft2232_spi.c */
#if CONFIG_FT2232_SPI == 1
struct usbdev_status {
--
Kind regards, Stefan Tauner
More information about the flashrom
mailing list