blob: 6c0f83834bb77a7ed6faa3a2270f061984938db5 [file] [log] [blame]
Kevin O'Connor4c52fb42011-12-24 00:44:07 -05001// Geode 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 "geodelx.h"
10#include "ioport.h" // outb
11#include "farptr.h" // SET_FARVAR
12#include "biosvar.h" // GET_BDA
13#include "vgatables.h" // VGAREG_*
14#include "util.h" // memset
15#include "config.h"
16#include "types.h"
17#include "bregs.h"
18
19
20/****************************************************************
21* MSR and High Mem access through VSA Virtual Register
22****************************************************************/
23
24static union u64_u32_u lx_msrRead(u32 msrAddr)
25{
26 union u64_u32_u val;
27 asm __volatile__ (
28 "movw $0x0AC1C, %%dx \n"
29 "movl $0xFC530007, %%eax \n"
30 "outl %%eax, %%dx \n"
31 "addb $2, %%dl \n"
32 "inw %%dx, %%ax \n"
33 : "=a" (val.lo), "=d"(val.hi)
34 : "c"(msrAddr)
35 : "cc"
36 );
37 return val;
38}
39
40static void lx_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
41{
42 asm __volatile__ (
43 "push %%eax \n"
44 "movw $0x0AC1C, %%dx \n"
45 "movl $0xFC530007, %%eax \n"
46 "outl %%eax, %%dx \n"
47 "addb $2, %%dl \n"
48 "pop %%eax \n"
49 "outw %%ax, %%dx \n"
50 :
51 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
52 : "%edx","cc"
53 );
54}
55
56static u32 lx_memRead(u32 addr)
57{
58 u32 val;
59 asm __volatile__ (
60 "movw $0x0AC1C, %%dx \n"
61 "movl $0xFC530001, %%eax \n"
62 "outl %%eax, %%dx \n"
63 "addb $2, %%dl \n"
64 "inw %%dx, %%ax \n"
65 : "=a" (val)
66 : "b"(addr)
67 : "cc"
68 );
69
70 return val;
71}
72
73static void lx_memWrite(u32 addr, u32 and, u32 or )
74{
75 asm __volatile__ (
76 "movw $0x0AC1C, %%dx \n"
77 "movl $0xFC530001, %%eax \n"
78 "outl %%eax, %%dx \n"
79 "addb $2, %%dl \n"
80 "outw %%ax, %%dx \n"
81 :
82 : "b"(addr), "S" (and), "D" (or)
83 : "%eax","cc"
84 );
85}
86
87static int legacyio_check(void)
88{
89 int ret=0;
90 union u64_u32_u val;
91
92 val=lx_msrRead(MSR_GLIU0_BASE4);
93 if (val.lo != 0x0A0fffe0)
94 ret|=1;
95
96 val=lx_msrRead(GLIU0_IOD_BM_0);
97 if (val.lo != 0x3c0ffff0)
98 ret|=2;
99
100 val=lx_msrRead(GLIU0_IOD_BM_1);
101 if (val.lo != 0x3d0ffff0)
102 ret|=4;
103
104 return ret;
105}
106
107/****************************************************************
108* Extened CRTC Register functions
109****************************************************************/
110static void crtce_lock(void)
111{
112 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
113 outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
114}
115
116static void crtce_unlock(void)
117{
118 outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
119 outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
120}
121
122static u8 crtce_read(u8 reg)
123{
124 u8 val;
125
126 crtce_unlock();
127 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
128 val = inb(VGAREG_VGA_CRTC_DATA);
129 crtce_lock();
130
131 return val;
132}
133
134static void crtce_write(u8 reg, u8 val)
135{
136 crtce_unlock();
137 outb(reg , VGAREG_VGA_CRTC_ADDRESS);
138 outb(val, VGAREG_VGA_CRTC_DATA);
139 crtce_lock();
140}
141
142/****************************************************************
143* Display Controller Functions
144****************************************************************/
145static u32 dc_read(u16 seg, u32 reg)
146{
147 u32 val, *dest_far = (void*)reg;
148 val = GET_FARVAR(seg,*dest_far);
149 return val;
150}
151
152static void dc_write(u16 seg, u32 reg, u32 val)
153{
154 u32 *dest_far = (void*)reg;
155 SET_FARVAR(seg,*dest_far,val);
156}
157
158static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
159{
160 u32 val = dc_read(seg,reg);
161 val &=and;
162 val |=or;
163 dc_write(seg,reg,val);
164}
165
166static void dc_unlock(u16 seg)
167{
168 dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
169}
170
171static void dc_lock(u16 seg)
172{
173 dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
174}
175
176static u16 dc_map(u16 seg)
177{
178 u8 reg;
179
180 reg = crtce_read(EXTENDED_MODE_CONTROL);
181 reg &= 0xf9;
182 switch (seg) {
183 case SEG_GRAPH:
184 reg |= 0x02;
185 break;
186 case SEG_MTEXT:
187 reg |= 0x04;
188 break;
189 case SEG_CTEXT:
190 reg |= 0x06;
191 break;
192 default:
193 seg=0;
194 break;
195 }
196
197 crtce_write(EXTENDED_MODE_CONTROL,reg);
198 return seg;
199}
200
201static void dc_unmap(void)
202{
203 dc_map(0);
204}
205
206
207/****************************************************************
208* Init Functions
209****************************************************************/
210
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
215*/
216static int dc_setup(void)
217{
218 u32 fb, dc_fb;
219 u16 seg;
220
221 dprintf(2, "DC_SETUP\n");
222
223 seg = dc_map(SEG_GRAPH);
224 dc_unlock(seg);
225
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);
230
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);
235 if (fb!=dc_fb) {
236 dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
237 }
238
239 dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
240 dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
241
242 dc_lock(seg);
243 dc_unmap();
244
245 return 0;
246}
247
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.
253*/
254int vp_setup(void)
255{
256 u32 reg,vp;
257
258 dprintf(2,"VP_SETUP\n");
259 /* set output to crt and RGB/YUV */
260 lx_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
261
262 /* get vp register base from pci */
263 outl(LX_PCI_VP,PORT_PCI_CMD);
264 vp = inl(PORT_PCI_DATA);
265
266 /* Set mmio registers
267 * there may be some timing issues here, the reads seem
268 * to slow things down enough work reliably
269 */
270
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);
276
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);
282
283 return 0;
284}
285
286static 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,
290 0xff };
291static 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,
295 0xff };
296static 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,
300 0xff };
301static 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,
305 0xff };
306static 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,
310 0xff };
311static 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,
315 0xff };
316static 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,
320 0xff };
321static 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,
325 0xff };
326static 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,
330 0xff };
331static 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,
335 0xff };
336static 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,
340 0xff };
341
342int geodelx_init(void)
343{
344 int ret;
345
346 dprintf(1,"GEODELX_INIT\n");
347
348 if ((ret=legacyio_check())) {
349 dprintf(1,"GEODELX_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 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,
356 0, 0, 0, 0, 0,
357 lx_crtc_0d, lx_crtc_0e, lx_crtc_0f, lx_crtc_0f,
358 lx_crtc_11, lx_crtc_11, lx_crtc_13 };
359 int i;
360 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
361 u8 *crtc = GET_GLOBAL(new_crtc[i]);
362 if (!crtc)
363 continue;
364 struct vgamode_s *vmode_g = find_vga_entry(i);
365 if (!vmode_g)
366 continue;
367 SET_VGA(vmode_g->crtc_regs, crtc);
368 }
369
370 ret |= vp_setup();
371 ret |= dc_setup();
372
373 return ret;
374}