Patchwork Geode LX VGA BIOS Patch

login
register
about
Submitter Chris Kindt
Date 2009-08-12 10:02:08
Message ID <4A829320.4020606@umbc.edu>
Download mbox | patch
Permalink /patch/107/
State Not Applicable
Headers show

Comments

Chris Kindt - 2009-08-12 10:02:08
Hello coreboot

     These initial patches enable booting with the SeaBIOS VGA BIOS on
Geode LX hardware.

     corebootv3-vga-msr.patch
         adds 3 vga legacy io routing msrs

     seabios-vgarom-geodelx.patch
         adds geodelx specific functions to the vgabios


     The rom will run from either coreboot/vm86 or SeaBIOS. When finished
"GeodeLX GPL VGA BIOS" should be displayed on the screen.

     My test hardware is an Artec Group DBE-61.  I have successfully
built and used the rom with gcc-4.1.2/binutils-2.17 and
gcc-4.3.3/binutils-2.18.  VGA functionality has been tested with the
linux vga console, svgalib utils, libpayload vga driver and SeaBIOS.  I 
have also confirmed that linux lxfb and Xorg function correctly after
the rom is loaded.


         Chris Kindt

Signed-off-by: Chris Kindt <chriskindt@umbc.edu>

diff --git a/Makefile b/Makefile
index 3758909..f69adf4 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..8154df0
--- /dev/null
+++ b/vgasrc/geodelx.c
@@ -0,0 +1,590 @@
+// Geode LX VGA functions
+//
+// Copyright (C) 2009 Chris Kindt
+//
+// Written 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"
+
+#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)
+    );
+    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)
+    );
+}
+
+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)
+    );
+    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)
+    );
+}
+
+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;
+}
+
+/****************************************************************
+* Extended 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 Controller 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 controller) portion of the geodelx
+*  The dc provides hardware support for VGA graphics
+*  for features not accessible from the VGA registers,
+*  the dc's pci bar can be mapped 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 available 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%08x\n",ret);
+        return ret;
+    }
+    ret |= vp_setup();
+    ret |= dc_setup();
+
+    return ret;
+
+}
+
+static inline void
+call16_vgaint_lx(u32 eax, u32 ebx,u32 ecx, u32 edx)
+{
+    asm volatile(
+        "int $0x10\n"
+        "cli\n"
+        "cld"
+        :
+        : "a"(eax), "b"(ebx),"c"(ecx), "d"(edx)
+        : "cc", "memory");
+}
+
+
+u8 geode_str[] VAR16 = "GeodeLX GPL VGA BIOS";
+
+void VISIBLE16 geodelx_demo()
+{
+    int x;
+
+    lxdprintf(2,"GEODELX_DEMO\n");
+
+    call16_vgaint_lx(0x0003,0x0000,0x0000,0x0000);
+
+    for (x=0;x<sizeof(geode_str)-1;x++) {
+        call16_vgaint_lx(0x0e00+GET_GLOBAL(geode_str[x]),0x0000,0x0000,0x0000);
+    }
+}
+
+/* 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 */
+    },
+};
+
+/* PCI Header
+*
+* This might deserve a pci_header.S file, it is here for now
+*/
+
+ASM16(
+    "   .globl _rom_pcidata             \n"
+    "_rom_pcidata:                      \n"
+    "_rom_pcidata_sig:                  \n"
+    "   .ascii \"PCIR\"                 \n"
+    "_rom_pcidata_venderid:             \n"
+    "   .word 0x1022                    \n"
+    "_rom_pcidata_productid:            \n"
+    "   .word 0x2081                    \n"
+    "_rom_pcidata_productdata:          \n"
+    "   .word 0x0000                    \n"
+    "_rom_pcidata_size:                 \n"
+    "   .word 0x0018                    \n"
+    "_rom_pcidata_rev:                  \n"
+    "   .byte 0x00                      \n"
+    "_rom_pcidata_class:                \n"
+    "   .byte 0x00                      \n"
+    "   .word 0x0300                    \n"
+    "_rom_pcidata_imglength:            \n"
+    "   .word 0x0000                    \n"
+    "_rom_pcidata_coderev:              \n"
+    "   .word 0x0000                    \n"
+    "_rom_pcidata_codetype:             \n"
+    "   .byte 0x00                      \n"
+    "_rom_pcidata_indicator:            \n"
+    "   .byte 0x80                      \n"
+    "_rom_pcidata_resvd:                \n"
+    "   .word 0x0000                    \n"
+);
+
diff --git a/vgasrc/geodelx.h b/vgasrc/geodelx.h
new file mode 100644
index 0000000..3fc49b3
--- /dev/null
+++ b/vgasrc/geodelx.h
@@ -0,0 +1,121 @@
+// Geode LX VGA functions
+//
+// Copyright (C) 2009 Chris Kindt
+//
+// Written 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 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[];
+
+int geodelx_init();
+void geodelx_demo();
+
+#endif
diff --git a/vgasrc/vga.c b/vgasrc/vga.c
index 88cbb01..d9c7bd1 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 1
 
 // 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,18 @@ vga_post(struct bregs *regs)
     // XXX - clear screen and display info
 
     // XXX: fill it
