blob: c1e4244b56b61bcb472d84e28cc3ce14d1571015 [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
15#include "stdvga.h" // VGAREG_VGA_CRTC_ADDRESS
16
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{
113 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
114 outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
115}
116
117static void crtce_unlock(void)
118{
119 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
120 outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
121}
122
123static u8 crtce_read(u8 reg)
124{
125 u8 val;
126
127 crtce_unlock();
128 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
129 val = inb(VGAREG_VGA_CRTC_DATA);
130 crtce_lock();
131
132 return val;
133}
134
135static void crtce_write(u8 reg, u8 val)
136{
137 crtce_unlock();
138 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
139 outb(val, VGAREG_VGA_CRTC_DATA);
140 crtce_lock();
141}
142
143/****************************************************************
144* Display Controller Functions
145****************************************************************/
146static u32 dc_read(u16 seg, u32 reg)
147{
148 u32 val, *dest_far = (void*)reg;
149 val = GET_FARVAR(seg,*dest_far);
150 return val;
151}
152
153static void dc_write(u16 seg, u32 reg, u32 val)
154{
155 u32 *dest_far = (void*)reg;
156 SET_FARVAR(seg,*dest_far,val);
157}
158
159static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
160{
161 u32 val = dc_read(seg,reg);
162 val &=and;
163 val |=or;
164 dc_write(seg,reg,val);
165}
166
167static void dc_unlock(u16 seg)
168{
169 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
170}
171
172static void dc_lock(u16 seg)
173{
174 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
175}
176
177static u16 dc_map(u16 seg)
178{
179 u8 reg;
180
181 reg = crtce_read(EXTENDED_MODE_CONTROL);
182 reg &= 0xf9;
183 switch (seg) {
184 case SEG_GRAPH:
185 reg |= 0x02;
186 break;
187 case SEG_MTEXT:
188 reg |= 0x04;
189 break;
190 case SEG_CTEXT:
191 reg |= 0x06;
192 break;
193 default:
194 seg=0;
195 break;
196 }
197
198 crtce_write(EXTENDED_MODE_CONTROL,reg);
199 return seg;
200}
201
202static void dc_unmap(void)
203{
204 dc_map(0);
205}
206
207
208/****************************************************************
209* Init Functions
210****************************************************************/
211
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
216*/
217static int dc_setup(void)
218{
219 u32 fb, dc_fb;
220 u16 seg;
221
222 dprintf(2, "DC_SETUP\n");
223
224 seg = dc_map(SEG_GRAPH);
225 dc_unlock(seg);
226
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);
231
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);
236 if (fb!=dc_fb) {
237 dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
238 }
239
240 dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
241 dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
242
243 dc_lock(seg);
244 dc_unmap();
245
246 return 0;
247}
248
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.
254*/
255int vp_setup(void)
256{
257 u32 reg,vp;
258
259 dprintf(2,"VP_SETUP\n");
260 /* set output to crt and RGB/YUV */
Nils24ddd862012-01-14 12:15:14 -0500261 if (CONFIG_VGA_GEODEGX2)
262 geode_msrWrite(VP_MSR_CONFIG_GX2,~0 ,~0xf8,0,0);
263 else
264 geode_msrWrite(VP_MSR_CONFIG_LX,~0 ,~0xf8,0,0);
Nils31eabf92012-01-14 12:11:41 -0500265
266 /* get vp register base from pci */
267 outl(GEODE_PCI_VP,PORT_PCI_CMD);
268 vp = inl(PORT_PCI_DATA);
269
270 /* Set mmio registers
271 * there may be some timing issues here, the reads seem
272 * to slow things down enough work reliably
273 */
274
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);
280
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);
286
287 return 0;
288}
289
290static 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,
294 0xff };
295static 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,
299 0xff };
300static 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,
304 0xff };
305static 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,
309 0xff };
310static 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,
314 0xff };
315static 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,
319 0xff };
320static 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,
324 0xff };
325static 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,
329 0xff };
330static 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,
334 0xff };
335static 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,
339 0xff };
340static 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,
344 0xff };
345
346int geodevga_init(void)
347{
348 int ret = stdvga_init();
349 if (ret)
350 return ret;
351
352 dprintf(1,"GEODEVGA_INIT\n");
353
354 if ((ret=legacyio_check())) {
355 dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
356 }
357
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,
362 0, 0, 0, 0, 0,
363 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
364 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
365 int i;
366 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
367 u8 *crtc = GET_GLOBAL(new_crtc[i]);
368 if (!crtc)
369 continue;
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500370 struct vgamode_s *vmode_g = stdvga_find_mode(i);
Nils31eabf92012-01-14 12:11:41 -0500371 if (!vmode_g)
372 continue;
Kevin O'Connor10dff3d2012-01-09 19:19:44 -0500373 struct stdvga_mode_s *stdmode_g = container_of(
374 vmode_g, struct stdvga_mode_s, info);
375 SET_VGA(stdmode_g->crtc_regs, crtc);
Nils31eabf92012-01-14 12:11:41 -0500376 }
377
378 ret |= vp_setup();
379 ret |= dc_setup();
380
381 return ret;
382}