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" // SET_VGA
17
#include "vgautil.h" // VBE_total_memory
20
/****************************************************************
21
* MSR and High Mem access through VSA Virtual Register
22
****************************************************************/
24
static u64 geode_msr_read(u32 msrAddr)
28
"movw $0x0AC1C, %%dx \n"
29
"movl $0xFC530007, %%eax \n"
33
: "=a" (val.lo), "=d"(val.hi)
38
dprintf(4, "%s(0x%08x) = 0x%08x-0x%08x\n"
39
, __func__, msrAddr, val.hi, val.lo);
43
static void geode_msr_mask(u32 msrAddr, u64 off, u64 on)
45
union u64_u32_u uand, uor;
49
dprintf(4, "%s(0x%08x, 0x%016llx, 0x%016llx)\n"
50
, __func__, msrAddr, off, on);
54
"movw $0x0AC1C, %%dx \n"
55
"movl $0xFC530007, %%eax \n"
61
: "c"(msrAddr), "S" (uand.hi), "D" (uand.lo), "b" (uor.hi), "a" (uor.lo)
66
static u32 geode_mem_read(u32 addr)
70
"movw $0x0AC1C, %%dx \n"
71
"movl $0xFC530001, %%eax \n"
83
static void geode_mem_mask(u32 addr, u32 off, u32 or)
86
"movw $0x0AC1C, %%dx \n"
87
"movl $0xFC530001, %%eax \n"
92
: "b"(addr), "S" (~off), "D" (or)
97
#define VP_FP_START 0x400
99
static u32 GeodeFB VAR16;
100
static u32 GeodeDC VAR16;
101
static u32 GeodeVP VAR16;
103
static u32 geode_dc_read(int reg)
105
u32 val = geode_mem_read(GET_GLOBAL(GeodeDC) + reg);
106
dprintf(4, "%s(0x%08x) = 0x%08x\n"
107
, __func__, GET_GLOBAL(GeodeDC) + reg, val);
111
static void geode_dc_write(int reg, u32 val)
113
dprintf(4, "%s(0x%08x, 0x%08x)\n"
114
, __func__, GET_GLOBAL(GeodeDC) + reg, val);
115
geode_mem_mask(GET_GLOBAL(GeodeDC) + reg, ~0, val);
118
static void geode_dc_mask(int reg, u32 off, u32 on)
120
dprintf(4, "%s(0x%08x, 0x%08x, 0x%08x)\n"
121
, __func__, GET_GLOBAL(GeodeDC) + reg, off, on);
122
geode_mem_mask(GET_GLOBAL(GeodeDC) + reg, off, on);
125
static u32 geode_vp_read(int reg)
127
u32 val = geode_mem_read(GET_GLOBAL(GeodeVP) + reg);
128
dprintf(4, "%s(0x%08x) = 0x%08x\n"
129
, __func__, GET_GLOBAL(GeodeVP) + reg, val);
133
static void geode_vp_write(int reg, u32 val)
135
dprintf(4, "%s(0x%08x, 0x%08x)\n"
136
, __func__, GET_GLOBAL(GeodeVP) + reg, val);
137
geode_mem_mask(GET_GLOBAL(GeodeVP) + reg, ~0, val);
140
static void geode_vp_mask(int reg, u32 off, u32 on)
142
dprintf(4, "%s(0x%08x, 0x%08x, 0x%08x)\n"
143
, __func__, GET_GLOBAL(GeodeVP) + reg, off, on);
144
geode_mem_mask(GET_GLOBAL(GeodeVP) + reg, off, on);
147
static u32 geode_fp_read(int reg)
149
u32 val = geode_mem_read(GET_GLOBAL(GeodeVP) + VP_FP_START + reg);
150
dprintf(4, "%s(0x%08x) = 0x%08x\n"
151
, __func__, GET_GLOBAL(GeodeVP) + VP_FP_START + reg, val);
155
static void geode_fp_write(int reg, u32 val)
157
dprintf(4, "%s(0x%08x, 0x%08x)\n"
158
, __func__, GET_GLOBAL(GeodeVP) + VP_FP_START + reg, val);
159
geode_mem_mask(GET_GLOBAL(GeodeVP) + VP_FP_START + reg, ~0, val);
162
/****************************************************************
164
****************************************************************/
166
static int legacyio_check(void)
171
if (CONFIG_VGA_GEODEGX2)
172
val = geode_msr_read(GLIU0_P2D_BM_4);
174
val = geode_msr_read(MSR_GLIU0_BASE4);
175
if ((val & 0xffffffff) != 0x0A0fffe0)
178
val = geode_msr_read(GLIU0_IOD_BM_0);
179
if ((val & 0xffffffff) != 0x3c0ffff0)
182
val = geode_msr_read(GLIU0_IOD_BM_1);
183
if ((val & 0xffffffff) != 0x3d0ffff0)
189
static u32 framebuffer_size(void)
191
/* We use the P2D_R0 msr to read out the number of pages.
192
* One page has a size of 4k
194
* Bit Name Description
195
* 39:20 PMAX Physical Memory Address Max
196
* 19:0 PMIX Physical Memory Address Min
199
u64 msr = geode_msr_read(GLIU0_P2D_RO);
201
u32 pmax = (msr >> 20) & 0x000fffff;
202
u32 pmin = msr & 0x000fffff;
204
u32 val = pmax - pmin;
207
/* The page size is 4k */
211
/****************************************************************
213
****************************************************************/
215
static void geodevga_set_output_mode(void)
220
/* set output to crt and RGB/YUV */
221
if (CONFIG_VGA_GEODEGX2)
222
msr_addr = VP_MSR_CONFIG_GX2;
224
msr_addr = VP_MSR_CONFIG_LX;
226
/* set output mode (RGB/YUV) */
227
msr = geode_msr_read(msr_addr);
228
msr &= ~VP_MSR_CONFIG_FMT; // mask out FMT (bits 5:3)
230
if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
231
msr |= VP_MSR_CONFIG_FMT_FP; // flat panel
233
if (CONFIG_VGA_OUTPUT_CRT_PANEL) {
234
msr |= VP_MSR_CONFIG_FPC; // simultaneous Flat Panel and CRT
235
dprintf(1, "output: simultaneous Flat Panel and CRT\n");
237
msr &= ~VP_MSR_CONFIG_FPC; // no simultaneous Flat Panel and CRT
238
dprintf(1, "ouput: flat panel\n");
241
msr |= VP_MSR_CONFIG_FMT_CRT; // CRT only
242
dprintf(1, "output: CRT\n");
244
geode_msr_mask(msr_addr, ~msr, msr);
247
/* Set up the dc (display controller) portion of the geodelx
248
* The dc provides hardware support for VGA graphics.
250
static void dc_setup(void)
252
dprintf(2, "DC_SETUP\n");
254
geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
256
/* zero memory config */
257
geode_dc_write(DC_FB_ST_OFFSET, 0x0);
258
geode_dc_write(DC_CB_ST_OFFSET, 0x0);
259
geode_dc_write(DC_CURS_ST_OFFSET, 0x0);
261
geode_dc_mask(DC_DISPLAY_CFG, ~DC_CFG_MSK, DC_DISPLAY_CFG_GDEN|DC_DISPLAY_CFG_TRUP);
262
geode_dc_write(DC_GENERAL_CFG, DC_GENERAL_CFG_VGAE);
264
geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
267
/* Setup the vp (video processor) portion of the geodelx
268
* Under VGA modes the vp was handled by softvg from inside VSA2.
269
* Without a softvg module, access is only available through a pci bar.
270
* The High Mem Access virtual register is used to configure the
271
* pci mmio bar from 16bit friendly io space.
273
static void vp_setup(void)
275
dprintf(2,"VP_SETUP\n");
277
geodevga_set_output_mode();
279
/* Set mmio registers
280
* there may be some timing issues here, the reads seem
281
* to slow things down enough work reliably
284
u32 reg = geode_vp_read(VP_MISC);
285
dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
286
geode_vp_write(VP_MISC, VP_DCFG_BYP_BOTH);
287
reg = geode_vp_read(VP_MISC);
288
dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
290
reg = geode_vp_read(VP_DCFG);
291
dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
292
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);
293
reg = geode_vp_read(VP_DCFG);
294
dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
296
/* setup flat panel */
297
if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
300
dprintf(1, "Setting up flat panel\n");
301
/* write timing register */
302
geode_fp_write(FP_PT1, 0x0);
303
geode_fp_write(FP_PT2, FP_PT2_SCRC);
305
/* set pad select for TFT/LVDS */
306
msr = VP_MSR_PADSEL_TFT_SEL_HIGH;
308
msr |= VP_MSR_PADSEL_TFT_SEL_LOW;
309
geode_msr_mask(VP_MSR_PADSEL, ~msr, msr);
311
/* turn the panel on (if it isn't already) */
312
reg = geode_fp_read(FP_PM);
314
geode_fp_write(FP_PM, reg);
318
static u8 geode_crtc_01[] VAR16 = {
319
0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
320
0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
321
0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
323
static u8 geode_crtc_03[] VAR16 = {
324
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
325
0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
326
0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
328
static u8 geode_crtc_04[] VAR16 = {
329
0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
330
0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331
0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
333
static u8 geode_crtc_05[] VAR16 = {
334
0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
335
0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336
0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
338
static u8 geode_crtc_06[] VAR16 = {
339
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
340
0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341
0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
343
static u8 geode_crtc_07[] VAR16 = {
344
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
345
0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
346
0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
348
static u8 geode_crtc_0d[] VAR16 = {
349
0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
350
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351
0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
353
static u8 geode_crtc_0e[] VAR16 = {
354
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
355
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356
0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
358
static u8 geode_crtc_0f[] VAR16 = {
359
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
360
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361
0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
363
static u8 geode_crtc_11[] VAR16 = {
364
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
365
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366
0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
368
static u8 geode_crtc_13[] VAR16 = {
369
0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
370
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371
0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
374
int geodevga_setup(void)
376
int ret = stdvga_setup();
380
dprintf(1,"GEODEVGA_SETUP\n");
382
if ((ret=legacyio_check())) {
383
dprintf(1,"GEODEVGA_SETUP legacyio_check=0x%x\n",ret);
386
// Updated timings from geode datasheets, table 6-53 in particular
387
static u8 *new_crtc[] VAR16 = {
388
geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
389
geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
391
geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
392
geode_crtc_11, geode_crtc_11, geode_crtc_13 };
394
for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
395
u8 *crtc = GET_GLOBAL(new_crtc[i]);
397
stdvga_override_crtc(i, crtc);
400
if (GET_GLOBAL(VgaBDF) < 0)
401
// Device should be at 00:01.1
402
SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
404
// setup geode struct which is used for register access
405
SET_VGA(GeodeFB, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0));
406
SET_VGA(GeodeDC, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_2));
407
SET_VGA(GeodeVP, pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3));
409
dprintf(1, "fb addr: 0x%08x\n", GET_GLOBAL(GeodeFB));
410
dprintf(1, "dc addr: 0x%08x\n", GET_GLOBAL(GeodeDC));
411
dprintf(1, "vp addr: 0x%08x\n", GET_GLOBAL(GeodeVP));
413
/* setup framebuffer */
414
geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
416
/* read fb-bar from pci, then point dc to the fb base */
417
u32 fb = GET_GLOBAL(GeodeFB);
418
if (geode_dc_read(DC_GLIU0_MEM_OFFSET) != fb)
419
geode_dc_write(DC_GLIU0_MEM_OFFSET, fb);
421
geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
423
u32 fb_size = framebuffer_size(); // in byte
424
dprintf(1, "%d KB of video memory at 0x%08x\n", fb_size / 1024, fb);
426
/* update VBE variables */
427
SET_VGA(VBE_framebuffer, fb);
428
SET_VGA(VBE_total_memory, fb_size / 1024 / 64); // number of 64K blocks