+    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;
     // 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..6d7b3d5 100644
--- a/vgasrc/vgaentry.S
+++ b/vgasrc/vgaentry.S
@@ -28,7 +28,20 @@ _rom_header_size:
 _rom_header_entry:
         jmp _optionrom_entry
 _rom_header_checksum:
-        .space 22
+
+.ifdef _rom_pcidata
+    .org 0x18 
+    .word _rom_pcidata
+    .space 2
+.else
+    .size 22
+.endif
+
+/* used by x */
+_rom_header_vga_magic:
+    .org 0x1e
+    .asciz "IBM VGA Compatible"
+
 
 
 /****************************************************************
Carl-Daniel Hailfinger - 2009-08-12 15:35:33
Hi Chris,

thanks for the patches.
A short licensing question if I may: You picked LGPLv3-only as the
license. Is that OK with all of your mentors?

Regards,
Carl-Daniel
Stefan Reinauer - 2009-08-12 15:44:39
On 8/12/09 5:35 PM, Carl-Daniel Hailfinger wrote:
> Hi Chris,
>
> thanks for the patches.
> A short licensing question if I may: You picked LGPLv3-only as the
> license. Is that OK with all of your mentors?
>
>   

Kevin licensed his vgabios code GPLv3. Since it's a so called viral
license, Chris didn't have much of a choice.


Stefan
Kevin O'Connor - 2009-08-14 01:00:10
On Wed, Aug 12, 2009 at 05:44:39PM +0200, Stefan Reinauer wrote:
> Kevin licensed his vgabios code GPLv3.

SeaBIOS (including the vgabios code) is LGPLv3.

-Kevin
Kevin O'Connor - 2009-08-14 01:33:55
On Wed, Aug 12, 2009 at 06:02:08AM -0400, Chris Kindt wrote:
>     These initial patches enable booting with the SeaBIOS VGA BIOS on
> Geode LX hardware.

Wow.  I was unaware that there was a GSOC project for this.

I have a few comments - see below.

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

Does the geode do something "magical" with the above sequence?
Otherwise, I'm a bit confused on how the asm works.

[...]
> +static inline void
> +call16_vgaint_lx(u32 eax, u32 ebx,u32 ecx, u32 edx)
> +{
> +    asm volatile(
> +        "int $0x10\n"
> +        "cli\n"
> +        "cld"
> +        :
> +        : "a"(eax), "b"(ebx),"c"(ecx), "d"(edx)
> +        : "cc", "memory");
> +}

It looks like you're not indicating that the registers could get
clobberred.  Also, the existing call16_simpint() or direct calls to
the bios handlers may work.

> +/* PCI Header
> +*
> +* This might deserve a pci_header.S file, it is here for now
> +*/
> +
> +ASM16(
> +    "   .globl _rom_pcidata             \n"
> +    "_rom_pcidata:                      \n"
> +    "_rom_pcidata_sig:                  \n"
> +    "   .ascii \"PCIR\"                 \n"
> +    "_rom_pcidata_venderid:             \n"
> +    "   .word 0x1022                    \n"
[...]

I think it would be better to define this with a C struct - see the
"struct pci_data" defined in src/optionroms.c.

> +    if(CONFIG_GEODELX)
> +        geodelx_demo();
> +
> +    // Fixup checksum
> +    extern u8 _rom_header_size, _rom_header_checksum;
>      // Fixup checksum
>      extern u8 _rom_header_size, _rom_header_checksum;

Bad merge?

[... out of order ...]
>  // XXX
>  #define CONFIG_VBE 0
>  #define CONFIG_CIRRUS 0
> +#define CONFIG_GEODELX 1

For SeaBIOS, I don't thing geode should be the default.

Finally, I'd be happy to commit this to SeaBIOS.  I think it does
re-raise the question of whether SeaBIOS' VGA support should be
spun-off into it's own repository, though.

-Kevin
Chris Kindt - 2009-08-15 04:00:36
Kevin O'Connor wrote:
> On Wed, Aug 12, 2009 at 06:02:08AM -0400, Chris Kindt wrote:
>>     These initial patches enable booting with the SeaBIOS VGA BIOS on
>> Geode LX hardware.
> 
> Wow.  I was unaware that there was a GSOC project for this.
> 
> I have a few comments - see below.
>> +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)
> 
> Does the geode do something "magical" with the above sequence?
> Otherwise, I'm a bit confused on how the asm works.
This is a magic port. The geode SMM (VSA2) provides a few functions from 
this interface.

