diff options
author | Luc Verhaegen <libv@skynet.be> | 2007-04-04 22:45:58 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2007-04-04 22:45:58 +0000 |
commit | b8c64378112fd61a698d545562dfbafaa353243d (patch) | |
tree | a2999d9f04671b54a1d850b029a82c813b9a9a54 /util/flashrom/board_enable.c | |
parent | 17d667b411685de57ea181cc496b29fea6d27d91 (diff) |
flashrom: split flash_enable.c into chipset_enable.c and board_enable.c
This splits up the ROM Write enable code into chipset specific and
board specific parts. This of course means that a lot of code is
plainly moved about.
* Allows for linuxbios name matching and pci-subsystem id matching.
The latter uses a double set to properly distuinguish boards despite
of some known vendors being lax about it.
* Fixes GPIO15 being raised on every VT8235 southbridge, regardless of what
that line actually controls; rom on EPIA-M, backlight on mitac 8999 laptop.
* Adds flashrom support for Asus A7V400-MX (KM400 + VT8235)
* Island aruma was renamed agami aruma, the board specific code now got
adjusted. A set of pci-ids was retrieved from source code.
Signed-off-by: Luc Verhaegen <libv@skynet.be>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2581 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'util/flashrom/board_enable.c')
-rw-r--r-- | util/flashrom/board_enable.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/util/flashrom/board_enable.c b/util/flashrom/board_enable.c new file mode 100644 index 0000000000..ac8de9f40e --- /dev/null +++ b/util/flashrom/board_enable.c @@ -0,0 +1,299 @@ +/* + * flash rom utility: enable flash writes (board specific) + * + * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de> + * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de> + * Copyright (C) 2007 Luc Verhaegen <libv@skynet.be> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +/* + * Contains the board specific flash enables. + */ + +#include <stdio.h> +#include <pci/pci.h> +#include <stdint.h> +#include <string.h> + +#include "flash.h" +#include "debug.h" + +/* + * Match on pci-ids, no report received, just data from the mainboard + * specific code: + * main: 0x1022:0x746B, which is the SMBUS controller. + * card: 0x1022:0x36C0... + */ + +static int board_agami_aruma(char *name) +{ + /* Extended function index register, either 0x2e or 0x4e */ +#define EFIR 0x2e + /* Extended function data register, one plus the index reg. */ +#define EFDR EFIR + 1 + char b; + + /* Disable the flash write protect. The flash write protect is + * connected to the WinBond w83627hf GPIO 24. + */ + outb(0x87, EFIR); /* sequence to unlock extended functions */ + outb(0x87, EFIR); + + outb(0x20, EFIR); /* SIO device ID register */ + b = inb(EFDR); + printf_debug("\nW83627HF device ID = 0x%x\n",b); + + if (b != 0x52) { + fprintf(stderr, "\nIncorrect device ID, aborting write protect disable\n"); + return -1; + } + + outb(0x2b, EFIR); /* GPIO multiplexed pin reg. */ + b = inb(EFDR) | 0x10; + outb(0x2b, EFIR); + outb(b, EFDR); /* select GPIO 24 instead of WDTO */ + + outb(0x7, EFIR); /* logical device select */ + outb(0x8, EFDR); /* point to device 8, GPIO port 2 */ + + outb(0x30, EFIR); /* logic device activation control */ + outb(0x1, EFDR); /* activate */ + + outb(0xf0, EFIR); /* GPIO 20-27 I/O selection register */ + b = inb(EFDR) & ~0x10; + outb(0xf0, EFIR); + outb(b, EFDR); /* set GPIO 24 as an output */ + + outb(0xf1, EFIR); /* GPIO 20-27 data register */ + b = inb(EFDR) | 0x10; + outb(0xf1, EFIR); + outb(b, EFDR); /* set GPIO 24 */ + + outb(0xaa, EFIR); /* command to exit extended functions */ + + return 0; +} + +/* + * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs. + * + * We don't need to do this when using linuxbios, GPIO15 is never lowered there. + */ + +static int board_via_epia_m(char *name) +{ + struct pci_dev *dev; + unsigned int base; + uint8_t val; + + dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8235 ISA Bridge not found.\n"); + return -1; + } + + /* GPIO12-15 -> output */ + val = pci_read_byte(dev, 0xE4); + val |= 0x10; + pci_write_byte(dev, 0xE4, val); + + /* Get Power Management IO address. */ + base = pci_read_word(dev, 0x88) & 0xFF80; + + /* enable GPIO15 which is connected to write protect. */ + val = inb(base + 0x4D); + val |= 0x80; + outb(val, base + 0x4D); + + return 0; +} + +/* + * Winbond LPC super IO. + * + * Raises the ROM MEMW# line. + */ + +static void w83697_rom_memw_enable(void) +{ + uint8_t val; + + outb(0x87, 0x2E); /* enable extended functions */ + outb(0x87, 0x2E); + + outb(0x24, 0x2E); /* rom bits live here */ + + val = inb(0x2F); + if (!(val & 0x02)) /* flash rom enabled? */ + outb(val | 0x08, 0x2F); /* enable MEMW# */ + + outb(0xAA, 0x2E); /* disable extended functions */ +} + +/* + * Suited for Asus A7V8X-MX SE and A7V400-MX. + * + */ + +static int board_asus_a7v8x_mx(char *name) +{ + struct pci_dev *dev; + uint8_t val; + + dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ + if (!dev) { + fprintf(stderr, "\nERROR: VT8235 ISA Bridge not found.\n"); + return -1; + } + + /* This bit is marked reserved actually */ + val = pci_read_byte(dev, 0x59); + val &= 0x7F; + pci_write_byte(dev, 0x59, val); + + w83697_rom_memw_enable(); + + return 0; +} + +/* + * We use 2 sets of ids here, you're free to choose which is which. This + * to provide a very high degree of certainty when matching a board on + * the basis of Subsystem/card ids. As not every vendor handles + * subsystem/card ids in a sane manner. + * + * Keep the second set nulled if it should be ignored. + * + */ + +struct board_pciid_enable { + /* Any device, but make it sensible, like the isa bridge. */ + uint16_t first_vendor; + uint16_t first_device; + uint16_t first_card_vendor; + uint16_t first_card_device; + + /* Any device, but make it sensible, like + * the host bridge. May be NULL + */ + uint16_t second_vendor; + uint16_t second_device; + uint16_t second_card_vendor; + uint16_t second_card_device; + + /* From linuxbios table */ + char *lb_vendor; + char *lb_part; + + char *name; + int (*enable)(char *name); +}; + +struct board_pciid_enable board_pciid_enables[] = { + { 0x1022, 0x746B, 0x1022, 0x36C0, 0x0000, 0x0000, 0x0000, 0x0000, + "AGAMI", "ARUMA", "Agami Aruma", board_agami_aruma }, + { 0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, + NULL, NULL, "VIA EPIA M/MII/...", board_via_epia_m }, + { 0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, + NULL, NULL, "Asus A7V8-MX SE", board_asus_a7v8x_mx }, + { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } /* Keep this */ + +}; + +/* + * Match boards on linuxbios table gathered vendor and part name. + * Require main pci-ids to match too as extra safety. + * + */ +static struct board_pciid_enable * +board_match_linuxbios_name(char *vendor, char *part) +{ + struct board_pciid_enable *board = board_pciid_enables; + + for (; board->name; board++) { + if (!board->lb_vendor || strcmp(board->lb_vendor, vendor)) + continue; + + if (!board->lb_part || strcmp(board->lb_part, part)) + continue; + + if (!pci_dev_find(board->first_vendor, board->first_device)) + continue; + + if (board->second_vendor && + !pci_dev_find(board->second_vendor, board->second_device)) + continue; + return board; + } + return NULL; +} + +/* + * Match boards on pci ids and subsystem ids. + * Second set of ids can be main only or missing completely. + */ +static struct board_pciid_enable *board_match_pci_card_ids(void) +{ + struct board_pciid_enable *board = board_pciid_enables; + + for (; board->name; board++) { + if (!board->first_card_vendor || !board->first_card_device) + continue; + + if (!pci_card_find(board->first_vendor, board->first_device, + board->first_card_vendor, + board->first_card_device)) + continue; + + if (board->second_vendor) { + if (board->second_card_vendor) { + if (!pci_card_find(board->second_vendor, + board->second_device, + board->second_card_vendor, + board->second_card_device)) + continue; + } else { + if (!pci_dev_find(board->second_vendor, + board->second_device)) + continue; + } + } + + return board; + } + + return NULL; +} + +/* + * + */ +int board_flash_enable(char *vendor, char *part) +{ + struct board_pciid_enable *board = NULL; + int ret = 0; + + if (vendor && part) + board = board_match_linuxbios_name(vendor, part); + + if (!board) + board = board_match_pci_card_ids(); + + if (board) { + printf("Found board \"%s\": Enabling flash write... ", + board->name); + + ret = board->enable(board->name); + if (ret) + printf("Failed!\n"); + else + printf("OK.\n"); + } + + return ret; +} |