qemu/vga-add-atiext-driver.patch
Bruce Rogers 0f796dd004 Accepting request 730437 from Virtualization:Staging
Update to v4.1.0. Also includes other major packaging changes as follows:
There is a new package maintenance workflow - see README.PACKAGING for details.
The sibling packages qemu-linux-user and qemu-testsuite are now created with the Build Service's MultiBuild feature. This also necessitates combining the qemu-linux-user changelog content back into qemu's. Luckily the delta there is quite small. Note that the qemu spec file is now that much busier, but added section markers should help reduce the confusion. Also qemu is being enabled for RISCV host compatibility, so some changes are related to that as well.

OBS-URL: https://build.opensuse.org/request/show/730437
OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=487
2019-09-12 15:54:03 +00:00

382 lines
13 KiB
Diff

From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 25 Feb 2019 10:51:37 +0100
Subject: vga: add atiext driver
Git-commit: 34b6ecc160749a691b80fcb8638216518d971c65
Supports qemu emulated ati cards. They have been added in qemu 4.0.
Acceleration support (in qemu) is pretty rough still. A simple
framebuffer works fine though.
Available models:
* ati rage 128 pro
* ati rv100
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Bruce Rogers <brogers@suse.com>
---
Makefile | 2 +-
vgasrc/Kconfig | 11 +++
vgasrc/atiext.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++
vgasrc/vgahw.h | 8 ++
vgasrc/vgautil.h | 6 ++
5 files changed, 271 insertions(+), 1 deletion(-)
diff --git a/roms/seabios/Makefile b/roms/seabios/Makefile
index 79b264ef87565106987fc88eeffe..ecec084825e706cc9d5afacefc10 100644
--- a/roms/seabios/Makefile
+++ b/roms/seabios/Makefile
@@ -212,7 +212,7 @@ SRCVGA=src/output.c src/string.c src/hw/pci.c src/hw/serialio.c \
vgasrc/vgainit.c vgasrc/vgabios.c vgasrc/vgafb.c vgasrc/swcursor.c \
vgasrc/vgafonts.c vgasrc/vbe.c \
vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \
- vgasrc/clext.c vgasrc/svgamodes.c vgasrc/bochsvga.c vgasrc/geodevga.c \
+ vgasrc/clext.c vgasrc/svgamodes.c vgasrc/atiext.c vgasrc/bochsvga.c vgasrc/geodevga.c \
src/fw/coreboot.c vgasrc/cbvga.c vgasrc/bochsdisplay.c vgasrc/ramfb.c
ifeq "$(CONFIG_VGA_FIXUP_ASM)" "y"
diff --git a/roms/seabios/vgasrc/Kconfig b/roms/seabios/vgasrc/Kconfig
index f6d843e0900bda3900bc268fae97..c8fac36fb92baa27e06076ec68c5 100644
--- a/roms/seabios/vgasrc/Kconfig
+++ b/roms/seabios/vgasrc/Kconfig
@@ -27,6 +27,15 @@ menu "VGA ROM"
and Bochs emulators. This is for emulators; it is not
intended for use on real Cirrus hardware.
+ config VGA_ATI
+ depends on QEMU
+ bool "QEMU ATI SVGA"
+ select VGA_STDVGA_PORTS
+ help
+ Build support for ATI VGA emulation found on QEMU
+ and emulators. This is for emulators; it is not
+ intended for use on real ATI hardware.
+
config VGA_BOCHS
depends on QEMU
bool "QEMU/Bochs VBE SVGA"
@@ -182,6 +191,7 @@ menu "VGA ROM"
hex
prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
default 0x1013 if VGA_CIRRUS
+ default 0x1002 if VGA_ATI
default 0x1234 if VGA_BOCHS_STDVGA
default 0x15ad if VGA_BOCHS_VMWARE
default 0x1b36 if VGA_BOCHS_QXL
@@ -198,6 +208,7 @@ menu "VGA ROM"
hex
prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
default 0x00b8 if VGA_CIRRUS
+ default 0x5159 if VGA_ATI
default 0x1111 if VGA_BOCHS_STDVGA
default 0x0405 if VGA_BOCHS_VMWARE
default 0x0100 if VGA_BOCHS_QXL
diff --git a/roms/seabios/vgasrc/atiext.c b/roms/seabios/vgasrc/atiext.c
new file mode 100644
index 0000000000000000000000000000000000000000..0586279ce214fac7d2a7e6c87a9409a6e32eb5af
--- /dev/null
+++ b/roms/seabios/vgasrc/atiext.c
@@ -0,0 +1,245 @@
+// QEMU ATI VGABIOS Extension.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "output.h" // dprintf
+#include "stdvga.h" // VGAREG_SEQU_ADDRESS
+#include "string.h" // memset16_far
+#include "vgabios.h" // SET_VGA
+#include "vgautil.h" // VBE_total_memory
+#include "vgafb.h" // memset_high
+
+#include "svgamodes.h"
+
+#define MM_INDEX 0x0000
+#define MM_DATA 0x0004
+#define CRTC_GEN_CNTL 0x0050
+#define CRTC_EXT_CNTL 0x0054
+#define CRTC_H_TOTAL_DISP 0x0200
+#define CRTC_V_TOTAL_DISP 0x0208
+#define CRTC_OFFSET 0x0224
+#define CRTC_PITCH 0x022c
+
+/* CRTC control values (CRTC_GEN_CNTL) */
+#define CRTC2_EXT_DISP_EN 0x01000000
+#define CRTC2_EN 0x02000000
+
+#define CRTC_PIX_WIDTH_MASK 0x00000700
+#define CRTC_PIX_WIDTH_4BPP 0x00000100
+#define CRTC_PIX_WIDTH_8BPP 0x00000200
+#define CRTC_PIX_WIDTH_15BPP 0x00000300
+#define CRTC_PIX_WIDTH_16BPP 0x00000400
+#define CRTC_PIX_WIDTH_24BPP 0x00000500
+#define CRTC_PIX_WIDTH_32BPP 0x00000600
+
+/* CRTC_EXT_CNTL */
+#define CRT_CRTC_DISPLAY_DIS 0x00000400
+#define CRT_CRTC_ON 0x00008000
+
+static u32 ati_io_addr VAR16 = 0;
+
+int
+is_ati_mode(struct vgamode_s *vmode_g)
+{
+ unsigned int mcount = GET_GLOBAL(svga_mcount);
+
+ return (vmode_g >= &svga_modes[0].info &&
+ vmode_g <= &svga_modes[mcount-1].info);
+}
+
+struct vgamode_s *
+ati_find_mode(int mode)
+{
+ u32 io_addr = GET_GLOBAL(ati_io_addr);
+ struct generic_svga_mode *table_g = svga_modes;
+ unsigned int mcount = GET_GLOBAL(svga_mcount);
+
+ if (io_addr) {
+ while (table_g < &svga_modes[mcount]) {
+ if (GET_GLOBAL(table_g->mode) == mode)
+ return &table_g->info;
+ table_g++;
+ }
+ }
+
+ return stdvga_find_mode(mode);
+}
+
+void
+ati_list_modes(u16 seg, u16 *dest, u16 *last)
+{
+ u32 io_addr = GET_GLOBAL(ati_io_addr);
+ unsigned int mcount = GET_GLOBAL(svga_mcount);
+
+ dprintf(1, "%s: ati ext %s\n", __func__, io_addr ? "yes" : "no");
+ if (io_addr) {
+ int i;
+ for (i=0; i<mcount && dest<last; i++) {
+ u16 mode = GET_GLOBAL(svga_modes[i].mode);
+ if (mode == 0xffff)
+ continue;
+ SET_FARVAR(seg, *dest, mode);
+ dest++;
+ }
+ }
+
+ stdvga_list_modes(seg, dest, last);
+}
+
+/****************************************************************
+ * Mode setting
+ ****************************************************************/
+
+static inline void ati_write(u32 reg, u32 val)
+{
+ u32 io_addr = GET_GLOBAL(ati_io_addr);
+
+ if (reg < 0x100) {
+ outl(val, io_addr + reg);
+ } else {
+ outl(reg, io_addr + MM_INDEX);
+ outl(val, io_addr + MM_DATA);
+ }
+}
+
+static void ati_clear(u32 offset, u32 size)
+{
+ u8 data[64];
+ void *datap = MAKE_FLATPTR(GET_SEG(SS), data);
+ void *fb = (void*)(GET_GLOBAL(VBE_framebuffer) + offset);
+ u32 i, pos;
+
+ for (i = 0; i < sizeof(data); i++)
+ data[i] = 0;
+ for (pos = 0; pos < size; pos += sizeof(data)) {
+ memcpy_high(fb, datap, sizeof(data));
+ fb += sizeof(data);
+ }
+}
+
+static int
+ati_ext_mode(struct generic_svga_mode *table, int flags)
+{
+ u32 width = GET_GLOBAL(table->info.width);
+ u32 height = GET_GLOBAL(table->info.height);
+ u32 depth = GET_GLOBAL(table->info.depth);
+ u32 stride = width;
+ u32 offset = 0;
+ u32 pxmask = 0;
+ u32 bytes = 0;
+
+ dprintf(1, "%s: 0x%x, %dx%d-%d\n", __func__,
+ GET_GLOBAL(table->mode),
+ width, height, depth);
+
+ switch (depth) {
+ case 8: pxmask = CRTC_PIX_WIDTH_8BPP; bytes = 1; break;
+ case 15: pxmask = CRTC_PIX_WIDTH_15BPP; bytes = 2; break;
+ case 16: pxmask = CRTC_PIX_WIDTH_16BPP; bytes = 2; break;
+ case 24: pxmask = CRTC_PIX_WIDTH_24BPP; bytes = 3; break;
+ case 32: pxmask = CRTC_PIX_WIDTH_32BPP; bytes = 4; break;
+ }
+
+ /* disable display */
+ ati_write(CRTC_EXT_CNTL, CRT_CRTC_DISPLAY_DIS);
+
+ /* modeset */
+ ati_write(CRTC_GEN_CNTL, CRTC2_EXT_DISP_EN | CRTC2_EN | pxmask);
+ ati_write(CRTC_H_TOTAL_DISP, ((width / 8) - 1) << 16);
+ ati_write(CRTC_V_TOTAL_DISP, (height - 1) << 16);
+ ati_write(CRTC_OFFSET, offset);
+ ati_write(CRTC_PITCH, stride / 8);
+
+ /* clear screen */
+ if (!(flags & MF_NOCLEARMEM)) {
+ u32 size = width * height * bytes;
+ ati_clear(offset, size);
+ }
+
+ /* enable display */
+ ati_write(CRTC_EXT_CNTL, 0);
+
+ return 0;
+}
+
+int
+ati_set_mode(struct vgamode_s *vmode_g, int flags)
+{
+ struct generic_svga_mode *table_g =
+ container_of(vmode_g, struct generic_svga_mode, info);
+
+ if (is_ati_mode(vmode_g)) {
+ return ati_ext_mode(table_g, flags);
+ }
+
+ ati_write(CRTC_GEN_CNTL, 0);
+ return stdvga_set_mode(vmode_g, flags);
+}
+
+/****************************************************************
+ * init
+ ****************************************************************/
+
+int
+ati_setup(void)
+{
+ int ret = stdvga_setup();
+ if (ret)
+ return ret;
+
+ dprintf(1, "%s:%d\n", __func__, __LINE__);
+
+ if (GET_GLOBAL(HaveRunInit))
+ return 0;
+
+ int bdf = GET_GLOBAL(VgaBDF);
+ if (!CONFIG_VGA_PCI || bdf == 0)
+ return 0;
+
+ u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ u32 lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;
+ pci_config_writel(bdf, PCI_BASE_ADDRESS_0, ~0);
+ u32 barmask = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ u32 totalmem = ~(barmask & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ pci_config_writel(bdf, PCI_BASE_ADDRESS_0, bar);
+
+ bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_1);
+ u32 io_addr = bar & PCI_BASE_ADDRESS_IO_MASK;
+
+ bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_2);
+ u32 mmio_addr = bar & PCI_BASE_ADDRESS_MEM_MASK;
+
+ dprintf(1, "ati: bdf %02x:%02x.%x, lfb 0x%x, %d MB, io 0x%x, mmio 0x%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf),
+ lfb_addr, totalmem / (1024 * 1024), io_addr, mmio_addr);
+
+ SET_VGA(VBE_framebuffer, lfb_addr);
+ SET_VGA(VBE_total_memory, totalmem);
+ SET_VGA(ati_io_addr, io_addr);
+
+ // Validate modes
+ struct generic_svga_mode *m = svga_modes;
+ unsigned int mcount = GET_GLOBAL(svga_mcount);
+ for (; m < &svga_modes[mcount]; m++) {
+ u8 memmodel = GET_GLOBAL(m->info.memmodel);
+ u16 width = GET_GLOBAL(m->info.width);
+ u16 height = GET_GLOBAL(m->info.height);
+ u32 mem = (height * DIV_ROUND_UP(width * vga_bpp(&m->info), 8)
+ * stdvga_vram_ratio(&m->info));
+
+ if (width % 8 != 0 ||
+ width > 0x7ff * 8 ||
+ height > 0xfff ||
+ mem > totalmem ||
+ memmodel != MM_DIRECT) {
+ dprintf(1, "ati: removing mode 0x%x\n", GET_GLOBAL(m->mode));
+ SET_VGA(m->mode, 0xffff);
+ }
+ }
+
+ return 0;
+}
diff --git a/roms/seabios/vgasrc/vgahw.h b/roms/seabios/vgasrc/vgahw.h
index 51777458da629a759f762317e9f6..c774f4f2c6b7c8012096bac2f0ed 100644
--- a/roms/seabios/vgasrc/vgahw.h
+++ b/roms/seabios/vgasrc/vgahw.h
@@ -12,6 +12,8 @@
static inline struct vgamode_s *vgahw_find_mode(int mode) {
if (CONFIG_VGA_CIRRUS)
return clext_find_mode(mode);
+ if (CONFIG_VGA_ATI)
+ return ati_find_mode(mode);
if (CONFIG_VGA_BOCHS)
return bochsvga_find_mode(mode);
if (CONFIG_VGA_EMULATE_TEXT)
@@ -22,6 +24,8 @@ static inline struct vgamode_s *vgahw_find_mode(int mode) {
static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
if (CONFIG_VGA_CIRRUS)
return clext_set_mode(vmode_g, flags);
+ if (CONFIG_VGA_ATI)
+ return ati_set_mode(vmode_g, flags);
if (CONFIG_VGA_BOCHS)
return bochsvga_set_mode(vmode_g, flags);
if (CONFIG_VGA_EMULATE_TEXT)
@@ -32,6 +36,8 @@ static inline int vgahw_set_mode(struct vgamode_s *vmode_g, int flags) {
static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
if (CONFIG_VGA_CIRRUS)
clext_list_modes(seg, dest, last);
+ if (CONFIG_VGA_ATI)
+ ati_list_modes(seg, dest, last);
else if (CONFIG_VGA_BOCHS)
bochsvga_list_modes(seg, dest, last);
else if (CONFIG_VGA_EMULATE_TEXT)
@@ -43,6 +49,8 @@ static inline void vgahw_list_modes(u16 seg, u16 *dest, u16 *last) {
static inline int vgahw_setup(void) {
if (CONFIG_VGA_CIRRUS)
return clext_setup();
+ if (CONFIG_VGA_ATI)
+ return ati_setup();
if (CONFIG_VGA_BOCHS)
return bochsvga_setup();
if (CONFIG_VGA_GEODEGX2 || CONFIG_VGA_GEODELX)
diff --git a/roms/seabios/vgasrc/vgautil.h b/roms/seabios/vgasrc/vgautil.h
index 4f37bf947c42e9f73f7148f668c8..a9940402e45bf293f95b29bbdc2c 100644
--- a/roms/seabios/vgasrc/vgautil.h
+++ b/roms/seabios/vgasrc/vgautil.h
@@ -42,6 +42,12 @@ struct bregs;
void clext_1012(struct bregs *regs);
int clext_setup(void);
+// atiext.c
+struct vgamode_s *ati_find_mode(int mode);
+void ati_list_modes(u16 seg, u16 *dest, u16 *last);
+int ati_set_mode(struct vgamode_s *vmode_g, int flags);
+int ati_setup(void);
+
// stdvgaio.c
u8 stdvga_pelmask_read(void);
void stdvga_pelmask_write(u8 val);