Thanks to Vadim Girlin for finding out how to do that The patent describing the overall implementation of DualBIOS can be found here: http://www.google.com/patents/US6892323 This is known to work on GA-MA770-UD3, GA-B75M-D3V, GA-B75N and GA-H61M-S1 (only M_BIOS is populated).
Signed-off-by: Vadim Girlin vadimgirlin@gmail.com Signed-off-by: Damien Zammit damien@zamaudio.com Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at Tested-by: Damien Zammit damien@zamaudio.com Tested-by: Anton Kochkov anton.kochkov@gmail.com --- flashrom.8 | 13 +++++++++++++ internal.c | 5 ++--- it87spi.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 55 insertions(+), 10 deletions(-)
diff --git a/flashrom.8 b/flashrom.8 index dccfd1a..c52542a 100644 --- a/flashrom.8 +++ b/flashrom.8 @@ -315,6 +315,19 @@ do not match, it will refuse to write the image unless you specify .TP .B ITE IT87 Super I/O .sp +If your mainboard is manufactured by GIGABYTE and supports DualBIOS it is very likely that it uses an +ITE IT87 series Super I/O to switch between the two flash chips. Only one of them can be accessed at a time +and you can manually select which one to use with the +.sp +.B " flashrom -p internal:dualbiosindex=chip" +.sp +syntax where +.B chip +is the index of the chip to use (0 = main, 1 = backup). You can check which one is currently selected by +leaving out the +.B chip +parameter. +.sp If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus translation, flashrom should autodetect that configuration. If you want to set the I/O base port of the IT87 series SPI controller manually instead of diff --git a/internal.c b/internal.c index ab3c81f..30b184f 100644 --- a/internal.c +++ b/internal.c @@ -331,9 +331,8 @@ int internal_init(void) return ret;
#if defined(__i386__) || defined(__x86_64__) - /* Probe unconditionally for IT87* LPC->SPI translation and for - * IT87* Parallel write enable. - */ + /* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and + * parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */ init_superio_ite(); #endif
diff --git a/it87spi.c b/it87spi.c index 8e4e0ad..dbba7b4 100644 --- a/it87spi.c +++ b/it87spi.c @@ -27,6 +27,7 @@
#include <string.h> #include <stdlib.h> +#include <errno.h> #include "flash.h" #include "chipdrivers.h" #include "programmer.h" @@ -36,7 +37,7 @@ #define ITE_SUPERIO_PORT1 0x2e #define ITE_SUPERIO_PORT2 0x4e
-uint16_t it8716f_flashport = 0; +static uint16_t it8716f_flashport = 0; /* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ static int fast_spi = 1;
@@ -124,10 +125,40 @@ static const struct spi_programmer spi_programmer_it87xx = { static uint16_t it87spi_probe(uint16_t port) { uint8_t tmp = 0; - char *portpos = NULL; uint16_t flashport = 0;
enter_conf_mode_ite(port); + + char *param = extract_programmer_param("dualbiosindex"); + if (param != NULL) { + sio_write(port, 0x07, 0x07); /* Select GPIO LDN */ + tmp = sio_read(port, 0xEF); + if (*param == '\0') { /* Print current setting only. */ + free(param); + } else { + char *dualbiosindex_suffix; + errno = 0; + long chip_index = strtol(param, &dualbiosindex_suffix, 0); + free(param); + if (errno != 0 || *dualbiosindex_suffix != '\0' || chip_index < 0 || chip_index > 1) { + msg_perr("DualBIOS: Invalid chip index requested.\n"); + exit_conf_mode_ite(port); + return 1; + } + if (chip_index != (tmp & 1)) { + msg_pdbg("DualBIOS: Previous chip index: %d\n", tmp & 1); + sio_write(port, 0xEF, (tmp & 0xFE) | chip_index); + tmp = sio_read(port, 0xEF); + if ((tmp & 1) != chip_index) { + msg_perr("DualBIOS: Chip selection failed.\n"); + exit_conf_mode_ite(port); + return 1; + } + } + } + msg_pinfo("DualBIOS: Selected chip: %d\n", tmp & 1); + } + /* NOLDN, reg 0x24, mask out lowest bit (suspend) */ tmp = sio_read(port, 0x24) & 0xFE; /* Check if LPC->SPI translation is active. */ @@ -163,11 +194,11 @@ static uint16_t it87spi_probe(uint16_t port) flashport |= sio_read(port, 0x65); msg_pdbg("Serial flash port 0x%04x\n", flashport); /* Non-default port requested? */ - portpos = extract_programmer_param("it87spiport"); - if (portpos) { + param = extract_programmer_param("it87spiport"); + if (param) { char *endptr = NULL; unsigned long forced_flashport; - forced_flashport = strtoul(portpos, &endptr, 0); + forced_flashport = strtoul(param, &endptr, 0); /* Port 0, port >0x1000, unaligned ports and garbage strings * are rejected. */ @@ -180,7 +211,8 @@ static uint16_t it87spi_probe(uint16_t port) msg_perr("Error: it87spiport specified, but no valid " "port specified.\nPort must be a multiple of " "0x8 and lie between 0x100 and 0xff8.\n"); - free(portpos); + exit_conf_mode_ite(port); + free(param); return 1; } else { flashport = (uint16_t)forced_flashport; @@ -190,7 +222,7 @@ static uint16_t it87spi_probe(uint16_t port) sio_write(port, 0x65, (flashport & 0xff)); } } - free(portpos); + free(param); exit_conf_mode_ite(port); it8716f_flashport = flashport; if (internal_buses_supported & BUS_SPI) @@ -228,6 +260,7 @@ int init_superio_ite(void) case 0x8716: case 0x8718: case 0x8720: + case 0x8728: ret |= it87spi_probe(superios[i].port); break; default: