blob: 5c6caf045397b307cb62aabe25ea8e5454d8b1c3 [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
Nils31eabf92012-01-14 12:11:41 -050010#include "farptr.h" // SET_FARVAR
11#include "biosvar.h" // GET_BDA
12#include "vgabios.h" // VGAREG_*
13#include "util.h" // memset
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -050014#include "stdvga.h" // stdvga_crtc_write
Kevin O'Connor707d2162012-01-15 00:06:33 -050015#include "pci.h" // pci_config_readl
16#include "pci_regs.h" // PCI_BASE_ADDRESS_0
Nils31eabf92012-01-14 12:11:41 -050017
18
19/****************************************************************
20* MSR and High Mem access through VSA Virtual Register
21****************************************************************/
22
23static union u64_u32_u geode_msrRead(u32 msrAddr)
24{
25 union u64_u32_u val;
26 asm __volatile__ (
27 "movw $0x0AC1C, %%dx \n"
28 "movl $0xFC530007, %%eax \n"
29 "outl %%eax, %%dx \n"
30 "addb $2, %%dl \n"
31 "inw %%dx, %%ax \n"
32 : "=a" (val.lo), "=d"(val.hi)
33 : "c"(msrAddr)
34 : "cc"
35 );
36 return val;
37}
38
39static void geode_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
40{
41 asm __volatile__ (
42 "push %%eax \n"
43 "movw $0x0AC1C, %%dx \n"
44 "movl $0xFC530007, %%eax \n"
45 "outl %%eax, %%dx \n"
46 "addb $2, %%dl \n"
47 "pop %%eax \n"
48 "outw %%ax, %%dx \n"
49 :
50 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
51 : "%edx","cc"
52 );
53}
54
55static u32 geode_memRead(u32 addr)
56{
57 u32 val;
58 asm __volatile__ (
59 "movw $0x0AC1C, %%dx \n"
60 "movl $0xFC530001, %%eax \n"
61 "outl %%eax, %%dx \n"
62 "addb $2, %%dl \n"
63 "inw %%dx, %%ax \n"
64 : "=a" (val)
65 : "b"(addr)
66 : "cc"
67 );
68
69 return val;
70}
71
72static void geode_memWrite(u32 addr, u32 and, u32 or )
73{
74 asm __volatile__ (
75 "movw $0x0AC1C, %%dx \n"
76 "movl $0xFC530001, %%eax \n"
77 "outl %%eax, %%dx \n"
78 "addb $2, %%dl \n"
79 "outw %%ax, %%dx \n"
80 :
81 : "b"(addr), "S" (and), "D" (or)
82 : "%eax","cc"
83 );
84}
85
86static int legacyio_check(void)
87{
88 int ret=0;
89 union u64_u32_u val;
90
Nils24ddd862012-01-14 12:15:14 -050091 if (CONFIG_VGA_GEODEGX2)
92 val=geode_msrRead(GLIU0_P2D_BM_4);
93 else
94 val=geode_msrRead(MSR_GLIU0_BASE4);
Nils31eabf92012-01-14 12:11:41 -050095 if (val.lo != 0x0A0fffe0)
96 ret|=1;
97
98 val=geode_msrRead(GLIU0_IOD_BM_0);
99 if (val.lo != 0x3c0ffff0)
100 ret|=2;
101
102 val=geode_msrRead(GLIU0_IOD_BM_1);
103 if (val.lo != 0x3d0ffff0)
104 ret|=4;
105
106 return ret;
107}
108
109/****************************************************************
110* Extened CRTC Register functions
111****************************************************************/
112static void crtce_lock(void)
113{
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500114 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
115 , CRTCE_LOCK);
Nils31eabf92012-01-14 12:11:41 -0500116}
117
118static void crtce_unlock(void)
119{
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500120 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
121 , CRTCE_UNLOCK);
Nils31eabf92012-01-14 12:11:41 -0500122}
123
124static u8 crtce_read(u8 reg)
125{
Nils31eabf92012-01-14 12:11:41 -0500126 crtce_unlock();
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500127 u8 val = stdvga_crtc_read(VGAREG_VGA_CRTC_ADDRESS, reg);
Nils31eabf92012-01-14 12:11:41 -0500128 crtce_lock();
Nils31eabf92012-01-14 12:11:41 -0500129 return val;
130}
131
132static void crtce_write(u8 reg, u8 val)
133{
134 crtce_unlock();
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500135 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, reg, val);
Nils31eabf92012-01-14 12:11:41 -0500136 crtce_lock();
137}
138
139/****************************************************************
140* Display Controller Functions
141****************************************************************/
142static u32 dc_read(u16 seg, u32 reg)
143{
144 u32 val, *dest_far = (void*)reg;
145 val = GET_FARVAR(seg,*dest_far);
146 return val;
147}
148
149static void dc_write(u16 seg, u32 reg, u32 val)
150{
151 u32 *dest_far = (void*)reg;
152 SET_FARVAR(seg,*dest_far,val);
153}
154
155static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
156{
157 u32 val = dc_read(seg,reg);
158 val &=and;
159 val |=or;
160 dc_write(seg,reg,val);
161}
162
163static void dc_unlock(u16 seg)
164{
165 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
166}
167
168static void dc_lock(u16 seg)
169{
170 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
171}
172
173static u16 dc_map(u16 seg)
174{
175 u8 reg;
176
177 reg = crtce_read(EXTENDED_MODE_CONTROL);
178 reg &= 0xf9;
179 switch (seg) {
180 case SEG_GRAPH:
181 reg |= 0x02;
182 break;
183 case SEG_MTEXT:
184 reg |= 0x04;
185 break;
186 case SEG_CTEXT:
187 reg |= 0x06;
188 break;
189 default:
190 seg=0;
191 break;
192 }
193
194 crtce_write(EXTENDED_MODE_CONTROL,reg);
195 return seg;
196}
197
198static void dc_unmap(void)
199{
200 dc_map(0);
201}
202
203
204/****************************************************************
205* Init Functions
206****************************************************************/
207
208/* Set up the dc (display controller) portion of the geodelx
209* The dc provides hardware support for VGA graphics
210* for features not accessible from the VGA registers,
211* the dc's pci bar can be mapped to a vga memory segment
212*/
213static int dc_setup(void)
214{
215 u32 fb, dc_fb;
216 u16 seg;
217
218 dprintf(2, "DC_SETUP\n");
219
220 seg = dc_map(SEG_GRAPH);
221 dc_unlock(seg);
222
223 /* zero memory config */
224 dc_write(seg,DC_FB_ST_OFFSET,0x0);
225 dc_write(seg,DC_CB_ST_OFFSET,0x0);
226 dc_write(seg,DC_CURS_ST_OFFSET,0x0);
227
228 /* read fb-bar from pci, then point dc to the fb base */
229 dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
Kevin O'Connor707d2162012-01-15 00:06:33 -0500230 fb = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0);
Nils31eabf92012-01-14 12:11:41 -0500231 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)
Kevin O'Connor707d2162012-01-15 00:06:33 -0500257 geode_msrWrite(VP_MSR_CONFIG_GX2, ~0, ~0xf8, 0, 0);
Nils24ddd862012-01-14 12:15:14 -0500258 else
Kevin O'Connor707d2162012-01-15 00:06:33 -0500259 geode_msrWrite(VP_MSR_CONFIG_LX, ~0, ~0xf8, 0, 0);
Nils31eabf92012-01-14 12:11:41 -0500260
261 /* get vp register base from pci */
Kevin O'Connor707d2162012-01-15 00:06:33 -0500262 vp = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3);
Nils31eabf92012-01-14 12:11:41 -0500263
264 /* Set mmio registers
265 * there may be some timing issues here, the reads seem
266 * to slow things down enough work reliably
267 */
268
269 reg = geode_memRead(vp+VP_MISC);
270 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
271 geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
272 reg = geode_memRead(vp+VP_MISC);
273 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
274
275 reg = geode_memRead(vp+VP_DCFG);
276 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
277 geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
278 reg = geode_memRead(vp+VP_DCFG);
279 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
280
281 return 0;
282}
283
284static u8 geode_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,
288 0xff };
289static u8 geode_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,
293 0xff };
294static u8 geode_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,
298 0xff };
299static u8 geode_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,
303 0xff };
304static u8 geode_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,
308 0xff };
309static u8 geode_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,
313 0xff };
314static u8 geode_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,
318 0xff };
319static u8 geode_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,
323 0xff };
324static u8 geode_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,
328 0xff };
329static u8 geode_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,
333 0xff };
334static u8 geode_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,
338 0xff };
339
340int geodevga_init(void)
341{
342 int ret = stdvga_init();
343 if (ret)
344 return ret;
345
346 dprintf(1,"GEODEVGA_INIT\n");
347
348 if ((ret=legacyio_check())) {
349 dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
350 }
351
352 // Updated timings from geode datasheets, table 6-53 in particular
353 static u8 *new_crtc[] VAR16 = {
354 geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
355 geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
356 0, 0, 0, 0, 0,
357 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
358 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
359 int i;
360 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
361 u8 *crtc = GET_GLOBAL(new_crtc[i]);
Kevin O'Connor69b01cb2012-01-14 23:25:24 -0500362 if (crtc)
363 stdvga_override_crtc(i, crtc);
Nils31eabf92012-01-14 12:11:41 -0500364 }
365
Kevin O'Connor8cf8f8e2012-01-16 19:05:27 -0500366 if (GET_GLOBAL(VgaBDF) < 0)
367 // Device should be at 00:01.1
368 SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
Nils31eabf92012-01-14 12:11:41 -0500369 ret |= vp_setup();
370 ret |= dc_setup();
371
372 return ret;
373}