From 4b402c22cdb6634bbb5bb479253bc07ff216fbbd Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 16 Dec 2023 18:26:39 -0300 Subject: [PATCH] vid_mga: Implement DDC on the Millennium --- src/include/86box/vid_svga.h | 1 + src/video/vid_mga.c | 22 ++++++++++++++++++++ src/video/vid_tvp3026_ramdac.c | 37 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index cb914aca9..682a66111 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -398,6 +398,7 @@ extern uint8_t tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, sv extern void tvp3026_recalctimings(void *priv, svga_t *svga); extern void tvp3026_hwcursor_draw(svga_t *svga, int displine); extern float tvp3026_getclock(int clock, void *priv); +extern void tvp3026_gpio(uint8_t (*read)(uint8_t cntl, void *priv), void (*write)(uint8_t cntl, uint8_t data, void *priv), void *cb_priv, void *priv); # ifdef EMU_DEVICE_H extern const device_t ati68860_ramdac_device; diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 320cd899a..2f701b33f 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -5314,6 +5314,27 @@ mystique_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr += 16; } +static uint8_t +mystique_tvp3026_gpio_read(uint8_t cntl, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + uint8_t ret = 0xff; + if (!i2c_gpio_get_scl(mystique->i2c_ddc)) + ret &= ~0x10; + if (!i2c_gpio_get_sda(mystique->i2c_ddc)) + ret &= ~0x04; + return ret; +} + +static void +mystique_tvp3026_gpio_write(uint8_t cntl, uint8_t data, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + i2c_gpio_set(mystique->i2c_ddc, !(cntl & 0x10) || (data & 0x10), !(cntl & 0x04) || (data & 0x04)); +} + static uint8_t mystique_pci_read(UNUSED(int func), int addr, void *priv) { @@ -5625,6 +5646,7 @@ mystique_init(const device_t *info) mystique->svga.ramdac = device_add(&tvp3026_ramdac_device); mystique->svga.clock_gen = mystique->svga.ramdac; mystique->svga.getclock = tvp3026_getclock; + tvp3026_gpio(mystique_tvp3026_gpio_read, mystique_tvp3026_gpio_write, mystique, mystique->svga.ramdac); } else { video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20, diff --git a/src/video/vid_tvp3026_ramdac.c b/src/video/vid_tvp3026_ramdac.c index 15215c45d..611527a35 100644 --- a/src/video/vid_tvp3026_ramdac.c +++ b/src/video/vid_tvp3026_ramdac.c @@ -55,6 +55,11 @@ typedef struct tvp3026_ramdac_t { uint8_t n; uint8_t p; } pix, mem, loop; + uint8_t gpio_cntl; + uint8_t gpio_data; + uint8_t (*gpio_read)(uint8_t cntl, void *priv); + void (*gpio_write)(uint8_t cntl, uint8_t val, void *priv); + void *gpio_priv; } tvp3026_ramdac_t; static void @@ -211,6 +216,16 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svg ramdac->misc = val; svga->ramdac_type = (val & 0x08) ? RAMDAC_8BIT : RAMDAC_6BIT; break; + case 0x2a: /* General-Purpose I/O Control */ + ramdac->gpio_cntl = val; + if (ramdac->gpio_write) + ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv); + break; + case 0x2b: /* General-Purpose I/O Data */ + ramdac->gpio_data = val; + if (ramdac->gpio_write) + ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv); + break; case 0x2c: /* PLL Address */ ramdac->pll_addr = val; break; @@ -389,6 +404,16 @@ tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga) case 0x1e: /* Miscellaneous Control */ temp = ramdac->misc; break; + case 0x2a: /* General-Purpose I/O Control */ + temp = ramdac->gpio_cntl; + break; + case 0x2b: /* General-Purpose I/O Data */ + if (ramdac->gpio_read) { + temp = 0xe0 | (ramdac->gpio_cntl & 0x1f); /* keep upper bits untouched */ + ramdac->gpio_data = (ramdac->gpio_data & temp) | (ramdac->gpio_read(ramdac->gpio_cntl, ramdac->gpio_priv) & ~temp); + } + temp = ramdac->gpio_data; + break; case 0x2c: /* PLL Address */ temp = ramdac->pll_addr; break; @@ -630,6 +655,18 @@ tvp3026_getclock(int clock, void *priv) return f_pll; } +void +tvp3026_gpio(uint8_t (*read)(uint8_t cntl, void *priv), + void (*write)(uint8_t cntl, uint8_t val, void *priv), + void *cb_priv, void *priv) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + + ramdac->gpio_read = read; + ramdac->gpio_write = write; + ramdac->gpio_priv = cb_priv; +} + void * tvp3026_ramdac_init(const device_t *info) {