From 4c52fb4ce7513e3f13bd8272309e66bb9e2488a7 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sat, 24 Dec 2011 00:44:07 -0500 Subject: [PATCH] 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 --- Makefile | 3 +- src/Kconfig | 14 +- vgasrc/geodelx.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++ vgasrc/geodelx.h | 81 ++++++++++ vgasrc/vga.c | 4 + 5 files changed, 472 insertions(+), 4 deletions(-) create mode 100644 vgasrc/geodelx.c create mode 100644 vgasrc/geodelx.h diff --git a/Makefile b/Makefile index 7ac65fa..da6999c 100644 --- a/Makefile +++ b/Makefile @@ -170,7 +170,8 @@ $(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py # 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/vbe.c + vgasrc/vgatables.c vgasrc/vgafonts.c \ + vgasrc/clext.c vgasrc/vbe.c vgasrc/geodelx.c CFLAGS16VGA = $(CFLAGS16INC) -g -Isrc diff --git a/src/Kconfig b/src/Kconfig index ad16502..bd4550e 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -330,13 +330,19 @@ menu "VGA ROM" default n help Build support for Cirrus VGA emulation. - + config VGA_BOCHS bool "Bochs DISPI interface VGA BIOS" default n help Build support for Bochs DISPI interface - + + config VGA_GEODELX + bool "GeodeLX interface VGA BIOS" + default n + help + Build support for Geode vga + config VGA_PCI bool "PCI ROM Headers" default y @@ -349,15 +355,17 @@ menu "VGA ROM" hex "PCI Vendor ID" default 0x1013 if VGA_CIRRUS default 0x1234 if VGA_BOCHS + default 0x1022 if VGA_GEODELX default 0x0000 help Vendor ID for the PCI ROM - + config VGA_DID depends on VGA_PCI hex "PCI Device ID" default 0x00b8 if VGA_CIRRUS default 0x1111 if VGA_BOCHS + default 0x2081 if VGA_GEODELX default 0x0000 help Device ID for the PCI ROM 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; icrtc_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 @@ vga_post(struct bregs *regs) vgahw_init(); + if (CONFIG_VGA_GEODELX) + geodelx_init(); + init_bios_area(); vbe_init(regs->ah, regs->al); -- 2.25.1