summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rudolph <patrick.rudolph@9elements.com>2020-05-14 16:37:46 +0200
committerPatrick Georgi <pgeorgi@google.com>2020-05-20 09:50:29 +0000
commitefaf1b32ba1eb69b8968de7e0f67e8fc66fca0d5 (patch)
treebbee4f4e88d204b34621546eadcef70f3f638bbd
parent2c26108208e4aa48de21be576ab6cad9286d7934 (diff)
drivers/emulation/qemu/bochs: Rewrite driver
Support MMIO mapped BOCHS interface supported since qemu 3.0. This allows to use multiple virtual GPUs by specifying: qemu -device bochs-display -device bochs-display ... Tested on qemu. std, qxl, vmware and multiple bochs displays are working fine. Change-Id: Ib0eba4815942625ce4859946efccca500301bb65 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41406 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Himanshu Sahdev <sahdev.himan@gmail.com> Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r--src/drivers/emulation/qemu/bochs.c112
1 files changed, 75 insertions, 37 deletions
diff --git a/src/drivers/emulation/qemu/bochs.c b/src/drivers/emulation/qemu/bochs.c
index 6372404021..5a6603ee1e 100644
--- a/src/drivers/emulation/qemu/bochs.c
+++ b/src/drivers/emulation/qemu/bochs.c
@@ -7,6 +7,7 @@
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ops.h>
+#include <device/pci_ids.h>
#include <pc80/vga.h>
#include <pc80/vga_io.h>
@@ -40,66 +41,103 @@
static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES;
static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES;
-static void bochs_write(int index, int val)
+static void bochs_write(struct resource *res, int index, int val)
{
- outw(index, VBE_DISPI_IOPORT_INDEX);
- outw(val, VBE_DISPI_IOPORT_DATA);
+ if (res->flags & IORESOURCE_IO) {
+ outw(index, res->base);
+ outw(val, res->base + 1);
+ } else {
+ write16(res2mmio(res, 0x500 + index * 2, 0), val);
+ }
}
-static int bochs_read(int index)
+static int bochs_read(struct resource *res, int index)
{
- outw(index, VBE_DISPI_IOPORT_INDEX);
- return inw(VBE_DISPI_IOPORT_DATA);
+ if (res->flags & IORESOURCE_IO) {
+ outw(index, res->base);
+ return inw(res->base + 1);
+ } else {
+ return read16(res2mmio(res, 0x500 + index * 2, 0));
+ }
}
+static void bochs_vga_write(struct resource *res, int index, uint8_t val)
+{
+ if (res->flags & IORESOURCE_IO)
+ outb(val, index + 0x3c0);
+ else
+ write8(res2mmio(res, (0x400 - 0x3c0) + index, 0), val);
+}
+
+static struct resource res_legacy = {
+ VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_IOPORT_DATA - VBE_DISPI_IOPORT_INDEX,
+ VBE_DISPI_IOPORT_DATA,
+ NULL,
+ IORESOURCE_IO,
+ 0,
+ 1,
+ 1
+};
+
static void bochs_init_linear_fb(struct device *dev)
{
struct edid edid;
+ struct resource *res_fb, *res_io;
int id, mem, bar;
- u32 addr;
-
- /* bochs dispi detection */
- id = bochs_read(VBE_DISPI_INDEX_ID);
- if ((id & 0xfff0) != VBE_DISPI_ID0) {
- printk(BIOS_DEBUG, "QEMU VGA: bochs dispi: ID mismatch.\n");
- return;
- }
- mem = bochs_read(VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024;
- /* find lfb pci bar */
- addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
- if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ res_fb = probe_resource(dev, PCI_BASE_ADDRESS_0);
+ if (res_fb && res_fb->flags & IORESOURCE_MEM) {
/* qemu -vga {std,qxl} */
bar = 0;
} else {
- /* qemu -vga vmware */
- addr = pci_read_config32(dev, PCI_BASE_ADDRESS_1);
- bar = 1;
+ res_fb = probe_resource(dev, PCI_BASE_ADDRESS_1);
+ if (res_fb && res_fb->flags & IORESOURCE_MEM) {
+ /* qemu -vga vmware */
+ bar = 1;
+ } else {
+ printk(BIOS_ERR, "%s: Not bochs compatible\n", dev_name(dev));
+ return;
+ }
}
- addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
- if (!addr)
+ /* MMIO bar supported since qemu 3.0+ */
+ res_io = probe_resource(dev, PCI_BASE_ADDRESS_2);
+ if (((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) ||
+ !res_io || !(res_io->flags & IORESOURCE_MEM)) {
+ printk(BIOS_DEBUG, "QEMU VGA: Using legacy VGA\n");
+ res_io = &res_legacy;
+ } else {
+ printk(BIOS_DEBUG, "QEMU VGA: Using I/O bar at %llx\n", res_io->base);
+ }
+
+ /* bochs dispi detection */
+ id = bochs_read(res_io, VBE_DISPI_INDEX_ID);
+ if ((id & 0xfff0) != VBE_DISPI_ID0) {
+ printk(BIOS_DEBUG, "QEMU VGA: bochs dispi: ID mismatch.\n");
return;
+ }
+ mem = bochs_read(res_io, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024;
printk(BIOS_DEBUG, "QEMU VGA: bochs dispi interface found, "
"%d MiB video memory\n", mem / (1024 * 1024));
- printk(BIOS_DEBUG, "QEMU VGA: framebuffer @ %x (pci bar %d)\n",
- addr, bar);
+ printk(BIOS_DEBUG, "QEMU VGA: framebuffer @ %llx (pci bar %d)\n",
+ res_fb->base, bar);
/* setup video mode */
- bochs_write(VBE_DISPI_INDEX_ENABLE, 0);
- bochs_write(VBE_DISPI_INDEX_BANK, 0);
- bochs_write(VBE_DISPI_INDEX_BPP, 32);
- bochs_write(VBE_DISPI_INDEX_XRES, width);
- bochs_write(VBE_DISPI_INDEX_YRES, height);
- bochs_write(VBE_DISPI_INDEX_VIRT_WIDTH, width);
- bochs_write(VBE_DISPI_INDEX_VIRT_HEIGHT, height);
- bochs_write(VBE_DISPI_INDEX_X_OFFSET, 0);
- bochs_write(VBE_DISPI_INDEX_Y_OFFSET, 0);
- bochs_write(VBE_DISPI_INDEX_ENABLE,
+ bochs_write(res_io, VBE_DISPI_INDEX_ENABLE, 0);
+ bochs_write(res_io, VBE_DISPI_INDEX_BANK, 0);
+ bochs_write(res_io, VBE_DISPI_INDEX_BPP, 32);
+ bochs_write(res_io, VBE_DISPI_INDEX_XRES, width);
+ bochs_write(res_io, VBE_DISPI_INDEX_YRES, height);
+ bochs_write(res_io, VBE_DISPI_INDEX_VIRT_WIDTH, width);
+ bochs_write(res_io, VBE_DISPI_INDEX_VIRT_HEIGHT, height);
+ bochs_write(res_io, VBE_DISPI_INDEX_X_OFFSET, 0);
+ bochs_write(res_io, VBE_DISPI_INDEX_Y_OFFSET, 0);
+ bochs_write(res_io, VBE_DISPI_INDEX_ENABLE,
VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
- outb(0x20, 0x3c0); /* disable blanking */
+ bochs_vga_write(res_io, 0, 0x20); /* disable blanking */
/* setup coreboot framebuffer */
edid.mode.ha = width;
@@ -107,7 +145,7 @@ static void bochs_init_linear_fb(struct device *dev)
edid.panel_bits_per_color = 8;
edid.panel_bits_per_pixel = 24;
edid_set_framebuffer_bits_per_pixel(&edid, 32, 0);
- set_vbe_mode_info_valid(&edid, addr);
+ set_vbe_mode_info_valid(&edid, res_fb->base);
}
static void bochs_init_text_mode(struct device *dev)