blob: dc20f540ae665b0814bdb288a4e991b260344609 [file] [log] [blame]
Vladimir Serbinenko7905f922013-11-25 11:20:20 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenko7905f922013-11-25 11:20:20 +010015 */
16
17#include <stdint.h>
18#include <delay.h>
19#include <edid.h>
20#include <stdlib.h>
21#include <string.h>
22#include <arch/io.h>
23
24#include <boot/coreboot_tables.h>
25#include <console/console.h>
26#include <device/device.h>
27#include <device/pci.h>
28#include <device/pci_ids.h>
29#include <device/pci_ops.h>
30
31#include <pc80/vga.h>
32#include <pc80/vga_io.h>
33
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +010034#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +010035static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES;
36static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES;
37static u32 addr = 0;
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +010038#endif
Vladimir Serbinenko7905f922013-11-25 11:20:20 +010039
40enum
41 {
42 VGA_CR_HTOTAL = 0x00,
43 VGA_CR_HORIZ_END = 0x01,
44 VGA_CR_HBLANK_START = 0x02,
45 VGA_CR_HBLANK_END = 0x03,
46 VGA_CR_HORIZ_SYNC_PULSE_START = 0x04,
47 VGA_CR_HORIZ_SYNC_PULSE_END = 0x05,
48 VGA_CR_VERT_TOTAL = 0x06,
49 VGA_CR_OVERFLOW = 0x07,
50 VGA_CR_BYTE_PANNING = 0x08,
51 VGA_CR_CELL_HEIGHT = 0x09,
52 VGA_CR_CURSOR_START = 0x0a,
53 VGA_CR_CURSOR_END = 0x0b,
54 VGA_CR_START_ADDR_HIGH_REGISTER = 0x0c,
55 VGA_CR_START_ADDR_LOW_REGISTER = 0x0d,
56 VGA_CR_CURSOR_ADDR_HIGH = 0x0e,
57 VGA_CR_CURSOR_ADDR_LOW = 0x0f,
58 VGA_CR_VSYNC_START = 0x10,
59 VGA_CR_VSYNC_END = 0x11,
60 VGA_CR_VDISPLAY_END = 0x12,
61 VGA_CR_PITCH = 0x13,
62 VGA_CR_UNDERLINE_LOCATION = 0x14,
63 VGA_CR_VERTICAL_BLANK_START = 0x15,
64 VGA_CR_VERTICAL_BLANK_END = 0x16,
65 VGA_CR_MODE = 0x17,
66 VGA_CR_LINE_COMPARE = 0x18,
67 };
68
69#define VGA_IO_MISC_COLOR 0x01
70
71#define VGA_CR_WIDTH_DIVISOR 8
72
73#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT 7
74#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK 0x02
75#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT 3
76#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK 0x40
77
78#define VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT 8
79#define VGA_CR_OVERFLOW_VERT_TOTAL1_MASK 0x01
80#define VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT 4
81#define VGA_CR_OVERFLOW_VERT_TOTAL2_MASK 0x20
82
83#define VGA_CR_OVERFLOW_VSYNC_START1_SHIFT 6
84#define VGA_CR_OVERFLOW_VSYNC_START1_MASK 0x04
85#define VGA_CR_OVERFLOW_VSYNC_START2_SHIFT 2
86#define VGA_CR_OVERFLOW_VSYNC_START2_MASK 0x80
87
88#define VGA_CR_OVERFLOW_HEIGHT1_SHIFT 7
89#define VGA_CR_OVERFLOW_HEIGHT1_MASK 0x02
90#define VGA_CR_OVERFLOW_HEIGHT2_SHIFT 3
91#define VGA_CR_OVERFLOW_HEIGHT2_MASK 0xc0
92#define VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT 4
93#define VGA_CR_OVERFLOW_LINE_COMPARE_MASK 0x10
94
95#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK 0x40
96#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT 3
97#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK 0x20
98#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT 4
99#define VGA_CR_CELL_HEIGHT_DOUBLE_SCAN 0x80
100enum
101 {
102 VGA_CR_CURSOR_START_DISABLE = (1 << 5)
103 };
104
105#define VGA_CR_PITCH_DIVISOR 8
106
107enum
108 {
109 VGA_CR_MODE_NO_CGA = 0x01,
110 VGA_CR_MODE_NO_HERCULES = 0x02,
111 VGA_CR_MODE_ADDRESS_WRAP = 0x20,
112 VGA_CR_MODE_BYTE_MODE = 0x40,
113 VGA_CR_MODE_TIMING_ENABLE = 0x80
114 };
115
116enum
117 {
118 VGA_SR_RESET = 0,
119 VGA_SR_CLOCKING_MODE = 1,
120 VGA_SR_MAP_MASK_REGISTER = 2,
121 VGA_SR_CHAR_MAP_SELECT = 3,
122 VGA_SR_MEMORY_MODE = 4,
123 };
124
125enum
126 {
127 VGA_SR_RESET_ASYNC = 1,
128 VGA_SR_RESET_SYNC = 2
129 };
130
131enum
132 {
133 VGA_SR_CLOCKING_MODE_8_DOT_CLOCK = 1
134 };
135
136enum
137 {
138 VGA_SR_MEMORY_MODE_NORMAL = 0,
139 VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY = 2,
140 VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING = 4,
141 VGA_SR_MEMORY_MODE_CHAIN4 = 8,
142 };
143
144enum
145 {
146 VGA_GR_SET_RESET_PLANE = 0,
147 VGA_GR_SET_RESET_PLANE_ENABLE = 1,
148 VGA_GR_COLOR_COMPARE = 2,
149 VGA_GR_READ_MAP_REGISTER = 4,
150 VGA_GR_MODE = 5,
151 VGA_GR_GR6 = 6,
152 VGA_GR_COLOR_COMPARE_DISABLE = 7,
153 VGA_GR_BITMASK = 8,
154 VGA_GR_MAX
155 };
156
157enum
158 {
159 VGA_TEXT_TEXT_PLANE = 0,
160 VGA_TEXT_ATTR_PLANE = 1,
161 VGA_TEXT_FONT_PLANE = 2
162 };
163
164enum
165 {
166 VGA_GR_GR6_GRAPHICS_MODE = 1,
167 VGA_GR_GR6_MMAP_A0 = (1 << 2),
168 VGA_GR_GR6_MMAP_CGA = (3 << 2)
169 };
170
171enum
172 {
173 VGA_GR_MODE_READ_MODE1 = 0x08,
174 VGA_GR_MODE_ODD_EVEN = 0x10,
175 VGA_GR_MODE_ODD_EVEN_SHIFT = 0x20,
176 VGA_GR_MODE_256_COLOR = 0x40
177 };
178
179#define CIRRUS_CR_EXTENDED_DISPLAY 0x1b
180#define CIRRUS_CR_EXTENDED_OVERLAY 0x1d
181
182#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK 0x10
183#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT 4
184#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1 0x1
185#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT1 16
186#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2 0xc
187#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT2 15
188
189#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK 0x80
190#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_SHIFT 12
191#define CIRRUS_SR_EXTENDED_MODE 7
192#define CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE 0xf0
193#define CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT 0x01
194#define CIRRUS_SR_EXTENDED_MODE_32BPP 0x08
195#define CIRRUS_HIDDEN_DAC_888COLOR 0xc5
196
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100197#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100198static void
199write_hidden_dac (uint8_t data)
200{
201 inb (0x3c8);
202 inb (0x3c6);
203 inb (0x3c6);
204 inb (0x3c6);
205 inb (0x3c6);
206 outb (data, 0x3c6);
207}
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100208#endif
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100209
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100210static void cirrus_init(struct device *dev)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100211{
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100212#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100213 uint8_t cr_ext, cr_overlay;
214 unsigned pitch = (width * 4) / VGA_CR_PITCH_DIVISOR;
215 uint8_t sr_ext = 0, hidden_dac = 0;
216 unsigned vdisplay_end = height - 2;
217 unsigned line_compare = 0x3ff;
218 uint8_t overflow, cell_height_reg;
219 unsigned horizontal_end = width / VGA_CR_WIDTH_DIVISOR;
220 unsigned horizontal_total = horizontal_end + 40;
221 unsigned horizontal_blank_start = horizontal_end;
222 unsigned horizontal_sync_pulse_start = horizontal_end + 3;
223 unsigned horizontal_sync_pulse_end = 0;
224
225 unsigned horizontal_blank_end = 0;
226 unsigned vertical_blank_start = height + 1;
227 unsigned vertical_blank_end = 0;
228 unsigned vertical_sync_start = height + 3;
229 unsigned vertical_sync_end = 0;
230 unsigned vertical_total = height + 40;
231
232 /* find lfb pci bar */
233 addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
234 addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
235 printk(BIOS_DEBUG, "QEMU VGA: cirrus framebuffer @ %x (pci bar 0)\n",
236 addr);
237
238 vga_misc_write (VGA_IO_MISC_COLOR);
239
240 vga_sr_write (VGA_SR_MEMORY_MODE,
241 VGA_SR_MEMORY_MODE_NORMAL);
242
243 vga_sr_write (VGA_SR_MAP_MASK_REGISTER,
244 (1 << VGA_TEXT_TEXT_PLANE)
245 | (1 << VGA_TEXT_ATTR_PLANE));
246
247 vga_sr_write (VGA_SR_CLOCKING_MODE,
248 VGA_SR_CLOCKING_MODE_8_DOT_CLOCK);
249
250 vga_palette_disable();
251
252 /* Disable CR0-7 write protection. */
253 vga_cr_write (VGA_CR_VSYNC_END, 0);
254
255 overflow = ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT)
256 & VGA_CR_OVERFLOW_VERT_TOTAL1_MASK)
257 | ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT)
258 & VGA_CR_OVERFLOW_VERT_TOTAL2_MASK)
259 | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START2_SHIFT)
260 & VGA_CR_OVERFLOW_VSYNC_START2_MASK)
261 | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT)
262 & VGA_CR_OVERFLOW_VSYNC_START1_MASK)
263 | ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT)
264 & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK)
265 | ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT)
266 & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK)
267 | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT)
268 & VGA_CR_OVERFLOW_VSYNC_START1_MASK)
269 | ((line_compare >> VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT)
270 & VGA_CR_OVERFLOW_LINE_COMPARE_MASK);
271
272 cell_height_reg = ((vertical_blank_start
273 >> VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT)
274 & VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK)
275 | ((line_compare >> VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT)
276 & VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK);
277
278 vga_cr_write (VGA_CR_HTOTAL, horizontal_total - 1);
279 vga_cr_write (VGA_CR_HORIZ_END, horizontal_end - 1);
280 vga_cr_write (VGA_CR_HBLANK_START, horizontal_blank_start - 1);
281 vga_cr_write (VGA_CR_HBLANK_END, horizontal_blank_end);
282 vga_cr_write (VGA_CR_HORIZ_SYNC_PULSE_START,
283 horizontal_sync_pulse_start);
284 vga_cr_write (VGA_CR_HORIZ_SYNC_PULSE_END,
285 horizontal_sync_pulse_end);
286 vga_cr_write (VGA_CR_VERT_TOTAL, vertical_total & 0xff);
287 vga_cr_write (VGA_CR_OVERFLOW, overflow);
288 vga_cr_write (VGA_CR_CELL_HEIGHT, cell_height_reg);
289 vga_cr_write (VGA_CR_VSYNC_START, vertical_sync_start & 0xff);
290 vga_cr_write (VGA_CR_VSYNC_END, vertical_sync_end & 0x0f);
291 vga_cr_write (VGA_CR_VDISPLAY_END, vdisplay_end & 0xff);
292 vga_cr_write (VGA_CR_PITCH, pitch & 0xff);
293 vga_cr_write (VGA_CR_VERTICAL_BLANK_START, vertical_blank_start & 0xff);
294 vga_cr_write (VGA_CR_VERTICAL_BLANK_END, vertical_blank_end & 0xff);
295 vga_cr_write (VGA_CR_LINE_COMPARE, line_compare & 0xff);
296
297 vga_gr_write (VGA_GR_MODE, VGA_GR_MODE_256_COLOR | VGA_GR_MODE_READ_MODE1);
298 vga_gr_write (VGA_GR_GR6, VGA_GR_GR6_GRAPHICS_MODE);
299
300 vga_sr_write (VGA_SR_MEMORY_MODE, VGA_SR_MEMORY_MODE_NORMAL);
301
302 vga_cr_write (CIRRUS_CR_EXTENDED_DISPLAY,
303 (pitch >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT)
304 & CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK);
305
306 vga_cr_write (VGA_CR_MODE, VGA_CR_MODE_TIMING_ENABLE
307 | VGA_CR_MODE_BYTE_MODE
308 | VGA_CR_MODE_NO_HERCULES | VGA_CR_MODE_NO_CGA);
309
310 vga_cr_write (VGA_CR_START_ADDR_LOW_REGISTER, 0);
311 vga_cr_write (VGA_CR_START_ADDR_HIGH_REGISTER, 0);
312
313 cr_ext = vga_cr_read (CIRRUS_CR_EXTENDED_DISPLAY);
314 cr_ext &= ~(CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1
315 | CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2);
316 vga_cr_write (CIRRUS_CR_EXTENDED_DISPLAY, cr_ext);
317
318 cr_overlay = vga_cr_read (CIRRUS_CR_EXTENDED_OVERLAY);
319 cr_overlay &= ~(CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK);
320 vga_cr_write (CIRRUS_CR_EXTENDED_OVERLAY, cr_overlay);
321
322 sr_ext = CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE
323 | CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT
324 | CIRRUS_SR_EXTENDED_MODE_32BPP;
325 hidden_dac = CIRRUS_HIDDEN_DAC_888COLOR;
326 vga_sr_write (CIRRUS_SR_EXTENDED_MODE, sr_ext);
327 write_hidden_dac (hidden_dac);
328
329
330 struct edid edid;
Gerd Hoffmann0bc3e3252015-09-04 12:58:00 +0200331 edid.mode.ha = width;
332 edid.mode.va = height;
Gerd Hoffmann2177f1b2014-08-27 11:23:35 +0200333 edid.panel_bits_per_color = 8;
334 edid.panel_bits_per_pixel = 24;
Julius Werner2b6db972016-04-06 12:50:40 -0700335 edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100336 set_vbe_mode_info_valid(&edid, addr);
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100337#else
338 vga_misc_write(0x1);
339
340 vga_textmode_init();
341#endif
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100342}
343
344static struct device_operations qemu_cirrus_graph_ops = {
345 .read_resources = pci_dev_read_resources,
346 .set_resources = pci_dev_set_resources,
347 .enable_resources = pci_dev_enable_resources,
348 .init = cirrus_init,
349 .scan_bus = 0,
350};
351
352static const struct pci_driver qemu_cirrus_driver __pci_driver = {
353 .ops = &qemu_cirrus_graph_ops,
354 .vendor = 0x1013,
355 .device = 0x00b8,
356};