diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-08-22 16:13:17 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-08-22 16:13:17 +0100 |
commit | e1391340c77e206644f6ecaeab5df0b7b1a1bf93 (patch) | |
tree | 395bccc2ef4bbae59ebeb0d96f67e8e8109e84f6 /hw/display | |
parent | 4a71d0af7b9c4ab861c9db2111db73771999c81b (diff) | |
parent | b7105d280cab053465de79ff1766d2f7e1ea7554 (diff) |
Merge remote-tracking branch 'remotes/kraxel/tags/vga-20190822-pull-request' into staging
vga: a collection of ati fixes/improvements.
# gpg: Signature made Thu 22 Aug 2019 09:04:52 BST
# gpg: using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138
* remotes/kraxel/tags/vga-20190822-pull-request:
ati-vga: Implement dummy VBlank IRQ
ati-vga: Add limited support for big endian frame buffer aperture
ati-vga: Attempt to handle CRTC offset not exact multiple of stride
ati-vga: Fix hardware cursor image offset
ati-vga: Fix cursor color with guest_hwcursor=true
ati-vga: Fix GPIO_MONID register write
ati-vga: Add some register definitions for debugging
ati-vga: Add registers for getting apertures
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/display')
-rw-r--r-- | hw/display/ati.c | 112 | ||||
-rw-r--r-- | hw/display/ati_dbg.c | 10 | ||||
-rw-r--r-- | hw/display/ati_int.h | 5 | ||||
-rw-r--r-- | hw/display/ati_regs.h | 17 |
4 files changed, 126 insertions, 18 deletions
diff --git a/hw/display/ati.c b/hw/display/ati.c index 35f49a591b..8f940eee22 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -50,6 +50,7 @@ static void ati_vga_switch_mode(ATIVGAState *s) s->mode = EXT_MODE; if (s->regs.crtc_gen_cntl & CRTC2_EN) { /* CRT controller enabled, use CRTC values */ + /* FIXME Should these be the same as VGA CRTC regs? */ uint32_t offs = s->regs.crtc_offset & 0x07ffffff; int stride = (s->regs.crtc_pitch & 0x7ff) * 8; int bpp = 0; @@ -89,7 +90,9 @@ static void ati_vga_switch_mode(ATIVGAState *s) DPRINTF("Switching to %dx%d %d %d @ %x\n", h, v, stride, bpp, offs); vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_ENABLE); vbe_ioport_write_data(&s->vga, 0, VBE_DISPI_DISABLED); - s->vga.big_endian_fb = false; + s->vga.big_endian_fb = (s->regs.config_cntl & APER_0_ENDIAN || + s->regs.config_cntl & APER_1_ENDIAN ? + true : false); /* reset VBE regs then set up mode */ s->vga.vbe_regs[VBE_DISPI_INDEX_XRES] = h; s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] = v; @@ -101,16 +104,23 @@ static void ati_vga_switch_mode(ATIVGAState *s) (s->regs.dac_cntl & DAC_8BIT_EN ? VBE_DISPI_8BIT_DAC : 0)); /* now set offset and stride after enable as that resets these */ if (stride) { + int bypp = DIV_ROUND_UP(bpp, BITS_PER_BYTE); + vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_VIRT_WIDTH); vbe_ioport_write_data(&s->vga, 0, stride); - if (offs % stride == 0) { - vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_Y_OFFSET); - vbe_ioport_write_data(&s->vga, 0, offs / stride); - } else { - /* FIXME what to do with this? */ - error_report("VGA offset is not multiple of pitch, " - "expect bad picture"); + stride *= bypp; + if (offs % stride) { + DPRINTF("CRTC offset is not multiple of pitch\n"); + vbe_ioport_write_index(&s->vga, 0, + VBE_DISPI_INDEX_X_OFFSET); + vbe_ioport_write_data(&s->vga, 0, offs % stride / bypp); } + vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_Y_OFFSET); + vbe_ioport_write_data(&s->vga, 0, offs / stride); + DPRINTF("VBE offset (%d,%d), vbe_start_addr=%x\n", + s->vga.vbe_regs[VBE_DISPI_INDEX_X_OFFSET], + s->vga.vbe_regs[VBE_DISPI_INDEX_Y_OFFSET], + s->vga.vbe_start_addr); } } } else { @@ -132,9 +142,8 @@ static void ati_cursor_define(ATIVGAState *s) return; /* Do not update cursor if locked or rendered by guest */ } /* FIXME handle cur_hv_offs correctly */ - src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) + - s->regs.cur_offset - (s->regs.cur_hv_offs >> 16) - - (s->regs.cur_hv_offs & 0xffff) * 16; + src = s->vga.vram_ptr + s->regs.cur_offset - + (s->regs.cur_hv_offs >> 16) - (s->regs.cur_hv_offs & 0xffff) * 16; for (i = 0; i < 64; i++) { for (j = 0; j < 8; j++, idx++) { data[idx] = src[i * 16 + j]; @@ -190,8 +199,7 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y) return; } /* FIXME handle cur_hv_offs correctly */ - src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) + - s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16; + src = s->vga.vram_ptr + s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16; dp = &dp[vga->hw_cursor_x]; h = ((s->regs.crtc_h_total_disp >> 16) + 1) * 8; for (i = 0; i < 8; i++) { @@ -207,7 +215,7 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y) } } else { color = (xbits & BIT(7) ? s->regs.cur_color1 : - s->regs.cur_color0) << 8 | 0xff; + s->regs.cur_color0) | 0xff000000; } if (vga->hw_cursor_x + i * 8 + j >= h) { return; /* end of screen, don't span to next line */ @@ -235,6 +243,21 @@ static uint64_t ati_i2c(bitbang_i2c_interface *i2c, uint64_t data, int base) return data; } +static void ati_vga_update_irq(ATIVGAState *s) +{ + pci_set_irq(&s->dev, !!(s->regs.gen_int_status & s->regs.gen_int_cntl)); +} + +static void ati_vga_vblank_irq(void *opaque) +{ + ATIVGAState *s = opaque; + + timer_mod(&s->vblank_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + NANOSECONDS_PER_SECOND / 60); + s->regs.gen_int_status |= CRTC_VBLANK_INT; + ati_vga_update_irq(s); +} + static inline uint64_t ati_reg_read_offs(uint32_t reg, int offs, unsigned int size) { @@ -275,6 +298,12 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) addr - (BIOS_0_SCRATCH + i * 4), size); break; } + case GEN_INT_CNTL: + val = s->regs.gen_int_cntl; + break; + case GEN_INT_STATUS: + val = s->regs.gen_int_status; + break; case CRTC_GEN_CNTL ... CRTC_GEN_CNTL + 3: val = ati_reg_read_offs(s->regs.crtc_gen_cntl, addr - CRTC_GEN_CNTL, size); @@ -304,9 +333,27 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case PALETTE_DATA: val = vga_ioport_read(&s->vga, VGA_PEL_D); break; + case CNFG_CNTL: + val = s->regs.config_cntl; + break; case CNFG_MEMSIZE: val = s->vga.vram_size; break; + case CONFIG_APER_0_BASE: + case CONFIG_APER_1_BASE: + val = pci_default_read_config(&s->dev, + PCI_BASE_ADDRESS_0, size) & 0xfffffff0; + break; + case CONFIG_APER_SIZE: + val = s->vga.vram_size; + break; + case CONFIG_REG_1_BASE: + val = pci_default_read_config(&s->dev, + PCI_BASE_ADDRESS_2, size) & 0xfffffff0; + break; + case CONFIG_REG_APER_SIZE: + val = memory_region_size(&s->mm); + break; case MC_STATUS: val = 5; break; @@ -486,6 +533,21 @@ static void ati_mm_write(void *opaque, hwaddr addr, addr - (BIOS_0_SCRATCH + i * 4), data, size); break; } + case GEN_INT_CNTL: + s->regs.gen_int_cntl = data; + if (data & CRTC_VBLANK_INT) { + ati_vga_vblank_irq(s); + } else { + timer_del(&s->vblank_timer); + ati_vga_update_irq(s); + } + break; + case GEN_INT_STATUS: + data &= (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF ? + 0x000f040fUL : 0xfc080effUL); + s->regs.gen_int_status &= ~data; + ati_vga_update_irq(s); + break; case CRTC_GEN_CNTL ... CRTC_GEN_CNTL + 3: { uint32_t val = s->regs.crtc_gen_cntl; @@ -549,12 +611,15 @@ static void ati_mm_write(void *opaque, hwaddr addr, addr - GPIO_MONID, data, size); /* * Rage128p accesses DDC used to get EDID via these bits. - * Only touch i2c when write overlaps 3rd byte because some - * drivers access this reg via multiple partial writes and - * without this spurious bits would be sent. + * Because some drivers access this via multiple byte writes + * we have to be careful when we send bits to avoid spurious + * changes in bitbang_i2c state. So only do it when mask is set + * and either the enable bits are changed or output bits changed + * while enabled. */ if ((s->regs.gpio_monid & BIT(25)) && - addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) { + ((addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) || + (addr == GPIO_MONID && (s->regs.gpio_monid & 0x60000)))) { s->regs.gpio_monid = ati_i2c(&s->bbi2c, s->regs.gpio_monid, 1); } } @@ -580,6 +645,9 @@ static void ati_mm_write(void *opaque, hwaddr addr, data >>= 8; vga_ioport_write(&s->vga, VGA_PEL_D, data & 0xff); break; + case CNFG_CNTL: + s->regs.config_cntl = data; + break; case CRTC_H_TOTAL_DISP: s->regs.crtc_h_total_disp = data & 0x07ff07ff; break; @@ -870,12 +938,19 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp) pci_register_bar(dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io); pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mm); + + /* most interrupts are not yet emulated but MacOS needs at least VBlank */ + dev->config[PCI_INTERRUPT_PIN] = 1; + timer_init_ns(&s->vblank_timer, QEMU_CLOCK_VIRTUAL, ati_vga_vblank_irq, s); } static void ati_vga_reset(DeviceState *dev) { ATIVGAState *s = ATI_VGA(dev); + timer_del(&s->vblank_timer); + ati_vga_update_irq(s); + /* reset vga */ vga_common_reset(&s->vga); s->mode = VGA_MODE; @@ -885,6 +960,7 @@ static void ati_vga_exit(PCIDevice *dev) { ATIVGAState *s = ATI_VGA(dev); + timer_del(&s->vblank_timer); graphic_console_close(s->vga.con); } diff --git a/hw/display/ati_dbg.c b/hw/display/ati_dbg.c index 88b3a11315..0ebbd36f14 100644 --- a/hw/display/ati_dbg.c +++ b/hw/display/ati_dbg.c @@ -16,6 +16,7 @@ static struct ati_regdesc ati_reg_names[] = { {"BUS_CNTL", 0x0030}, {"BUS_CNTL1", 0x0034}, {"GEN_INT_CNTL", 0x0040}, + {"GEN_INT_STATUS", 0x0044}, {"CRTC_GEN_CNTL", 0x0050}, {"CRTC_EXT_CNTL", 0x0054}, {"DAC_CNTL", 0x0058}, @@ -23,11 +24,20 @@ static struct ati_regdesc ati_reg_names[] = { {"GPIO_DVI_DDC", 0x0064}, {"GPIO_MONID", 0x0068}, {"I2C_CNTL_1", 0x0094}, + {"AMCGPIO_MASK_MIR", 0x009c}, + {"AMCGPIO_A_MIR", 0x00a0}, + {"AMCGPIO_Y_MIR", 0x00a4}, + {"AMCGPIO_EN_MIR", 0x00a8}, {"PALETTE_INDEX", 0x00b0}, {"PALETTE_DATA", 0x00b4}, {"CNFG_CNTL", 0x00e0}, {"GEN_RESET_CNTL", 0x00f0}, {"CNFG_MEMSIZE", 0x00f8}, + {"CONFIG_APER_0_BASE", 0x0100}, + {"CONFIG_APER_1_BASE", 0x0104}, + {"CONFIG_APER_SIZE", 0x0108}, + {"CONFIG_REG_1_BASE", 0x010c}, + {"CONFIG_REG_APER_SIZE", 0x0110}, {"MEM_CNTL", 0x0140}, {"MC_FB_LOCATION", 0x0148}, {"MC_AGP_LOCATION", 0x014C}, diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h index 31a1927b3e..2a16708e4f 100644 --- a/hw/display/ati_int.h +++ b/hw/display/ati_int.h @@ -9,6 +9,7 @@ #ifndef ATI_INT_H #define ATI_INT_H +#include "qemu/timer.h" #include "hw/pci/pci.h" #include "hw/i2c/bitbang_i2c.h" #include "vga_int.h" @@ -33,12 +34,15 @@ typedef struct ATIVGARegs { uint32_t mm_index; uint32_t bios_scratch[8]; + uint32_t gen_int_cntl; + uint32_t gen_int_status; uint32_t crtc_gen_cntl; uint32_t crtc_ext_cntl; uint32_t dac_cntl; uint32_t gpio_vga_ddc; uint32_t gpio_dvi_ddc; uint32_t gpio_monid; + uint32_t config_cntl; uint32_t crtc_h_total_disp; uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; @@ -88,6 +92,7 @@ typedef struct ATIVGAState { uint16_t cursor_size; uint32_t cursor_offset; QEMUCursor *cursor; + QEMUTimer vblank_timer; bitbang_i2c_interface bbi2c; MemoryRegion io; MemoryRegion mm; diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index d7155c93d5..ebd37ee30d 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -34,6 +34,7 @@ #define BUS_CNTL 0x0030 #define BUS_CNTL1 0x0034 #define GEN_INT_CNTL 0x0040 +#define GEN_INT_STATUS 0x0044 #define CRTC_GEN_CNTL 0x0050 #define CRTC_EXT_CNTL 0x0054 #define DAC_CNTL 0x0058 @@ -41,11 +42,20 @@ #define GPIO_DVI_DDC 0x0064 #define GPIO_MONID 0x0068 #define I2C_CNTL_1 0x0094 +#define AMCGPIO_MASK_MIR 0x009c +#define AMCGPIO_A_MIR 0x00a0 +#define AMCGPIO_Y_MIR 0x00a4 +#define AMCGPIO_EN_MIR 0x00a8 #define PALETTE_INDEX 0x00b0 #define PALETTE_DATA 0x00b4 #define CNFG_CNTL 0x00e0 #define GEN_RESET_CNTL 0x00f0 #define CNFG_MEMSIZE 0x00f8 +#define CONFIG_APER_0_BASE 0x0100 +#define CONFIG_APER_1_BASE 0x0104 +#define CONFIG_APER_SIZE 0x0108 +#define CONFIG_REG_1_BASE 0x010c +#define CONFIG_REG_APER_SIZE 0x0110 #define MEM_CNTL 0x0140 #define MC_FB_LOCATION 0x0148 #define MC_AGP_LOCATION 0x014C @@ -307,7 +317,14 @@ #define XPLL_FB_DIV_MASK 0x0000FF00 #define X_MPLL_REF_DIV_MASK 0x000000FF +/* GEN_INT_CNTL) */ +#define CRTC_VBLANK_INT 0x00000001 +#define CRTC_VLINE_INT 0x00000002 +#define CRTC_VSYNC_INT 0x00000004 + /* Config control values (CONFIG_CNTL) */ +#define APER_0_ENDIAN 0x00000003 +#define APER_1_ENDIAN 0x0000000c #define CFG_VGA_IO_DIS 0x00000400 /* CRTC control values (CRTC_GEN_CNTL) */ |