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.
9 #include "geodelx.h" // geodelx_init
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
15 #include "stdvga.h" // VGAREG_VGA_CRTC_ADDRESS
18 /****************************************************************
19 * MSR and High Mem access through VSA Virtual Register
20 ****************************************************************/
22 static union u64_u32_u lx_msrRead(u32 msrAddr)
26 "movw $0x0AC1C, %%dx \n"
27 "movl $0xFC530007, %%eax \n"
31 : "=a" (val.lo), "=d"(val.hi)
38 static void lx_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
42 "movw $0x0AC1C, %%dx \n"
43 "movl $0xFC530007, %%eax \n"
49 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
54 static u32 lx_memRead(u32 addr)
58 "movw $0x0AC1C, %%dx \n"
59 "movl $0xFC530001, %%eax \n"
71 static void lx_memWrite(u32 addr, u32 and, u32 or )
74 "movw $0x0AC1C, %%dx \n"
75 "movl $0xFC530001, %%eax \n"
80 : "b"(addr), "S" (and), "D" (or)
85 static int legacyio_check(void)
90 val=lx_msrRead(MSR_GLIU0_BASE4);
91 if (val.lo != 0x0A0fffe0)
94 val=lx_msrRead(GLIU0_IOD_BM_0);
95 if (val.lo != 0x3c0ffff0)
98 val=lx_msrRead(GLIU0_IOD_BM_1);
99 if (val.lo != 0x3d0ffff0)
105 /****************************************************************
106 * Extened CRTC Register functions
107 ****************************************************************/
108 static void crtce_lock(void)
110 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
111 outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
114 static void crtce_unlock(void)
116 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
117 outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
120 static u8 crtce_read(u8 reg)
125 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
126 val = inb(VGAREG_VGA_CRTC_DATA);
132 static void crtce_write(u8 reg, u8 val)
135 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
136 outb(val, VGAREG_VGA_CRTC_DATA);
140 /****************************************************************
141 * Display Controller Functions
142 ****************************************************************/
143 static u32 dc_read(u16 seg, u32 reg)
145 u32 val, *dest_far = (void*)reg;
146 val = GET_FARVAR(seg,*dest_far);
150 static void dc_write(u16 seg, u32 reg, u32 val)
152 u32 *dest_far = (void*)reg;
153 SET_FARVAR(seg,*dest_far,val);
156 static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
158 u32 val = dc_read(seg,reg);
161 dc_write(seg,reg,val);
164 static void dc_unlock(u16 seg)
166 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
169 static void dc_lock(u16 seg)
171 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
174 static u16 dc_map(u16 seg)
178 reg = crtce_read(EXTENDED_MODE_CONTROL);
195 crtce_write(EXTENDED_MODE_CONTROL,reg);
199 static void dc_unmap(void)
205 /****************************************************************
207 ****************************************************************/
209 /* Set up the dc (display controller) portion of the geodelx
210 * The dc provides hardware support for VGA graphics
211 * for features not accessible from the VGA registers,
212 * the dc's pci bar can be mapped to a vga memory segment
214 static int dc_setup(void)
219 dprintf(2, "DC_SETUP\n");
221 seg = dc_map(SEG_GRAPH);
224 /* zero memory config */
225 dc_write(seg,DC_FB_ST_OFFSET,0x0);
226 dc_write(seg,DC_CB_ST_OFFSET,0x0);
227 dc_write(seg,DC_CURS_ST_OFFSET,0x0);
229 /* read fb-bar from pci, then point dc to the fb base */
230 dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
231 outl(LX_PCI_FB,PORT_PCI_CMD);
232 fb = inl(PORT_PCI_DATA);
234 dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
237 dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
238 dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
246 /* Setup the vp (video processor) portion of the geodelx
247 * Under VGA modes the vp was handled by softvg from inside VSA2.
248 * Without a softvg module, access is only available through a pci bar.
249 * The High Mem Access virtual register is used to configure the
250 * pci mmio bar from 16bit friendly io space.
256 dprintf(2,"VP_SETUP\n");
257 /* set output to crt and RGB/YUV */
258 lx_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
260 /* get vp register base from pci */
261 outl(LX_PCI_VP,PORT_PCI_CMD);
262 vp = inl(PORT_PCI_DATA);
264 /* Set mmio registers
265 * there may be some timing issues here, the reads seem
266 * to slow things down enough work reliably
269 reg = lx_memRead(vp+VP_MISC);
270 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
271 lx_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
272 reg = lx_memRead(vp+VP_MISC);
273 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
275 reg = lx_memRead(vp+VP_DCFG);
276 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
277 lx_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
278 reg = lx_memRead(vp+VP_DCFG);
279 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
284 static u8 lx_crtc_01[] VAR16 = {
285 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
286 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
287 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
289 static u8 lx_crtc_03[] VAR16 = {
290 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
291 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
292 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
294 static u8 lx_crtc_04[] VAR16 = {
295 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
296 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
299 static u8 lx_crtc_05[] VAR16 = {
300 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
301 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
304 static u8 lx_crtc_06[] VAR16 = {
305 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
306 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
309 static u8 lx_crtc_07[] VAR16 = {
310 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
311 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
312 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
314 static u8 lx_crtc_0d[] VAR16 = {
315 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
316 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
319 static u8 lx_crtc_0e[] VAR16 = {
320 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
321 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
324 static u8 lx_crtc_0f[] VAR16 = {
325 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
326 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
329 static u8 lx_crtc_11[] VAR16 = {
330 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
331 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
334 static u8 lx_crtc_13[] VAR16 = {
335 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
336 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
340 int geodelx_init(void)
342 int ret = stdvga_init();
346 dprintf(1,"GEODELX_INIT\n");
348 if ((ret=legacyio_check())) {
349 dprintf(1,"GEODELX_INIT legacyio_check=0x%x\n",ret);
352 // Updated timings from geode datasheets, table 6-53 in particular
353 static u8 *new_crtc[] VAR16 = {
354 lx_crtc_01, lx_crtc_01, lx_crtc_03, lx_crtc_03,
355 lx_crtc_04, lx_crtc_05, lx_crtc_06, lx_crtc_07,
357 lx_crtc_0d, lx_crtc_0e, lx_crtc_0f, lx_crtc_0f,
358 lx_crtc_11, lx_crtc_11, lx_crtc_13 };
360 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
361 u8 *crtc = GET_GLOBAL(new_crtc[i]);
364 struct vgamode_s *vmode_g = find_vga_entry(i);
367 SET_VGA(vmode_g->crtc_regs, crtc);