qemu: cirrus native video init

Recent commit proposal by Ron Minnich proposes to move to native gfx init for
qemu. Unfortunately we didn't have native init for default qemu video (cirrus)
Here is one extracted from GRUB one which I wrote couple of years ago.

Change-Id: Icb89cf918ef5d276bcc703c48c568e7b9c1be756
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-on: http://review.coreboot.org/4270
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Vladimir Serbinenko 2013-11-25 11:20:20 +01:00
parent c6f6be0929
commit 7905f9254e
2 changed files with 351 additions and 0 deletions

View File

@ -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

View File

@ -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,
};