diff options
-rw-r--r-- | src/drivers/emulation/qemu/Makefile.inc | 2 | ||||
-rw-r--r-- | src/drivers/emulation/qemu/cirrus.c | 349 |
2 files changed, 351 insertions, 0 deletions
diff --git a/src/drivers/emulation/qemu/Makefile.inc b/src/drivers/emulation/qemu/Makefile.inc index 77b8c74665..e7dc5edc3b 100644 --- a/src/drivers/emulation/qemu/Makefile.inc +++ b/src/drivers/emulation/qemu/Makefile.inc @@ -1 +1,3 @@ ramstage-$(CONFIG_DRIVERS_EMULATION_QEMU_BOCHS) += bochs.c +ramstage-$(CONFIG_DRIVERS_EMULATION_QEMU_BOCHS) += cirrus.c +ramstage-$(CONFIG_DRIVERS_EMULATION_QEMU_BOCHS) += ../../pc80/vga/vga_io.c diff --git a/src/drivers/emulation/qemu/cirrus.c b/src/drivers/emulation/qemu/cirrus.c new file mode 100644 index 0000000000..9f79d31149 --- /dev/null +++ b/src/drivers/emulation/qemu/cirrus.c @@ -0,0 +1,349 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <stdint.h> +#include <delay.h> +#include <edid.h> +#include <stdlib.h> +#include <string.h> +#include <arch/io.h> + +#include <boot/coreboot_tables.h> +#include <console/console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> + +#include <pc80/vga.h> +#include <pc80/vga_io.h> + +static int width = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_XRES; +static int height = CONFIG_DRIVERS_EMULATION_QEMU_BOCHS_YRES; +static u32 addr = 0; + +enum + { + VGA_CR_HTOTAL = 0x00, + VGA_CR_HORIZ_END = 0x01, + VGA_CR_HBLANK_START = 0x02, + VGA_CR_HBLANK_END = 0x03, + VGA_CR_HORIZ_SYNC_PULSE_START = 0x04, + VGA_CR_HORIZ_SYNC_PULSE_END = 0x05, + VGA_CR_VERT_TOTAL = 0x06, + VGA_CR_OVERFLOW = 0x07, + VGA_CR_BYTE_PANNING = 0x08, + VGA_CR_CELL_HEIGHT = 0x09, + VGA_CR_CURSOR_START = 0x0a, + VGA_CR_CURSOR_END = 0x0b, + VGA_CR_START_ADDR_HIGH_REGISTER = 0x0c, + VGA_CR_START_ADDR_LOW_REGISTER = 0x0d, + VGA_CR_CURSOR_ADDR_HIGH = 0x0e, + VGA_CR_CURSOR_ADDR_LOW = 0x0f, + VGA_CR_VSYNC_START = 0x10, + VGA_CR_VSYNC_END = 0x11, + VGA_CR_VDISPLAY_END = 0x12, + VGA_CR_PITCH = 0x13, + VGA_CR_UNDERLINE_LOCATION = 0x14, + VGA_CR_VERTICAL_BLANK_START = 0x15, + VGA_CR_VERTICAL_BLANK_END = 0x16, + VGA_CR_MODE = 0x17, + VGA_CR_LINE_COMPARE = 0x18, + }; + +#define VGA_IO_MISC_COLOR 0x01 + +#define VGA_CR_WIDTH_DIVISOR 8 + +#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT 7 +#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK 0x02 +#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT 3 +#define VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK 0x40 + +#define VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT 8 +#define VGA_CR_OVERFLOW_VERT_TOTAL1_MASK 0x01 +#define VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT 4 +#define VGA_CR_OVERFLOW_VERT_TOTAL2_MASK 0x20 + +#define VGA_CR_OVERFLOW_VSYNC_START1_SHIFT 6 +#define VGA_CR_OVERFLOW_VSYNC_START1_MASK 0x04 +#define VGA_CR_OVERFLOW_VSYNC_START2_SHIFT 2 +#define VGA_CR_OVERFLOW_VSYNC_START2_MASK 0x80 + +#define VGA_CR_OVERFLOW_HEIGHT1_SHIFT 7 +#define VGA_CR_OVERFLOW_HEIGHT1_MASK 0x02 +#define VGA_CR_OVERFLOW_HEIGHT2_SHIFT 3 +#define VGA_CR_OVERFLOW_HEIGHT2_MASK 0xc0 +#define VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT 4 +#define VGA_CR_OVERFLOW_LINE_COMPARE_MASK 0x10 + +#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK 0x40 +#define VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT 3 +#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK 0x20 +#define VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT 4 +#define VGA_CR_CELL_HEIGHT_DOUBLE_SCAN 0x80 +enum + { + VGA_CR_CURSOR_START_DISABLE = (1 << 5) + }; + +#define VGA_CR_PITCH_DIVISOR 8 + +enum + { + VGA_CR_MODE_NO_CGA = 0x01, + VGA_CR_MODE_NO_HERCULES = 0x02, + VGA_CR_MODE_ADDRESS_WRAP = 0x20, + VGA_CR_MODE_BYTE_MODE = 0x40, + VGA_CR_MODE_TIMING_ENABLE = 0x80 + }; + +enum + { + VGA_SR_RESET = 0, + VGA_SR_CLOCKING_MODE = 1, + VGA_SR_MAP_MASK_REGISTER = 2, + VGA_SR_CHAR_MAP_SELECT = 3, + VGA_SR_MEMORY_MODE = 4, + }; + +enum + { + VGA_SR_RESET_ASYNC = 1, + VGA_SR_RESET_SYNC = 2 + }; + +enum + { + VGA_SR_CLOCKING_MODE_8_DOT_CLOCK = 1 + }; + +enum + { + VGA_SR_MEMORY_MODE_NORMAL = 0, + VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY = 2, + VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING = 4, + VGA_SR_MEMORY_MODE_CHAIN4 = 8, + }; + +enum + { + VGA_GR_SET_RESET_PLANE = 0, + VGA_GR_SET_RESET_PLANE_ENABLE = 1, + VGA_GR_COLOR_COMPARE = 2, + VGA_GR_READ_MAP_REGISTER = 4, + VGA_GR_MODE = 5, + VGA_GR_GR6 = 6, + VGA_GR_COLOR_COMPARE_DISABLE = 7, + VGA_GR_BITMASK = 8, + VGA_GR_MAX + }; + +enum + { + VGA_TEXT_TEXT_PLANE = 0, + VGA_TEXT_ATTR_PLANE = 1, + VGA_TEXT_FONT_PLANE = 2 + }; + +enum + { + VGA_GR_GR6_GRAPHICS_MODE = 1, + VGA_GR_GR6_MMAP_A0 = (1 << 2), + VGA_GR_GR6_MMAP_CGA = (3 << 2) + }; + +enum + { + VGA_GR_MODE_READ_MODE1 = 0x08, + VGA_GR_MODE_ODD_EVEN = 0x10, + VGA_GR_MODE_ODD_EVEN_SHIFT = 0x20, + VGA_GR_MODE_256_COLOR = 0x40 + }; + +#define CIRRUS_CR_EXTENDED_DISPLAY 0x1b +#define CIRRUS_CR_EXTENDED_OVERLAY 0x1d + +#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK 0x10 +#define CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT 4 +#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1 0x1 +#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT1 16 +#define CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2 0xc +#define CIRRUS_CR_EXTENDED_DISPLAY_START_SHIFT2 15 + +#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK 0x80 +#define CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_SHIFT 12 +#define CIRRUS_SR_EXTENDED_MODE 7 +#define CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE 0xf0 +#define CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT 0x01 +#define CIRRUS_SR_EXTENDED_MODE_32BPP 0x08 +#define CIRRUS_HIDDEN_DAC_888COLOR 0xc5 + +static void +write_hidden_dac (uint8_t data) +{ + inb (0x3c8); + inb (0x3c6); + inb (0x3c6); + inb (0x3c6); + inb (0x3c6); + outb (data, 0x3c6); +} + +static void cirrus_init(device_t dev) +{ + uint8_t cr_ext, cr_overlay; + unsigned pitch = (width * 4) / VGA_CR_PITCH_DIVISOR; + uint8_t sr_ext = 0, hidden_dac = 0; + unsigned vdisplay_end = height - 2; + unsigned line_compare = 0x3ff; + uint8_t overflow, cell_height_reg; + unsigned horizontal_end = width / VGA_CR_WIDTH_DIVISOR; + unsigned horizontal_total = horizontal_end + 40; + unsigned horizontal_blank_start = horizontal_end; + unsigned horizontal_sync_pulse_start = horizontal_end + 3; + unsigned horizontal_sync_pulse_end = 0; + + unsigned horizontal_blank_end = 0; + unsigned vertical_blank_start = height + 1; + unsigned vertical_blank_end = 0; + unsigned vertical_sync_start = height + 3; + unsigned vertical_sync_end = 0; + unsigned vertical_total = height + 40; + + /* find lfb pci bar */ + addr = pci_read_config32(dev, PCI_BASE_ADDRESS_0); + addr &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + printk(BIOS_DEBUG, "QEMU VGA: cirrus framebuffer @ %x (pci bar 0)\n", + addr); + + vga_misc_write (VGA_IO_MISC_COLOR); + + vga_sr_write (VGA_SR_MEMORY_MODE, + VGA_SR_MEMORY_MODE_NORMAL); + + vga_sr_write (VGA_SR_MAP_MASK_REGISTER, + (1 << VGA_TEXT_TEXT_PLANE) + | (1 << VGA_TEXT_ATTR_PLANE)); + + vga_sr_write (VGA_SR_CLOCKING_MODE, + VGA_SR_CLOCKING_MODE_8_DOT_CLOCK); + + vga_palette_disable(); + + /* Disable CR0-7 write protection. */ + vga_cr_write (VGA_CR_VSYNC_END, 0); + + overflow = ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT) + & VGA_CR_OVERFLOW_VERT_TOTAL1_MASK) + | ((vertical_total >> VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT) + & VGA_CR_OVERFLOW_VERT_TOTAL2_MASK) + | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START2_SHIFT) + & VGA_CR_OVERFLOW_VSYNC_START2_MASK) + | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT) + & VGA_CR_OVERFLOW_VSYNC_START1_MASK) + | ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT) + & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK) + | ((vdisplay_end >> VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT) + & VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK) + | ((vertical_sync_start >> VGA_CR_OVERFLOW_VSYNC_START1_SHIFT) + & VGA_CR_OVERFLOW_VSYNC_START1_MASK) + | ((line_compare >> VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT) + & VGA_CR_OVERFLOW_LINE_COMPARE_MASK); + + cell_height_reg = ((vertical_blank_start + >> VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT) + & VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK) + | ((line_compare >> VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT) + & VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK); + + vga_cr_write (VGA_CR_HTOTAL, horizontal_total - 1); + vga_cr_write (VGA_CR_HORIZ_END, horizontal_end - 1); + vga_cr_write (VGA_CR_HBLANK_START, horizontal_blank_start - 1); + vga_cr_write (VGA_CR_HBLANK_END, horizontal_blank_end); + vga_cr_write (VGA_CR_HORIZ_SYNC_PULSE_START, + horizontal_sync_pulse_start); + vga_cr_write (VGA_CR_HORIZ_SYNC_PULSE_END, + horizontal_sync_pulse_end); + vga_cr_write (VGA_CR_VERT_TOTAL, vertical_total & 0xff); + vga_cr_write (VGA_CR_OVERFLOW, overflow); + vga_cr_write (VGA_CR_CELL_HEIGHT, cell_height_reg); + vga_cr_write (VGA_CR_VSYNC_START, vertical_sync_start & 0xff); + vga_cr_write (VGA_CR_VSYNC_END, vertical_sync_end & 0x0f); + vga_cr_write (VGA_CR_VDISPLAY_END, vdisplay_end & 0xff); + vga_cr_write (VGA_CR_PITCH, pitch & 0xff); + vga_cr_write (VGA_CR_VERTICAL_BLANK_START, vertical_blank_start & 0xff); + vga_cr_write (VGA_CR_VERTICAL_BLANK_END, vertical_blank_end & 0xff); + vga_cr_write (VGA_CR_LINE_COMPARE, line_compare & 0xff); + + vga_gr_write (VGA_GR_MODE, VGA_GR_MODE_256_COLOR | VGA_GR_MODE_READ_MODE1); + vga_gr_write (VGA_GR_GR6, VGA_GR_GR6_GRAPHICS_MODE); + + vga_sr_write (VGA_SR_MEMORY_MODE, VGA_SR_MEMORY_MODE_NORMAL); + + vga_cr_write (CIRRUS_CR_EXTENDED_DISPLAY, + (pitch >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT) + & CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK); + + vga_cr_write (VGA_CR_MODE, VGA_CR_MODE_TIMING_ENABLE + | VGA_CR_MODE_BYTE_MODE + | VGA_CR_MODE_NO_HERCULES | VGA_CR_MODE_NO_CGA); + + vga_cr_write (VGA_CR_START_ADDR_LOW_REGISTER, 0); + vga_cr_write (VGA_CR_START_ADDR_HIGH_REGISTER, 0); + + cr_ext = vga_cr_read (CIRRUS_CR_EXTENDED_DISPLAY); + cr_ext &= ~(CIRRUS_CR_EXTENDED_DISPLAY_START_MASK1 + | CIRRUS_CR_EXTENDED_DISPLAY_START_MASK2); + vga_cr_write (CIRRUS_CR_EXTENDED_DISPLAY, cr_ext); + + cr_overlay = vga_cr_read (CIRRUS_CR_EXTENDED_OVERLAY); + cr_overlay &= ~(CIRRUS_CR_EXTENDED_OVERLAY_DISPLAY_START_MASK); + vga_cr_write (CIRRUS_CR_EXTENDED_OVERLAY, cr_overlay); + + sr_ext = CIRRUS_SR_EXTENDED_MODE_LFB_ENABLE + | CIRRUS_SR_EXTENDED_MODE_ENABLE_EXT + | CIRRUS_SR_EXTENDED_MODE_32BPP; + hidden_dac = CIRRUS_HIDDEN_DAC_888COLOR; + vga_sr_write (CIRRUS_SR_EXTENDED_MODE, sr_ext); + write_hidden_dac (hidden_dac); + + + struct edid edid; + edid.ha = width; + edid.va = height; + edid.bpp = 32; + set_vbe_mode_info_valid(&edid, addr); +} + +static struct device_operations qemu_cirrus_graph_ops = { + .read_resources = pci_dev_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = cirrus_init, + .scan_bus = 0, +}; + +static const struct pci_driver qemu_cirrus_driver __pci_driver = { + .ops = &qemu_cirrus_graph_ops, + .vendor = 0x1013, + .device = 0x00b8, +}; |