[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.dehttp://www.coresystems.de/
Registergericht: Amtsgericht Freiburg • HRB 7656
Geschäftsführer: Stefan Reinauer • Ust-IdNr.: DE245674866




More information about the coreboot mailing list