~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/seabios/vgasrc/geodevga.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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" // SET_VGA
 
17
#include "vgautil.h" // VBE_total_memory
 
18
 
 
19
 
 
20
/****************************************************************
 
21
* MSR and High Mem access through VSA Virtual Register
 
22
****************************************************************/
 
23
 
 
24
static u64 geode_msr_read(u32 msrAddr)
 
25
{
 
26
    union u64_u32_u val;
 
27
    asm __volatile__ (
 
28
        "movw   $0x0AC1C, %%dx          \n"
 
29
        "movl   $0xFC530007, %%eax      \n"
 
30
        "outl   %%eax, %%dx             \n"
 
31
        "addb   $2, %%dl                \n"
 
32
        "inw    %%dx, %%ax              \n"
 
33
        : "=a" (val.lo), "=d"(val.hi)
 
34
        : "c"(msrAddr)
 
35
        : "cc"
 
36
    );
 
37
 
 
38
    dprintf(4, "%s(0x%08x) = 0x%08x-0x%08x\n"
 
39
            , __func__, msrAddr, val.hi, val.lo);
 
40
    return val.val;
 
41
}
 
42
 
 
43
static void geode_msr_mask(u32 msrAddr, u64 off, u64 on)
 
44
{
 
45
    union u64_u32_u uand, uor;
 
46
    uand.val = ~off;
 
47
    uor.val = on;
 
48
 
 
49
    dprintf(4, "%s(0x%08x, 0x%016llx, 0x%016llx)\n"
 
50
            , __func__, msrAddr, off, on);
 
51
 
 
52
    asm __volatile__ (
 
53
        "push   %%eax                   \n"
 
54
        "movw   $0x0AC1C, %%dx          \n"
 
55
        "movl   $0xFC530007, %%eax      \n"
 
56
        "outl   %%eax, %%dx             \n"
 
57
        "addb   $2, %%dl                \n"
 
58
        "pop    %%eax                   \n"
 
59
        "outw   %%ax, %%dx              \n"
 
60
        :
 
61
        : "c"(msrAddr), "S" (uand.hi), "D" (uand.lo), "b" (uor.hi), "a" (uor.lo)
 
62
        : "%edx","cc"
 
63
    );
 
64
}
 
65
 
 
66
static u32 geode_mem_read(u32 addr)
 
67
{
 
68
    u32 val;
 
69
    asm __volatile__ (
 
70
        "movw   $0x0AC1C, %%dx          \n"
 
71
        "movl   $0xFC530001, %%eax      \n"
 
72
        "outl   %%eax, %%dx             \n"
 
73
        "addb   $2, %%dl                \n"
 
74
        "inw    %%dx, %%ax              \n"
 
75
        : "=a" (val)
 
76
        : "b"(addr)
 
77
        : "cc"
 
78
    );
 
79
 
 
80
    return val;
 
81
}
 
82
 
 
83
static void geode_mem_mask(u32 addr, u32 off, u32 or)
 
84
{
 
85
    asm __volatile__ (
 
86
        "movw   $0x0AC1C, %%dx          \n"
 
87
        "movl   $0xFC530001, %%eax      \n"
 
88
        "outl   %%eax, %%dx             \n"
 
89
        "addb   $2, %%dl                \n"
 
90
        "outw   %%ax, %%dx              \n"
 
91
        :
 
92
        : "b"(addr), "S" (~off), "D" (or)
 
93
        : "%eax","cc"
 
94
    );
 
95
}
 
96
 
 
97
#define VP_FP_START     0x400
 
98
 
 
99
static u32 GeodeFB VAR16;
 
100
static u32 GeodeDC VAR16;
 
101
static u32 GeodeVP VAR16;
 
102
 
 
103
static u32 geode_dc_read(int reg)
 
104
{
 
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);
 
108
    return val;
 
109
}
 
110
 
 
111
static void geode_dc_write(int reg, u32 val)
 
112
{
 
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);
 
116
}
 
117
 
 
118
static void geode_dc_mask(int reg, u32 off, u32 on)
 
119
{
 
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);
 
