blob: cdd2c20f5afd755f15ad59998075076a9757fefa [file] [log] [blame]
Martin Rothe20f3d02017-04-04 14:26:57 -06001/*
2 * This file is part of the coreboot project.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
Ronald G. Minnichcae09e02013-11-19 17:42:41 -080014#include <stdint.h>
Gerd Hoffmann414b9472013-06-18 23:41:21 +020015#include <delay.h>
Ronald G. Minnichcae09e02013-11-19 17:42:41 -080016#include <edid.h>
Gerd Hoffmann414b9472013-06-18 23:41:21 +020017#include <stdlib.h>
18#include <string.h>
19#include <arch/io.h>
20
21#include <boot/coreboot_tables.h>
22#include <console/console.h>
23#include <device/device.h>
24#include <device/pci.h>
25#include <device/pci_ids.h>
26#include <device/pci_ops.h>
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +010027#include <pc80/vga.h>
28#include <pc80/vga_io.h>
Gerd Hoffmann414b9472013-06-18 23:41:21 +020029
30/* VGA init. We use the Bochs VESA VBE extensions */
31#define VBE_DISPI_IOPORT_INDEX 0x01CE
32#define VBE_DISPI_IOPORT_DATA 0x01CF
33
34#define VBE_DISPI_INDEX_ID 0x0
35#define VBE_DISPI_INDEX_XRES 0x1
36#define VBE_DISPI_INDEX_YRES 0x2
37#define VBE_DISPI_INDEX_BPP 0x3
38#define VBE_DISPI_INDEX_ENABLE 0x4
39#define VBE_DISPI_INDEX_BANK 0x5
40#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
41#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
42#define VBE_DISPI_INDEX_X_OFFSET 0x8
43#define VBE_DISPI_INDEX_Y_OFFSET 0x9
44#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
45
46#define VBE_DISPI_ID0 0xB0C0
47#define VBE_DISPI_ID1 0xB0C1
48#define VBE_DISPI_ID2 0xB0C2
49#define VBE_DISPI_ID4 0xB0C4
50#define VBE_DISPI_ID5 0xB0C5
51
52#define VBE_DISPI_DISABLED 0x00
53#define VBE_DISPI_ENABLED 0x01
54#define VBE_DISPI_LFB_ENABLED 0x40
55#define VBE_DISPI_NOCLEARMEM 0x80
56
57static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES;
58static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020059
60static void bochs_write(int index, int val)
61{
62 outw(index, VBE_DISPI_IOPORT_INDEX);
63 outw(val, VBE_DISPI_IOPORT_DATA);
64}
65
66static int bochs_read(int index)
67{
68 outw(index, VBE_DISPI_IOPORT_INDEX);
69 return inw(VBE_DISPI_IOPORT_DATA);
70}
71
Nico Huber6d8266b2017-05-20 16:46:01 +020072static void bochs_init_linear_fb(struct device *dev)
Gerd Hoffmann414b9472013-06-18 23:41:21 +020073{
Gerd Hoffmann748a6b12013-11-25 17:12:07 +010074 struct edid edid;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020075 int id, mem, bar;
Gerd Hoffmann748a6b12013-11-25 17:12:07 +010076 u32 addr;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020077
78 /* bochs dispi detection */
79 id = bochs_read(VBE_DISPI_INDEX_ID);
80 if ((id & 0xfff0) != VBE_DISPI_ID0) {
81 printk(BIOS_DEBUG, "QEMU VGA: bochs dispi: ID mismatch.\n");
82 return;
83 }
84 mem = bochs_read(VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020085
86 /* find lfb pci bar */
87 addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
88 if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
89 /* qemu -vga {std,qxl} */
90 bar = 0;
91 } else {
92 /* qemu -vga vmware */
93 addr = pci_read_config32(dev, PCI_BASE_ADDRESS_1);
94 bar = 1;
95 }
96 addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
Ronald G. Minnichcae09e02013-11-19 17:42:41 -080097
98 if (!addr)
99 return;
100
101 printk(BIOS_DEBUG, "QEMU VGA: bochs dispi interface found, "
Elyes HAOUASa342f392018-10-17 10:56:26 +0200102 "%d MiB video memory\n", mem / (1024 * 1024));
Gerd Hoffmann414b9472013-06-18 23:41:21 +0200103 printk(BIOS_DEBUG, "QEMU VGA: framebuffer @ %x (pci bar %d)\n",
104 addr, bar);
105
106 /* setup video mode */
107 bochs_write(VBE_DISPI_INDEX_ENABLE, 0);
108 bochs_write(VBE_DISPI_INDEX_BANK, 0);
109 bochs_write(VBE_DISPI_INDEX_BPP, 32);
110 bochs_write(VBE_DISPI_INDEX_XRES, width);
111 bochs_write(VBE_DISPI_INDEX_YRES, height);
112 bochs_write(VBE_DISPI_INDEX_VIRT_WIDTH, width);
113 bochs_write(VBE_DISPI_INDEX_VIRT_HEIGHT, height);
114 bochs_write(VBE_DISPI_INDEX_X_OFFSET, 0);
115 bochs_write(VBE_DISPI_INDEX_Y_OFFSET, 0);
116 bochs_write(VBE_DISPI_INDEX_ENABLE,
117 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
118
119 outb(0x20, 0x3c0); /* disable blanking */
Gerd Hoffmann748a6b12013-11-25 17:12:07 +0100120
121 /* setup coreboot framebuffer */
Gerd Hoffmann0bc3e3252015-09-04 12:58:00 +0200122 edid.mode.ha = width;
123 edid.mode.va = height;
Gerd Hoffmann4f627322014-08-27 10:42:47 +0200124 edid.panel_bits_per_color = 8;
125 edid.panel_bits_per_pixel = 24;
Julius Werner2b6db972016-04-06 12:50:40 -0700126 edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
Ronald G. Minnichcae09e02013-11-19 17:42:41 -0800127 set_vbe_mode_info_valid(&edid, addr);
Nico Huber6d8266b2017-05-20 16:46:01 +0200128}
129
130static void bochs_init_text_mode(struct device *dev)
131{
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100132 vga_misc_write(0x1);
133 vga_textmode_init();
Nico Huber6d8266b2017-05-20 16:46:01 +0200134}
135
136static void bochs_init(struct device *dev)
137{
138 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER))
139 bochs_init_linear_fb(dev);
140 else if (IS_ENABLED(CONFIG_VGA_TEXT_FRAMEBUFFER))
141 bochs_init_text_mode(dev);
Gerd Hoffmann414b9472013-06-18 23:41:21 +0200142}
143
144static struct device_operations qemu_graph_ops = {
145 .read_resources = pci_dev_read_resources,
146 .set_resources = pci_dev_set_resources,
147 .enable_resources = pci_dev_enable_resources,
148 .init = bochs_init,
149 .scan_bus = 0,
150};
151
152static const struct pci_driver qemu_stdvga_driver __pci_driver = {
153 .ops = &qemu_graph_ops,
154 .vendor = 0x1234,
155 .device = 0x1111,
156};
157
158static const struct pci_driver qemu_vmware_driver __pci_driver = {
159 .ops = &qemu_graph_ops,
160 .vendor = 0x15ad,
161 .device = 0x0405,
162};
163static const struct pci_driver qemu_qxl_driver __pci_driver = {
164 .ops = &qemu_graph_ops,
165 .vendor = 0x1b36,
166 .device = 0x0100,
167};