Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / 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 "biosvar.h" // GET_BDA
10 #include "farptr.h" // SET_FARVAR
11 #include "geodevga.h" // geodevga_setup
12 #include "hw/pci.h" // pci_config_readl
13 #include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
14 #include "output.h" // dprintf
15 #include "stdvga.h" // stdvga_crtc_write
16 #include "vgabios.h" // VGAREG_*
17
18
19 /****************************************************************
20 * MSR and High Mem access through VSA Virtual Register
21 ****************************************************************/
22
23 static u64 geode_msr_read(u32 msrAddr)
24 {
25     union u64_u32_u val;
26     asm __volatile__ (
27         "movw   $0x0AC1C, %%dx          \n"
28         "movl   $0xFC530007, %%eax      \n"
29         "outl   %%eax, %%dx             \n"
30         "addb   $2, %%dl                \n"
31         "inw    %%dx, %%ax              \n"
32         : "=a" (val.lo), "=d"(val.hi)
33         : "c"(msrAddr)
34         : "cc"
35     );
36
37     dprintf(4, "%s(0x%08x) = 0x%08x-0x%08x\n"
38             , __func__, msrAddr, val.hi, val.lo);
39     return val.val;
40 }
41
42 static void geode_msr_mask(u32 msrAddr, u64 off, u64 on)
43 {
44     union u64_u32_u uand, uor;
45     uand.val = ~off;
46     uor.val = on;
47
48     dprintf(4, "%s(0x%08x, 0x%016llx, 0x%016llx)\n"
49             , __func__, msrAddr, off, on);
50
51     asm __volatile__ (
52         "push   %%eax                   \n"
53         "movw   $0x0AC1C, %%dx          \n"
54         "movl   $0xFC530007, %%eax      \n"
55         "outl   %%eax, %%dx             \n"
56         "addb   $2, %%dl                \n"
57         "pop    %%eax                   \n"
58         "outw   %%ax, %%dx              \n"
59         :
60         : "c"(msrAddr), "S" (uand.hi), "D" (uand.lo), "b" (uor.hi), "a" (uor.lo)
61         : "%edx","cc"
62     );
63 }
64
65 static u32 geode_mem_read(u32 addr)
66 {
67     u32 val;
68     asm __volatile__ (
69         "movw   $0x0AC1C, %%dx          \n"
70         "movl   $0xFC530001, %%eax      \n"
71         "outl   %%eax, %%dx             \n"
72         "addb   $2, %%dl                \n"
73         "inw    %%dx, %%ax              \n"
74         : "=a" (val)
75         : "b"(addr)
76         : "cc"
77     );
78
79     return val;
80 }
81
82 static void geode_mem_mask(u32 addr, u32 off, u32 or)
83 {
84     asm __volatile__ (
85         "movw   $0x0AC1C, %%dx          \n"
86         "movl   $0xFC530001, %%eax      \n"
87         "outl   %%eax, %%dx             \n"
88         "addb   $2, %%dl                \n"
89         "outw   %%ax, %%dx              \n"
90         :
91         : "b"(addr), "S" (~off), "D" (or)
92         : "%eax","cc"
93     );
94 }
95
96 #define VP_FP_START     0x400
97
98 static u32 GeodeFB VAR16;
99 static u32 GeodeDC VAR16;
100 static u32 GeodeVP VAR16;
101
102 static u32 geode_dc_read(int reg)
103 {
104     u32 val = geode_mem_read(GET_GLOBAL(GeodeDC) + reg);
105     dprintf(4, "%s(0x%08x) = 0x%08x\n"
106             , __func__, GET_GLOBAL(GeodeDC) + reg, val);
107     return val;
108 }
109
110 static void geode_dc_write(int reg, u32 val)
111 {
112     dprintf(4, "%s(0x%08x, 0x%08x)\n"
113             , __func__, GET_GLOBAL(GeodeDC) + reg, val);
114     geode_mem_mask(GET_GLOBAL(GeodeDC) + reg, ~0, val);
115 }
116
117 static void geode_dc_mask(int reg, u32 off, u32 on)
118 {
119     dprintf(4, "%s(0x%08x, 0x%08x, 0x%08x)\n"
120             , __func__, GET_GLOBAL(GeodeDC) + reg, off, on);
121     geode_mem_mask(GET_GLOBAL(GeodeDC) + reg, off, on);
122 }
123
124 static u32 geode_vp_read(int reg)
125 {
126     u32 val = geode_mem_read(GET_GLOBAL(GeodeVP) + reg);
127     dprintf(4, "%s(0x%08x) = 0x%08x\n"
128             , __func__, GET_GLOBAL(GeodeVP) + reg, val);
129     return val;
130 }
131
132 static void geode_vp_write(int reg, u32 val)
133 {
134     dprintf(4, "%s(0x%08x, 0x%08x)\n"
135             , __func__, GET_GLOBAL(GeodeVP) + reg, val);
136     geode_mem_mask(GET_GLOBAL(GeodeVP) + reg, ~0, val);
137 }
138
139 static void geode_vp_mask(int reg, u32 off, u32 on)
140 {
141     dprintf(4, "%s(0x%08x, 0x%08x, 0x%08x)\n"
142             , __func__, GET_GLOBAL(GeodeVP) + reg, off, on);
143     geode_mem_mask(GET_GLOBAL(GeodeVP) + reg, off, on);
144 }
145
146 static u32 geode_fp_read(int reg)
147 {
148     u32 val = geode_mem_read(GET_GLOBAL(GeodeVP) + VP_FP_START + reg);
149     dprintf(4, "%s(0x%08x) = 0x%08x\n"
150             , __func__, GET_GLOBAL(GeodeVP) + VP_FP_START + reg, val);
151     return val;
152 }
153
154 static void geode_fp_write(int reg, u32 val)
155 {
156     dprintf(4, "%s(0x%08x, 0x%08x)\n"
157             , __func__, GET_GLOBAL(GeodeVP) + VP_FP_START + reg, val);
158     geode_mem_mask(GET_GLOBAL(GeodeVP) + VP_FP_START + reg, ~0, val);
159 }
160
161 /****************************************************************
162  * Helper functions
163  ****************************************************************/
164
165 static int legacyio_check(void)
166 {
167     int ret=0;
168     u64 val;
169
170     if (CONFIG_VGA_GEODEGX2)
171         val = geode_msr_read(GLIU0_P2D_BM_4);
172     else
173         val = geode_msr_read(MSR_GLIU0_BASE4);
174     if ((val & 0xffffffff) != 0x0A0fffe0)
175         ret|=1;
176
177     val = geode_msr_read(GLIU0_IOD_BM_0);
178     if ((val & 0xffffffff) != 0x3c0ffff0)
179         ret|=2;
180
181     val = geode_msr_read(GLIU0_IOD_BM_1);
182     if ((val & 0xffffffff) != 0x3d0ffff0)
183         ret|=4;
184
185     return ret;
186 }
187
188 static u32 framebuffer_size(void)
189 {
190     /* We use the P2D_R0 msr to read out the number of pages.
191      * One page has a size of 4k
192      *
193      * Bit      Name    Description
194      * 39:20    PMAX    Physical Memory Address Max
195      * 19:0     PMIX    Physical Memory Address Min
196      *
197      */
198     u64 msr = geode_msr_read(GLIU0_P2D_RO);
199
200     u32 pmax = (msr >> 20) & 0x000fffff;
201     u32 pmin = msr & 0x000fffff;
202
203     u32 val = pmax - pmin;
204     val += 1;
205
206     /* The page size is 4k */
207     return (val << 12);
208 }
209
210 /****************************************************************
211 * Init Functions
212 ****************************************************************/
213
214 static void geodevga_set_output_mode(void)
215 {
216     u64 msr_addr;
217     u64 msr;
218
219     /* set output to crt and RGB/YUV */
220     if (CONFIG_VGA_GEODEGX2)
221         msr_addr = VP_MSR_CONFIG_GX2;
222     else
223         msr_addr = VP_MSR_CONFIG_LX;
224
225     /* set output mode (RGB/YUV) */
226     msr = geode_msr_read(msr_addr);
227     msr &= ~VP_MSR_CONFIG_FMT;         // mask out FMT (bits 5:3)
228
229     if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
230         msr |= VP_MSR_CONFIG_FMT_FP;   // flat panel
231
232         if (CONFIG_VGA_OUTPUT_CRT_PANEL) {
233             msr |= VP_MSR_CONFIG_FPC;  // simultaneous Flat Panel and CRT
234             dprintf(1, "output: simultaneous Flat Panel and CRT\n");
235         } else {
236             msr &= ~VP_MSR_CONFIG_FPC; // no simultaneous Flat Panel and CRT
237             dprintf(1, "ouput: flat panel\n");
238         }
239     } else {
240         msr |= VP_MSR_CONFIG_FMT_CRT;  // CRT only
241        dprintf(1, "output: CRT\n");
242     }
243     geode_msr_mask(msr_addr, ~msr, msr);
244 }
245
246 /* Set up the dc (display controller) portion of the geodelx
247 *  The dc provides hardware support for VGA graphics.
248 */
249 static void dc_setup(void)
250 {
251     dprintf(2, "DC_SETUP\n");
252
253     geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
254
255     /* zero memory config */
256     geode_dc_write(DC_FB_ST_OFFSET, 0x0);
257     geode_dc_write(DC_CB_ST_OFFSET, 0x0);
258     geode_dc_write(DC_CURS_ST_OFFSET, 0x0);
259
260     geode_dc_mask(DC_DISPLAY_CFG, ~DC_CFG_MSK, DC_DISPLAY_CFG_GDEN|DC_DISPLAY_CFG_TRUP);
261     geode_dc_write(DC_GENERAL_CFG, DC_GENERAL_CFG_VGAE);
262
263     geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
264 }
265
266 /* Setup the vp (video processor) portion of the geodelx
267 *  Under VGA modes the vp was handled by softvg from inside VSA2.
268 *  Without a softvg module, access is only available through a pci bar.
269 *  The High Mem Access virtual register is used to  configure the
270 *   pci mmio bar from 16bit friendly io space.
271 */
272 static void vp_setup(void)
273 {
274     dprintf(2,"VP_SETUP\n");
275
276     geodevga_set_output_mode();
277
278     /* Set mmio registers
279     * there may be some timing issues here, the reads seem
280     * to slow things down enough work reliably
281     */
282
283     u32 reg = geode_vp_read(VP_MISC);
284     dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
285     geode_vp_write(VP_MISC, VP_DCFG_BYP_BOTH);
286     reg = geode_vp_read(VP_MISC);
287     dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
288
289     reg = geode_vp_read(VP_DCFG);
290     dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
291     geode_vp_mask(VP_DCFG, 0, VP_DCFG_CRT_EN|VP_DCFG_HSYNC_EN|VP_DCFG_VSYNC_EN|VP_DCFG_DAC_BL_EN|VP_DCFG_CRT_SKEW);
292     reg = geode_vp_read(VP_DCFG);
293     dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
294
295     /* setup flat panel */
296     if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
297         u64 msr;
298
299         dprintf(1, "Setting up flat panel\n");
300         /* write timing register */
301         geode_fp_write(FP_PT1, 0x0);
302         geode_fp_write(FP_PT2, FP_PT2_SCRC);
303
304         /* set pad select for TFT/LVDS */
305         msr  = VP_MSR_PADSEL_TFT_SEL_HIGH;
306         msr  = msr << 32;
307         msr |= VP_MSR_PADSEL_TFT_SEL_LOW;
308         geode_msr_mask(VP_MSR_PADSEL, ~msr, msr);
309
310         /* turn the panel on (if it isn't already) */
311         reg = geode_fp_read(FP_PM);
312         reg |= FP_PM_P;
313         geode_fp_write(FP_PM, reg);
314     }
315 }
316
317 static u8 geode_crtc_01[] VAR16 = {
318     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
319     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
320     0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
321     0xff };
322 static u8 geode_crtc_03[] VAR16 = {
323     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
324     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
325     0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
326     0xff };
327 static u8 geode_crtc_04[] VAR16 = {
328     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
329     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330     0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
331     0xff };
332 static u8 geode_crtc_05[] VAR16 = {
333     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
334     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335     0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
336     0xff };
337 static u8 geode_crtc_06[] VAR16 = {
338     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
339     0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340     0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
341     0xff };
342 static u8 geode_crtc_07[] VAR16 = {
343     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
344     0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
345     0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
346     0xff };
347 static u8 geode_crtc_0d[] VAR16 = {
348     0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
349     0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350     0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
351     0xff };
352 static u8 geode_crtc_0e[] VAR16 = {
353     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
354     0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355     0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
356     0xff };
357 static u8 geode_crtc_0f[] VAR16 = {
358     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
359     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360     0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
361     0xff };
362 static u8 geode_crtc_11[] VAR16 = {
363     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
364     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365     0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
366     0xff };
367 static u8 geode_crtc_13[] VAR16 = {
368     0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
369     0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370     0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
371     0xff };
372
373 int geodevga_setup(void)
374 {
375     int ret = stdvga_setup();
376     if (ret)
377         return ret;
378
379     dprintf(1,"GEODEVGA_SETUP\n");
380
381     if ((ret=legacyio_check())) {
382         dprintf(1,"GEODEVGA_SETUP legacyio_check=0x%x\n",ret);
383     }
384
385     // Updated timings from geode datasheets, table 6-53 in particular
386     static u8 *new_crtc[] VAR16 = {
387         geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
388         geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
389         0, 0, 0, 0, 0,
390         geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
391         geode_crtc_11, geode_crtc_11, geode_crtc_13 };
392     int i;
393     for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
394         u8 *crtc = GET_GLOBAL(new_crtc[i]);
395         if (crtc)
396             stdvga_override_crtc(i, crtc);
397     }
398
399     if (GET_GLOBAL(VgaBDF) < 0)
400         // Device should be at 00:01.1
401         SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
402
403     // setup geode struct which is used for register access
404     SET_VGA(GeodeFB, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0));
405     SET_VGA(GeodeDC, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_2));
406     SET_VGA(GeodeVP, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3));
407
408     dprintf(1, "fb addr: 0x%08x\n", GET_GLOBAL(GeodeFB));
409     dprintf(1, "dc addr: 0x%08x\n", GET_GLOBAL(GeodeDC));
410     dprintf(1, "vp addr: 0x%08x\n", GET_GLOBAL(GeodeVP));
411
412     /* setup framebuffer */
413     geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
414
415     /* read fb-bar from pci, then point dc to the fb base */
416     u32 fb = GET_GLOBAL(GeodeFB);
417     if (geode_dc_read(DC_GLIU0_MEM_OFFSET) != fb)
418         geode_dc_write(DC_GLIU0_MEM_OFFSET, fb);
419
420     geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
421
422     u32 fb_size = framebuffer_size(); // in byte
423     dprintf(1, "%d KB of video memory at 0x%08x\n", fb_size / 1024, fb);
424
425     /* update VBE variables */
426     SET_VGA(VBE_framebuffer, fb);
427     SET_VGA(VBE_total_memory, fb_size / 1024 / 64); // number of 64K blocks
428
429     vp_setup();
430     dc_setup();
431
432     return 0;
433 }