-// 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" // geodelx_init
-#include "ioport.h" // outb
-#include "farptr.h" // SET_FARVAR
-#include "biosvar.h" // GET_BDA
-#include "vgabios.h" // VGAREG_*
-#include "util.h" // memset
-#include "stdvga.h" // VGAREG_VGA_CRTC_ADDRESS
-
-
-/****************************************************************
-* 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 = stdvga_init();
- if (ret)
- return ret;
-
- dprintf(1,"GEODELX_INIT\n");
-
- if ((ret=legacyio_check())) {
- dprintf(1,"GEODELX_INIT legacyio_check=0x%x\n",ret);
- }
-
- // Updated timings from geode datasheets, table 6-53 in particular
- static u8 *new_crtc[] VAR16 = {
- lx_crtc_01, lx_crtc_01, lx_crtc_03, lx_crtc_03,
- lx_crtc_04, lx_crtc_05, lx_crtc_06, lx_crtc_07,
- 0, 0, 0, 0, 0,
- lx_crtc_0d, lx_crtc_0e, lx_crtc_0f, lx_crtc_0f,
- lx_crtc_11, lx_crtc_11, lx_crtc_13 };
- int i;
- for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
- u8 *crtc = GET_GLOBAL(new_crtc[i]);
- if (!crtc)
- continue;
- struct vgamode_s *vmode_g = find_vga_entry(i);
- if (!vmode_g)
- continue;
- SET_VGA(vmode_g->crtc_regs, crtc);
- }
-
- ret |= vp_setup();
- ret |= dc_setup();
-
- return ret;
-}