• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/io.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/mmio.h>
7 #include <device/pci.h>
8 #include <device/pci_ids.h>
9 #include <device/pci_ops.h>
10 #include <framebuffer_info.h>
11 #include <pc80/vga.h>
12 #include <pc80/vga_io.h>
13 #include <stdint.h>
14 
15 /* VGA init. We use the Bochs VESA VBE extensions  */
16 #define VBE_DISPI_IOPORT_INDEX          0x01CE
17 #define VBE_DISPI_IOPORT_DATA           0x01CF
18 
19 #define VBE_DISPI_INDEX_ID              0x0
20 #define VBE_DISPI_INDEX_XRES            0x1
21 #define VBE_DISPI_INDEX_YRES            0x2
22 #define VBE_DISPI_INDEX_BPP             0x3
23 #define VBE_DISPI_INDEX_ENABLE          0x4
24 #define VBE_DISPI_INDEX_BANK            0x5
25 #define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
26 #define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
27 #define VBE_DISPI_INDEX_X_OFFSET        0x8
28 #define VBE_DISPI_INDEX_Y_OFFSET        0x9
29 #define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
30 
31 #define VBE_DISPI_ID0                   0xB0C0
32 #define VBE_DISPI_ID1                   0xB0C1
33 #define VBE_DISPI_ID2                   0xB0C2
34 #define VBE_DISPI_ID4                   0xB0C4
35 #define VBE_DISPI_ID5                   0xB0C5
36 
37 #define VBE_DISPI_DISABLED              0x00
38 #define VBE_DISPI_ENABLED               0x01
39 #define VBE_DISPI_LFB_ENABLED           0x40
40 #define VBE_DISPI_NOCLEARMEM            0x80
41 
42 static int width  = CONFIG_DRIVERS_EMULATION_QEMU_XRES;
43 static int height = CONFIG_DRIVERS_EMULATION_QEMU_YRES;
44 
bochs_write(struct resource * res,int index,int val)45 static void bochs_write(struct resource *res, int index, int val)
46 {
47 	if (res->flags & IORESOURCE_IO) {
48 		outw(index, res->base);
49 		outw(val, res->base + 1);
50 	} else {
51 		write16(res2mmio(res, 0x500 + index * 2, 0), val);
52 	}
53 }
54 
bochs_read(struct resource * res,int index)55 static int bochs_read(struct resource *res, int index)
56 {
57 	if (res->flags & IORESOURCE_IO) {
58 		outw(index, res->base);
59 		return inw(res->base + 1);
60 	} else {
61 		return read16(res2mmio(res, 0x500 + index * 2, 0));
62 	}
63 }
64 
bochs_vga_write(struct resource * res,int index,uint8_t val)65 static void bochs_vga_write(struct resource *res, int index, uint8_t val)
66 {
67 	if (res->flags & IORESOURCE_IO)
68 		outb(val, index + 0x3c0);
69 	else
70 		write8(res2mmio(res, 0x400 + index, 0), val);
71 }
72 
73 static struct resource res_legacy = {
74 	VBE_DISPI_IOPORT_INDEX,
75 	VBE_DISPI_IOPORT_DATA - VBE_DISPI_IOPORT_INDEX,
76 	VBE_DISPI_IOPORT_DATA,
77 	NULL,
78 	IORESOURCE_IO,
79 	0,
80 	1,
81 	1
82 };
83 
bochs_init_linear_fb(struct device * dev)84 static void bochs_init_linear_fb(struct device *dev)
85 {
86 	struct resource *res_fb, *res_io;
87 	int id, mem, bar;
88 
89 	res_fb = probe_resource(dev, PCI_BASE_ADDRESS_0);
90 	if (res_fb && res_fb->flags & IORESOURCE_MEM) {
91 		/* qemu -vga {std,qxl} */
92 		bar = 0;
93 	} else {
94 		res_fb = probe_resource(dev, PCI_BASE_ADDRESS_1);
95 		if (res_fb && res_fb->flags & IORESOURCE_MEM) {
96 			/* qemu -vga vmware */
97 			bar = 1;
98 		} else {
99 			printk(BIOS_ERR, "%s: Not bochs compatible\n", dev_name(dev));
100 			return;
101 		}
102 	}
103 
104 	/* MMIO bar supported since qemu 3.0+ */
105 	res_io = probe_resource(dev, PCI_BASE_ADDRESS_2);
106 	if (((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) ||
107 	    !res_io || !(res_io->flags & IORESOURCE_MEM)) {
108 		printk(BIOS_DEBUG, "QEMU VGA: Using legacy VGA\n");
109 		res_io = &res_legacy;
110 	} else {
111 		printk(BIOS_DEBUG, "QEMU VGA: Using I/O bar at %llx\n", res_io->base);
112 	}
113 
114 	/* bochs dispi detection */
115 	id = bochs_read(res_io, VBE_DISPI_INDEX_ID);
116 	if ((id & 0xfff0) != VBE_DISPI_ID0) {
117 		printk(BIOS_DEBUG, "QEMU VGA: bochs dispi: ID mismatch.\n");
118 		return;
119 	}
120 	mem = bochs_read(res_io, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024;
121 
122 	printk(BIOS_DEBUG, "QEMU VGA: bochs dispi interface found, "
123 	       "%d MiB video memory\n", mem / (1024 * 1024));
124 	printk(BIOS_DEBUG, "QEMU VGA: framebuffer @ %llx (pci bar %d)\n",
125 	       res_fb->base, bar);
126 
127 	/* setup video mode */
128 	bochs_write(res_io, VBE_DISPI_INDEX_ENABLE,	 0);
129 	bochs_write(res_io, VBE_DISPI_INDEX_BANK,	 0);
130 	bochs_write(res_io, VBE_DISPI_INDEX_BPP,	 32);
131 	bochs_write(res_io, VBE_DISPI_INDEX_XRES,	 width);
132 	bochs_write(res_io, VBE_DISPI_INDEX_YRES,	 height);
133 	bochs_write(res_io, VBE_DISPI_INDEX_VIRT_WIDTH,	 width);
134 	bochs_write(res_io, VBE_DISPI_INDEX_VIRT_HEIGHT, height);
135 	bochs_write(res_io, VBE_DISPI_INDEX_X_OFFSET,	 0);
136 	bochs_write(res_io, VBE_DISPI_INDEX_Y_OFFSET,	 0);
137 	bochs_write(res_io, VBE_DISPI_INDEX_ENABLE,
138 		    VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
139 
140 	bochs_vga_write(res_io, 0, 0x20);	/* disable blanking */
141 
142 	/* Advertise new mode */
143 	fb_add_framebuffer_info(res_fb->base, width, height, 4 * width, 32);
144 }
145 
bochs_init_text_mode(struct device * dev)146 static void bochs_init_text_mode(struct device *dev)
147 {
148 	vga_misc_write(0x1);
149 	vga_textmode_init();
150 }
151 
bochs_init(struct device * dev)152 static void bochs_init(struct device *dev)
153 {
154 	if (CONFIG(LINEAR_FRAMEBUFFER))
155 		bochs_init_linear_fb(dev);
156 	else if (CONFIG(VGA_TEXT_FRAMEBUFFER))
157 		bochs_init_text_mode(dev);
158 }
159 
160 static struct device_operations qemu_graph_ops = {
161 	.read_resources	  = pci_dev_read_resources,
162 	.set_resources	  = pci_dev_set_resources,
163 	.enable_resources = pci_dev_enable_resources,
164 	.init		  = bochs_init,
165 };
166 
167 static const struct pci_driver qemu_stdvga_driver __pci_driver = {
168 	.ops	= &qemu_graph_ops,
169 	.vendor = 0x1234,
170 	.device = 0x1111,
171 };
172 
173 static const struct pci_driver qemu_vmware_driver __pci_driver = {
174 	.ops	= &qemu_graph_ops,
175 	.vendor = 0x15ad,
176 	.device = 0x0405,
177 };
178 static const struct pci_driver qemu_qxl_driver __pci_driver = {
179 	.ops	= &qemu_graph_ops,
180 	.vendor = 0x1b36,
181 	.device = 0x0100,
182 };
183