blob: d44b7c16fc5a5d32407b0c2b42c6c764a101b763 [file] [log] [blame]
Nils31eabf92012-01-14 12:11:41 -05001// 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
Nils31eabf92012-01-14 12:11:41 -050010#include "farptr.h" // SET_FARVAR
11#include "biosvar.h" // GET_BDA
12#include "vgabios.h" // VGAREG_*
13#include "util.h" // memset
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -050014#include "stdvga.h" // stdvga_crtc_write
Kevin O'Connor707d2162012-01-15 00:06:33 -050015#include "pci.h" // pci_config_readl
16#include "pci_regs.h" // PCI_BASE_ADDRESS_0
Nils31eabf92012-01-14 12:11:41 -050017
18
19/****************************************************************
20* MSR and High Mem access through VSA Virtual Register
21****************************************************************/
22
23static union u64_u32_u geode_msrRead(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 return val;
37}
38
39static void geode_msrWrite(u32 msrAddr,u32 andhi, u32 andlo, u32 orhi, u32 orlo)
40{
41 asm __volatile__ (
42 "push %%eax \n"
43 "movw $0x0AC1C, %%dx \n"
44 "movl $0xFC530007, %%eax \n"
45 "outl %%eax, %%dx \n"
46 "addb $2, %%dl \n"
47 "pop %%eax \n"
48 "outw %%ax, %%dx \n"
49 :
50 : "c"(msrAddr), "S" (andhi), "D" (andlo), "b" (orhi), "a" (orlo)
51 : "%edx","cc"
52 );
53}
54
55static u32 geode_memRead(u32 addr)
56{
57 u32 val;
58 asm __volatile__ (
59 "movw $0x0AC1C, %%dx \n"
60 "movl $0xFC530001, %%eax \n"
61 "outl %%eax, %%dx \n"
62 "addb $2, %%dl \n"
63 "inw %%dx, %%ax \n"
64 : "=a" (val)
65 : "b"(addr)
66 : "cc"
67 );
68
69 return val;
70}
71
72static void geode_memWrite(u32 addr, u32 and, u32 or )
73{
74 asm __volatile__ (
75 "movw $0x0AC1C, %%dx \n"
76 "movl $0xFC530001, %%eax \n"
77 "outl %%eax, %%dx \n"
78 "addb $2, %%dl \n"
79 "outw %%ax, %%dx \n"
80 :
81 : "b"(addr), "S" (and), "D" (or)
82 : "%eax","cc"
83 );
84}
85
Christian Gmeiner7bec6db2012-09-01 17:13:02 +020086/****************************************************************
87 * Helper functions
88 ****************************************************************/
89
90struct geode {
91 u32 fb;
92 u32 dc;
93 u32 vp;
94};
95struct geode geode VAR16;
96
Nils31eabf92012-01-14 12:11:41 -050097static int legacyio_check(void)
98{
99 int ret=0;
100 union u64_u32_u val;
101
Nils24ddd862012-01-14 12:15:14 -0500102 if (CONFIG_VGA_GEODEGX2)
103 val=geode_msrRead(GLIU0_P2D_BM_4);
104 else
105 val=geode_msrRead(MSR_GLIU0_BASE4);
Nils31eabf92012-01-14 12:11:41 -0500106 if (val.lo != 0x0A0fffe0)
107 ret|=1;
108
109 val=geode_msrRead(GLIU0_IOD_BM_0);
110 if (val.lo != 0x3c0ffff0)
111 ret|=2;
112
113 val=geode_msrRead(GLIU0_IOD_BM_1);
114 if (val.lo != 0x3d0ffff0)
115 ret|=4;
116
117 return ret;
118}
119
Christian Gmeiner9de339d2012-09-01 17:12:56 +0200120static u32 framebuffer_size(void)
121{
122 u32 val;
123 union u64_u32_u msr;
124
125 /* We use the P2D_R0 msr to read out the number of pages.
126 * One page has a size of 4k
127 *
128 * Bit Name Description
129 * 39:20 PMAX Physical Memory Address Max
130 * 19:0 PMIX Physical Memory Address Min
131 *
132 */
133 msr = geode_msrRead(GLIU0_P2D_RO);
134
135 u32 pmax = ((msr.hi & 0xff) << 12) | ((msr.lo & 0xfff00000) >> 20);
136 u32 pmin = (msr.lo & 0x000fffff);
137
138 val = pmax - pmin;
139 val += 1;
140
141 /* The page size is 4k */
142 return (val << 12);
143}
Nils31eabf92012-01-14 12:11:41 -0500144
145/****************************************************************
Nils31eabf92012-01-14 12:11:41 -0500146* Init Functions
147****************************************************************/
148
149/* Set up the dc (display controller) portion of the geodelx
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200150* The dc provides hardware support for VGA graphics.
Nils31eabf92012-01-14 12:11:41 -0500151*/
152static int dc_setup(void)
153{
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200154 u32 dc_fb;
Nils31eabf92012-01-14 12:11:41 -0500155
156 dprintf(2, "DC_SETUP\n");
157
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200158 geode_memWrite(geode.dc + DC_UNLOCK, 0x0, DC_LOCK_UNLOCK);
Nils31eabf92012-01-14 12:11:41 -0500159
160 /* zero memory config */
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200161 geode_memWrite(geode.dc + DC_FB_ST_OFFSET, 0x0, 0x0);
162 geode_memWrite(geode.dc + DC_CB_ST_OFFSET, 0x0, 0x0);
163 geode_memWrite(geode.dc + DC_CURS_ST_OFFSET, 0x0, 0x0);
Nils31eabf92012-01-14 12:11:41 -0500164
165 /* read fb-bar from pci, then point dc to the fb base */
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200166 dc_fb = geode_memRead(geode.dc + DC_GLIU0_MEM_OFFSET);
167 if (geode.fb != dc_fb) {
168 geode_memWrite(geode.dc + DC_GLIU0_MEM_OFFSET, 0x0, geode.fb);
Nils31eabf92012-01-14 12:11:41 -0500169 }
170
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200171 geode_memWrite(geode.dc + DC_DISPLAY_CFG, DC_CFG_MSK, DC_GDEN+DC_TRUP);
172 geode_memWrite(geode.dc + DC_GENERAL_CFG, 0, DC_VGAE);
Nils31eabf92012-01-14 12:11:41 -0500173
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200174 geode_memWrite(geode.dc + DC_UNLOCK, 0x0, DC_LOCK_LOCK);
Nils31eabf92012-01-14 12:11:41 -0500175
Christian Gmeiner9de339d2012-09-01 17:12:56 +0200176 u32 fb_size = framebuffer_size(); // in byte
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200177 dprintf(1, "%d KB of video memory at 0x%08x\n", fb_size / 1024, geode.fb);
Christian Gmeiner517f7422012-09-01 17:13:01 +0200178
179 /* update VBE variables */
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200180 SET_VGA(VBE_framebuffer, geode.fb);
Christian Gmeiner517f7422012-09-01 17:13:01 +0200181 SET_VGA(VBE_total_memory, fb_size / 1024 / 64); // number of 64K blocks
Christian Gmeiner9de339d2012-09-01 17:12:56 +0200182
Nils31eabf92012-01-14 12:11:41 -0500183 return 0;
184}
185
186/* Setup the vp (video processor) portion of the geodelx
187* Under VGA modes the vp was handled by softvg from inside VSA2.
188* Without a softvg module, access is only available through a pci bar.
189* The High Mem Access virtual register is used to configure the
190* pci mmio bar from 16bit friendly io space.
191*/
192int vp_setup(void)
193{
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200194 u32 reg;
Nils31eabf92012-01-14 12:11:41 -0500195
196 dprintf(2,"VP_SETUP\n");
197 /* set output to crt and RGB/YUV */
Nils24ddd862012-01-14 12:15:14 -0500198 if (CONFIG_VGA_GEODEGX2)
Kevin O'Connor707d2162012-01-15 00:06:33 -0500199 geode_msrWrite(VP_MSR_CONFIG_GX2, ~0, ~0xf8, 0, 0);
Nils24ddd862012-01-14 12:15:14 -0500200 else
Kevin O'Connor707d2162012-01-15 00:06:33 -0500201 geode_msrWrite(VP_MSR_CONFIG_LX, ~0, ~0xf8, 0, 0);
Nils31eabf92012-01-14 12:11:41 -0500202
Nils31eabf92012-01-14 12:11:41 -0500203 /* Set mmio registers
204 * there may be some timing issues here, the reads seem
205 * to slow things down enough work reliably
206 */
207
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200208 reg = geode_memRead(geode.vp + VP_MISC);
Nils31eabf92012-01-14 12:11:41 -0500209 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200210 geode_memWrite(geode.vp + VP_MISC,0,VP_BYP_BOTH);
211 reg = geode_memRead(geode.vp + VP_MISC);
Nils31eabf92012-01-14 12:11:41 -0500212 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
213
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200214 reg = geode_memRead(geode.vp + VP_DCFG);
Nils31eabf92012-01-14 12:11:41 -0500215 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200216 geode_memWrite(geode.vp + VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
217 reg = geode_memRead(geode.vp + VP_DCFG);
Nils31eabf92012-01-14 12:11:41 -0500218 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
219
220 return 0;
221}
222
223static u8 geode_crtc_01[] VAR16 = {
224 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
225 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
226 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
227 0xff };
228static u8 geode_crtc_03[] VAR16 = {
229 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
230 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
231 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
232 0xff };
233static u8 geode_crtc_04[] VAR16 = {
234 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
235 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
237 0xff };
238static u8 geode_crtc_05[] VAR16 = {
239 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
240 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
242 0xff };
243static u8 geode_crtc_06[] VAR16 = {
244 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
245 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
247 0xff };
248static u8 geode_crtc_07[] VAR16 = {
249 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
250 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
251 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
252 0xff };
253static u8 geode_crtc_0d[] VAR16 = {
254 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
255 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
257 0xff };
258static u8 geode_crtc_0e[] VAR16 = {
259 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
260 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
262 0xff };
263static u8 geode_crtc_0f[] VAR16 = {
264 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
265 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
267 0xff };
268static u8 geode_crtc_11[] VAR16 = {
269 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
270 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
272 0xff };
273static u8 geode_crtc_13[] VAR16 = {
274 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
275 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
276 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
277 0xff };
278
279int geodevga_init(void)
280{
281 int ret = stdvga_init();
282 if (ret)
283 return ret;
284
285 dprintf(1,"GEODEVGA_INIT\n");
286
287 if ((ret=legacyio_check())) {
288 dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
289 }
290
291 // Updated timings from geode datasheets, table 6-53 in particular
292 static u8 *new_crtc[] VAR16 = {
293 geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
294 geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
295 0, 0, 0, 0, 0,
296 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
297 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
298 int i;
299 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
300 u8 *crtc = GET_GLOBAL(new_crtc[i]);
Kevin O'Connor69b01cb2012-01-14 23:25:24 -0500301 if (crtc)
302 stdvga_override_crtc(i, crtc);
Nils31eabf92012-01-14 12:11:41 -0500303 }
304
Kevin O'Connor8cf8f8e2012-01-16 19:05:27 -0500305 if (GET_GLOBAL(VgaBDF) < 0)
306 // Device should be at 00:01.1
307 SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
Christian Gmeiner7bec6db2012-09-01 17:13:02 +0200308
309 // setup geode struct which is used for register access
310 geode.fb = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0);
311 geode.dc = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_2);
312 geode.vp = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3);
313
314 dprintf(1, "fb addr: 0x%08x\n", geode.fb);
315 dprintf(1, "dc addr: 0x%08x\n", geode.dc);
316 dprintf(1, "vp addr: 0x%08x\n", geode.vp);
317
Nils31eabf92012-01-14 12:11:41 -0500318 ret |= vp_setup();
319 ret |= dc_setup();
320
321 return ret;
322}