blob: 2cf11a083524b459e6d9e7d3675c2a18cb7cb61c [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
86static int legacyio_check(void)
87{
88 int ret=0;
89 union u64_u32_u val;
90
Nils24ddd862012-01-14 12:15:14 -050091 if (CONFIG_VGA_GEODEGX2)
92 val=geode_msrRead(GLIU0_P2D_BM_4);
93 else
94 val=geode_msrRead(MSR_GLIU0_BASE4);
Nils31eabf92012-01-14 12:11:41 -050095 if (val.lo != 0x0A0fffe0)
96 ret|=1;
97
98 val=geode_msrRead(GLIU0_IOD_BM_0);
99 if (val.lo != 0x3c0ffff0)
100 ret|=2;
101
102 val=geode_msrRead(GLIU0_IOD_BM_1);
103 if (val.lo != 0x3d0ffff0)
104 ret|=4;
105
106 return ret;
107}
108
109/****************************************************************
110* Extened CRTC Register functions
111****************************************************************/
112static void crtce_lock(void)
113{
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500114 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
115 , CRTCE_LOCK);
Nils31eabf92012-01-14 12:11:41 -0500116}
117
118static void crtce_unlock(void)
119{
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500120 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, EXTENDED_REGISTER_LOCK
121 , CRTCE_UNLOCK);
Nils31eabf92012-01-14 12:11:41 -0500122}
123
124static u8 crtce_read(u8 reg)
125{
Nils31eabf92012-01-14 12:11:41 -0500126 crtce_unlock();
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500127 u8 val = stdvga_crtc_read(VGAREG_VGA_CRTC_ADDRESS, reg);
Nils31eabf92012-01-14 12:11:41 -0500128 crtce_lock();
Nils31eabf92012-01-14 12:11:41 -0500129 return val;
130}
131
132static void crtce_write(u8 reg, u8 val)
133{
134 crtce_unlock();
Kevin O'Connor2c23a7a2012-01-14 22:18:18 -0500135 stdvga_crtc_write(VGAREG_VGA_CRTC_ADDRESS, reg, val);
Nils31eabf92012-01-14 12:11:41 -0500136 crtce_lock();
137}
138
139/****************************************************************
Nils31eabf92012-01-14 12:11:41 -0500140* Init Functions
141****************************************************************/
142
143/* Set up the dc (display controller) portion of the geodelx
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200144* The dc provides hardware support for VGA graphics.
Nils31eabf92012-01-14 12:11:41 -0500145*/
146static int dc_setup(void)
147{
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200148 u32 fb, dc_fb, dc_base;
Nils31eabf92012-01-14 12:11:41 -0500149
150 dprintf(2, "DC_SETUP\n");
151
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200152 dc_base = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_2);
153 geode_memWrite(dc_base + DC_UNLOCK, 0x0, DC_LOCK_UNLOCK);
Nils31eabf92012-01-14 12:11:41 -0500154
155 /* zero memory config */
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200156 geode_memWrite(dc_base + DC_FB_ST_OFFSET, 0x0, 0x0);
157 geode_memWrite(dc_base + DC_CB_ST_OFFSET, 0x0, 0x0);
158 geode_memWrite(dc_base + DC_CURS_ST_OFFSET, 0x0, 0x0);
Nils31eabf92012-01-14 12:11:41 -0500159
160 /* read fb-bar from pci, then point dc to the fb base */
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200161 dc_fb = geode_memRead(dc_base + DC_GLIU0_MEM_OFFSET);
Kevin O'Connor707d2162012-01-15 00:06:33 -0500162 fb = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_0);
Nils31eabf92012-01-14 12:11:41 -0500163 if (fb!=dc_fb) {
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200164 geode_memWrite(dc_base + DC_GLIU0_MEM_OFFSET, 0x0, fb);
Nils31eabf92012-01-14 12:11:41 -0500165 }
166
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200167 geode_memWrite(dc_base + DC_DISPLAY_CFG, DC_CFG_MSK, DC_GDEN+DC_TRUP);
168 geode_memWrite(dc_base + DC_GENERAL_CFG, 0, DC_VGAE);
Nils31eabf92012-01-14 12:11:41 -0500169
Christian Gmeinerc13c1812012-09-01 17:12:52 +0200170 geode_memWrite(dc_base + DC_UNLOCK, 0x0, DC_LOCK_LOCK);
Nils31eabf92012-01-14 12:11:41 -0500171
172 return 0;
173}
174
175/* Setup the vp (video processor) portion of the geodelx
176* Under VGA modes the vp was handled by softvg from inside VSA2.
177* Without a softvg module, access is only available through a pci bar.
178* The High Mem Access virtual register is used to configure the
179* pci mmio bar from 16bit friendly io space.
180*/
181int vp_setup(void)
182{
183 u32 reg,vp;
184
185 dprintf(2,"VP_SETUP\n");
186 /* set output to crt and RGB/YUV */
Nils24ddd862012-01-14 12:15:14 -0500187 if (CONFIG_VGA_GEODEGX2)
Kevin O'Connor707d2162012-01-15 00:06:33 -0500188 geode_msrWrite(VP_MSR_CONFIG_GX2, ~0, ~0xf8, 0, 0);
Nils24ddd862012-01-14 12:15:14 -0500189 else
Kevin O'Connor707d2162012-01-15 00:06:33 -0500190 geode_msrWrite(VP_MSR_CONFIG_LX, ~0, ~0xf8, 0, 0);
Nils31eabf92012-01-14 12:11:41 -0500191
192 /* get vp register base from pci */
Kevin O'Connor707d2162012-01-15 00:06:33 -0500193 vp = pci_config_readl(GET_GLOBAL(VgaBDF), PCI_BASE_ADDRESS_3);
Nils31eabf92012-01-14 12:11:41 -0500194
195 /* Set mmio registers
196 * there may be some timing issues here, the reads seem
197 * to slow things down enough work reliably
198 */
199
200 reg = geode_memRead(vp+VP_MISC);
201 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
202 geode_memWrite(vp+VP_MISC,0,VP_BYP_BOTH);
203 reg = geode_memRead(vp+VP_MISC);
204 dprintf(1,"VP_SETUP VP_MISC=0x%08x\n",reg);
205
206 reg = geode_memRead(vp+VP_DCFG);
207 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
208 geode_memWrite(vp+VP_DCFG, ~0,VP_CRT_EN+VP_HSYNC_EN+VP_VSYNC_EN+VP_DAC_BL_EN+VP_CRT_SKEW);
209 reg = geode_memRead(vp+VP_DCFG);
210 dprintf(1,"VP_SETUP VP_DCFG=0x%08x\n",reg);
211
212 return 0;
213}
214
215static u8 geode_crtc_01[] VAR16 = {
216 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
217 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
218 0x9b, 0x8d, 0x8f, 0x14, 0x1f, 0x97, 0xb9, 0xa3,
219 0xff };
220static u8 geode_crtc_03[] VAR16 = {
221 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
222 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
223 0x9b, 0x8d, 0x8f, 0x28, 0x1f, 0x97, 0xb9, 0xa3,
224 0xff };
225static u8 geode_crtc_04[] VAR16 = {
226 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
227 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
229 0xff };
230static u8 geode_crtc_05[] VAR16 = {
231 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
232 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x9b, 0x8e, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xa2,
234 0xff };
235static u8 geode_crtc_06[] VAR16 = {
236 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
237 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xc2,
239 0xff };
240static u8 geode_crtc_07[] VAR16 = {
241 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
242 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
243 0x9b, 0x8d, 0x8f, 0x28, 0x0f, 0x97, 0xb9, 0xa3,
244 0xff };
245static u8 geode_crtc_0d[] VAR16 = {
246 0x2d, 0x27, 0x28, 0x90, 0x29, 0x8e, 0xbf, 0x1f,
247 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x9b, 0x8d, 0x8f, 0x14, 0x00, 0x97, 0xb9, 0xe3,
249 0xff };
250static u8 geode_crtc_0e[] VAR16 = {
251 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
252 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 0x9b, 0x8d, 0x8f, 0x28, 0x00, 0x97, 0xb9, 0xe3,
254 0xff };
255static u8 geode_crtc_0f[] VAR16 = {
256 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
257 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x65, 0xb9, 0xe3,
259 0xff };
260static u8 geode_crtc_11[] VAR16 = {
261 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0x0b, 0x3e,
262 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
264 0xff };
265static u8 geode_crtc_13[] VAR16 = {
266 0x5f, 0x4f, 0x50, 0x82, 0x51, 0x9e, 0xbf, 0x1f,
267 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x9b, 0x8d, 0x8f, 0x28, 0x40, 0x98, 0xb9, 0xa3,
269 0xff };
270
271int geodevga_init(void)
272{
273 int ret = stdvga_init();
274 if (ret)
275 return ret;
276
277 dprintf(1,"GEODEVGA_INIT\n");
278
279 if ((ret=legacyio_check())) {
280 dprintf(1,"GEODEVGA_INIT legacyio_check=0x%x\n",ret);
281 }
282
283 // Updated timings from geode datasheets, table 6-53 in particular
284 static u8 *new_crtc[] VAR16 = {
285 geode_crtc_01, geode_crtc_01, geode_crtc_03, geode_crtc_03,
286 geode_crtc_04, geode_crtc_05, geode_crtc_06, geode_crtc_07,
287 0, 0, 0, 0, 0,
288 geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
289 geode_crtc_11, geode_crtc_11, geode_crtc_13 };
290 int i;
291 for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
292 u8 *crtc = GET_GLOBAL(new_crtc[i]);
Kevin O'Connor69b01cb2012-01-14 23:25:24 -0500293 if (crtc)
294 stdvga_override_crtc(i, crtc);
Nils31eabf92012-01-14 12:11:41 -0500295 }
296
Kevin O'Connor8cf8f8e2012-01-16 19:05:27 -0500297 if (GET_GLOBAL(VgaBDF) < 0)
298 // Device should be at 00:01.1
299 SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
Nils31eabf92012-01-14 12:11:41 -0500300 ret |= vp_setup();
301 ret |= dc_setup();
302
303 return ret;
304}