blob: 48556a8150229a10fc13e74b5b83a9b880e1e411 [file] [log] [blame]
Ronald G. Minnichcae09e02013-11-19 17:42:41 -08001#include <stdint.h>
Gerd Hoffmann414b9472013-06-18 23:41:21 +02002#include <delay.h>
Ronald G. Minnichcae09e02013-11-19 17:42:41 -08003#include <edid.h>
Gerd Hoffmann414b9472013-06-18 23:41:21 +02004#include <stdlib.h>
5#include <string.h>
6#include <arch/io.h>
7
8#include <boot/coreboot_tables.h>
9#include <console/console.h>
10#include <device/device.h>
11#include <device/pci.h>
12#include <device/pci_ids.h>
13#include <device/pci_ops.h>
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +010014#include <pc80/vga.h>
15#include <pc80/vga_io.h>
Gerd Hoffmann414b9472013-06-18 23:41:21 +020016
17/* VGA init. We use the Bochs VESA VBE extensions */
18#define VBE_DISPI_IOPORT_INDEX 0x01CE
19#define VBE_DISPI_IOPORT_DATA 0x01CF
20
21#define VBE_DISPI_INDEX_ID 0x0
22#define VBE_DISPI_INDEX_XRES 0x1
23#define VBE_DISPI_INDEX_YRES 0x2
24#define VBE_DISPI_INDEX_BPP 0x3
25#define VBE_DISPI_INDEX_ENABLE 0x4
26#define VBE_DISPI_INDEX_BANK 0x5
27#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
28#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
29#define VBE_DISPI_INDEX_X_OFFSET 0x8
30#define VBE_DISPI_INDEX_Y_OFFSET 0x9
31#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
32
33#define VBE_DISPI_ID0 0xB0C0
34#define VBE_DISPI_ID1 0xB0C1
35#define VBE_DISPI_ID2 0xB0C2
36#define VBE_DISPI_ID4 0xB0C4
37#define VBE_DISPI_ID5 0xB0C5
38
39#define VBE_DISPI_DISABLED 0x00
40#define VBE_DISPI_ENABLED 0x01
41#define VBE_DISPI_LFB_ENABLED 0x40
42#define VBE_DISPI_NOCLEARMEM 0x80
43
44static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES;
45static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020046
47static void bochs_write(int index, int val)
48{
49 outw(index, VBE_DISPI_IOPORT_INDEX);
50 outw(val, VBE_DISPI_IOPORT_DATA);
51}
52
53static int bochs_read(int index)
54{
55 outw(index, VBE_DISPI_IOPORT_INDEX);
56 return inw(VBE_DISPI_IOPORT_DATA);
57}
58
Nico Huber6d8266b2017-05-20 16:46:01 +020059static void bochs_init_linear_fb(struct device *dev)
Gerd Hoffmann414b9472013-06-18 23:41:21 +020060{
Gerd Hoffmann748a6b12013-11-25 17:12:07 +010061 struct edid edid;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020062 int id, mem, bar;
Gerd Hoffmann748a6b12013-11-25 17:12:07 +010063 u32 addr;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020064
65 /* bochs dispi detection */
66 id = bochs_read(VBE_DISPI_INDEX_ID);
67 if ((id & 0xfff0) != VBE_DISPI_ID0) {
68 printk(BIOS_DEBUG, "QEMU VGA: bochs dispi: ID mismatch.\n");
69 return;
70 }
71 mem = bochs_read(VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024;
Gerd Hoffmann414b9472013-06-18 23:41:21 +020072
73 /* find lfb pci bar */
74 addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
75 if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
76 /* qemu -vga {std,qxl} */
77 bar = 0;
78 } else {
79 /* qemu -vga vmware */
80 addr = pci_read_config32(dev, PCI_BASE_ADDRESS_1);
81 bar = 1;
82 }
83 addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
Ronald G. Minnichcae09e02013-11-19 17:42:41 -080084
85 if (!addr)
86 return;
87
88 printk(BIOS_DEBUG, "QEMU VGA: bochs dispi interface found, "
89 "%d MiB video memory\n", mem / ( 1024 * 1024));
Gerd Hoffmann414b9472013-06-18 23:41:21 +020090 printk(BIOS_DEBUG, "QEMU VGA: framebuffer @ %x (pci bar %d)\n",
91 addr, bar);
92
93 /* setup video mode */
94 bochs_write(VBE_DISPI_INDEX_ENABLE, 0);
95 bochs_write(VBE_DISPI_INDEX_BANK, 0);
96 bochs_write(VBE_DISPI_INDEX_BPP, 32);
97 bochs_write(VBE_DISPI_INDEX_XRES, width);
98 bochs_write(VBE_DISPI_INDEX_YRES, height);
99 bochs_write(VBE_DISPI_INDEX_VIRT_WIDTH, width);
100 bochs_write(VBE_DISPI_INDEX_VIRT_HEIGHT, height);
101 bochs_write(VBE_DISPI_INDEX_X_OFFSET, 0);
102 bochs_write(VBE_DISPI_INDEX_Y_OFFSET, 0);
103 bochs_write(VBE_DISPI_INDEX_ENABLE,
104 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
105
106 outb(0x20, 0x3c0); /* disable blanking */
Gerd Hoffmann748a6b12013-11-25 17:12:07 +0100107
108 /* setup coreboot framebuffer */
Gerd Hoffmann0bc3e3252015-09-04 12:58:00 +0200109 edid.mode.ha = width;
110 edid.mode.va = height;
Gerd Hoffmann4f627322014-08-27 10:42:47 +0200111 edid.panel_bits_per_color = 8;
112 edid.panel_bits_per_pixel = 24;
Julius Werner2b6db972016-04-06 12:50:40 -0700113 edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
Ronald G. Minnichcae09e02013-11-19 17:42:41 -0800114 set_vbe_mode_info_valid(&edid, addr);
Nico Huber6d8266b2017-05-20 16:46:01 +0200115}
116
117static void bochs_init_text_mode(struct device *dev)
118{
Vladimir Serbinenkodb7d04d2014-02-22 10:35:45 +0100119 vga_misc_write(0x1);
120 vga_textmode_init();
Nico Huber6d8266b2017-05-20 16:46:01 +0200121}
122
123static void bochs_init(struct device *dev)
124{
125 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER))
126 bochs_init_linear_fb(dev);
127 else if (IS_ENABLED(CONFIG_VGA_TEXT_FRAMEBUFFER))
128 bochs_init_text_mode(dev);
Gerd Hoffmann414b9472013-06-18 23:41:21 +0200129}
130
131static struct device_operations qemu_graph_ops = {
132 .read_resources = pci_dev_read_resources,
133 .set_resources = pci_dev_set_resources,
134 .enable_resources = pci_dev_enable_resources,
135 .init = bochs_init,
136 .scan_bus = 0,
137};
138
139static const struct pci_driver qemu_stdvga_driver __pci_driver = {
140 .ops = &qemu_graph_ops,
141 .vendor = 0x1234,
142 .device = 0x1111,
143};
144
145static const struct pci_driver qemu_vmware_driver __pci_driver = {
146 .ops = &qemu_graph_ops,
147 .vendor = 0x15ad,
148 .device = 0x0405,
149};
150static const struct pci_driver qemu_qxl_driver __pci_driver = {
151 .ops = &qemu_graph_ops,
152 .vendor = 0x1b36,
153 .device = 0x0100,
154};