Expand int155f "vgahook" detection.

Verify VGA card vendor is via before supporting via 155f calls.
Add support for future code depending on coreboot board id.
Add code for via VX855 memory size and speed detection.
diff --git a/Makefile b/Makefile
index 2978105..41e6514 100644
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,8 @@
 # Source files
 SRCBOTH=output.c util.c floppy.c ata.c misc.c mouse.c kbd.c pci.c \
         serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
-        pnpbios.c pirtable.c
-SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c vgahooks.c font.c
+        pnpbios.c pirtable.c vgahooks.c
+SRC16=$(SRCBOTH) system.c disk.c apm.c pcibios.c font.c
 SRC32=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
       lzmadecode.c
diff --git a/src/coreboot.c b/src/coreboot.c
index b8479c5..a760414 100644
--- a/src/coreboot.c
+++ b/src/coreboot.c
@@ -143,6 +143,16 @@
 #define MEM_RANGE_COUNT(_rec) \
         (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
 
+struct cb_mainboard {
+    u32 tag;
+    u32 size;
+    u8  vendor_idx;
+    u8  part_idx;
+    char  strings[0];
+};
+
+#define CB_TAG_MAINBOARD 0x0003
+
 struct cb_forward {
     u32 tag;
     u32 size;
@@ -260,6 +270,15 @@
     // smbios/dmi table is found from coreboot and use that instead.
     smbios_init();
 
+    struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
+    if (cbmb) {
+        const char *vendor = &cbmb->strings[cbmb->vendor_idx];
+        const char *part = &cbmb->strings[cbmb->part_idx];
+        dprintf(1, "Found mainboard %s %s\n", vendor, part);
+
+        vgahook_setup(vendor, part);
+    }
+
     return;
 
 fail:
diff --git a/src/optionroms.c b/src/optionroms.c
index 24fc4c3..1d47c1e 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -408,6 +408,7 @@
         return;
 
     dprintf(1, "Scan for VGA option rom\n");
+    VGAbdf = -1;
     next_rom = OPTION_ROM_START;
 
     if (CONFIG_OPTIONROMS_DEPLOYED) {
@@ -415,7 +416,7 @@
         init_optionrom((void*)OPTION_ROM_START, 0, 1);
     } else {
         // Find and deploy PCI VGA rom.
-        int bdf = pci_find_class(PCI_CLASS_DISPLAY_VGA);
+        int bdf = VGAbdf = pci_find_class(PCI_CLASS_DISPLAY_VGA);
         if (bdf >= 0)
             init_pcirom(bdf, 1);
 
diff --git a/src/util.h b/src/util.h
index b32a517..b566f56 100644
--- a/src/util.h
+++ b/src/util.h
@@ -211,7 +211,9 @@
 void coreboot_setup();
 
 // vgahooks.c
+extern int VGAbdf;
 void handle_155f();
+void vgahook_setup(const char *vendor, const char *part);
 
 // optionroms.c
 void call_bcv(u16 seg, u16 ip);
diff --git a/src/vgahooks.c b/src/vgahooks.c
index fcb7793..ddeb1d3 100644
--- a/src/vgahooks.c
+++ b/src/vgahooks.c
@@ -7,12 +7,29 @@
 #include "bregs.h" // set_code_fail
 #include "biosvar.h" // GET_GLOBAL
 #include "pci.h" // pci_find_device
+#include "pci_regs.h" // PCI_VENDOR_ID
 #include "pci_ids.h" // PCI_VENDOR_ID_VIA
 #include "util.h" // handle_155f
 #include "config.h" // CONFIG_*
 
+// The Bus/Dev/Fn of the primary VGA device.
+int VGAbdf VAR16_32;
+// Coreboot board detected.
+int CBmainboard VAR16_32;
+
 static void
-handle_155f01(struct bregs *regs)
+handle_155fXX(struct bregs *regs)
+{
+    set_code_fail(regs, RET_EUNSUPPORTED);
+}
+
+
+/****************************************************************
+ * Via hooks
+ ****************************************************************/
+
+static void
+via_155f01(struct bregs *regs)
 {
     regs->eax = 0x5f;
     regs->cl = 2; // panel type =  2 = 1024 * 768
@@ -21,7 +38,7 @@
 }
 
 static void
-handle_155f02(struct bregs *regs)
+via_155f02(struct bregs *regs)
 {
     regs->eax = 0x5f;
     regs->bx = 2;
@@ -32,40 +49,34 @@
 }
 
 static int
-getFBSize()
+getFBSize(u16 bdf)
 {
-    /* Find K8M890 */
-    int bdf = pci_find_device(PCI_VENDOR_ID_VIA, 0x3336);
-    if (bdf < 0)
-        goto err;
-
     /* FB config */
     u8 reg = pci_config_readb(bdf, 0xa1);
 
     /* GFX disabled ? */
     if (!(reg & 0x80))
-        goto err;
+        return -1;
 
     static u8 mem_power[] VAR16 = {0, 3, 4, 5, 6, 7, 8, 9};
     return GET_GLOBAL(mem_power[(reg >> 4) & 0x7]);
-err:
-    dprintf(1, "Warning: VGA memory size is hardcoded\n");
-    return 5; // 32M frame buffer
 }
 
 static int
-getRamSpeed()
+getViaRamSpeed(u16 bdf)
+{
+    return (pci_config_readb(bdf, 0x90) & 0x07) + 3;
+}
+
+static int
+getAMDRamSpeed()
 {
     int bdf = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
     if (bdf < 0)
-        goto err;
+        return -1;
 
     /* mem clk 0 = DDR2 400 */
-    u8 reg = pci_config_readb(bdf, 0x94) & 0x7;
-    return reg + 6;
-err:
-    dprintf(1, "Warning: VGA memory clock speed is hardcoded\n");
-    return 4; // MCLK = DDR266
+    return (pci_config_readb(bdf, 0x94) & 0x7) + 6;
 }
 
 /* int 0x15 - 5f18
@@ -87,46 +98,96 @@
        B: and above: Unknown
    EBX[?..8] Total memory size?
    EAX = 0x5f for success
-
-    K8M890 BIOS wants only this call (Desktop NoTv)
 */
 
+#define PCI_DEVICE_ID_VIA_K8M890CE_3    0x3336
+#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
+
 static void
-handle_155f18(struct bregs *regs)
+via_155f18(struct bregs *regs)
 {
+    u32 ramspeed, fbsize;
+
+    int bdf = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_K8M890CE_3);
+    if (bdf >= 0) {
+        fbsize = getFBSize(bdf);
+        ramspeed = getAMDRamSpeed();
+        goto done;
+    }
+    bdf = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
+    if (bdf >= 0) {
+        fbsize = getFBSize(bdf);
+        ramspeed = getViaRamSpeed(bdf);
+        goto done;
+    }
+
+    dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
+    fbsize = 5; // 32M frame buffer
+    ramspeed = 4; // MCLK = DDR266
+
+done:
+    if (fbsize < 0 || ramspeed < 0) {
+        set_code_fail(regs, RET_EUNSUPPORTED);
+        return;
+    }
     regs->eax = 0x5f;
-    u32 ramspeed = getRamSpeed();
-    u32 fbsize = getFBSize();
     regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
     regs->ecx = 0x060;
     set_success(regs);
 }
 
 static void
-handle_155f19(struct bregs *regs)
+via_155f19(struct bregs *regs)
 {
     set_fail_silent(regs);
 }
 
 static void
-handle_155fXX(struct bregs *regs)
+via_155f(struct bregs *regs)
 {
-    set_code_fail(regs, RET_EUNSUPPORTED);
+    switch (regs->al) {
+    case 0x01: via_155f01(regs); break;
+    case 0x02: via_155f02(regs); break;
+    case 0x18: via_155f18(regs); break;
+    case 0x19: via_155f19(regs); break;
+    default:   handle_155fXX(regs); break;
+    }
 }
 
+
+/****************************************************************
+ * Entry and setup
+ ****************************************************************/
+
+// Main 16bit entry point
 void
 handle_155f(struct bregs *regs)
 {
-    if (! CONFIG_VGAHOOKS) {
-        handle_155fXX(regs);
+    if (! CONFIG_VGAHOOKS)
+        goto fail;
+
+    // XXX - Use this value later.
+    //int cbmb = GET_GLOBAL(CBmainboard);
+
+    int bdf = GET_GLOBAL(VGAbdf);
+    if (bdf < 0)
+        goto fail;
+    u16 vendor = pci_config_readw(bdf, PCI_VENDOR_ID);
+    if (vendor == PCI_VENDOR_ID_VIA) {
+        via_155f(regs);
         return;
     }
 
-    switch (regs->al) {
-    case 0x01: handle_155f01(regs); break;
-    case 0x02: handle_155f02(regs); break;
-    case 0x18: handle_155f18(regs); break;
-    case 0x19: handle_155f19(regs); break;
-    default:   handle_155fXX(regs); break;
-    }
+fail:
+    handle_155fXX(regs);
+}
+
+// Setup
+void
+vgahook_setup(const char *vendor, const char *part)
+{
+    if (! CONFIG_VGAHOOKS)
+        return;
+    // XXX - add support later.
+    CBmainboard = 0;
 }