1 // Geode LX VGA functions
3 // Copyright (C) 2009 Chris Kindt
5 // Written for Google Summer of Code 2009 for the coreboot project
7 // This file may be distributed under the terms of the GNU LGPLv3 license.
10 #include "ioport.h" // outb
11 #include "farptr.h" // SET_FARVAR
12 #include "biosvar.h" // GET_BDA
13 #include "vgabios.h" // VGAREG_*
14 #include "util.h" // memset
18 #include "stdvga.h" // VGAREG_VGA_CRTC_ADDRESS
21 /****************************************************************
22 * MSR and High Mem access through VSA Virtual Register
23 ****************************************************************/
25 static union u64_u32_u lx_msrRead(u32 msrAddr)
29 "movw $0x0AC1C, %%dx \n"
30 "movl $0xFC530007, %%eax \n"
34 : "=a" (val.lo), "=d"(val.hi)
41 static void lx_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
45 "movw $0x0AC1C, %%dx \n"
46 "movl $0xFC530007, %%eax \n"
52 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
57 static u32 lx_memRead(u32 addr)
61 "movw $0x0AC1C, %%dx \n"
62 "movl $0xFC530001, %%eax \n"
74 static void lx_memWrite(u32 addr, u32 and, u32 or )
77 "movw $0x0AC1C, %%dx \n"
78 "movl $0xFC530001, %%eax \n"
83 : "b"(addr), "S" (and), "D" (or)
88 static int legacyio_check(void)
93 val=lx_msrRead(MSR_GLIU0_BASE4);
94 if (val.lo != 0x0A0fffe0)
97 val=lx_msrRead(GLIU0_IOD_BM_0);
98 if (val.lo != 0x3c0ffff0)
101 val=lx_msrRead(GLIU0_IOD_BM_1);
102 if (val.lo != 0x3d0ffff0)
108 /****************************************************************
109 * Extened CRTC Register functions
110 ****************************************************************/
111 static void crtce_lock(void)
113 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
114 outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
117 static void crtce_unlock(void)
119 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
120 outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
123 static u8 crtce_read(u8 reg)
128 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
129 val = inb(VGAREG_VGA_CRTC_DATA);
135 static void crtce_write(u8 reg, u8 val)
138 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
139 outb(val, VGAREG_VGA_CRTC_DATA);
143 /****************************************************************
144 * Display Controller Functions
145 ****************************************************************/
146 static u32 dc_read(u16 seg, u32 reg)
148 u32 val, *dest_far = (void*)reg;
149 val = GET_FARVAR(seg,*dest_far);
153 static void dc_write(u16 seg, u32 reg, u32 val)
155 u32 *dest_far = (void*)reg;
156 SET_FARVAR(seg,*dest_far,val);
159 static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
161 u32 val = dc_read(seg,reg);
164 dc_write(seg,reg,val);
167 static void dc_unlock(u16 seg)
169 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
172 static void dc_lock(u16 seg)
174 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
177 static u16 dc_map(u16 seg)
181 reg = crtce_read(EXTENDED_MODE_CONTROL);
198 crtce_write(EXTENDED_MODE_CONTROL,reg);
202 static void dc_unmap(void)
208 /****************************************************************
210 ****************************************************************/
212 /* Set up the dc (display controller) portion of the geodelx
213 * The dc provides hardware support for VGA graphics
214 * for features not accessible from the VGA registers,
215 * the dc's pci bar can be mapped to a vga memory segment
217 static int dc_setup(void)
222 dprintf(2, "DC_SETUP\n");
224 seg = dc_map(SEG_GRAPH);
227 /* zero memory config */
228 dc_write(seg,DC_FB_ST_OFFSET,0x0);
229 dc_write(seg,DC_CB_ST_OFFSET,0x0);
230 dc_write(seg,DC_CURS_ST_OFFSET,0x0);
232 /* read fb-bar from pci, then point dc to the fb base */
233 dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
234 outl(LX_PCI_FB,PORT_PCI_CMD);
235 fb = inl(PORT_PCI_DATA);
237 dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
240 dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
241 dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
249 /* Setup the vp (video processor) portion of the geodelx
250 * Under VGA modes the vp was handled by softvg from inside VSA2.
251 * Without a softvg module, access is only available through a pci bar.
252 * The High Mem Access virtual register is used to configure the
253 * pci mmio bar from 16bit friendly io space.
259 dprintf(2,"VP_SETUP\n");
260 /* set output to crt and RGB/YUV */
261 lx_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
263 /* get vp register base from pci */
264 outl(LX_PCI_VP,PORT_PCI_CMD);
265 vp = inl(PORT_PCI_DATA);
267 /* Set mmio registers
268 * there may be some timing issues here, the reads seem
269 * to slow things down enough work reliably
272 reg = lx_memRead(vp+VP_MISC);
273 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
274 lx_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
275 reg = lx_memRead(vp+VP_MISC);
276 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
278 reg = lx_memRead(vp+VP_DCFG);
279 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
280 lx_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
281 reg = lx_memRead(vp+VP_DCFG);
282 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
287 static u8 lx_crtc_01[] VAR16 = {
288 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
289 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
290 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
292 static u8 lx_crtc_03[] VAR16 = {
293 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
294 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
295 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
297 static u8 lx_crtc_04[] VAR16 = {
298 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
299 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
302 static u8 lx_crtc_05[] VAR16 = {
303 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
304 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
307 static u8 lx_crtc_06[] VAR16 = {
308 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
309 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
312 static u8 lx_crtc_07[] VAR16 = {
313 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
314 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
315 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
317 static u8 lx_crtc_0d[] VAR16 = {
318 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
319 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
322 static u8 lx_crtc_0e[] VAR16 = {
323 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
324 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
327 static u8 lx_crtc_0f[] VAR16 = {
328 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
329 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
332 static u8 lx_crtc_11[] VAR16 = {
333 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
334 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
337 static u8 lx_crtc_13[] VAR16 = {
338 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
339 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
343 int geodelx_init(void)
347 dprintf(1,"GEODELX_INIT\n");
349 if ((ret=legacyio_check())) {
350 dprintf(1,"GEODELX_INIT legacyio_check=0x%x\n",ret);
353 // Updated timings from geode datasheets, table 6-53 in particular
354 static u8 *new_crtc[] VAR16 = {
355 lx_crtc_01, lx_crtc_01, lx_crtc_03, lx_crtc_03,
356 lx_crtc_04, lx_crtc_05, lx_crtc_06, lx_crtc_07,
358 lx_crtc_0d, lx_crtc_0e, lx_crtc_0f, lx_crtc_0f,
359 lx_crtc_11, lx_crtc_11, lx_crtc_13 };
361 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
362 u8 *crtc = GET_GLOBAL(new_crtc[i]);
365 struct vgamode_s *vmode_g = find_vga_entry(i);
368 SET_VGA(vmode_g->crtc_regs, crtc);