123
}
 
124
 
 
125
static u32 geode_vp_read(int reg)
 
126
{
 
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);
 
130
    return val;
 
131
}
 
132
 
 
133
static void geode_vp_write(int reg, u32 val)
 
134
{
 
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);
 
138
}
 
139
 
 
140
static void geode_vp_mask(int reg, u32 off, u32 on)
 
141
{
 
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);
 
145
}
 
146
 
 
147
static u32 geode_fp_read(int reg)
 
148
{
 
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);
 
152
    return val;
 
153
}
 
154
 
 
155
static void geode_fp_write(int reg, u32 val)
 
156
{
 
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);
 
160
}
 
161
 
 
162
/****************************************************************
 
163
 * Helper functions
 
164
 ****************************************************************/
 
165
 
 
166
static int legacyio_check(void)
 
167
{
 
168
    int ret=0;
 
169
    u64 val;
 
170
 
 
171
    if (CONFIG_VGA_GEODEGX2)
 
172
        val = geode_msr_read(GLIU0_P2D_BM_4);
 
173
    else
 
174
        val = geode_msr_read(MSR_GLIU0_BASE4);
 
175
    if ((val & 0xffffffff) != 0x0A0fffe0)
 
176
        ret|=1;
 
177
 
 
178
    val = geode_msr_read(GLIU0_IOD_BM_0);
 
179
    if ((val & 0xffffffff) != 0x3c0ffff0)
 
180
        ret|=2;
 
181
 
 
182
    val = geode_msr_read(GLIU0_IOD_BM_1);
 
183
    if ((val & 0xffffffff) != 0x3d0ffff0)
 
184
        ret|=4;
 
185
 
 
186
    return ret;
 
187
}
 
188
 
 
189
static u32 framebuffer_size(void)
 
190
{
 
191
    /* We use the P2D_R0 msr to read out the number of pages.
 
192
     * One page has a size of 4k
 
193
     *
 
194
     * Bit      Name    Description
 
195
     * 39:20    PMAX    Physical Memory Address Max
 
196
     * 19:0     PMIX    Physical Memory Address Min
 
197
     *
 
198
     */
 
199
    u64 msr = geode_msr_read(GLIU0_P2D_RO);
 
200
 
 
201
    u32 pmax = (msr >> 20) & 0x000fffff;
 
202
    u32 pmin = msr & 0x000fffff;
 
203
 
 
204
    u32 val = pmax - pmin;
 
205
    val += 1;
 
206
 
 
207
    /* The page size is 4k */
 
208
    return (val << 12);
 
209
}
 
210
 
 
211
/****************************************************************
 
212
* Init Functions
 
213
****************************************************************/
 
214
 
 
215
static void geodevga_set_output_mode(void)
 
216
{
 
217
    u64 msr_addr;
 
218
    u64 msr;
 
219
 
 
220
    /* set output to crt and RGB/YUV */
 
221
    if (CONFIG_VGA_GEODEGX2)
 
222
        msr_addr = VP_MSR_CONFIG_GX2;
 
223
    else
 
224
        msr_addr = VP_MSR_CONFIG_LX;
 
225
 
 
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)
 
229
 
 
230
    if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
 
231
        msr |= VP_MSR_CONFIG_FMT_FP;   // flat panel
 
232
 
 
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");
 
236
        } else {
 
237
            msr &= ~VP_MSR_CONFIG_FPC; // no simultaneous Flat Panel and CRT
 
238
            dprintf(1, "ouput: flat panel\n");
 
239
        }
 
240
    } else {
 
241
        msr |= VP_MSR_CONFIG_FMT_CRT;  // CRT only
 
242
       dprintf(1, "output: CRT\n");
 
243
    }
 
244
    geode_msr_mask(msr_addr, ~msr, msr);
 
245
}
 
246
 
 
247
/* Set up the dc (display controller) portion of the geodelx
 
248
*  The dc provides hardware support for VGA graphics.
 
249
*/
 
250
static void dc_setup(void)
 
251
{
 
252
    dprintf(2, "DC_SETUP\n");
 
253
 
 
254
    geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
 
255
 
 
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);
 
