blob: 3da1b7c085e3a75f285cf58bc67436c91d90e80f [file] [log] [blame]
Nils31eabf92012-01-14 12:11:41 -05001// Geode GX2/LX VGA functions
2//
3// Copyright (C) 2009 Chris Kindt
4//
5// Written for Google Summer of Code 2009 for the coreboot project
6//
7// This file may be distributed under the terms of the GNU LGPLv3 license.
8
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
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -050015#include "stdvga.h" // stdvga_crtc_write
Nils31eabf92012-01-14 12:11:41 -050016
17
18/****************************************************************
19* MSR and High Mem access through VSA Virtual Register
20****************************************************************/
21
22static union u64_u32_u geode_msrRead(u32 msrAddr)
23{
24 union u64_u32_u val;
25 asm __volatile__ (
26 "movw $0x0AC1C, %%dx \n"
27 "movl $0xFC530007, %%eax \n"
28 "outl %%eax, %%dx \n"
29 "addb $2, %%dl \n"
30 "inw %%dx, %%ax \n"
31 : "=a" (val.lo), "=d"(val.hi)
32 : "c"(msrAddr)
33 : "cc"
34 );
35 return val;
36}
37
38static void geode_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
39{
40 asm __volatile__ (
41 "push %%eax \n"
42 "movw $0x0AC1C, %%dx \n"
43 "movl $0xFC530007, %%eax \n"
44 "outl %%eax, %%dx \n"
45 "addb $2, %%dl \n"
46 "pop %%eax \n"
47 "outw %%ax, %%dx \n"
48 :
49 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
50 : "%edx","cc"
51 );
52}
53
54static u32 geode_memRead(u32 addr)
55{
56 u32 val;
57 asm __volatile__ (
58 "movw $0x0AC1C, %%dx \n"
59 "movl $0xFC530001, %%eax \n"
60 "outl %%eax, %%dx \n"
61 "addb $2, %%dl \n"
62 "inw %%dx, %%ax \n"
63 : "=a" (val)
64 : "b"(addr)
65 : "cc"
66 );
67
68 return val;
69}
70
71static void geode_memWrite(u32 addr, u32 and, u32 or )
72{
73 asm __volatile__ (
74 "movw $0x0AC1C, %%dx \n"
75 "movl $0xFC530001, %%eax \n"
76 "outl %%eax, %%dx \n"
77 "addb $2, %%dl \n"
78 "outw %%ax, %%dx \n"
79 :
80 : "b"(addr), "S" (and), "D" (or)
81 : "%eax","cc"
82 );
83}
84
85static int legacyio_check(void)
86{
87 int ret=0;
88 union u64_u32_u val;
89
Nils24ddd862012-01-14 12:15:14 -050090 if (CONFIG_VGA_GEODEGX2)
91 val=geode_msrRead(GLIU0_P2D_BM_4);
92 else
93 val=geode_msrRead(MSR_GLIU0_BASE4);
Nils31eabf92012-01-14 12:11:41 -050094 if (val.lo != 0x0A0fffe0)
95 ret|=1;
96
97 val=geode_msrRead(GLIU0_IOD_BM_0);
98 if (val.lo != 0x3c0ffff0)
99 ret|=2;
100
101 val=geode_msrRead(GLIU0_IOD_BM_1);
102 if (val.lo != 0x3d0ffff0)
103 ret|=4;
104
105 return ret;
106}
107
108/****************************************************************
109* Extened CRTC Register functions
110****************************************************************/
111static void crtce_lock(void)
112{
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500113 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
114 , CRTCE_LOCK);
Nils31eabf92012-01-14 12:11:41 -0500115}
116
117static void crtce_unlock(void)
118{
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500119 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
120 , CRTCE_UNLOCK);
Nils31eabf92012-01-14 12:11:41 -0500121}
122
123static u8 crtce_read(u8 reg)
124{
Nils31eabf92012-01-14 12:11:41 -0500125 crtce_unlock();
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500126 u8 val = stdvga_crtc_read(VGAREG_VGA_CRTC_ADDRESS, reg);
Nils31eabf92012-01-14 12:11:41 -0500127 crtce_lock();
Nils31eabf92012-01-14 12:11:41 -0500128 return val;
129}
130
131static void crtce_write(u8 reg, u8 val)
132{
133 crtce_unlock();
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500134 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, reg, val);
Nils31eabf92012-01-14 12:11:41 -0500135 crtce_lock();
136}
137
138/****************************************************************
139* Display Controller Functions
140****************************************************************/
141static u32 dc_read(u16 seg, u32 reg)
142{
143 u32 val, *dest_far = (void*)reg;
144 val = GET_FARVAR(seg,*dest_far);
145 return val;
146}
147
148static void dc_write(u16 seg, u32 reg, u32 val)
149{
150 u32 *dest_far = (void*)reg;
151 SET_FARVAR(seg,*dest_far,val);
152}
153
154static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
155{
156 u32 val = dc_read(seg,reg);
157 val &=and;
158 val |=or;
159 dc_write(seg,reg,val);
160}
161
162static void dc_unlock(u16 seg)
163{
164 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
165}
166
167static void dc_lock(u16 seg)
168{
169 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
170}
171
172static u16 dc_map(u16 seg)
173{
174 u8 reg;
175
176 reg = crtce_read(EXTENDED_MODE_CONTROL);
177 reg &= 0xf9;
178 switch (seg) {
179 case SEG_GRAPH:
180 reg |= 0x02;
181 break;
182 case SEG_MTEXT:
183 reg |= 0x04;
184 break;
185 case SEG_CTEXT:
186 reg |= 0x06;
187 break;
188 default:
189 seg=0;
190 break;
191 }
192
193 crtce_write(EXTENDED_MODE_CONTROL,reg);
194 return seg;
195}
196
197static void dc_unmap(void)
198{
199 dc_map(0);
200}
201
202
203/****************************************************************
204* Init Functions
205****************************************************************/
206
207/* Set up the dc (display controller) portion of the geodelx
208* The dc provides hardware support for VGA graphics
209* for features not accessible from the VGA registers,
210* the dc's pci bar can be mapped to a vga memory segment
211*/
212static int dc_setup(void)
213{
214 u32 fb, dc_fb;
215 u16 seg;
216
217 dprintf(2, "DC_SETUP\n");
218
219 seg = dc_map(SEG_GRAPH);
220 dc_unlock(seg);
221
222 /* zero memory config */
223 dc_write(seg,DC_FB_ST_OFFSET,0x0);
224 dc_write(seg,DC_CB_ST_OFFSET,0x0);
225 dc_write(seg,DC_CURS_ST_OFFSET,0x0);
226
227 /* read fb-bar from pci, then point dc to the fb base */
228 dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
229 outl(GEODE_PCI_FB,PORT_PCI_CMD);
230 fb = inl(PORT_PCI_DATA);
231 if (fb!=dc_fb) {
232 dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
233 }
234
235 dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
236 dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
237
238 dc_lock(seg);
239 dc_unmap();
240
241 return 0;
242}
243
244/* Setup the vp (video processor) portion of the geodelx
245* Under VGA modes the vp was handled by softvg from inside VSA2.
246* Without a softvg module, access is only available through a pci bar.
247* The High Mem Access virtual register is used to configure the
248* pci mmio bar from 16bit friendly io space.
249*/
250int vp_setup(void)
251{
252 u32 reg,vp;
253
254 dprintf(2,"VP_SETUP\n");
255 /* set output to crt and RGB/YUV */
Nils24ddd862012-01-14 12:15:14 -0500256 if (CONFIG_VGA_GEODEGX2)
257 geode_msrWrite(VP_MSR_CONFIG_GX2,~0 ,~0xf8,0,0);
258 else
259 geode_msrWrite(VP_MSR_CONFIG_LX,~0 ,~0xf8,0,0);
Nils31eabf92012-01-14 12:11:41 -0500260
261 /* get vp register base from pci */
262 outl(GEODE_PCI_VP,PORT_PCI_CMD);
263 vp = inl(PORT_PCI_DATA);
264
265 /* Set mmio registers
266 * there may be some timing issues here, the reads seem
267 * to slow things down enough work reliably
268 */
269
270 reg = geode_memRead(vp+VP_MISC);
271 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
272 geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
273 reg = geode_memRead(vp+VP_MISC);
274 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
275
276 reg = geode_memRead(vp+VP_DCFG);
277 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
278 geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
279 reg = geode_memRead(vp+VP_DCFG);
280 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
281
282 return 0;
283}
284
285static u8 geode_crtc_01[] VAR16 = {
286 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
287 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
288 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
289 0xff };
290static u8 geode_crtc_03[] VAR16 = {
291 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
292 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
293 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
294 0xff };
295static u8 geode_crtc_04[] VAR16 = {
296 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
297 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
299 0xff };
300static u8 geode_crtc_05[] VAR16 = {
301 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
302 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
304 0xff };
305static u8 geode_crtc_06[] VAR16 = {
306 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
307 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
309 0xff };
310static u8 geode_crtc_07[] VAR16 = {
311 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
312 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
313 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
314 0xff };
315static u8 geode_crtc_0d[] VAR16 = {
316 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
317 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
319 0xff };
320static u8 geode_crtc_0e[] VAR16 = {
321 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
322 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
324 0xff };
325static u8 geode_crtc_0f[] VAR16 = {
326 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
327 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
329 0xff };
330static u8 geode_crtc_11[] VAR16 = {
331 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
332 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
334 0xff };
335static u8 geode_crtc_13[] VAR16 = {
336 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
337 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
339 0xff };
340
341int geodevga_init(void)
342{
343 int ret = stdvga_init();
344 if (ret)
345 return ret;
346
347 dprintf(1,"GEODEVGA_INIT\n");
348
349 if ((ret=legacyio_check())) {
350 dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
351 }
352
353 // Updated timings from geode datasheets, table 6-53 in particular
354 static u8 *new_crtc[] VAR16 = {
355 geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
356 geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
357 0, 0, 0, 0, 0,
358 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
359 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
360 int i;
361 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
362 u8 *crtc = GET_GLOBAL(new_crtc[i]);
363 if (!crtc)
364 continue;
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500365 struct vgamode_s *vmode_g = stdvga_find_mode(i);
Nils31eabf92012-01-14 12:11:41 -0500366 if (!vmode_g)
367 continue;
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500368 struct stdvga_mode_s *stdmode_g = container_of(
369 vmode_g, struct stdvga_mode_s, info);
370 SET_VGA(stdmode_g->crtc_regs, crtc);
Nils31eabf92012-01-14 12:11:41 -0500371 }
372
373 ret |= vp_setup();
374 ret |= dc_setup();
375
376 return ret;
377}