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
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. */
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" +
/****************************************************************
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
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
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
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
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
On Sat, Aug 15, 2009 at 12:00 AM, Chris Kindtchriskindt@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.
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
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(®s); + + for (x=0;x<sizeof(geode_str)-1;x++) { + regs.eax=(0x0e00 + GET_GLOBAL(geode_str[x])); + handle_10(®s); + } +} + +/* 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" +
/****************************************************************
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
Another Updated Patch:
So far I have heard of problems when using a lcd connected to the vga port and when switching from X to back to the console. I was able to replicate problems and address them with this patch.
For the lcd issues, the left side of the screen was distorted and cropped. This was a timing problem from using incorrect modes. My crt was able to function correctly with these modes. There were two issues with the mode table. When creating the patch I copied the original seabios table instead of the geodelx modified table. Then even with the correct geodelx table, the seabios table is still addressed at compile time. The geodelx-v3 patch includes the modified table, while the geodelx-modehack patch is a temporary quick fix to address the right table.
For switching from X to the console, the display controller registers need to be reset to enable vga . These are DC_GENERAL_CFG=0x80 and DC_DISPLAY_CFG=0x48. The linux vgacon vt driver only saves the standard vga io ports and memory. I am looking into doing this with vesa extensions from X. For now an easy way to do this is to re-post the vgabios with vbetool or svgalib. I removed exiting if legacy io checking fails so reposting is possible.
seabios-geodelx-v3.patch -replaced video parameter table -removed quiting when legacy io fails -fixed spelling
seabios-geodelx-modehack.patch -temporary fix to use correct video timing
Chris Kindt
Signed-off-by: Chris Kindt chriskindt@umbc.edu
diff --git a/Makefile b/Makefile index d697fca..a3696c1 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..c0c8a70 --- /dev/null +++ b/vgasrc/geodelx.c @@ -0,0 +1,573 @@ +// 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" + +#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 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%x\n",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(®s); + + for (x=0;x<sizeof(geode_str)-1;x++) { + regs.eax=(0x0e00 + GET_GLOBAL(geode_str[x])); + handle_10(®s); + } +} + +/* 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, 0x8e, 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, 0x51, 0x9e, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9b, 0x8d, 0x8f, 0x28, 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, 0x00, 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, 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=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" +
/****************************************************************
diff --git a/vgasrc/vgatables.c b/vgasrc/vgatables.c index 0587e65..66ad3fc 100644 --- a/vgasrc/vgatables.c +++ b/vgasrc/vgatables.c @@ -380,7 +380,10 @@ static u8 palette3[] VAR16 = { ****************************************************************/
#define PAL(x) x, sizeof(x) -#define VPARAM(x) &video_param_table[x] + +extern struct VideoParam_s lx_video_param_table[]; +#define VPARAM(x) &lx_video_param_table[x] +//#define VPARAM(x) &video_param_table[x]
static struct vgamode_s vga_modes[] VAR16 = { //mode vparam model bits sstart pelm dac
On Tue, Aug 25, 2009 at 02:54:48PM -0400, Chris Kindt wrote:
Another Updated Patch:
So far I have heard of problems when using a lcd connected to the vga port and when switching from X to back to the console. I was able to replicate problems and address them with this patch.
For the lcd issues, the left side of the screen was distorted and cropped. This was a timing problem from using incorrect modes. My crt was able to function correctly with these modes. There were two issues with the mode table. When creating the patch I copied the original seabios table instead of the geodelx modified table. Then even with the correct geodelx table, the seabios table is still addressed at compile time. The geodelx-v3 patch includes the modified table, while the geodelx-modehack patch is a temporary quick fix to address the right table.
Hi Chris,
As before, the main seabios patch looks good to me. The "modehack" patch, of course, needs to be cleaned up before committing. Are you still working on this?
-Kevin
Kevin O'Connor wrote:
As before, the main seabios patch looks good to me. The "modehack" patch, of course, needs to be cleaned up before committing. Are you still working on this?
-Kevin
Yes, it is on my todo list. I was thinking about using a device operations structure or macros to replace the "if(hw_type)" statements. This might be overkill at the moment, however it would be helpful for any future hardware specific expansion. I am lacking insight on what such a struct should be. The following example is crafted mostly to fix the current problems I am having.
struct videoDevice { int (*present) (void); /* check for existence */ void (*enable) (int); /* enable device/mode */
void (*pre_init) (void); void (*post_init) (void); void (*set_mode) (u8 mode); struct VideoParam_s *vga_param_table[]; struct vgamode_s *vga_mode_table[];
void *hw_tables; };
struct videoDevice geodelx = { .present = legacyio_check, .pre_init = geodelx_init, .post_init = geodelx_demo, .vga_param_table = lx_param_table, .vga_mode_table = lx_mode_table, };
struct videoDevice cirrus = { .pre_init = cirrus_init, .set_mode = cirrus_set_video_mode, .hw_tables = cirrus_modes, };
struct videoDevice vbe = { .present = vbe_has_vbe_display, .enable = dispi_set_enable, .pre_init = vbe_init, .hw_tables = vbe_modes, };
Let me know what you think and I can work on a patch,
Chris Kindt
Hi Chris,
On Sun, Sep 13, 2009 at 03:48:58PM -0400, Chris Kindt wrote:
Kevin O'Connor wrote:
As before, the main seabios patch looks good to me. The "modehack" patch, of course, needs to be cleaned up before committing. Are you still working on this?
Yes, it is on my todo list. I was thinking about using a device operations structure or macros to replace the "if(hw_type)" statements. This might be overkill at the moment, however it would be helpful for any future hardware specific expansion. I am lacking insight on what such a struct should be. The following example is crafted mostly to fix the current problems I am having.
Is the intent to support multiple hardware backends with the same option rom binary?
The "if(hw_type)" scheme has the benefit that gcc can remove the unused code from the resulting binary. I think that will be harder for gcc if function pointers are used.
-Kevin