260
 
 
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);
 
263
 
 
264
    geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
 
265
}
 
266
 
 
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.
 
272
*/
 
273
static void vp_setup(void)
 
274
{
 
275
    dprintf(2,"VP_SETUP\n");
 
276
 
 
277
    geodevga_set_output_mode();
 
278
 
 
279
    /* Set mmio registers
 
280
    * there may be some timing issues here, the reads seem
 
281
    * to slow things down enough work reliably
 
282
    */
 
283
 
 
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);
 
289
 
 
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);
 
295
 
 
296
    /* setup flat panel */
 
297
    if (CONFIG_VGA_OUTPUT_PANEL || CONFIG_VGA_OUTPUT_CRT_PANEL) {
 
298
        u64 msr;
 
299
 
 
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);
 
304
 
 
305
        /* set pad select for TFT/LVDS */
 
306
        msr  = VP_MSR_PADSEL_TFT_SEL_HIGH;
 
307
        msr  = msr << 32;
 
308
        msr |= VP_MSR_PADSEL_TFT_SEL_LOW;
 
309
        geode_msr_mask(VP_MSR_PADSEL, ~msr, msr);
 
310
 
 
311
        /* turn the panel on (if it isn't already) */
 
312
        reg = geode_fp_read(FP_PM);
 
313
        reg |= FP_PM_P;
 
314
        geode_fp_write(FP_PM, reg);
 
315
    }
 
316
}
 
317
 
 
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,
 
322
    0xff };
 
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,
 
327
    0xff };
 
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,
 
332
    0xff };
 
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,
 
337
    0xff };
 
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,
 
342
    0xff };
 
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,
 
347
    0xff };
 
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,
 
352
    0xff };
 
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,
 
357
    0xff };
 
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,
 
362
    0xff };
 
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,
 
367
    0xff };
 
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,
 
372
    0xff };
 
373
 
 
374
int geodevga_setup(void)
 
375
{
 
376
    int ret = stdvga_setup();
 
377
    if (ret)
 
378
        return ret;
 
379
 
 
380
    dprintf(1,"GEODEVGA_SETUP\n");
 
381
 
 
382
    if ((ret=legacyio_check())) {
 
383
        dprintf(1,"GEODEVGA_SETUP legacyio_check=0x%x\n",ret);
 
384
    }
 
385
 
 
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,
 
390
        0, 0, 0, 0, 0,
 
391
        geode_crtc_0d, geode_crtc_0e, geode_crtc_0f, geode_crtc_0f,
 
392
        geode_crtc_11, geode_crtc_11, geode_crtc_13 };
 
393
    int i;
 
394
    for (i=0; i<ARRAY_SIZE(new_crtc); i++) {
 
395
        u8 *crtc = GET_GLOBAL(new_crtc[i]);
 
396
        if (crtc)
 
397
            stdvga_override_crtc(i, crtc);
 
398
    }
 
399
 
 
400
    if (GET_GLOBAL(VgaBDF) < 0)
 
401
        // Device should be at 00:01.1
 
402
        SET_VGA(VgaBDF, pci_to_bdf(0, 1, 1));
 
403
 
 
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));
 
408
 
 
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));
 
412
 
 
413
    /* setup framebuffer */
 
414
    geode_dc_write(DC_UNLOCK, DC_LOCK_UNLOCK);
 
415
 
 
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);
 
420
 
 
421
    geode_dc_write(DC_UNLOCK, DC_LOCK_LOCK);
 
422
 
 
423
    u32 fb_size = framebuffer_size(); // in byte
 
424
    dprintf(1, "%d KB of video memory at 0x%08x\n", fb_size / 1024, fb);
 
425
 
 
426
    /* update VBE variables */
 
427
    SET_VGA(VBE_framebuffer, fb);
 
428
    SET_VGA(VBE_total_memory, fb_size / 1024 / 64); // number of 64K blocks
 
429
 
 
430
    vp_setup();
 
431
    dc_setup();
 
432
 
 
433
    return 0;
 
434
}