blob: 9f79d31149d9f7b8b7f32c2d0839a1c14baadf54 [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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include <stdint.h>
23#include <delay.h>
24#include <edid.h>
25#include <stdlib.h>
26#include <string.h>
27#include <arch/io.h>
28
29#include <boot/coreboot_tables.h>
30#include <console/console.h>
31#include <device/device.h>
32#include <device/pci.h>
33#include <device/pci_ids.h>
34#include <device/pci_ops.h>
35
36#include <pc80/vga.h>
37#include <pc80/vga_io.h>
38
39static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES;
40static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES;
41static u32 addr = 0;
42
43enum
44 {
45 VGA_CR_HTOTAL = 0x00,
46 VGA_CR_HORIZ_END = 0x01,
47 VGA_CR_HBLANK_START = 0x02,
48 VGA_CR_HBLANK_END = 0x03,
49 VGA_CR_HORIZ_SYNC_PULSE_START = 0x04,
50 VGA_CR_HORIZ_SYNC_PULSE_END = 0x05,
51 VGA_CR_VERT_TOTAL = 0x06,
52 VGA_CR_OVERFLOW = 0x07,
53 VGA_CR_BYTE_PANNING = 0x08,
54 VGA_CR_CELL_HEIGHT = 0x09,
55 VGA_CR_CURSOR_START = 0x0a,
56 VGA_CR_CURSOR_END = 0x0b,
57 VGA_CR_START_ADDR_HIGH_REGISTER = 0x0c,
58 VGA_CR_START_ADDR_LOW_REGISTER = 0x0d,
59 VGA_CR_CURSOR_ADDR_HIGH = 0x0e,
60 VGA_CR_CURSOR_ADDR_LOW = 0x0f,
61 VGA_CR_VSYNC_START = 0x10,
62 VGA_CR_VSYNC_END = 0x11,
63 VGA_CR_VDISPLAY_END = 0x12,
64 VGA_CR_PITCH = 0x13,
65 VGA_CR_UNDERLINE_LOCATION = 0x14,
66 VGA_CR_VERTICAL_BLANK_START = 0x15,
67 VGA_CR_VERTICAL_BLANK_END = 0x16,
68 VGA_CR_MODE = 0x17,
69 VGA_CR_LINE_COMPARE = 0x18,
70 };
71
72#define VGA_IO_MISC_COLOR 0x01
73
74#define VGA_CR_WIDTH_DIVISOR 8
75
76#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT 7
77#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK 0x02
78#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT 3
79#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK 0x40
80
81#define VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT 8
82#define VGA_CR_OVERFLOW_VERT_TOTAL1_MASK 0x01
83#define VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT 4
84#define VGA_CR_OVERFLOW_VERT_TOTAL2_MASK 0x20
85
86#define VGA_CR_OVERFLOW_VSYNC_START1_SHIFT 6
87#define VGA_CR_OVERFLOW_VSYNC_START1_MASK 0x04
88#define VGA_CR_OVERFLOW_VSYNC_START2_SHIFT 2
89#define VGA_CR_OVERFLOW_VSYNC_START2_MASK 0x80
90
91#define VGA_CR_OVERFLOW_HEIGHT1_SHIFT 7
92#define VGA_CR_OVERFLOW_HEIGHT1_MASK 0x02
93#define VGA_CR_OVERFLOW_HEIGHT2_SHIFT 3
94#define VGA_CR_OVERFLOW_HEIGHT2_MASK 0xc0
95#define VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT 4
96#define VGA_CR_OVERFLOW_LINE_COMPARE_MASK 0x10
97
98#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK 0x40
99#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT 3
100#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK 0x20
101#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT 4
102#define VGA_CR_CELL_HEIGHT_DOUBLE_SCAN 0x80
103enum
104 {
105 VGA_CR_CURSOR_START_DISABLE = (1 << 5)
106 };
107
108#define VGA_CR_PITCH_DIVISOR 8
109
110enum
111 {
112 VGA_CR_MODE_NO_CGA = 0x01,
113 VGA_CR_MODE_NO_HERCULES = 0x02,
114 VGA_CR_MODE_ADDRESS_WRAP = 0x20,
115 VGA_CR_MODE_BYTE_MODE = 0x40,
116 VGA_CR_MODE_TIMING_ENABLE = 0x80
117 };
118
119enum
120 {
121 VGA_SR_RESET = 0,
122 VGA_SR_CLOCKING_MODE = 1,
123 VGA_SR_MAP_MASK_REGISTER = 2,
124 VGA_SR_CHAR_MAP_SELECT = 3,
125 VGA_SR_MEMORY_MODE = 4,
126 };
127
128enum
129 {
130 VGA_SR_RESET_ASYNC = 1,
131 VGA_SR_RESET_SYNC = 2
132 };
133
134enum
135 {
136 VGA_SR_CLOCKING_MODE_8_DOT_CLOCK = 1
137 };
138
139enum
140 {
141 VGA_SR_MEMORY_MODE_NORMAL = 0,
142 VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY = 2,
143 VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING = 4,
144 VGA_SR_MEMORY_MODE_CHAIN4 = 8,
145 };
146
147enum
148 {
149 VGA_GR_SET_RESET_PLANE = 0,
150 VGA_GR_SET_RESET_PLANE_ENABLE = 1,
151 VGA_GR_COLOR_COMPARE = 2,
152 VGA_GR_READ_MAP_REGISTER = 4,
153 VGA_GR_MODE = 5,
154 VGA_GR_GR6 = 6,
155 VGA_GR_COLOR_COMPARE_DISABLE = 7,
156 VGA_GR_BITMASK = 8,
157 VGA_GR_MAX
158 };
159
160enum
161 {
162 VGA_TEXT_TEXT_PLANE = 0,
163 VGA_TEXT_ATTR_PLANE = 1,
164 VGA_TEXT_FONT_PLANE = 2
165 };
166
167enum
168 {
169 VGA_GR_GR6_GRAPHICS_MODE = 1,
170 VGA_GR_GR6_MMAP_A0 = (1 << 2),
171 VGA_GR_GR6_MMAP_CGA = (3 << 2)
172 };
173
174enum
175 {
176 VGA_GR_MODE_READ_MODE1 = 0x08,
177 VGA_GR_MODE_ODD_EVEN = 0x10,
178 VGA_GR_MODE_ODD_EVEN_SHIFT = 0x20,
179 VGA_GR_MODE_256_COLOR = 0x40
180 };
181
182#define CIRRUS_CR_EXTENDED_DISPLAY 0x1b
183#define CIRRUS_CR_EXTENDED_OVERLAY 0x1d
184
185#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK 0x10
186#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT 4
187#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1 0x1
188#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT1 16
189#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2 0xc
190#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT2 15
191
192#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK 0x80
193#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_SHIFT 12
194#define CIRRUS_SR_EXTENDED_MODE 7
195#define CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE 0xf0
196#define CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT 0x01
197#define CIRRUS_SR_EXTENDED_MODE_32BPP 0x08
198#define CIRRUS_HIDDEN_DAC_888COLOR 0xc5
199
200static void
201write_hidden_dac (uint8_t data)
202{
203 inb (0x3c8);
204 inb (0x3c6);
205 inb (0x3c6);
206 inb (0x3c6);
207 inb (0x3c6);
208 outb (data, 0x3c6);
209}
210
211static void cirrus_init(device_t dev)
212{
213 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;
331 edid.ha = width;
332 edid.va = height;
333 edid.bpp = 32;
334 set_vbe_mode_info_valid(&edid, addr);
335}
336
337static struct device_operations qemu_cirrus_graph_ops = {
338 .read_resources = pci_dev_read_resources,
339 .set_resources = pci_dev_set_resources,
340 .enable_resources = pci_dev_enable_resources,
341 .init = cirrus_init,
342 .scan_bus = 0,
343};
344
345static const struct pci_driver qemu_cirrus_driver __pci_driver = {
346 .ops = &qemu_cirrus_graph_ops,
347 .vendor = 0x1013,
348 .device = 0x00b8,
349};