Implement plug and play monitor support on Voodoo Banshee & 3.
This commit is contained in:
parent
c9891895da
commit
5eb6f4d168
7 changed files with 343 additions and 3 deletions
|
|
@ -43,7 +43,7 @@ scsi_ibm.c scsi_zip.c serial.c sio.c sis496.c sl82c460.c sound.c sound_ad1848.c
|
|||
sound_azt2316a.c sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \
|
||||
sound_sb.c sound_sb_dsp.c sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c \
|
||||
sst39sf010.c tandy_eeprom.c tandy_rom.c t1000.c t3100e.c timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c \
|
||||
vid_ati18800.c vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_compaq_cga.c vid_ega.c \
|
||||
vid_ati18800.c vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_compaq_cga.c vid_ddc.c vid_ega.c \
|
||||
vid_et4000.c vid_et4000w32.c vid_genius.c vid_hercules.c vid_ht216.c vid_icd2061.c vid_ics2595.c vid_im1024.c \
|
||||
vid_incolor.c vid_mda.c vid_mga.c vid_olivetti_m24.c vid_oti037.c vid_oti067.c vid_paradise.c vid_pc200.c vid_pc1512.c \
|
||||
vid_pc1640.c vid_pcjr.c vid_pgc.c vid_ps1_svga.c vid_s3.c vid_s3_virge.c vid_sdac_ramdac.c vid_sigma.c \
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
|
|||
sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
|
||||
sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \
|
||||
vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \
|
||||
vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \
|
||||
vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ddc.o vid_ega.o vid_et4000.o vid_et4000w32.o \
|
||||
vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \
|
||||
vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
|
||||
vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203
|
|||
sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
|
||||
sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \
|
||||
vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \
|
||||
vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \
|
||||
vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ddc.o vid_ega.o vid_et4000.o vid_et4000w32.o \
|
||||
vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \
|
||||
vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \
|
||||
vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \
|
||||
|
|
|
|||
301
src/vid_ddc.c
Normal file
301
src/vid_ddc.c
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
#include "ibm.h"
|
||||
#include "vid_ddc.h"
|
||||
#include "x86.h"
|
||||
|
||||
static uint8_t edid_data[128] =
|
||||
{
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /*Fixed header pattern*/
|
||||
0x65, 0x40, /*Manufacturer "PCE" - apparently unassigned by UEFI*/
|
||||
0x00, 0x00, /*Product code*/
|
||||
0x12, 0x34, 0x56, 0x78, /*Serial number*/
|
||||
0x01, 9, /*Manufacturer week and year*/
|
||||
0x01, 0x03, /*EDID version (1.3)*/
|
||||
|
||||
0x08, /*Analogue input, separate sync*/
|
||||
34, 0, /*Landscape, 4:3*/
|
||||
0, /*Gamma*/
|
||||
0x08, /*RGB colour*/
|
||||
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /*Chromaticity*/
|
||||
|
||||
0xff, 0xff, 0xff, /*Established timing bitmap*/
|
||||
0x00, 0x00, /*Standard timing information*/
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
|
||||
/*Detailed mode descriptions*/
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, /*No extensions*/
|
||||
0x00
|
||||
};
|
||||
|
||||
/*This should probably be split off into a separate I2C module*/
|
||||
enum
|
||||
{
|
||||
TRANSMITTER_MONITOR = 1,
|
||||
TRANSMITTER_HOST = -1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
I2C_IDLE = 0,
|
||||
I2C_RECEIVE,
|
||||
I2C_RECEIVE_WAIT,
|
||||
I2C_TRANSMIT_START,
|
||||
I2C_TRANSMIT,
|
||||
I2C_ACKNOWLEDGE,
|
||||
I2C_TRANSACKNOWLEDGE,
|
||||
I2C_TRANSMIT_WAIT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROM_IDLE = 0,
|
||||
PROM_RECEIVEADDR,
|
||||
PROM_RECEIVEDATA,
|
||||
PROM_SENDDATA,
|
||||
PROM_INVALID
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int clock, data;
|
||||
int state;
|
||||
int last_data;
|
||||
int pos;
|
||||
int transmit;
|
||||
uint8_t byte;
|
||||
} i2c;
|
||||
|
||||
static struct
|
||||
{
|
||||
int state;
|
||||
int addr;
|
||||
int rw;
|
||||
} prom;
|
||||
|
||||
static void prom_stop(void)
|
||||
{
|
||||
// pclog("prom_stop()\n");
|
||||
prom.state = PROM_IDLE;
|
||||
i2c.transmit = TRANSMITTER_HOST;
|
||||
}
|
||||
|
||||
static void prom_next_byte(void)
|
||||
{
|
||||
// pclog("prom_next_byte(%d)\n", prom.addr);
|
||||
i2c.byte = edid_data[(prom.addr++) & 0x7F];
|
||||
}
|
||||
|
||||
static void prom_write(uint8_t byte)
|
||||
{
|
||||
// pclog("prom_write: byte=%02x\n", byte);
|
||||
switch (prom.state)
|
||||
{
|
||||
case PROM_IDLE:
|
||||
if ((byte & 0xfe) != 0xa0)
|
||||
{
|
||||
// pclog("I2C address not PROM\n");
|
||||
prom.state = PROM_INVALID;
|
||||
break;
|
||||
}
|
||||
prom.rw = byte & 1;
|
||||
if (prom.rw)
|
||||
{
|
||||
prom.state = PROM_SENDDATA;
|
||||
i2c.transmit = TRANSMITTER_MONITOR;
|
||||
i2c.byte = edid_data[(prom.addr++) & 0x7F];
|
||||
// pclog("PROM - %02X from %02X\n",i2c.byte, prom.addr-1);
|
||||
// pclog("Transmitter now PROM\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
prom.state = PROM_RECEIVEADDR;
|
||||
i2c.transmit = TRANSMITTER_HOST;
|
||||
}
|
||||
// pclog("PROM R/W=%i\n",promrw);
|
||||
return;
|
||||
|
||||
case PROM_RECEIVEADDR:
|
||||
// pclog("PROM addr=%02X\n",byte);
|
||||
prom.addr = byte;
|
||||
if (prom.rw)
|
||||
prom.state = PROM_SENDDATA;
|
||||
else
|
||||
prom.state = PROM_RECEIVEDATA;
|
||||
break;
|
||||
|
||||
case PROM_RECEIVEDATA:
|
||||
// pclog("PROM write %02X %02X\n",promaddr,byte);
|
||||
break;
|
||||
|
||||
case PROM_SENDDATA:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ddc_i2c_change(int new_clock, int new_data)
|
||||
{
|
||||
// pclog("I2C update clock %i->%i data %i->%i state %i\n",i2c.clock,new_clock,i2c.last_data,new_data,i2c.state);
|
||||
switch (i2c.state)
|
||||
{
|
||||
case I2C_IDLE:
|
||||
if (i2c.clock && new_clock)
|
||||
{
|
||||
if (i2c.last_data && !new_data) /*Start bit*/
|
||||
{
|
||||
// pclog("Start bit received\n");
|
||||
i2c.state = I2C_RECEIVE;
|
||||
i2c.pos = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_RECEIVE_WAIT:
|
||||
if (!i2c.clock && new_clock)
|
||||
i2c.state = I2C_RECEIVE;
|
||||
case I2C_RECEIVE:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
i2c.byte <<= 1;
|
||||
if (new_data)
|
||||
i2c.byte |= 1;
|
||||
else
|
||||
i2c.byte &= 0xFE;
|
||||
i2c.pos++;
|
||||
if (i2c.pos == 8)
|
||||
{
|
||||
prom_write(i2c.byte);
|
||||
i2c.state = I2C_ACKNOWLEDGE;
|
||||
}
|
||||
}
|
||||
else if (i2c.clock && new_clock && new_data && !i2c.last_data) /*Stop bit*/
|
||||
{
|
||||
// pclog("Stop bit received\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
else if (i2c.clock && new_clock && !new_data && i2c.last_data) /*Start bit*/
|
||||
{
|
||||
// pclog("Start bit received\n");
|
||||
i2c.pos = 0;
|
||||
prom.state = PROM_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_ACKNOWLEDGE:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
// pclog("Acknowledging transfer\n");
|
||||
new_data = 0;
|
||||
i2c.pos = 0;
|
||||
if (i2c.transmit == TRANSMITTER_HOST)
|
||||
i2c.state = I2C_RECEIVE_WAIT;
|
||||
else
|
||||
i2c.state = I2C_TRANSMIT;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_TRANSACKNOWLEDGE:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
if (new_data) /*It's not acknowledged - must be end of transfer*/
|
||||
{
|
||||
// pclog("End of transfer\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
else /*Next byte to transfer*/
|
||||
{
|
||||
i2c.state = I2C_TRANSMIT_START;
|
||||
prom_next_byte();
|
||||
i2c.pos = 0;
|
||||
// pclog("Next byte - %02X\n",i2c.byte);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_TRANSMIT_WAIT:
|
||||
if (i2c.clock && new_clock)
|
||||
{
|
||||
if (i2c.last_data && !new_data) /*Start bit*/
|
||||
{
|
||||
prom_next_byte();
|
||||
i2c.pos = 0;
|
||||
// pclog("Next byte - %02X\n",i2c.byte);
|
||||
}
|
||||
if (!i2c.last_data && new_data) /*Stop bit*/
|
||||
{
|
||||
// pclog("Stop bit received\n");
|
||||
i2c.state = I2C_IDLE;
|
||||
prom_stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_TRANSMIT_START:
|
||||
if (!i2c.clock && new_clock)
|
||||
i2c.state = I2C_TRANSMIT;
|
||||
case I2C_TRANSMIT:
|
||||
if (!i2c.clock && new_clock)
|
||||
{
|
||||
i2c.clock = new_clock;
|
||||
// if (!i2c.pos)
|
||||
// pclog("Transmit byte %02x\n", i2c.byte);
|
||||
i2c.data = new_data = i2c.byte & 0x80;
|
||||
// pclog("Transmit bit %i %i\n", i2c.byte, i2c.pos);
|
||||
i2c.byte <<= 1;
|
||||
i2c.pos++;
|
||||
return;
|
||||
}
|
||||
if (i2c.clock && !new_clock && i2c.pos == 8)
|
||||
{
|
||||
i2c.state = I2C_TRANSACKNOWLEDGE;
|
||||
// pclog("Acknowledge mode\n");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if (!i2c.clock && new_clock)
|
||||
i2c.data = new_data;
|
||||
i2c.last_data = new_data;
|
||||
i2c.clock = new_clock;
|
||||
}
|
||||
|
||||
int ddc_read_clock(void)
|
||||
{
|
||||
return i2c.clock;
|
||||
}
|
||||
int ddc_read_data(void)
|
||||
{
|
||||
if (i2c.state == I2C_TRANSMIT || i2c.state == I2C_ACKNOWLEDGE)
|
||||
return i2c.data;
|
||||
if (i2c.state == I2C_RECEIVE_WAIT)
|
||||
return 0; /*ACK*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ddc_init(void)
|
||||
{
|
||||
int c;
|
||||
uint8_t checksum = 0;
|
||||
|
||||
for (c = 0; c < 127; c++)
|
||||
checksum += edid_data[c];
|
||||
edid_data[127] = 256 - checksum;
|
||||
}
|
||||
4
src/vid_ddc.h
Normal file
4
src/vid_ddc.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
void ddc_init(void);
|
||||
void ddc_i2c_change(int new_clock, int new_data);
|
||||
int ddc_read_clock(void);
|
||||
int ddc_read_data(void);
|
||||
BIN
src/vid_ddc.o
Normal file
BIN
src/vid_ddc.o
Normal file
Binary file not shown.
|
|
@ -7,6 +7,7 @@
|
|||
#include "rom.h"
|
||||
#include "thread.h"
|
||||
#include "video.h"
|
||||
#include "vid_ddc.h"
|
||||
#include "vid_svga.h"
|
||||
#include "vid_svga_render.h"
|
||||
#include "vid_voodoo_banshee.h"
|
||||
|
|
@ -58,6 +59,7 @@ typedef struct banshee_t
|
|||
uint32_t vidDesktopStartAddr;
|
||||
uint32_t vidProcCfg;
|
||||
uint32_t vidScreenSize;
|
||||
uint32_t vidSerialParallelPort;
|
||||
|
||||
int overlay_pix_fmt;
|
||||
|
||||
|
|
@ -110,6 +112,7 @@ enum
|
|||
Video_hwCurLoc = 0x64,
|
||||
Video_hwCurC0 = 0x68,
|
||||
Video_hwCurC1 = 0x6c,
|
||||
Video_vidSerialParallelPort = 0x78,
|
||||
Video_vidScreenSize = 0x98,
|
||||
Video_vidOverlayStartCoords = 0x9c,
|
||||
Video_vidOverlayEndScreenCoords = 0xa0,
|
||||
|
|
@ -180,6 +183,14 @@ enum
|
|||
#define PIX_FORMAT_RGB24 2
|
||||
#define PIX_FORMAT_RGB32 3
|
||||
|
||||
#define VIDSERIAL_DDC_DCK_W (1 << 19)
|
||||
#define VIDSERIAL_DDC_DDA_W (1 << 20)
|
||||
#define VIDSERIAL_DDC_DCK_R (1 << 21)
|
||||
#define VIDSERIAL_DDC_DDA_R (1 << 22)
|
||||
#define VIDSERIAL_I2C_SCK_W (1 << 24)
|
||||
#define VIDSERIAL_I2C_SDA_W (1 << 25)
|
||||
#define VIDSERIAL_I2C_SCK_R (1 << 26)
|
||||
#define VIDSERIAL_I2C_SDA_R (1 << 27)
|
||||
|
||||
static uint32_t banshee_status(banshee_t *banshee);
|
||||
|
||||
|
|
@ -596,6 +607,12 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
|
|||
banshee->hwCurC1 = val;
|
||||
break;
|
||||
|
||||
case Video_vidSerialParallelPort:
|
||||
banshee->vidSerialParallelPort = val;
|
||||
// pclog("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc);
|
||||
ddc_i2c_change((val & VIDSERIAL_DDC_DCK_W) ? 1 : 0, (val & VIDSERIAL_DDC_DDA_W) ? 1 : 0);
|
||||
break;
|
||||
|
||||
case Video_vidScreenSize:
|
||||
banshee->vidScreenSize = val;
|
||||
voodoo->h_disp = (val & 0xfff) + 1;
|
||||
|
|
@ -824,6 +841,20 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p)
|
|||
ret = banshee->hwCurC1;
|
||||
break;
|
||||
|
||||
case Video_vidSerialParallelPort:
|
||||
ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R);
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && ddc_read_clock())
|
||||
ret |= VIDSERIAL_DDC_DCK_R;
|
||||
if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && ddc_read_data())
|
||||
ret |= VIDSERIAL_DDC_DDA_R;
|
||||
ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R);
|
||||
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W)
|
||||
ret |= VIDSERIAL_I2C_SCK_R;
|
||||
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W)
|
||||
ret |= VIDSERIAL_I2C_SDA_R;
|
||||
// pclog("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc);
|
||||
break;
|
||||
|
||||
case Video_vidScreenSize:
|
||||
ret = banshee->vidScreenSize;
|
||||
break;
|
||||
|
|
@ -2169,6 +2200,10 @@ static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_t
|
|||
banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram;
|
||||
banshee->voodoo->texture_mask = banshee->svga.vram_mask;
|
||||
|
||||
banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W;
|
||||
|
||||
ddc_init();
|
||||
|
||||
return banshee;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue