[LinuxBIOS] [PATCH] flashrom: board specific enables based on matching pci-ids.

Luc Verhaegen libv at skynet.be
Fri Mar 23 06:47:43 CET 2007


Hi,

This patch adds initial flashrom support for matching mainboards based 
on pci-ids and pci subsystem/card ids.

I've been using subsystem/card ids as part of my unichrome driver for 
years (xf86-video-unichrome/src/via_id.c). It is a very easy and 
painless system for identifying boards.

It is relatively reliable, as it's always the same vendors that bugger 
them up (like VIA and ECS). Most vendors do play nice. But, in order to 
not mess up on devices like the EPIA-M, 2 sets of ids can be provided 
here. This gives pretty absolute reliability. Boards that don't need 2 
matches can just null the second set.

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.
* Asus A7V400-MX now works correctly (the CrashFree BIOS). This involves
  poking the Winbond LPC superio:
  $ Found "Asus A7V8-MX SE": Enabling flash write... OK.
  (This different name is correct. The difference is the northbridge 
   revision and a sticker over "A7V8-MX SE")
* Mitac 8999 laptop. Here GPIO15 enables the panel backlight, while on
  EPIA-M it enables rom write. Hence this being highly incorrect here.
  Requires nothing board specific and can flash np.
* Shuttle SK43G requires nothing board specific.

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.

When no match has been made, or an error occured, then the name based 
matching is still attempted.

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. Testing here should imho involve editing flash_enable.c 
directly.

Island aruma code can be converted with little effort, all it takes is 
the output of lspci -vn.

Commit message, signed-off, etc are done git-style.

Luc Verhaegen.
-------------- next part --------------
flashrom: Add board specific flash enables based on matching pci-ids.

* Matches mainboards with up to two full sets of pci-ids, and if matched
  calls the respective enable function.
* Falls back to name based matching/enable.
* Cleans up VT823x enable code. Moves GPIO15 enable code to EPIA-M board
  specific code as GPIO15 doubles up as backlight enable in at least one
  laptop.
* Adds support for Asus A7V8X-MX/A7V400-MX, a VIA KM400/VT8235 
  mainboard.

signed-off-by: Luc Verhaegen <libv at skynet.be>

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);


More information about the coreboot mailing list