vgabios: Make the naming in the LX code generic to Geode.
[seabios.git] / vgasrc / geodevga.c
1 // 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
22 static 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
38 static 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
54 static 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
71 static 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
85 static int legacyio_check(void)
86 {
87     int ret=0;
88     union u64_u32_u val;
89
90     val=geode_msrRead(MSR_GLIU0_BASE4);
91     if (val.lo != 0x0A0fffe0)
92         ret|=1;
93
94     val=geode_msrRead(GLIU0_IOD_BM_0);
95     if (val.lo != 0x3c0ffff0)
96         ret|=2;
97
98     val=geode_msrRead(GLIU0_IOD_BM_1);
99     if (val.lo != 0x3d0ffff0)
100         ret|=4;
101
102     return ret;
103 }
104
105 /****************************************************************
106 * Extened CRTC Register functions
107 ****************************************************************/
108 static void crtce_lock(void)
109 {
110     outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
111     outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
112 }
113
114 static void crtce_unlock(void)
115 {
116     outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
117     outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
118 }
119
120 static u8 crtce_read(u8 reg)
121 {
122     u8 val;
123
124     crtce_unlock();
125     outb(reg , VGAREG_VGA_CRTC_ADDRESS);
126     val = inb(VGAREG_VGA_CRTC_DATA);
127     crtce_lock();
128
129     return val;
130 }
131
132 static void crtce_write(u8 reg, u8 val)
133 {
134     crtce_unlock();
135     outb(reg , VGAREG_VGA_CRTC_ADDRESS);
136     outb(val, VGAREG_VGA_CRTC_DATA);
137     crtce_lock();
138 }
139
140 /****************************************************************
141 * Display Controller Functions
142 ****************************************************************/
143 static u32 dc_read(u16 seg, u32 reg)
144 {
145     u32 val, *dest_far = (void*)reg;
146     val = GET_FARVAR(seg,*dest_far);
147     return val;
148 }
149
150 static void dc_write(u16 seg, u32 reg, u32 val)
151 {
152     u32 *dest_far = (void*)reg;
153     SET_FARVAR(seg,*dest_far,val);
154 }
155
156 static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
157 {
158     u32 val = dc_read(seg,reg);
159     val &=and;
160     val |=or;
161     dc_write(seg,reg,val);
162 }
163
164 static void dc_unlock(u16 seg)
165 {
166     dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
167 }
168
169 static void dc_lock(u16 seg)
170 {
171     dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
172 }
173
174 static u16 dc_map(u16 seg)
175 {
176     u8 reg;
177
178     reg = crtce_read(EXTENDED_MODE_CONTROL);
179     reg &= 0xf9;
180     switch (seg) {
181     case SEG_GRAPH:
182         reg |= 0x02;
183         break;
184     case SEG_MTEXT:
185         reg |= 0x04;
186         break;
187     case SEG_CTEXT:
188         reg |= 0x06;
189         break;
190     default:
191         seg=0;
192         break;
193     }
194
195     crtce_write(EXTENDED_MODE_CONTROL,reg);
196     return seg;
197 }
198
199 static void dc_unmap(void)
200 {
201     dc_map(0);
202 }
203
204
205 /****************************************************************
206 * Init Functions
207 ****************************************************************/
208
209 /* Set up the dc (display controller) portion of the geodelx
210 *  The dc provides hardware support for VGA graphics
211 *  for features not accessible from the VGA registers,
212 *  the dc's pci bar can be mapped to a vga memory segment
213 */
214 static int dc_setup(void)
215 {
216     u32 fb, dc_fb;
217     u16 seg;
218
219     dprintf(2, "DC_SETUP\n");
220
221     seg = dc_map(SEG_GRAPH);
222     dc_unlock(seg);
223
224     /* zero memory config */
225     dc_write(seg,DC_FB_ST_OFFSET,0x0);
226     dc_write(seg,DC_CB_ST_OFFSET,0x0);
227     dc_write(seg,DC_CURS_ST_OFFSET,0x0);
228
229     /* read fb-bar from pci, then point dc to the fb base */
230     dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
231     outl(GEODE_PCI_FB,PORT_PCI_CMD);
232     fb = inl(PORT_PCI_DATA);
233     if (fb!=dc_fb) {
234         dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
235     }
236
237     dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
238     dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
239
240     dc_lock(seg);
241     dc_unmap();
242
243     return 0;
244 }
245
246 /* Setup the vp (video processor) portion of the geodelx
247 *  Under VGA modes the vp was handled by softvg from inside VSA2.
248 *  Without a softvg module, access is only available through a pci bar.
249 *  The High Mem Access virtual register is used to  configure the
250 *   pci mmio bar from 16bit friendly io space.
251 */
252 int vp_setup(void)
253 {
254     u32 reg,vp;
255
256     dprintf(2,"VP_SETUP\n");
257     /* set output to crt and RGB/YUV */
258     geode_msrWrite(VP_MSR_CONFIG,~0 ,~0xf8,0,0);
259
260     /* get vp register base from pci */
261     outl(GEODE_PCI_VP,PORT_PCI_CMD);
262     vp = inl(PORT_PCI_DATA);
263
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
284 static 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 };
289 static 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 };
294 static 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 };
299 static 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 };
304 static 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 };
309 static 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 };
314 static 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 };
319 static 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 };
324 static 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 };
329 static 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 };
334 static 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
340 int 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]);
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 }