Offset (display start address) should also be updated when changing
the register value not only on mode change. Fix the register write
mask to hard code bits 0:2 to 0 as the chip docs say and update the
start address on register write. This fixes virtual screen panning for
screens larger than displayed resolution.
As this register allows values that cannot be handled by the VBE_DISPI
X and Y offsets (which is restricted by line length) we add a function
to set it directly not through the VBE offsets.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
hw/display/ati.c | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/hw/display/ati.c b/hw/display/ati.c
index eb00382902..3976f5f01c 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -48,6 +48,19 @@ static const struct {
enum { VGA_MODE, EXT_MODE };
+static void ati_vga_set_offset(VGACommonState *vga, uint32_t offs)
+{
+ int bypp = DIV_ROUND_UP(vga->vbe_regs[VBE_DISPI_INDEX_BPP], BITS_PER_BYTE);
+
+ if (!bypp ||
+ vga->vbe_regs[VBE_DISPI_INDEX_YRES] *
+ vga->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] * bypp + offs >
+ vga->vbe_size) {
+ return;
+ }
+ vga->vbe_start_addr = offs / 4;
+}
+
static void ati_vga_switch_mode(ATIVGAState *s)
{
DPRINTF("%d -> %d\n",
@@ -110,26 +123,12 @@ static void ati_vga_switch_mode(ATIVGAState *s)
vbe_ioport_write_data(&s->vga, 0, VBE_DISPI_ENABLED |
VBE_DISPI_LFB_ENABLED | VBE_DISPI_NOCLEARMEM |
(s->regs.dac_cntl & DAC_8BIT_EN ? VBE_DISPI_8BIT_DAC : 0));
- /* now set offset and stride after enable as that resets these */
+ /* now set offset and stride because enable 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);
- 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);
}
+ ati_vga_set_offset(&s->vga, offs);
}
} else {
/* VGA mode enabled */
@@ -752,7 +751,8 @@ static void ati_mm_write(void *opaque, hwaddr addr,
s->regs.crtc_v_sync_strt_wid = data & 0x9f0fff;
break;
case CRTC_OFFSET:
- s->regs.crtc_offset = data & 0xc7ffffff;
+ s->regs.crtc_offset = data & 0x87fffff8;
+ ati_vga_set_offset(&s->vga, s->regs.crtc_offset & 0x07ffffff);
break;
case CRTC_OFFSET_CNTL:
s->regs.crtc_offset_cntl = data; /* FIXME */
--
2.41.3
I've tested this under X.org 1.7.7 with:
SubSection "Display"
Depth 24
Modes "640x480"
Virtual 1024 768
EndSubSection
Prior to this patch output is garbled. After, the screen draws correctly
and panning works correctly. I did notice a bug when typing in xterm. If
the screen is panned at all the first character will appear but any
additional characters typed don't appear until the mouse is moved. But
that seems unrelated to this fix.
Tested-by: Chad Jablonski <chad@jablonski.xyz>
Reviewed-by: Chad Jablonski <chad@jablonski.xyz>
© 2016 - 2026 Red Hat, Inc.