1 // Geode GX2/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 "geodevga.h" // geodevga_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 geode_msrRead(u32 msrAddr)
26 "movw $0x0AC1C, %%dx \n"
27 "movl $0xFC530007, %%eax \n"
31 : "=a" (val.lo), "=d"(val.hi)
38 static void geode_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 geode_memRead(u32 addr)
58 "movw $0x0AC1C, %%dx \n"
59 "movl $0xFC530001, %%eax \n"
71 static void geode_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 if (CONFIG_VGA_GEODEGX2)
91 val=geode_msrRead(GLIU0_P2D_BM_4);
93 val=geode_msrRead(MSR_GLIU0_BASE4);
94 if (val.lo != 0x0A0fffe0)
97 val=geode_msrRead(GLIU0_IOD_BM_0);
98 if (val.lo != 0x3c0ffff0)
101 val=geode_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(GEODE_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 if (CONFIG_VGA_GEODEGX2)
262 geode_msrWrite(VP_MSR_CONFIG_GX2,~0 ,~0xf8,0,0);
264 geode_msrWrite(VP_MSR_CONFIG_LX,~0 ,~0xf8,0,0);
266 /* get vp register base from pci */
267 outl(GEODE_PCI_VP,PORT_PCI_CMD);
268 vp = inl(PORT_PCI_DATA);
270 /* Set mmio registers
271 * there may be some timing issues here, the reads seem
272 * to slow things down enough work reliably
275 reg = geode_memRead(vp+VP_MISC);
276 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
277 geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
278 reg = geode_memRead(vp+VP_MISC);
279 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
281 reg = geode_memRead(vp+VP_DCFG);
282 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
283 geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
284 reg = geode_memRead(vp+VP_DCFG);
285 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
290 static u8 geode_crtc_01[] VAR16 = {
291 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
292 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
293 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
295 static u8 geode_crtc_03[] VAR16 = {
296 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
297 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
298 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
300 static u8 geode_crtc_04[] VAR16 = {
301 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
302 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
305 static u8 geode_crtc_05[] VAR16 = {
306 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
307 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
310 static u8 geode_crtc_06[] VAR16 = {
311 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
312 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
315 static u8 geode_crtc_07[] VAR16 = {
316 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
317 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
318 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
320 static u8 geode_crtc_0d[] VAR16 = {
321 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
322 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
325 static u8 geode_crtc_0e[] VAR16 = {
326 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
327 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
330 static u8 geode_crtc_0f[] VAR16 = {
331 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
332 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
335 static u8 geode_crtc_11[] VAR16 = {
336 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
337 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
340 static u8 geode_crtc_13[] VAR16 = {
341 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
342 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
346 int geodevga_init(void)
348 int ret = stdvga_init();
352 dprintf(1,"GEODEVGA_INIT\n");
354 if ((ret=legacyio_check())) {
355 dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
358 // Updated timings from geode datasheets, table 6-53 in particular
359 static u8 *new_crtc[] VAR16 = {
360 geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
361 geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
363 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
364 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
366 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
367 u8 *crtc = GET_GLOBAL(new_crtc[i]);
370 struct vgamode_s *vmode_g = stdvga_find_mode(i);
373 struct stdvga_mode_s *stdmode_g = container_of(
374 vmode_g, struct stdvga_mode_s, info);
375 SET_VGA(stdmode_g->crtc_regs, crtc);