vgabios: Merge support for GeodeLX vga bios.
GeodeLX support based on a patch sent by Chris Kindt on 20090825. The
patch provides basic support for running the vga bios on a Geode
device.
The original patch has been updated with the following:
* Updates to merge with the current code,
* geode specific timings are loaded at init time
* PCI code was dropped as the current code now supports pci
* Updates for Kconfig
* dropped redundant lxdprintf
* dropped geode_demo screen writing
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
diff --git a/vgasrc/geodelx.c b/vgasrc/geodelx.c
new file mode 100644
index 0000000..6c0f838
--- /dev/null
+++ b/vgasrc/geodelx.c
@@ -0,0 +1,374 @@
+// 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"
+#include "bregs.h"
+
+
+/****************************************************************
+* 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(void)
+{
+ 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(void)
+{
+ outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
+ outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
+}
+
+static void crtce_unlock(void)
+{
+ 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(void)
+{
+ 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(void)
+{
+ u32 fb, dc_fb;
+ u16 seg;
+
+ dprintf(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(void)
+{
+ u32 reg,vp;
+
+ dprintf(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);
+ dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
+ lx_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
+ reg = lx_memRead(vp+VP_MISC);
+ dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
+
+ reg = lx_memRead(vp+VP_DCFG);
+ dprintf(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);
+ dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
+
+ return 0;
+}
+
+static u8 lx_crtc_01[] VAR16 = {
+ 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 };
+static u8 lx_crtc_03[] VAR16 = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
+ 0xff };
+static u8 lx_crtc_04[] VAR16 = {
+ 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 };
+static u8 lx_crtc_05[] VAR16 = {
+ 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
+ 0xff };
+static u8 lx_crtc_06[] VAR16 = {
+ 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 };
+static u8 lx_crtc_07[] VAR16 = {
+ 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 };
+static u8 lx_crtc_0d[] VAR16 = {
+ 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 };
+static u8 lx_crtc_0e[] VAR16 = {
+ 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 };
+static u8 lx_crtc_0f[] VAR16 = {
+ 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 };
+static u8 lx_crtc_11[] VAR16 = {
+ 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 };
+static u8 lx_crtc_13[] VAR16 = {
+ 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 };
+
+int geodelx_init(void)
+{
+ int ret;
+
+ dprintf(1,"GEODELX_INIT\n");
+
+ if ((ret=legacyio_check())) {
+ dprintf(1,"GEODELX_INIT legacyio_check=0x%x\n",ret);
+ }
+
+ // Updated timings from geode datasheets, table 6-53 in particular
+ static u8 *new_crtc[] VAR16 = {
+ lx_crtc_01, lx_crtc_01, lx_crtc_03, lx_crtc_03,
+ lx_crtc_04, lx_crtc_05, lx_crtc_06, lx_crtc_07,
+ 0, 0, 0, 0, 0,
+ lx_crtc_0d, lx_crtc_0e, lx_crtc_0f, lx_crtc_0f,
+ lx_crtc_11, lx_crtc_11, lx_crtc_13 };
+ int i;
+ for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
+ u8 *crtc = GET_GLOBAL(new_crtc[i]);
+ if (!crtc)
+ continue;
+ struct vgamode_s *vmode_g = find_vga_entry(i);
+ if (!vmode_g)
+ continue;
+ SET_VGA(vmode_g->crtc_regs, crtc);
+ }
+
+ ret |= vp_setup();
+ ret |= dc_setup();
+
+ return ret;
+}
diff --git a/vgasrc/geodelx.h b/vgasrc/geodelx.h
new file mode 100644
index 0000000..8ce07bb
--- /dev/null
+++ b/vgasrc/geodelx.h
@@ -0,0 +1,81 @@
+// 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
+
+#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
+
+// 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
+
+int geodelx_init();
+
+#endif
diff --git a/vgasrc/vga.c b/vgasrc/vga.c
index ba07584..37f227c 100644
--- a/vgasrc/vga.c
+++ b/vgasrc/vga.c
@@ -18,6 +18,7 @@
#include "optionroms.h" // struct pci_data
#include "config.h" // CONFIG_*
#include "vbe.h" // vbe_*
+#include "geodelx.h" // geodelx_init
// XXX
#define DEBUG_VGA_POST 1
@@ -1569,6 +1570,9 @@
vgahw_init();
+ if (CONFIG_VGA_GEODELX)
+ geodelx_init();
+
init_bios_area();
vbe_init(regs->ah, regs->al);