7735fdca628a2b872cf26a04b08ea128c9428358
[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     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     outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
114     outb(CRTCE_LOCK, VGAREG_VGA_CRTC_DATA);
115 }
116
117 static void crtce_unlock(void)
118 {
119     outb(EXTENDED_REGISTER_LOCK , VGAREG_VGA_CRTC_ADDRESS);
120     outb(CRTCE_UNLOCK, VGAREG_VGA_CRTC_DATA);
121 }
122
123 static 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
135 static 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 ****************************************************************/
146 static 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
153 static 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
159 static 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
167 static void dc_unlock(u16 seg)
168 {
169     dc_write(seg,DC_UNLOCK,DC_LOCK_UNLOCK);
170 }
171
172 static void dc_lock(u16 seg)
173 {
174     dc_write(seg,DC_UNLOCK,DC_LOCK_LOCK);
175 }
176
177 static 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
202 static 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 */
217 static 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(GEODE_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 */
255 int vp_setup(void)
256 {
257     u32 reg,vp;
258
259     dprintf(2,"VP_SETUP\n");
260     /* set output to crt and RGB/YUV */
261     if (CONFIG_VGA_GEODEGX2)
262     geode_msrWrite(VP_MSR_CONFIG_GX2,~0 ,~0xf8,0,0);
263     else
264     geode_msrWrite(VP_MSR_CONFIG_LX,~0 ,~0xf8,0,0);
265
266     /* get vp register base from pci */
267     outl(GEODE_PCI_VP,PORT_PCI_CMD);
268     vp = inl(PORT_PCI_DATA);
269
270     /* Set mmio registers
271     * there may be some timing issues here, the reads seem
272     * to slow things down enough work reliably
273     */
274
275     reg = geode_memRead(vp+VP_MISC);
276     dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
277     geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
278     reg = geode_memRead(vp+VP_MISC);
279     dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
280
281     reg = geode_memRead(vp+VP_DCFG);
282     dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
283     geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
284     reg = geode_memRead(vp+VP_DCFG);
285     dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
286
287     return 0;
288 }
289
290 static u8 geode_crtc_01[] VAR16 = {
291     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
292     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
293     0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
294     0xff };
295 static u8 geode_crtc_03[] VAR16 = {
296     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
297     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
298     0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
299     0xff };
300 static u8 geode_crtc_04[] VAR16 = {
301     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
302     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303     0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
304     0xff };
305 static u8 geode_crtc_05[] VAR16 = {
306     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
307     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308     0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
309     0xff };
310 static u8 geode_crtc_06[] VAR16 = {
311     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
312     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313     0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
314     0xff };
315 static u8 geode_crtc_07[] VAR16 = {
316     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
317     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
318     0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
319     0xff };
320 static u8 geode_crtc_0d[] VAR16 = {
321     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
322     0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323     0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
324     0xff };
325 static u8 geode_crtc_0e[] VAR16 = {
326     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
327     0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328     0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
329     0xff };
330 static u8 geode_crtc_0f[] VAR16 = {
331     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
332     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333     0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
334     0xff };
335 static u8 geode_crtc_11[] VAR16 = {
336     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
337     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338     0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
339     0xff };
340 static u8 geode_crtc_13[] VAR16 = {
341     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
342     0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343     0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
344     0xff };
345
346 int geodevga_init(void)
347 {
348     int ret = stdvga_init();
349     if (ret)
350         return ret;
351
352     dprintf(1,"GEODEVGA_INIT\n");
353
354     if ((ret=legacyio_check())) {
355         dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
356     }
357
358     // Updated timings from geode datasheets, table 6-53 in particular
359     static u8 *new_crtc[] VAR16 = {
360         geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
361         geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
362         0, 0, 0, 0, 0,
363         geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
364         geode_crtc_11, geode_crtc_11, geode_crtc_13 };
365     int i;
366     for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
367         u8 *crtc = GET_GLOBAL(new_crtc[i]);
368         if (!crtc)
369             continue;
370         struct vgamode_s *vmode_g = find_vga_entry(i);
371         if (!vmode_g)
372             continue;
373         SET_VGA(vmode_g->crtc_regs, crtc);
374     }
375
376     ret |= vp_setup();
377     ret |= dc_setup();
378
379     return ret;
380 }