[LinuxBIOS] [PATCH] flashrom: board specific enables based on matching pci-ids.
Stefan Reinauer
stepan at coresystems.de
Fri Mar 23 18:42:46 CET 2007
* Luc Verhaegen <libv at skynet.be> [070323 06:47]:
> This patch adds initial flashrom support for matching mainboards based
> on pci-ids and pci subsystem/card ids.
> This code works correctly on:
> * EPIA-M with original BIOS. Matched and enabled correctly:
> $ Found "VIA EPIA M/MII/...": Enabling flash write... OK.
> * EPIA-M with linuxbios: not matched - pci subsystem ids not set
> correctly (yet!) - but not a problem as linuxbios never disabled write
> in the first place.
Ok, so do I get this right: all boards below might be supported by
LinuxBIOS as well, if we create ports for them based on the Epia-M
and start setting correct subsystem vendor ids?
[..]
do you have all these devices available for testing?
> There is one more VT823x based device in this house that might get
> tested, and possibly implemented, this weekend.
>
> The Island Aruma support is currently kept as is.
fine.
> When no match has been made, or an error occured, then the name based
> matching is still attempted.
so no regressions. Good.
> I'm not a big fan of doing board specific things on the name alone. A
> user also shouldn't be allowed to specify a board name as that would
> lead to very randomly poking bits with potentially not-so-fun
> consequences.
I trust the user more on knowing what he bought than the board vendors
on always creating a sane design for something they would never see the
need for.
Also: This is nothing that the user would manually choose, except during
migration process. Later these strings are read from the linuxbios
table, which is "the one correct answer" rather than a solution based on
heuristics..
> Testing here should imho involve editing flash_enable.c
> directly.
Testing?
> Island aruma code can be converted with little effort, all it takes is
> the output of lspci -vn.
No need to do so. There is no more legacy bios for the island aruma.
It's a LinuxBIOS only machine.
One issue with subsystem IDs: In LinuxBIOS they are board wide.
All devices on a board get the same subsystem id. I would assume this is
a wrong approach, from reading your code. Is it?
> Index: util/flashrom/flash_enable.c
> ===================================================================
> --- util/flashrom/flash_enable.c (revision 2573)
> +++ util/flashrom/flash_enable.c (working copy)
> @@ -158,10 +158,13 @@
> return enable_flash_ich(dev, name, 0xdc);
> }
>
> -static int enable_flash_vt823x(struct pci_dev *dev, char *name)
> +/*
> + *
> + */
> +static int
> +enable_flash_vt823x(struct pci_dev *dev, char *name)
> {
> uint8_t val;
> - int ret = 0;
>
> /* ROM Write enable */
> val = pci_read_byte(dev, 0x40);
> @@ -170,37 +173,10 @@
>
> if (pci_read_byte(dev, 0x40) != val) {
> printf("Warning: Failed to enable ROM Write on %s\n", name);
> - ret = -1;
> + return -1;
> }
>
> - if (dev->device_id == 0x3177) { /* VT8235 */
> - if (!iopl(3)) { /* enable full IO access */
> - unsigned int base;
> -
> - /* GPIO12-15 -> output */
> - val = pci_read_byte(dev, 0xE4);
> - val |= 0x38;
> - 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 |= 0xFF;
> - outb(val, base + 0x4d);
> -
> - val = inb(base + 0x4E);
> - val |= 0x0F;
> - outb(val, base + 0x4E);
> - } else {
> - printf("Warning; Failed to disable Write Protect"
> - " on %s (iopl failed)\n", name);
> - return -1;
> - }
> - }
> -
> - return ret;
> + return 0;
> }
>
> static int enable_flash_cs5530(struct pci_dev *dev, char *name)
> @@ -531,9 +507,194 @@
> { "ISLAND", "ARUMA", mbenable_island_aruma },
> };
>
> +/*
> + *
> + * Board specific handling, matched by up to two full sets of pci-ids.
> + *
> + */
> +
> +/*
> + * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
> + *
> + * First pci_dev is used and a VT8235 ISA Bridge (0x1106:0x3177)
> + * Second pci_dev is VIA CLE266 Host Bridge and not used.
> + *
> + * This line doesn't really need to be raised when using linuxbios,
> + * but it doesn't hurt.
> + */
> +static int
> +enable_flash_via_epia_m(struct pci_dev *first, struct pci_dev *second,
> + char *name)
> +{
> + unsigned int base;
> + uint8_t val;
> +
> + /* GPIO12-15 -> output */
> + val = pci_read_byte(first, 0xE4);
> + val |= 0x10;
> + pci_write_byte(first, 0xE4, val);
> +
> + /* Get Power Management IO address. */
> + base = pci_read_word(first, 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.
> + *
> + * First pci_dev is used and a VT8235 ISA Bridge (0x1106:0x3177)
> + * Second pci_dev is VIA KM400 Host Bridge and not used.
> + */
> +static int
> +enable_flash_asus_a7v8x_mx(struct pci_dev *first, struct pci_dev *second,
> + char *name)
> +{
> + uint8_t val;
> +
> + /* This bit is marked reserved actually */
> + val = pci_read_byte(first, 0x59);
> + val &= 0x7F;
> + pci_write_byte(first, 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. Not every
> + * vendor handles subsystem/card ids in a sane manner.
> + *
> + * Keep the second set nulled if it should be ignored.
> + *
> + * This does require that linuxbios sets up the subsystem ids properly.
> + *
> + */
> +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 */
> + uint16_t second_vendor;
> + uint16_t second_device;
> + uint16_t second_card_vendor;
> + uint16_t second_card_device;
> +
> + char *name;
> + int (*enable)(struct pci_dev *first, struct pci_dev *second, char *name);
> +};
> +
> +struct board_pciid_enable board_pciid_enables[] = {
> + { 0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, "VIA EPIA M/MII/...", enable_flash_via_epia_m },
> + { 0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, "Asus A7V8-MX SE", enable_flash_asus_a7v8x_mx },
> + { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } /* Keep this */
> +
> +};
> +
> +/*
> + *
> + */
> +static struct pci_dev *
> +device_pciids_match(uint16_t vendor, uint16_t device,
> + uint16_t card_vendor, uint16_t card_device)
> +{
> + struct pci_dev *temp;
> + struct pci_filter filter;
> +
> + pci_filter_init(NULL, &filter);
> + filter.vendor = vendor;
> + filter.device = device;
> +
> + for (temp = pacc->devices; temp; temp = temp->next)
> + if (pci_filter_match(&filter, temp)) {
> + if ((card_vendor == pci_read_word(temp, 0x2C)) &&
> + (card_device == pci_read_word(temp, 0x2E)))
> + return temp;
> + }
> +
> + return NULL;
> +}
> +
> +/*
> + *
> + */
> +static int
> +board_flash_enable_from_pciids(void)
> +{
> + struct board_pciid_enable *board = board_pciid_enables;
> + struct pci_dev *first, *second;
> + int ret;
> +
> + for (; board->name; board++) {
> + first = device_pciids_match(board->first_vendor,
> + board->first_device,
> + board->first_card_vendor,
> + board->first_card_device);
> + if (!first)
> + continue;
> +
> + if (board->second_vendor) {
> + second = device_pciids_match(board->second_vendor,
> + board->second_device,
> + board->second_card_vendor,
> + board->second_card_device);
> + if (!second)
> + continue;
> + } else
> + second = NULL;
> +
> +
> + printf("Found \"%s\": Enabling flash write...",
> + board->name);
> +
> + ret = board->enable(first, second, board->name);
> + if (!ret) {
> + printf(" OK.\n");
> + return 1; /* Found and success */
> + } else {
> + printf(" Failed!\n");
> + return ret; /* error */
> + }
> + }
> +
> + return 0; /* nothing found */
> +}
> +
> int enable_flash_write()
> {
> - int i;
> + int i, ret;
> struct pci_dev *dev = 0;
> FLASH_ENABLE *enable = 0;
>
> @@ -558,13 +719,19 @@
> /* First look whether we have to do something for this
> * motherboard.
> */
> - for (i = 0; i < sizeof(mbenables) / sizeof(mbenables[0]); i++) {
> - if(lb_vendor && !strcmp(mbenables[i].vendor, lb_vendor) &&
> - lb_part && !strcmp(mbenables[i].part, lb_part)) {
> - mbenables[i].doit();
> - break;
> - }
> - }
> + ret = board_flash_enable_from_pciids();
> + if (ret < 0)
> + printf("Attempting to continue regardless.\n");
> +
> + if (ret != 1) { /* Try to match on name instead. */
> + for (i = 0; i < sizeof(mbenables) / sizeof(mbenables[0]); i++) {
> + if(lb_vendor && !strcmp(mbenables[i].vendor, lb_vendor) &&
> + lb_part && !strcmp(mbenables[i].part, lb_part)) {
> + mbenables[i].doit();
> + break;
> + }
> + }
> + }
>
> /* now let's try to find the chipset we have ... */
> for (i = 0; i < sizeof(enables) / sizeof(enables[0]) && (!dev);
--
coresystems GmbH • Brahmsstr. 16 • D-79104 Freiburg i. Br.
Tel.: +49 761 7668825 • Fax: +49 761 7664613
Email: info at coresystems.de • http://www.coresystems.de/
Registergericht: Amtsgericht Freiburg • HRB 7656
Geschäftsführer: Stefan Reinauer • Ust-IdNr.: DE245674866
More information about the coreboot
mailing list