3da1b7c085e3a75f285cf58bc67436c91d90e80f
[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" // stdvga_crtc_write
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     if (CONFIG_VGA_GEODEGX2)
91         val=geode_msrRead(GLIU0_P2D_BM_4);
92     else
93         val=geode_msrRead(MSR_GLIU0_BASE4);
94     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 ****************************************************************/
111 static void crtce_lock(void)
112 {
113     stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
114                       , CRTCE_LOCK);
115 }
116
117 static void crtce_unlock(void)
118 {
119     stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
120                       , CRTCE_UNLOCK);
121 }
122
123 static u8 crtce_read(u8 reg)
124 {
125     crtce_unlock();
126     u8 val = stdvga_crtc_read(VGAREG_VGA_CRTC_ADDRESS, reg);
127     crtce_lock();
128     return val;
129 }
130
131 static void crtce_write(u8 reg, u8 val)
132 {
133     crtce_unlock();
134     stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, reg, val);
135     crtce_lock();
136 }
137
138 /****************************************************************
139 * Display Controller Functions
140 ****************************************************************/
141 static u32 dc_read(u16 seg, u32 reg)
142 {
143     u32 val, *dest_far = (void*)reg;
144     val = GET_FARVAR(seg,*dest_far);
145     return val;
146 }
147
148 static void dc_write(u16 seg, u32 reg, u32 val)
149 {
150     u32 *dest_far = (void*)reg;
151     SET_FARVAR(seg,*dest_far,val);
152 }
153
154 static void dc_set(u16 seg, u32 reg, u32 and, u32 or)
155 {
156     u32 val = dc_read(seg,reg);
157     val &=and;
158     val |=or;
159     dc_write(seg,reg,val);
160 }
161
162 static void dc_unlock(u16 seg)
163 {
164     dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
165 }
166
167 static void dc_lock(u16 seg)
168 {
169     dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
170 }
171
172 static u16 dc_map(u16 seg)
173 {
174     u8 reg;
175
176     reg = crtce_read(EXTENDED_MODE_CONTROL);
177     reg &= 0xf9;
178     switch (seg) {
179     case SEG_GRAPH:
180         reg |= 0x02;
181         break;
182     case SEG_MTEXT:
183         reg |= 0x04;
184         break;
185     case SEG_CTEXT:
186         reg |= 0x06;
187         break;
188     default:
189         seg=0;
190         break;
191     }
192
193     crtce_write(EXTENDED_MODE_CONTROL,reg);
194     return seg;
195 }
196
197 static void dc_unmap(void)
198 {
199     dc_map(0);
200 }
201
202
203 /****************************************************************
204 * Init Functions
205 ****************************************************************/
206
207 /* Set up the dc (display controller) portion of the geodelx
208 *  The dc provides hardware support for VGA graphics
209 *  for features not accessible from the VGA registers,
210 *  the dc's pci bar can be mapped to a vga memory segment
211 */
212 static int dc_setup(void)
213 {
214     u32 fb, dc_fb;
215     u16 seg;
216
217     dprintf(2, "DC_SETUP\n");
218
219     seg = dc_map(SEG_GRAPH);
220     dc_unlock(seg);
221
222     /* zero memory config */
223     dc_write(seg,DC_FB_ST_OFFSET,0x0);
224     dc_write(seg,DC_CB_ST_OFFSET,0x0);
225     dc_write(seg,DC_CURS_ST_OFFSET,0x0);
226
227     /* read fb-bar from pci, then point dc to the fb base */
228     dc_fb = dc_read(seg,DC_GLIU0_MEM_OFFSET);
229     outl(GEODE_PCI_FB,PORT_PCI_CMD);
230     fb = inl(PORT_PCI_DATA);
231     if (fb!=dc_fb) {
232         dc_write(seg,DC_GLIU0_MEM_OFFSET,fb);
233     }
234
235     dc_set(seg,DC_DISPLAY_CFG,DC_CFG_MSK,DC_GDEN+DC_TRUP);
236     dc_set(seg,DC_GENERAL_CFG,0,DC_VGAE);
237
238     dc_lock(seg);
239     dc_unmap();
240
241     return 0;
242 }
243
244 /* Setup the vp (video processor) portion of the geodelx
245 *  Under VGA modes the vp was handled by softvg from inside VSA2.
246 *  Without a softvg module, access is only available through a pci bar.
247 *  The High Mem Access virtual register is used to  configure the
248 *   pci mmio bar from 16bit friendly io space.
249 */
250 int vp_setup(void)
251 {
252     u32 reg,vp;
253
254     dprintf(2,"VP_SETUP\n");
255     /* set output to crt and RGB/YUV */
256     if (CONFIG_VGA_GEODEGX2)
257     geode_msrWrite(VP_MSR_CONFIG_GX2,~0 ,~0xf8,0,0);
258     else
259     geode_msrWrite(VP_MSR_CONFIG_LX,~0 ,~0xf8,0,0);
260
261     /* get vp register base from pci */
262     outl(GEODE_PCI_VP,PORT_PCI_CMD);
263     vp = inl(PORT_PCI_DATA);
264
265     /* Set mmio registers
266     * there may be some timing issues here, the reads seem
267     * to slow things down enough work reliably
268     */
269
270     reg = geode_memRead(vp+VP_MISC);
271     dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
272     geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
273     reg = geode_memRead(vp+VP_MISC);
274     dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
275
276     reg = geode_memRead(vp+VP_DCFG);
277     dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
278     geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
279     reg = geode_memRead(vp+VP_DCFG);
280     dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
281
282     return 0;
283 }
284
285 static u8 geode_crtc_01[] VAR16 = {
286     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
287     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
288     0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
289     0xff };
290 static u8 geode_crtc_03[] VAR16 = {
291     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
292     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
293     0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
294     0xff };
295 static u8 geode_crtc_04[] VAR16 = {
296     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
297     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298     0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
299     0xff };
300 static u8 geode_crtc_05[] VAR16 = {
301     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
302     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303     0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
304     0xff };
305 static u8 geode_crtc_06[] VAR16 = {
306     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
307     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308     0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
309     0xff };
310 static u8 geode_crtc_07[] VAR16 = {
311     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
312     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
313     0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
314     0xff };
315 static u8 geode_crtc_0d[] VAR16 = {
316     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
317     0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318     0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
319     0xff };
320 static u8 geode_crtc_0e[] VAR16 = {
321     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
322     0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323     0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
324     0xff };
325 static u8 geode_crtc_0f[] VAR16 = {
326     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
327     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328     0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
329     0xff };
330 static u8 geode_crtc_11[] VAR16 = {
331     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
332     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333     0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
334     0xff };
335 static u8 geode_crtc_13[] VAR16 = {
336     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
337     0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338     0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
339     0xff };
340
341 int geodevga_init(void)
342 {
343     int ret = stdvga_init();
344     if (ret)
345         return ret;
346
347     dprintf(1,"GEODEVGA_INIT\n");
348
349     if ((ret=legacyio_check())) {
350         dprintf(1,"GEODEVGA_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         geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
356         geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
357         0, 0, 0, 0, 0,
358         geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
359         geode_crtc_11, geode_crtc_11, geode_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 = stdvga_find_mode(i);
366         if (!vmode_g)
367             continue;
368         struct stdvga_mode_s *stdmode_g = container_of(
369             vmode_g, struct stdvga_mode_s, info);
370         SET_VGA(stdmode_g->crtc_regs, crtc);
371     }
372
373     ret |= vp_setup();
374     ret |= dc_setup();
375
376     return ret;
377 }