Patchwork Geode LX VGA BIOS Patch

login
register
about
Submitter Chris Kindt
Date 2009-08-15 04:23:10
Message ID <4A86382E.80106@umbc.edu>
Download mbox | patch
Permalink /patch/128/
State Not Applicable
Headers show

Comments

Chris Kindt - 2009-08-15 04:23:10
Updated Patch:

    seabios-vgarom-geodelx-v2.patch
        -added  clobber  list to  VSA2 functions
        -converted _rom_pci data to c structure
        -replaced asm int10 with direct call
        -unset CONFIG_GEODELX


Signed-off-by: Chris Kindt <chriskindt@umbc.edu>
Paul Menzel - 2009-08-17 14:03:51
Dear Chris,


Am Samstag, den 15.08.2009, 00:23 -0400 schrieb Chris Kindt:
> +// Writen for Google Summer of Code 2009 for the coreboot project

s/Writen/Written/


Bests,

Paul

Patch

diff --git a/Makefile b/Makefile
index 2b8d0d2..71e6db2 100644
--- a/Makefile
+++ b/Makefile
@@ -159,7 +159,7 @@  $(OUT)bios.bin: $(OUT)bios.bin.elf
 
 # VGA src files
 SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \
-       vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c
+       vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c vgasrc/geodelx.c 
 
 $(OUT)vgaccode.16.s: ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@)
 
