Skip to content
Snippets Groups Projects
Commit c82c7336 authored by BALATON Zoltan's avatar BALATON Zoltan Committed by Gerd Hoffmann
Browse files

ati-vga: Implement DDC and EDID info from monitor

This adds DDC support to ati-vga and connects i2c-ddc to it. This
allows at least MacOS with an ATI ndrv, Linux radeonfb and MorphOS to
get monitor EDID info (although MorphOS splash screen is not displayed
and radeonfb needs additional tables from vgabios-rv100). Xorg needs
additional support from VESA vgabios, it's missing INT10 0x4F15
function (see
https://gitlab.freedesktop.org/xorg/xserver/blob/master/hw/xfree86/vbe/vbe.c

)
without which no DDC is available that also prevents loading the
accelerated X driver.

Signed-off-by: default avatarBALATON Zoltan <balaton@eik.bme.hu>
Message-id: 046ddebb7ec8db48c4e877ee444ec1c41e385a74.1561028123.git.balaton@eik.bme.hu

ati-vga: Clarify comment

Signed-off-by: default avatarBALATON Zoltan <balaton@eik.bme.hu>
Message-id: 20190620195213.C54127461AE@zero.eik.bme.hu

ati-vga: Add DDC reg names for debug

Signed-off-by: default avatarBALATON Zoltan <balaton@eik.bme.hu>
Message-id: 20190621181459.2F8207462AA@zero.eik.bme.hu
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent d718b747
No related branches found
No related tags found
No related merge requests found
......@@ -130,3 +130,5 @@ config ATI_VGA
default y if PCI_DEVICES
depends on PCI
select VGA
select BITBANG_I2C
select DDC
......@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "hw/hw.h"
#include "ui/console.h"
#include "hw/display/i2c-ddc.h"
#include "trace.h"
#define ATI_DEBUG_HW_CURSOR 0
......@@ -215,6 +216,24 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y)
}
}
static uint64_t ati_i2c(bitbang_i2c_interface *i2c, uint64_t data, int base)
{
bool c = (data & BIT(base + 17) ? !!(data & BIT(base + 1)) : 1);
bool d = (data & BIT(base + 16) ? !!(data & BIT(base)) : 1);
bitbang_i2c_set(i2c, BITBANG_I2C_SCL, c);
d = bitbang_i2c_set(i2c, BITBANG_I2C_SDA, d);
data &= ~0xf00ULL;
if (c) {
data |= BIT(base + 9);
}
if (d) {
data |= BIT(base + 8);
}
return data;
}
static inline uint64_t ati_reg_read_offs(uint32_t reg, int offs,
unsigned int size)
{
......@@ -266,7 +285,16 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
case DAC_CNTL:
val = s->regs.dac_cntl;
break;
/* case GPIO_MONID: FIXME hook up DDC I2C here */
case GPIO_VGA_DDC:
val = s->regs.gpio_vga_ddc;
break;
case GPIO_DVI_DDC:
val = s->regs.gpio_dvi_ddc;
break;
case GPIO_MONID ... GPIO_MONID + 3:
val = ati_reg_read_offs(s->regs.gpio_monid,
addr - GPIO_MONID, size);
break;
case PALETTE_INDEX:
/* FIXME unaligned access */
val = vga_ioport_read(&s->vga, VGA_PEL_IR) << 16;
......@@ -497,7 +525,33 @@ 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_MONID: FIXME hook up DDC I2C here */
case GPIO_VGA_DDC:
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:
if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) {
s->regs.gpio_dvi_ddc = ati_i2c(s->bbi2c, data, 0);
}
break;
case GPIO_MONID ... GPIO_MONID + 3:
/* FIXME What does Radeon have here? */
if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) {
ati_reg_write_offs(&s->regs.gpio_monid,
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.
*/
if ((s->regs.gpio_monid & BIT(25)) &&
addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) {
s->regs.gpio_monid = ati_i2c(s->bbi2c, s->regs.gpio_monid, 1);
}
}
break;
case PALETTE_INDEX ... PALETTE_INDEX + 3:
if (size == 4) {
vga_ioport_write(&s->vga, VGA_PEL_IR, (data >> 16) & 0xff);
......@@ -788,6 +842,12 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp)
vga->cursor_draw_line = ati_cursor_draw_line;
}
/* ddc, edid */
I2CBus *i2cbus = i2c_init_bus(DEVICE(s), "ati-vga.ddc");
s->bbi2c = bitbang_i2c_init(i2cbus);
I2CSlave *i2cddc = I2C_SLAVE(qdev_create(BUS(i2cbus), TYPE_I2CDDC));
i2c_set_slave_address(i2cddc, 0x50);
/* mmio register space */
memory_region_init_io(&s->mm, OBJECT(s), &ati_mm_ops, s,
"ati.mmregs", 0x4000);
......@@ -813,6 +873,7 @@ static void ati_vga_exit(PCIDevice *dev)
ATIVGAState *s = ATI_VGA(dev);
graphic_console_close(s->vga.con);
g_free(s->bbi2c);
}
static Property ati_vga_properties[] = {
......
......@@ -19,6 +19,8 @@ static struct ati_regdesc ati_reg_names[] = {
{"CRTC_GEN_CNTL", 0x0050},
{"CRTC_EXT_CNTL", 0x0054},
{"DAC_CNTL", 0x0058},
{"GPIO_VGA_DDC", 0x0060},
{"GPIO_DVI_DDC", 0x0064},
{"GPIO_MONID", 0x0068},
{"I2C_CNTL_1", 0x0094},
{"PALETTE_INDEX", 0x00b0},
......
......@@ -10,6 +10,7 @@
#define ATI_INT_H
#include "hw/pci/pci.h"
#include "hw/i2c/bitbang_i2c.h"
#include "vga_int.h"
/*#define DEBUG_ATI*/
......@@ -35,6 +36,9 @@ typedef struct ATIVGARegs {
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 crtc_h_total_disp;
uint32_t crtc_h_sync_strt_wid;
uint32_t crtc_v_total_disp;
......@@ -83,6 +87,7 @@ typedef struct ATIVGAState {
uint16_t cursor_size;
uint32_t cursor_offset;
QEMUCursor *cursor;
bitbang_i2c_interface *bbi2c;
MemoryRegion io;
MemoryRegion mm;
ATIVGARegs regs;
......
......@@ -37,6 +37,8 @@
#define CRTC_GEN_CNTL 0x0050
#define CRTC_EXT_CNTL 0x0054
#define DAC_CNTL 0x0058
#define GPIO_VGA_DDC 0x0060
#define GPIO_DVI_DDC 0x0064
#define GPIO_MONID 0x0068
#define I2C_CNTL_1 0x0094
#define PALETTE_INDEX 0x00b0
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment