blob: 1c659eb5f04847f18ec065ba6818a7e9b51d9dce [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
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +010039#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +010040static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES;
41static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES;
42static u32 addr = 0;
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +010043#endif
Vladimir Serbinenko7905f922013-11-25 11:20:20 +010044
45enum
46 {
47 VGA_CR_HTOTAL = 0x00,
48 VGA_CR_HORIZ_END = 0x01,
49 VGA_CR_HBLANK_START = 0x02,
50 VGA_CR_HBLANK_END = 0x03,
51 VGA_CR_HORIZ_SYNC_PULSE_START = 0x04,
52 VGA_CR_HORIZ_SYNC_PULSE_END = 0x05,
53 VGA_CR_VERT_TOTAL = 0x06,
54 VGA_CR_OVERFLOW = 0x07,
55 VGA_CR_BYTE_PANNING = 0x08,
56 VGA_CR_CELL_HEIGHT = 0x09,
57 VGA_CR_CURSOR_START = 0x0a,
58 VGA_CR_CURSOR_END = 0x0b,
59 VGA_CR_START_ADDR_HIGH_REGISTER = 0x0c,
60 VGA_CR_START_ADDR_LOW_REGISTER = 0x0d,
61 VGA_CR_CURSOR_ADDR_HIGH = 0x0e,
62 VGA_CR_CURSOR_ADDR_LOW = 0x0f,
63 VGA_CR_VSYNC_START = 0x10,
64 VGA_CR_VSYNC_END = 0x11,
65 VGA_CR_VDISPLAY_END = 0x12,
66 VGA_CR_PITCH = 0x13,
67 VGA_CR_UNDERLINE_LOCATION = 0x14,
68 VGA_CR_VERTICAL_BLANK_START = 0x15,
69 VGA_CR_VERTICAL_BLANK_END = 0x16,
70 VGA_CR_MODE = 0x17,
71 VGA_CR_LINE_COMPARE = 0x18,
72 };
73
74#define VGA_IO_MISC_COLOR 0x01
75
76#define VGA_CR_WIDTH_DIVISOR 8
77
78#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT 7
79#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK 0x02
80#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT 3
81#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK 0x40
82
83#define VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT 8
84#define VGA_CR_OVERFLOW_VERT_TOTAL1_MASK 0x01
85#define VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT 4
86#define VGA_CR_OVERFLOW_VERT_TOTAL2_MASK 0x20
87
88#define VGA_CR_OVERFLOW_VSYNC_START1_SHIFT 6
89#define VGA_CR_OVERFLOW_VSYNC_START1_MASK 0x04
90#define VGA_CR_OVERFLOW_VSYNC_START2_SHIFT 2
91#define VGA_CR_OVERFLOW_VSYNC_START2_MASK 0x80
92
93#define VGA_CR_OVERFLOW_HEIGHT1_SHIFT 7
94#define VGA_CR_OVERFLOW_HEIGHT1_MASK 0x02
95#define VGA_CR_OVERFLOW_HEIGHT2_SHIFT 3
96#define VGA_CR_OVERFLOW_HEIGHT2_MASK 0xc0
97#define VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT 4
98#define VGA_CR_OVERFLOW_LINE_COMPARE_MASK 0x10
99
100#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK 0x40
101#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT 3
102#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK 0x20
103#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT 4
104#define VGA_CR_CELL_HEIGHT_DOUBLE_SCAN 0x80
105enum
106 {
107 VGA_CR_CURSOR_START_DISABLE = (1 << 5)
108 };
109
110#define VGA_CR_PITCH_DIVISOR 8
111
112enum
113 {
114 VGA_CR_MODE_NO_CGA = 0x01,
115 VGA_CR_MODE_NO_HERCULES = 0x02,
116 VGA_CR_MODE_ADDRESS_WRAP = 0x20,
117 VGA_CR_MODE_BYTE_MODE = 0x40,
118 VGA_CR_MODE_TIMING_ENABLE = 0x80
119 };
120
121enum
122 {
123 VGA_SR_RESET = 0,
124 VGA_SR_CLOCKING_MODE = 1,
125 VGA_SR_MAP_MASK_REGISTER = 2,
126 VGA_SR_CHAR_MAP_SELECT = 3,
127 VGA_SR_MEMORY_MODE = 4,
128 };
129
130enum
131 {
132 VGA_SR_RESET_ASYNC = 1,
133 VGA_SR_RESET_SYNC = 2
134 };
135
136enum
137 {
138 VGA_SR_CLOCKING_MODE_8_DOT_CLOCK = 1
139 };
140
141enum
142 {
143 VGA_SR_MEMORY_MODE_NORMAL = 0,
144 VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY = 2,
145 VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING = 4,
146 VGA_SR_MEMORY_MODE_CHAIN4 = 8,
147 };
148
149enum
150 {
151 VGA_GR_SET_RESET_PLANE = 0,
152 VGA_GR_SET_RESET_PLANE_ENABLE = 1,
153 VGA_GR_COLOR_COMPARE = 2,
154 VGA_GR_READ_MAP_REGISTER = 4,
155 VGA_GR_MODE = 5,
156 VGA_GR_GR6 = 6,
157 VGA_GR_COLOR_COMPARE_DISABLE = 7,
158 VGA_GR_BITMASK = 8,
159 VGA_GR_MAX
160 };
161
162enum
163 {
164 VGA_TEXT_TEXT_PLANE = 0,
165 VGA_TEXT_ATTR_PLANE = 1,
166 VGA_TEXT_FONT_PLANE = 2
167 };
168
169enum
170 {
171 VGA_GR_GR6_GRAPHICS_MODE = 1,
172 VGA_GR_GR6_MMAP_A0 = (1 << 2),
173 VGA_GR_GR6_MMAP_CGA = (3 << 2)
174 };
175
176enum
177 {
178 VGA_GR_MODE_READ_MODE1 = 0x08,
179 VGA_GR_MODE_ODD_EVEN = 0x10,
180 VGA_GR_MODE_ODD_EVEN_SHIFT = 0x20,
181 VGA_GR_MODE_256_COLOR = 0x40
182 };
183
184#define CIRRUS_CR_EXTENDED_DISPLAY 0x1b
185#define CIRRUS_CR_EXTENDED_OVERLAY 0x1d
186
187#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK 0x10
188#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT 4
189#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1 0x1
190#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT1 16
191#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2 0xc
192#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT2 15
193
194#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK 0x80
195#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_SHIFT 12
196#define CIRRUS_SR_EXTENDED_MODE 7
197#define CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE 0xf0
198#define CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT 0x01
199#define CIRRUS_SR_EXTENDED_MODE_32BPP 0x08
200#define CIRRUS_HIDDEN_DAC_888COLOR 0xc5
201
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100202#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100203static void
204write_hidden_dac (uint8_t data)
205{
206 inb (0x3c8);
207 inb (0x3c6);
208 inb (0x3c6);
209 inb (0x3c6);
210 inb (0x3c6);
211 outb (data, 0x3c6);
212}
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100213#endif
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100214
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100215static void cirrus_init(struct device *dev)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100216{
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100217#if IS_ENABLED(CONFIG_FRAMEBUFFER_KEEP_VESA_MODE)
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100218 uint8_t cr_ext, cr_overlay;
219 unsigned pitch = (width * 4) / VGA_CR_PITCH_DIVISOR;
220 uint8_t sr_ext = 0, hidden_dac = 0;
221 unsigned vdisplay_end = height - 2;
222 unsigned line_compare = 0x3ff;
223 uint8_t overflow, cell_height_reg;
224 unsigned horizontal_end = width / VGA_CR_WIDTH_DIVISOR;
225 unsigned horizontal_total = horizontal_end + 40;
226 unsigned horizontal_blank_start = horizontal_end;
227 unsigned horizontal_sync_pulse_start = horizontal_end + 3;
228 unsigned horizontal_sync_pulse_end = 0;
229
230 unsigned horizontal_blank_end = 0;
231 unsigned vertical_blank_start = height + 1;
232 unsigned vertical_blank_end = 0;
233 unsigned vertical_sync_start = height + 3;
234 unsigned vertical_sync_end = 0;
235 unsigned vertical_total = height + 40;
236
237 /* find lfb pci bar */
238 addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
239 addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
240 printk(BIOS_DEBUG, "QEMU VGA: cirrus framebuffer @ %x (pci bar 0)\n",
241 addr);
242
243 vga_misc_write (VGA_IO_MISC_COLOR);
244
245 vga_sr_write (VGA_SR_MEMORY_MODE,
246 VGA_SR_MEMORY_MODE_NORMAL);
247
248 vga_sr_write (VGA_SR_MAP_MASK_REGISTER,
249 (1 << VGA_TEXT_TEXT_PLANE)
250 | (1 << VGA_TEXT_ATTR_PLANE));
251
252 vga_sr_write (VGA_SR_CLOCKING_MODE,
253 VGA_SR_CLOCKING_MODE_8_DOT_CLOCK);
254
255 vga_palette_disable();
256
257 /* Disable CR0-7 write protection. */
258 vga_cr_write (VGA_CR_VSYNC_END, 0);
259
260 overflow = ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT)
261 & VGA_CR_OVERFLOW_VERT_TOTAL1_MASK)
262 | ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT)
263 & VGA_CR_OVERFLOW_VERT_TOTAL2_MASK)
264 | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START2_SHIFT)
265 & VGA_CR_OVERFLOW_VSYNC_START2_MASK)
266 | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT)
267 & VGA_CR_OVERFLOW_VSYNC_START1_MASK)
268 | ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT)
269 & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK)
270 | ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT)
271 & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK)
272 | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT)
273 & VGA_CR_OVERFLOW_VSYNC_START1_MASK)
274 | ((line_compare >> VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT)
275 & VGA_CR_OVERFLOW_LINE_COMPARE_MASK);
276
277 cell_height_reg = ((vertical_blank_start
278 >> VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT)
279 & VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK)
280 | ((line_compare >> VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT)
281 & VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK);
282
283 vga_cr_write (VGA_CR_HTOTAL, horizontal_total - 1);
284 vga_cr_write (VGA_CR_HORIZ_END, horizontal_end - 1);
285 vga_cr_write (VGA_CR_HBLANK_START, horizontal_blank_start - 1);
286 vga_cr_write (VGA_CR_HBLANK_END, horizontal_blank_end);
287 vga_cr_write (VGA_CR_HORIZ_SYNC_PULSE_START,
288 horizontal_sync_pulse_start);
289 vga_cr_write (VGA_CR_HORIZ_SYNC_PULSE_END,
290 horizontal_sync_pulse_end);
291 vga_cr_write (VGA_CR_VERT_TOTAL, vertical_total & 0xff);
292 vga_cr_write (VGA_CR_OVERFLOW, overflow);
293 vga_cr_write (VGA_CR_CELL_HEIGHT, cell_height_reg);
294 vga_cr_write (VGA_CR_VSYNC_START, vertical_sync_start & 0xff);
295 vga_cr_write (VGA_CR_VSYNC_END, vertical_sync_end & 0x0f);
296 vga_cr_write (VGA_CR_VDISPLAY_END, vdisplay_end & 0xff);
297 vga_cr_write (VGA_CR_PITCH, pitch & 0xff);
298 vga_cr_write (VGA_CR_VERTICAL_BLANK_START, vertical_blank_start & 0xff);
299 vga_cr_write (VGA_CR_VERTICAL_BLANK_END, vertical_blank_end & 0xff);
300 vga_cr_write (VGA_CR_LINE_COMPARE, line_compare & 0xff);
301
302 vga_gr_write (VGA_GR_MODE, VGA_GR_MODE_256_COLOR | VGA_GR_MODE_READ_MODE1);
303 vga_gr_write (VGA_GR_GR6, VGA_GR_GR6_GRAPHICS_MODE);
304
305 vga_sr_write (VGA_SR_MEMORY_MODE, VGA_SR_MEMORY_MODE_NORMAL);
306
307 vga_cr_write (CIRRUS_CR_EXTENDED_DISPLAY,
308 (pitch >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT)
309 & CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK);
310
311 vga_cr_write (VGA_CR_MODE, VGA_CR_MODE_TIMING_ENABLE
312 | VGA_CR_MODE_BYTE_MODE
313 | VGA_CR_MODE_NO_HERCULES | VGA_CR_MODE_NO_CGA);
314
315 vga_cr_write (VGA_CR_START_ADDR_LOW_REGISTER, 0);
316 vga_cr_write (VGA_CR_START_ADDR_HIGH_REGISTER, 0);
317
318 cr_ext = vga_cr_read (CIRRUS_CR_EXTENDED_DISPLAY);
319 cr_ext &= ~(CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1
320 | CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2);
321 vga_cr_write (CIRRUS_CR_EXTENDED_DISPLAY, cr_ext);
322
323 cr_overlay = vga_cr_read (CIRRUS_CR_EXTENDED_OVERLAY);
324 cr_overlay &= ~(CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK);
325 vga_cr_write (CIRRUS_CR_EXTENDED_OVERLAY, cr_overlay);
326
327 sr_ext = CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE
328 | CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT
329 | CIRRUS_SR_EXTENDED_MODE_32BPP;
330 hidden_dac = CIRRUS_HIDDEN_DAC_888COLOR;
331 vga_sr_write (CIRRUS_SR_EXTENDED_MODE, sr_ext);
332 write_hidden_dac (hidden_dac);
333
334
335 struct edid edid;
336 edid.ha = width;
337 edid.va = height;
Vladimir Serbinenkodd9945b2013-12-16 23:19:01 +0100338 edid.x_resolution = width;
339 edid.y_resolution = height;
340 edid.bytes_per_line = width * 4;
Gerd Hoffmann2177f1b2014-08-27 11:23:35 +0200341 edid.framebuffer_bits_per_pixel = 32;
342 edid.panel_bits_per_color = 8;
343 edid.panel_bits_per_pixel = 24;
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100344 set_vbe_mode_info_valid(&edid, addr);
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100345#else
346 vga_misc_write(0x1);
347
348 vga_textmode_init();
349#endif
Vladimir Serbinenko7905f922013-11-25 11:20:20 +0100350}
351
352static struct device_operations qemu_cirrus_graph_ops = {
353 .read_resources = pci_dev_read_resources,
354 .set_resources = pci_dev_set_resources,
355 .enable_resources = pci_dev_enable_resources,
356 .init = cirrus_init,
357 .scan_bus = 0,
358};
359
360static const struct pci_driver qemu_cirrus_driver __pci_driver = {
361 .ops = &qemu_cirrus_graph_ops,
362 .vendor = 0x1013,
363 .device = 0x00b8,
364};