> 
> [...]
>> +static inline void
>> +call16_vgaint_lx(u32 eax, u32 ebx,u32 ecx, u32 edx)
>> +{
>> +    asm volatile(
>> +        "int $0x10\n"
>> +        "cli\n"
>> +        "cld"
>> +        :
>> +        : "a"(eax), "b"(ebx),"c"(ecx), "d"(edx)
>> +        : "cc", "memory");
>> +}
> 
> It looks like you're not indicating that the registers could get
> clobberred.  Also, the existing call16_simpint() or direct calls to
> the bios handlers may work.
I am replacing it with direct calls.

> 
>> +/* PCI Header
>> +*
>> +* This might deserve a pci_header.S file, it is here for now
>> +*/
>> +
>> +ASM16(
>> +    "   .globl _rom_pcidata             \n"
>> +    "_rom_pcidata:                      \n"
>> +    "_rom_pcidata_sig:                  \n"
>> +    "   .ascii \"PCIR\"                 \n"
>> +    "_rom_pcidata_venderid:             \n"
>> +    "   .word 0x1022                    \n"
> [...]
> 
> I think it would be better to define this with a C struct - see the
> "struct pci_data" defined in src/optionroms.c.
> 
This was originally added in vgaentry.S. It was relocated in an attempt 
to contain everything in geodelx.* files. I agree that a struct would be 
a much better format.

>> +    if(CONFIG_GEODELX)
>> +        geodelx_demo();
>> +
>> +    // Fixup checksum
>> +    extern u8 _rom_header_size, _rom_header_checksum;
>>      // Fixup checksum
>>      extern u8 _rom_header_size, _rom_header_checksum;
> 
> Bad merge?
> 
I missed that.


> [... out of order ...]
>>  // XXX
>>  #define CONFIG_VBE 0
>>  #define CONFIG_CIRRUS 0
>> +#define CONFIG_GEODELX 1
> 
> For SeaBIOS, I don't thing geode should be the default.

I intended this patch to be used by someone wishing to build a geode 
rom. I wasn't thinking about inclusion yet.

> 
> Finally, I'd be happy to commit this to SeaBIOS.  I think it does
> re-raise the question of whether SeaBIOS' VGA support should be
> spun-off into it's own repository, though.
> 
> -Kevin
> 

I am happy that you would be willing to commit. An updated file is on 
the way.

	Thanks,
	Chris Kindt
Tom Sylla - 2009-08-17 14:32:37
On Sat, Aug 15, 2009 at 12:00 AM, Chris Kindt<chriskindt@umbc.edu> wrote:
>>> +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)
>>
>> Does the geode do something "magical" with the above sequence?
>> Otherwise, I'm a bit confused on how the asm works.
>
> This is a magic port. The geode SMM (VSA2) provides a few functions from
> this interface.

To be a little more clear, writing to port ac1c causes an SMI, VSA
looks at the value written to the fake port, does whatever it is
asked, and returns things based on the "function" being called. If
this particular case is just used to read an MSR, you could just do it
natively instead.

Patch

Index: northbridge/amd/geodelx/grphinit.c
===================================================================
--- northbridge/amd/geodelx/grphinit.c	(revision 1166)
+++ northbridge/amd/geodelx/grphinit.c	(working copy)
@@ -22,7 +22,25 @@ 
 #include <amd_geodelx.h>
 #include <console.h>
 #include <statictree.h>
+#include <msr.h>
+#include <lib.h>
 
+#ifdef CONFIG_PCI_OPTION_ROM_RUN
+/* Legacy VGA Ports , from AMD's Virtualized PCI Config Space datasheet */
+static const struct msrinit geodelx_vga_msr[] = {
+    {.msrnum = MSR_GLIU0_BASE4, {.lo = 0x0a0fffe0, .hi = 0x80000000}},
+    {.msrnum = GLIU0_IOD_BM_0,  {.lo = 0x3c0ffff0, .hi = 0x80000000}},
+    {.msrnum = GLIU0_IOD_BM_1,  {.lo = 0x3d0ffff0, .hi = 0x80000000}},
+};
+
+void geodelx_vga_msr_init(void)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(geodelx_vga_msr); i++)
+        wrmsr(geodelx_vga_msr[i].msrnum, geodelx_vga_msr[i].msr);
+}
+#endif
+
 /**
  * This function mirrors the Graphics_Init routine in GeodeROM.
  *
@@ -35,6 +53,10 @@ 
 	/* SoftVG initialization */
 	printk(BIOS_DEBUG, "Graphics init...\n");
 
+#ifdef CONFIG_PCI_OPTION_ROM_RUN
+	geodelx_vga_msr_init();
+#endif
+
 	/* Call SoftVG with the main configuration parameters. */
 	/* NOTE: SoftVG expects the memory size to be given in 2MB blocks. */