ati-vga: Support unaligned access to GPIO DDC registers

The GPIO_VGA_DDC and GPIO_DVI_DDC registers are used on Radeon for DDC
access. Some drivers like the PPC Mac FCode ROM uses unaligned writes
to these registers so implement this the same way as already done for
GPIO_MONID which is used the same way for the Rage 128 Pro.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <dff6ce16ccabdfd54ffda348bf57c6d8b810cd98.1698871239.git.balaton@eik.bme.hu>
master
BALATON Zoltan 2023-11-01 21:45:37 +01:00 committed by Marc-André Lureau
parent f7ecde051d
commit e876b3400a
1 changed files with 22 additions and 15 deletions

View File

@ -319,11 +319,13 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
case DAC_CNTL:
val = s->regs.dac_cntl;
break;
case GPIO_VGA_DDC:
val = s->regs.gpio_vga_ddc;
case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3:
val = ati_reg_read_offs(s->regs.gpio_vga_ddc,
addr - GPIO_VGA_DDC, size);
break;
case GPIO_DVI_DDC:
val = s->regs.gpio_dvi_ddc;
case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3:
val = ati_reg_read_offs(s->regs.gpio_dvi_ddc,
addr - GPIO_DVI_DDC, size);
break;
case GPIO_MONID ... GPIO_MONID + 3:
val = ati_reg_read_offs(s->regs.gpio_monid,
@ -615,29 +617,34 @@ static void ati_mm_write(void *opaque, hwaddr addr,
s->regs.dac_cntl = data & 0xffffe3ff;
s->vga.dac_8bit = !!(data & DAC_8BIT_EN);
break;
case GPIO_VGA_DDC:
/*
* GPIO regs for DDC access. Because some drivers access these via
* multiple byte writes we have to be careful when we send bits to
* avoid spurious changes in bitbang_i2c state. Only do it when either
* the enable bits are changed or output bits changed while enabled.
*/
case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3:
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
/* FIXME: Maybe add a property to select VGA or DVI port? */
}
break;
case GPIO_DVI_DDC:
case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3:
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c, data, 0);
ati_reg_write_offs(&s->regs.gpio_dvi_ddc,
addr - GPIO_DVI_DDC, data, size);
if ((addr <= GPIO_DVI_DDC + 2 && addr + size > GPIO_DVI_DDC + 2) ||
(addr == GPIO_DVI_DDC && (s->regs.gpio_dvi_ddc & 0x30000))) {
s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c,
s->regs.gpio_dvi_ddc, 0);
}
}
break;
case GPIO_MONID ... GPIO_MONID + 3:
/* FIXME What does Radeon have here? */
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
/* Rage128p accesses DDC via MONID(1-2) with additional mask bit */
ati_reg_write_offs(&s->regs.gpio_monid,
addr - GPIO_MONID, data, size);
/*
* Rage128p accesses DDC used to get EDID via these bits.
* 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 && (s->regs.gpio_monid & 0x60000)))) {