1 // Geode GX2/LX VGA functions
3 // Copyright (C) 2009 Chris Kindt
5 // Written for Google Summer of Code 2009 for the coreboot project
7 // This file may be distributed under the terms of the GNU LGPLv3 license.
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_*
19 /****************************************************************
20 * MSR and High Mem access through VSA Virtual Register
21 ****************************************************************/
23 static u64 geode_msr_read(u32 msrAddr)
27 "movw $0x0AC1C, %%dx \n"
28 "movl $0xFC530007, %%eax \n"
32 : "=a" (val.lo), "=d"(val.hi)
37 dprintf(4, "%s(0x%08x) = 0x%08x-0x%08x\n"
38 , __func__, msrAddr, val.hi, val.lo);
42 static void geode_msr_mask(u32 msrAddr, u64 off, u64 on)
44 union u64_u32_u uand, uor;
48 dprintf(4, "%s(0x%08x, 0x%016llx, 0x%016llx)\n"
49 , __func__, msrAddr, off, on);
53 "movw $0x0AC1C, %%dx \n"
54 "movl $0xFC530007, %%eax \n"
60 : "c"(msrAddr), "S" (uand.hi), "D" (uand.lo), "b" (uor.hi), "a" (uor.lo)
65 static u32 geode_mem_read(u32 addr)
69 "movw $0x0AC1C, %%dx \n"
70 "movl $0xFC530001, %%eax \n"
82 static void geode_mem_mask(u32 addr, u32 off, u32 or)
85 "movw $0x0AC1C, %%dx \n"
86 "movl $0xFC530001, %%eax \n"
91 : "b"(addr), "S" (~off), "D" (or)
96 #define VP_FP_START 0x400
98 static u32 GeodeFB VAR16;
99 static u32 GeodeDC VAR16;
100 static u32 GeodeVP VAR16;
102 static u32 geode_dc_read(int reg)
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);
110 static void geode_dc_write(int reg, u32 val)
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);
117 static void geode_dc_mask(int reg, u32 off, u32 on)
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);
124 static u32 geode_vp_read(int reg)
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);
132 static void geode_vp_write(int reg, u32 val)
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);
139 static void geode_vp_mask(int reg, u32 off, u32 on)
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);
146 static u32 geode_fp_read(int reg)
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);
154 static void geode_fp_write(int reg, u32 val)
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);
161 /****************************************************************
163 ****************************************************************/
165 static int legacyio_check(void)
170 if (CONFIG_VGA_GEODEGX2)
171 val = geode_msr_read(GLIU0_P2D_BM_4);
173 val = geode_msr_read(MSR_GLIU0_BASE4);
174 if ((val & 0xffffffff) != 0x0A0fffe0)
177 val = geode_msr_read(GLIU0_IOD_BM_0);
178 if ((val & 0xffffffff) != 0x3c0ffff0)
181 val = geode_msr_read(GLIU0_IOD_BM_1);
182 if ((val & 0xffffffff) != 0x3d0ffff0)
188 static u32 framebuffer_size(void)
190 /* We use the P2D_R0 msr to read out the number of pages.
191 * One page has a size of 4k
193 * Bit Name Description
194 * 39:20 PMAX Physical Memory Address Max
195 * 19:0 PMIX Physical Memory Address Min
198 u64 msr = geode_msr_read(GLIU0_P2D_RO);
200 u32 pmax = (msr >> 20) & 0x000fffff;
201 u32 pmin = msr & 0x000fffff;
203 u32 val = pmax - pmin;
206 /* The page size is 4k */
210 /****************************************************************
212 ****************************************************************/
214 static void geodevga_set_output_mode(void)
219 /* set output to crt and RGB/YUV */
220 if (CONFIG_VGA_GEODEGX2)
221 msr_addr = VP_MSR_CONFIG_GX2;
223 msr_addr = VP_MSR_CONFIG_LX;
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)
229 if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
230 msr |= VP_MSR_CONFIG_FMT_FP; // flat panel
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");
236 msr &= ~VP_MSR_CONFIG_FPC; // no simultaneous Flat Panel and CRT
237 dprintf(1, "ouput: flat panel\n");
240 msr |= VP_MSR_CONFIG_FMT_CRT; // CRT only
241 dprintf(1, "output: CRT\n");
243 geode_msr_mask(msr_addr, ~msr, msr);
246 /* Set up the dc (display controller) portion of the geodelx
247 * The dc provides hardware support for VGA graphics.
249 static void dc_setup(void)
251 dprintf(2, "DC_SETUP\n");
253 geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
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);
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);
263 geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
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.
272 static void vp_setup(void)
274 dprintf(2,"VP_SETUP\n");
276 geodevga_set_output_mode();
278 /* Set mmio registers
279 * there may be some timing issues here, the reads seem
280 * to slow things down enough work reliably
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);
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);
295 /* setup flat panel */
296 if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
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);
304 /* set pad select for TFT/LVDS */
305 msr = VP_MSR_PADSEL_TFT_SEL_HIGH;
307 msr |= VP_MSR_PADSEL_TFT_SEL_LOW;
308 geode_msr_mask(VP_MSR_PADSEL, ~msr, msr);
310 /* turn the panel on (if it isn't already) */
311 reg = geode_fp_read(FP_PM);
313 geode_fp_write(FP_PM, reg);
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
373 int geodevga_setup(void)
375 int ret = stdvga_setup();
379 dprintf(1,"GEODEVGA_SETUP\n");
381 if ((ret=legacyio_check())) {
382 dprintf(1,"GEODEVGA_SETUP legacyio_check=0x%x\n",ret);
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,
390 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
391 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
393 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
394 u8 *crtc = GET_GLOBAL(new_crtc[i]);
396 stdvga_override_crtc(i, crtc);
399 if (GET_GLOBAL(VgaBDF) < 0)
400 // Device should be at 00:01.1
401 SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
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));
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));
412 /* setup framebuffer */
413 geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
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);
420 geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
422 u32 fb_size = framebuffer_size(); // in byte
423 dprintf(1, "%d KB of video memory at 0x%08x\n", fb_size / 1024, fb);
425 /* update VBE variables */
426 SET_VGA(VBE_framebuffer, fb);
427 SET_VGA(VBE_total_memory, fb_size / 1024 / 64); // number of 64K blocks