blob: 4a5f8734f5df1237632dd61f0a77a9a57a6dde1c [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
Kevin O'Connore1e000b2011-12-31 03:30:40 -050013#include "vgabios.h" // VGAREG_*
Kevin O'Connor4c52fb42011-12-24 00:44:07 -050014#include "util.h" // memset
15#include "config.h"
16#include "types.h"
17#include "bregs.h"
Kevin O'Connored68e5b2011-12-31 04:15:12 -050018#include "stdvga.h" // VGAREG_VGA_CRTC_ADDRESS
Kevin O'Connor4c52fb42011-12-24 00:44:07 -050019
20
21/****************************************************************
22* MSR and High Mem access through VSA Virtual Register
23****************************************************************/
24
25static union u64_u32_u lx_msrRead(u32 msrAddr)
26{
27 union u64_u32_u val;
28 asm __volatile__ (
29 "movw $0x0AC1C, %%dx \n"
30 "movl $0xFC530007, %%eax \n"
31 "outl %%eax, %%dx \n"
32 "addb $2, %%dl \n"
33 "inw %%dx, %%ax \n"
34 : "=a" (val.lo), "=d"(val.hi)
35 : "c"(msrAddr)
36 : "cc"
37 );
38 return val;
39}
40
41static void lx_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
42{
43 asm __volatile__ (
44 "push %%eax \n"
45 "movw $0x0AC1C, %%dx \n"
46 "movl $0xFC530007, %%eax \n"
47 "outl %%eax, %%dx \n"
48 "addb $2, %%dl \n"
49 "pop %%eax \n"
50 "outw %%ax, %%dx \n"
51 :
52 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
53 : "%edx","cc"
54 );
55}
56
57static u32 lx_memRead(u32 addr)
58{
59 u32 val;
60 asm __volatile__ (
61 "movw $0x0AC1C, %%dx \n"
62 "movl $0xFC530001, %%eax \n"
63 "outl %%eax, %%dx \n"
64 "addb $2, %%dl \n"
65 "inw %%dx, %%ax \n"
66 : "=a" (val)
67 : "b"(addr)
68 : "cc"
69 );
70
71 return val;
72}
73
74static void lx_memWrite(u32 addr, u32 and, u32 or )
75{
76 asm __volatile__ (
77 "movw $0x0AC1C, %%dx \n"
78 "movl $0xFC530001, %%eax \n"
79 "outl %%eax, %%dx \n"
80 "addb $2, %%dl \n"
81 "outw %%ax, %%dx \n"
82 :
83 : "b"(addr), "S" (and), "D" (or)
84 : "%eax","cc"
85 );
86}
87
88static int legacyio_check(void)
89{
90 int ret=0;
91 union u64_u32_u val;
92
93 val=lx_msrRead(MSR_GLIU0_BASE4);
94 if (val.lo != 0x0A0fffe0)
95 ret|=1;
96
97 val=lx_msrRead(GLIU0_IOD_BM_0);
98 if (val.lo != 0x3c0ffff0)
99 ret|=2;
100
101 val=lx_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(LX_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 */
261 lx_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
262
263 /* get vp register base from pci */
264 outl(LX_PCI_VP,PORT_PCI_CMD);
265 vp = inl(PORT_PCI_DATA);
266
267 /* Set mmio registers
268 * there may be some timing issues here, the reads seem
269 * to slow things down enough work reliably
270 */
271
272 reg = lx_memRead(vp+VP_MISC);
273 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
274 lx_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
275 reg = lx_memRead(vp+VP_MISC);
276 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
277
278 reg = lx_memRead(vp+VP_DCFG);
279 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
280 lx_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
281 reg = lx_memRead(vp+VP_DCFG);
282 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
283
284 return 0;
285}
286
287static u8 lx_crtc_01[] VAR16 = {
288 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
289 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
290 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
291 0xff };
292static u8 lx_crtc_03[] VAR16 = {
293 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
294 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
295 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
296 0xff };
297static u8 lx_crtc_04[] VAR16 = {
298 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
299 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
301 0xff };
302static u8 lx_crtc_05[] VAR16 = {
303 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
304 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
306 0xff };
307static u8 lx_crtc_06[] VAR16 = {
308 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
309 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
311 0xff };
312static u8 lx_crtc_07[] VAR16 = {
313 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
314 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
315 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
316 0xff };
317static u8 lx_crtc_0d[] VAR16 = {
318 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
319 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
321 0xff };
322static u8 lx_crtc_0e[] VAR16 = {
323 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
324 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
326 0xff };
327static u8 lx_crtc_0f[] VAR16 = {
328 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
329 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
331 0xff };
332static u8 lx_crtc_11[] VAR16 = {
333 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
334 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
336 0xff };
337static u8 lx_crtc_13[] VAR16 = {
338 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
339 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
341 0xff };
342
343int geodelx_init(void)
344{
345 int ret;
346
347 dprintf(1,"GEODELX_INIT\n");
348
349 if ((ret=legacyio_check())) {
350 dprintf(1,"GEODELX_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 lx_crtc_01, lx_crtc_01, lx_crtc_03, lx_crtc_03,
356 lx_crtc_04, lx_crtc_05, lx_crtc_06, lx_crtc_07,
357 0, 0, 0, 0, 0,
358 lx_crtc_0d, lx_crtc_0e, lx_crtc_0f, lx_crtc_0f,
359 lx_crtc_11, lx_crtc_11, lx_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;
365 struct vgamode_s *vmode_g = find_vga_entry(i);
366 if (!vmode_g)
367 continue;
368 SET_VGA(vmode_g->crtc_regs, crtc);
369 }
370
371 ret |= vp_setup();
372 ret |= dc_setup();
373
374 return ret;
375}