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
20 /****************************************************************
21 * MSR and High Mem access through VSA Virtual Register
22 ****************************************************************/
24 static union u64_u32_u lx_msrRead(u32 msrAddr)
28 "movw $0x0AC1C, %%dx \n"
29 "movl $0xFC530007, %%eax \n"
33 : "=a" (val.lo), "=d"(val.hi)
40 static void lx_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
44 "movw $0x0AC1C, %%dx \n"
45 "movl $0xFC530007, %%eax \n"
51 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
56 static u32 lx_memRead(u32 addr)
60 "movw $0x0AC1C, %%dx \n"
61 "movl $0xFC530001, %%eax \n"
73 static void lx_memWrite(u32 addr, u32 and, u32 or )
76 "movw $0x0AC1C, %%dx \n"
77 "movl $0xFC530001, %%eax \n"
82 : "b"(addr), "S" (and), "D" (or)
87 static int legacyio_check(void)
92 val=lx_msrRead(MSR_GLIU0_BASE4);
93 if (val.lo != 0x0A0fffe0)
96 val=lx_msrRead(GLIU0_IOD_BM_0);
97 if (val.lo != 0x3c0ffff0)
100 val=lx_msrRead(GLIU0_IOD_BM_1);
101 if (val.lo != 0x3d0ffff0)
107 /****************************************************************
108 * Extened CRTC Register functions
109 ****************************************************************/
110 static void crtce_lock(void)
112 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
113 outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
116 static void crtce_unlock(void)
118 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
119 outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
122 static u8 crtce_read(u8 reg)
127 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
128 val = inb(VGAREG_VGA_CRTC_DATA);
134 static void crtce_write(u8 reg, u8 val)
137 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
138 outb(val, VGAREG_VGA_CRTC_DATA);
142 /****************************************************************
143 * Display Controller Functions
144 ****************************************************************/
145 static u32 dc_read(u16 seg, u32 reg)
147 u32 val, *dest_far = (void*)reg;
148 val = GET_FARVAR(seg,*dest_far);
152 static void dc_write(u16 seg, u32 reg, u32 val)
154 u32 *dest_far = (void*)reg;
155 SET_FARVAR(seg,*dest_far,val);
158 static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
160 u32 val = dc_read(seg,reg);
163 dc_write(seg,reg,val);
166 static void dc_unlock(u16 seg)
168 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
171 static void dc_lock(u16 seg)
173 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
176 static u16 dc_map(u16 seg)
180 reg = crtce_read(EXTENDED_MODE_CONTROL);
197 crtce_write(EXTENDED_MODE_CONTROL,reg);
201 static void dc_unmap(void)
207 /****************************************************************
209 ****************************************************************/
211 /* Set up the dc (display controller) portion of the geodelx
212 * The dc provides hardware support for VGA graphics
213 * for features not accessible from the VGA registers,
214 * the dc's pci bar can be mapped to a vga memory segment
216 static int dc_setup(void)
221 dprintf(2, "DC_SETUP\n");
223 seg = dc_map(SEG_GRAPH);
226 /* zero memory config */
227 dc_write(seg,DC_FB_ST_OFFSET,0x0);
228 dc_write(seg,DC_CB_ST_OFFSET,0x0);
229 dc_write(seg,DC_CURS_ST_OFFSET,0x0);
231 /* read fb-bar from pci, then point dc to the fb base */
232 dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
233 outl(LX_PCI_FB,PORT_PCI_CMD);
234 fb = inl(PORT_PCI_DATA);
236 dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
239 dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
240 dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
248 /* Setup the vp (video processor) portion of the geodelx
249 * Under VGA modes the vp was handled by softvg from inside VSA2.
250 * Without a softvg module, access is only available through a pci bar.
251 * The High Mem Access virtual register is used to configure the
252 * pci mmio bar from 16bit friendly io space.
258 dprintf(2,"VP_SETUP\n");
259 /* set output to crt and RGB/YUV */
260 lx_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
262 /* get vp register base from pci */
263 outl(LX_PCI_VP,PORT_PCI_CMD);
264 vp = inl(PORT_PCI_DATA);
266 /* Set mmio registers
267 * there may be some timing issues here, the reads seem
268 * to slow things down enough work reliably
271 reg = lx_memRead(vp+VP_MISC);
272 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
273 lx_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
274 reg = lx_memRead(vp+VP_MISC);
275 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
277 reg = lx_memRead(vp+VP_DCFG);
278 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
279 lx_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
280 reg = lx_memRead(vp+VP_DCFG);
281 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
286 static u8 lx_crtc_01[] VAR16 = {
287 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
288 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
289 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
291 static u8 lx_crtc_03[] VAR16 = {
292 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
293 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
294 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
296 static u8 lx_crtc_04[] VAR16 = {
297 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
298 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
301 static u8 lx_crtc_05[] VAR16 = {
302 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
303 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
306 static u8 lx_crtc_06[] VAR16 = {
307 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
308 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
311 static u8 lx_crtc_07[] VAR16 = {
312 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
313 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
314 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
316 static u8 lx_crtc_0d[] VAR16 = {
317 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
318 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
321 static u8 lx_crtc_0e[] VAR16 = {
322 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
323 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
326 static u8 lx_crtc_0f[] VAR16 = {
327 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
328 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
331 static u8 lx_crtc_11[] VAR16 = {
332 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
333 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
336 static u8 lx_crtc_13[] VAR16 = {
337 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
338 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
342 int geodelx_init(void)
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);