diff options
-rw-r--r-- | src/drivers/emulation/qemu/bochs.c | 112 |
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) |