diff --git a/vgasrc/geodelx.c b/vgasrc/geodelx.c
new file mode 100644
index 0000000..a11909b
--- /dev/null
+++ b/vgasrc/geodelx.c
@@ -0,0 +1,570 @@ 
+// Geode LX VGA functions
+//
+// Copyright (C) 2009 Chris Kindt
+//
+// Writen for Google Summer of Code 2009 for the coreboot project
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "geodelx.h"
+#include "ioport.h" // outb
+#include "farptr.h" // SET_FARVAR
+#include "biosvar.h" // GET_BDA
+#include "vgatables.h" // VGAREG_*
+#include "util.h" // memset
+#include "config.h"
+#include "types.h"
+#include "bregs.h"
+
+#define DEBUG_GEODELX 4
+
+/****************************************************************
+* MSR and High Mem access through VSA Virtual Register
+****************************************************************/
+
+static union u64_u32_u lx_msrRead(u32 msrAddr)
+{
+    union u64_u32_u val;
+    asm __volatile__ (
+        "movw   $0x0AC1C, %%dx          \n"
+        "movl   $0xFC530007, %%eax      \n"
+        "outl   %%eax, %%dx             \n"
+        "addb   $2, %%dl                \n"
+        "inw    %%dx, %%ax              \n"
+        : "=a" (val.lo), "=d"(val.hi)
+        : "c"(msrAddr)
+        : "cc"
+    );
+    return val;
+}
+
+static void lx_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
+{
+    asm __volatile__ (
+        "push   %%eax                   \n"
+        "movw   $0x0AC1C, %%dx          \n"
+        "movl   $0xFC530007, %%eax      \n"
+        "outl   %%eax, %%dx             \n"
+        "addb   $2, %%dl                \n"
+        "pop    %%eax                   \n"
+        "outw   %%ax, %%dx              \n"
+        :
+        : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
+        : "%edx","cc"
+    );
+}
+
+static u32 lx_memRead(u32 addr)
+{
+    u32 val;
+    asm __volatile__ (
+        "movw   $0x0AC1C, %%dx          \n"
+        "movl   $0xFC530001, %%eax      \n"
+        "outl   %%eax, %%dx             \n"
+        "addb   $2, %%dl                \n"
+        "inw    %%dx, %%ax              \n"
+        : "=a" (val)
+        : "b"(addr)
+        : "cc"
+    );
+
+    return val;
+}
+
+static void lx_memWrite(u32 addr, u32 and, u32 or )
+{
+    asm __volatile__ (
+        "movw   $0x0AC1C, %%dx          \n"
+        "movl   $0xFC530001, %%eax      \n"
+        "outl   %%eax, %%dx             \n"
+        "addb   $2, %%dl                \n"
+        "outw   %%ax, %%dx              \n"
+        :
+        : "b"(addr), "S" (and), "D" (or)
+        : "%eax","cc"
+    );
+}
+
+static int legacyio_check()
+{
+    int ret=0;
+    union u64_u32_u val;
+
+    val=lx_msrRead(MSR_GLIU0_BASE4);
+    if (val.lo != 0x0A0fffe0)
+        ret|=1;
+
+    val=lx_msrRead(GLIU0_IOD_BM_0);
+    if (val.lo != 0x3c0ffff0)
+        ret|=2;
+
+    val=lx_msrRead(GLIU0_IOD_BM_1);
+    if (val.lo != 0x3d0ffff0)
+        ret|=4;
+
+    return ret;
+}
+
+/****************************************************************
+* Extened CRTC Register functions
+****************************************************************/
+static void crtce_lock()
+{
+    outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
+    outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
+}
+
+static void crtce_unlock()
+{
+    outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
+    outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
+}
+
+static u8 crtce_read(u8 reg)
+{
+    u8 val;
+
+    crtce_unlock();
+    outb(reg , VGAREG_VGA_CRTC_ADDRESS);
+    val = inb(VGAREG_VGA_CRTC_DATA);
+    crtce_lock();
+
+    return val;
+}
+
+static void crtce_write(u8 reg, u8 val)
+{
+    crtce_unlock();
+    outb(reg , VGAREG_VGA_CRTC_ADDRESS);
+    outb(val, VGAREG_VGA_CRTC_DATA);
+    crtce_lock();
+}
+
+/****************************************************************
+* Display Controler Functions
+****************************************************************/
+static u32 dc_read(u16 seg, u32 reg)
+{
+    u32 val, *dest_far = (void*)reg;
+    val = GET_FARVAR(seg,*dest_far);
+    return val;
+}
+
+static void dc_write(u16 seg, u32 reg, u32 val)
+{
+    u32 *dest_far = (void*)reg;
+    SET_FARVAR(seg,*dest_far,val);
+}
+
+static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
+{
+    u32 val = dc_read(seg,reg);
+    val &=and;
+    val |=or;
+    dc_write(seg,reg,val);
+}
+
+static void dc_unlock(u16 seg)
+{
+    dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
+}
+
+static void dc_lock(u16 seg)
+{
+    dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
+}
+
+static u16 dc_map(u16 seg)
+{
+    u8 reg;
+
+    reg = crtce_read(EXTENDED_MODE_CONTROL);
+    reg &= 0xf9;
+    switch (seg) {
+    case SEG_GRAPH:
+        reg |= 0x02;
+        break;
+    case SEG_MTEXT:
+        reg |= 0x04;
+        break;
+    case SEG_CTEXT:
+        reg |= 0x06;
+        break;
+    default:
+        seg=0;
+        break;
+    }
+
+    crtce_write(EXTENDED_MODE_CONTROL,reg);
+    return seg;
+}
+
+static void dc_unmap()
+{
+    dc_map(0);
+}
+
+
+/****************************************************************
+* Init Functions
+****************************************************************/
+
+/* Set up the dc (display contoller) portion of the geodelx
+*  The dc proivides harware support for VGA graphics
+*  for features not accessiable from the VGA registers,
+*  the dc's pci bar can be maped to a vga memory segment
+*/
+static int dc_setup()
+{
+    u32 fb, dc_fb;
+    u16 seg;
+
+    lxdprintf(2,"DC_SETUP\n");
+
+    seg = dc_map(SEG_GRAPH);
+    dc_unlock(seg);
+
+    /* zero memory config */
+    dc_write(seg,DC_FB_ST_OFFSET,0x0);
+    dc_write(seg,DC_CB_ST_OFFSET,0x0);
+    dc_write(seg,DC_CURS_ST_OFFSET,0x0);
+
+    /* read fb-bar from pci, then point dc to the fb base */
+    dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
+    outl(LX_PCI_FB,PORT_PCI_CMD);
+    fb = inl(PORT_PCI_DATA);
+    if (fb!=dc_fb) {
+        dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
+    }
+
+    dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
+    dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
+
+    dc_lock(seg);
+    dc_unmap();
+
+    return 0;
+}
+
+/* Setup the vp (video processor) portion of the geodelx
+*  Under VGA modes the vp was handled by softvg from inside VSA2.
+*  Without a softvg module, access is only avaliable through a pci bar.
+*  The High Mem Access virtual register is used to  configure the
+*   pci mmio bar from 16bit friendly io space.
+*/
+int vp_setup()
+{
+    u32 reg,vp;
+
+    lxdprintf(2,"VP_SETUP\n");
+    /* set output to crt and RGB/YUV */
+    lx_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
+
+    /* get vp register base from pci */
+    outl(LX_PCI_VP,PORT_PCI_CMD);
+    vp = inl(PORT_PCI_DATA);
+
+    /* Set mmio registers
+    * there may be some timing issues here, the reads seem
+    * to slow things down enough work reliably
+    */
+
+    reg = lx_memRead(vp+VP_MISC);
+    lxdprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
+    lx_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
+    reg = lx_memRead(vp+VP_MISC);
+    lxdprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
+
+    reg = lx_memRead(vp+VP_DCFG);
+    lxdprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
+    lx_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
+    reg = lx_memRead(vp+VP_DCFG);
+    lxdprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
+
+    return 0;
+}
+
+
+int geodelx_init()
+{
+    int ret;
+
+    lxdprintf(1,"GEODELX_INIT\n");
+
+    if ((ret=legacyio_check())) {
+        lxdprintf(1,"GEODELX_INIT legacyio_check=0x%x\n",ret);
+        return ret;
+    }
+    ret |= vp_setup();
+    ret |= dc_setup();
+
+    return ret;
+
+}
+
+u8 geode_str[] VAR16 = "GeodeLX GPL VGA BIOS";
+
+void VISIBLE16 geodelx_demo()
+{
+    int x;
+    struct bregs regs;
+
+    lxdprintf(2,"GEODELX_DEMO\n");
+
+    extern void handle_10(struct bregs *);
+    regs.eax=0x3;
+    handle_10(&regs);
+
+    for (x=0;x<sizeof(geode_str)-1;x++) {
+        regs.eax=(0x0e00 + GET_GLOBAL(geode_str[x]));
+        handle_10(&regs);
+    }
+}
+
+/* PCI Header */
+struct pci_data	_rom_pcidata VAR16EXPORT = {
+
+    .signature = PCI_ROM_SIGNATURE,
+    .vendor = AMD_PCI_ID,
+    .device = LX_PCI_ID,
+    .vitaldata = 0,
+    .dlen = sizeof(struct pci_data),
+    .drevision = 0,
+    .class_lo = 0,
+    .class_hi = 0x0300,
+    .ilen = 0,
+    .irevision = 0,
+    .type = PCIROM_CODETYPE_X86,
+    .indicator = LAST_IMAGE ,
+    .reserved = 0
+};
+
+/* modified from seabios/vgabios with values
+* from geode datasheets, table 6-53 in particular */
+struct VideoParam_s lx_video_param_table[] VAR16 = {
+    // index=0x00 no mode defined
+    {},
+    // index=0x01 no mode defined
+    {},
+    // index=0x02 no mode defined
+    {},
+    // index=0x03 no mode defined
+    {},
+    // index=0x04 vga mode 0x04
+    { 40, 24, 8, 0x0800,      /* tw, th-1, ch, slength */
+      { 0x09, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+        0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x03, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x05 vga mode 0x05 */
+    { 40, 24, 8, 0x0800,     /* tw, th-1, ch, slength */
+      { 0x09, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+        0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x03, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x06 vga mode 0x06 */
+    { 80, 24, 8, 0x1000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x01, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+        0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+        0x01, 0x00, 0x01, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x07 vga mode 0x07 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x66,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x0e, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x08 no mode defined */
+    {},
+    /* index=0x09 no mode defined */
+    {},
+    /* index=0x0a no mode defined */
+    {},
+    /* index=0x0b no mode defined */
+    {},
+    /* index=0x0c no mode defined */
+    {},
+    /* index=0x0d vga mode 0x0d */
+    { 40, 24, 8, 0x2000,     /* tw, th-1, ch, slength */
+      { 0x09, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+        0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x0e vga mode 0x0e */
+    { 80, 24, 8, 0x4000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+        0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x0f no mode defined */
+    {},
+    /* index=0x10 no mode defined */
+    {},
+    /* index=0x11 vga mode 0x0f */
+    { 80, 24, 14, 0x8000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xa3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+        0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+        0x01, 0x00, 0x01, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x12 vga mode 0x10 */
+    { 80, 24, 14, 0x8000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xa3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x13 no mode defined */
+    {},
+    /* index=0x14 no mode defined */
+    {},
+    /* index=0x15 no mode defined */
+    {},
+    /* index=0x16 no mode defined */
+    {},
+    /* index=0x17 vga mode 0x01 */
+    { 40, 24, 16, 0x0800,    /* tw, th-1, ch, slength */
+      { 0x08, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x67,                      /* miscreg */
+      { 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x0c, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x18 vga mode 0x03 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x67,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x0c, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x19 vga mode 0x07 */
+    { 80, 24, 16, 0x1000,    /* tw, th-1, ch, slength */
+      { 0x00, 0x03, 0x00, 0x02 },    /* sequ_regs */
+      0x66,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+        0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+        0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+        0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+        0x0e, 0x00, 0x0f, 0x08 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1a vga mode 0x11 */
+    { 80, 29, 16, 0x0000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+        0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1b vga mode 0x12 */
+    { 80, 29, 16, 0x0000,    /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
+        0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1c vga mode 0x13 */
+    { 40, 24, 8, 0x0000,     /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x0e },    /* sequ_regs */
+      0x63,                      /* miscreg */
+      { 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+        0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+        0x41, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+    /* index=0x1d vga mode 0x6a */
+    { 100, 36, 16, 0x0000,   /* tw, th-1, ch, slength */
+      { 0x01, 0x0f, 0x00, 0x06 },    /* sequ_regs */
+      0xe3,                      /* miscreg */
+      { 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
+        0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
+        0xff },                      /* crtc_regs */
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+        0x01, 0x00, 0x0f, 0x00 },    /* actl_regs */
+      { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+    },
+};
diff --git a/vgasrc/geodelx.h b/vgasrc/geodelx.h
new file mode 100644
index 0000000..d825c87
--- /dev/null
+++ b/vgasrc/geodelx.h
@@ -0,0 +1,144 @@ 
+// Geode LX VGA functions
+//
+// Copyright (C) 2009 Chris Kindt
+//
+// Writen for Google Summer of Code 2009 for the coreboot project
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+#ifndef  GEODELX_H
+#define  GEODELX_H
+
+#include "ioport.h" // outb
+#include "farptr.h" // SET_FARVAR
+#include "biosvar.h" // GET_BDA
+#include "vgatables.h" // VGAREG_*
+#include "util.h" // memset
+#include "types.h"
+
+#define lxdprintf(lvl, fmt, args...) do {             \
+        if (DEBUG_GEODELX && (lvl) <= DEBUG_GEODELX)  \
+            __dprintf((fmt) , ##args );               \
+    } while (0)
+
+
+#define VRC_INDEX                       0xAC1C  // Index register
+#define VRC_DATA                        0xAC1E  // Data register
+#define VR_UNLOCK                       0xFC53  // Virtual register unlock code
+
+#define EXTENDED_REGISTER_LOCK          0x30
+#define EXTENDED_MODE_CONTROL           0x43
+#define EXTENDED_START_ADDR             0x44
+
+#define CRTCE_UNLOCK                    0x4c
+#define CRTCE_LOCK                      0xff
+
+/* PCI */
+#define AMD_PCI_ID                      0x1022
+#define LX_PCI_ID                       0x2081
+
+#define VENDOR_ID                       0x00
+#define COMMAND                         0x04
+#define IO_SPACE                        (1 << 0)
+#define MEM_SPACE                       (1 << 1)
+#define BUS_MASTER                      (1 << 2)
+#define SPECIAL_CYCLES                  (1 << 3)
+#define MEM_WR_INVALIDATE               (1 << 4)
+#define VGA_PALETTE_SNOOP               (1 << 5)
+#define PARITY_RESPONSE                 (1 << 6)
+#define WAIT_CYCLE_CONTROL              (1 << 7)
+#define SERR_ENABLE                     (1 << 8)
+#define FAST_BACK_TO_BACK               (1 << 9)
+
+#define BAR0                            0x10
+#define BAR1                            0x14
+#define BAR2                            0x18
+#define BAR3                            0x1C
+#define BAR4                            0x20
+#define BAR5                            0x24
+// Graphics-specific registers:
+#define OEM_BAR0                        0x50
+#define OEM_BAR1                        0x54
+#define OEM_BAR2                        0x58
+#define OEM_BAR3                        0x5C
+
+#define LX_PCI_ADDR                     0x80000900
+#define LX_PCI_CMD                      (LX_PCI_ADDR + 0x04)
+#define LX_PCI_FB                       (LX_PCI_ADDR + 0x10)
+#define LX_PCI_DC                       (LX_PCI_ADDR + 0x18)
+#define LX_PCI_VP                       (LX_PCI_ADDR + 0x1c)
+
+#define DC_LOCK_LOCK                    0x00000000
+#define DC_LOCK_UNLOCK                  0x00004758
+
+/* LX MSRs */
+#define MSR_GLIU0                       (1 << 28)
+#define MSR_GLIU0_BASE4                 (MSR_GLIU0 + 0x23)
+#define GLIU0_IOD_BM_0                  (MSR_GLIU0 + 0xE0)
+#define GLIU0_IOD_BM_1                  (MSR_GLIU0 + 0xE1)
+#define DC_SPARE                        0x80000011
+#define VP_MSR_CONFIG                   0x48002001
+
+/* DC REG OFFSET */
+#define DC_UNLOCK                       0x0
+#define DC_GENERAL_CFG                  0x4
+#define DC_DISPLAY_CFG                  0x8
+#define DC_ARB_CFG                      0xc
+#define DC_FB_ST_OFFSET                 0x10
+#define DC_CB_ST_OFFSET                 0x14
+#define DC_CURS_ST_OFFSET               0x18
+#define DC_GLIU0_MEM_OFFSET             0x84
+
+/* VP REG OFFSET */
+#define VP_VCFG                         0x0
+#define VP_DCFG                         0x8
+#define VP_MISC                         0x50
+
+
+/* DC bits */
+#define DC_VGAE                         (1 << 7)
+#define DC_GDEN                         (1 << 3)
+#define DC_TRUP                         (1 << 6)
+
+/* VP bits */
+#define VP_CRT_EN                       (1 << 0)
+#define VP_HSYNC_EN                     (1 << 1)
+#define VP_VSYNC_EN                     (1 << 2)
+#define VP_DAC_BL_EN                    (1 << 3)
+#define VP_CRT_SKEW                     (1 << 16)
+#define VP_BYP_BOTH                     (1 << 0)
+
+/* Masks */
+#define VP_MSR_CFG_MSK                  0x0
+#define DC_CFG_MSK                      0xf000a6
+
+extern struct VideoParam_s lx_video_param_table[];
+extern u8 geode_str[];
+
+struct pci_data {
+    u32 signature;
+    u16 vendor;
+    u16 device;
+    u16 vitaldata;
+    u16 dlen;
+    u8 drevision;
+    u8 class_lo;
+    u16 class_hi;
+    u16 ilen;
+    u16 irevision;
+    u8 type;
+    u8 indicator;
+    u16 reserved;
+} PACKED;
+
+#define PCI_ROM_SIGNATURE 0x52494350 // PCIR
+#define PCIROM_CODETYPE_X86 0
+#define LAST_IMAGE 0x80
+#define PNP_SIGNATURE 0x506e5024 // $PnP
+
+
+int geodelx_init();
+void geodelx_demo();
+
+#endif
diff --git a/vgasrc/vga.c b/vgasrc/vga.c
index 88cbb01..3be0a1d 100644
--- a/vgasrc/vga.c
+++ b/vgasrc/vga.c
@@ -15,10 +15,12 @@ 
 #include "biosvar.h" // GET_BDA
 #include "util.h" // memset
 #include "vgatables.h" // find_vga_entry
+#include "geodelx.h"
 
 // XXX
 #define CONFIG_VBE 0
 #define CONFIG_CIRRUS 0
+#define CONFIG_GEODELX 0
 
 // XXX
 #define DEBUG_VGA_POST 1
@@ -1362,6 +1364,9 @@  vga_post(struct bregs *regs)
 
     vgahw_init();
 
+    if(CONFIG_GEODELX)
+        geodelx_init();
+
     init_bios_area();
 
     if (CONFIG_VBE)
@@ -1376,9 +1381,16 @@  vga_post(struct bregs *regs)
     // XXX - clear screen and display info
 
     // XXX: fill it
-    SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
+    if(CONFIG_GEODELX)
+        SET_VGA(video_save_pointer_table[0], (u32)lx_video_param_table);
+    else
+        SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
+
     SET_VGA(video_save_pointer_table[1], get_global_seg());
 
+    if(CONFIG_GEODELX)
+        geodelx_demo();
+
     // Fixup checksum
     extern u8 _rom_header_size, _rom_header_checksum;
     SET_VGA(_rom_header_checksum, 0);
diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S
index 7802bdb..844ca3e 100644
--- a/vgasrc/vgaentry.S
+++ b/vgasrc/vgaentry.S
@@ -28,7 +28,26 @@  _rom_header_size:
 _rom_header_entry:
         jmp _optionrom_entry
 _rom_header_checksum:
-        .space 22
+
+.ifdef _rom_pcidata
+    .org 0x18
+    .word _rom_pcidata
+.else
+    .space 20
+.endif
+
+.ifdef _rom_pnpdata
+    .org 0x1a
+    .word _rom_pnpdata
+.else
+    .space 2
+.endif
+
+/* used by x */
+_rom_header_vga_magic:
+    .org 0x1e
+    .asciz "IBM VGA Compatible"
+
 
 
 /****************************************************************