vgabios: Merge support for GeodeLX vga bios.
[seabios.git] / vgasrc / geodelx.c
1 // 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
24 static 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
40 static 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
56 static 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
73 static 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
87 static 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 ****************************************************************/
110 static void crtce_lock(void)
111 {
112     outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
113     outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
114 }
115
116 static void crtce_unlock(void)
117 {
118     outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
119     outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
120 }
121
122 static 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
134 static 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 ****************************************************************/
145 static 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
152 static 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
158 static 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
166 static void dc_unlock(u16 seg)
167 {
168     dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
169 }
170
171 static void dc_lock(u16 seg)
172 {
173     dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
174 }
175
176 static 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
201 static 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 */
216 static 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 */
254 int 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
286 static 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 };
291 static 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 };
296 static 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 };
301 static 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 };
306 static 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 };
311 static 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 };
316 static 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 };
321 static 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 };
326 static 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 };
331 static 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 };
336 static 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
342 int 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 }