I2C overhaul part 7: S3 Trio and Cirrus Logic

This commit is contained in:
RichardG867
2020-11-25 00:16:42 -03:00
parent 315e3e8d11
commit 64249d50a3
9 changed files with 194 additions and 95 deletions

View File

@@ -33,6 +33,8 @@
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/video.h>
#include <86box/i2c.h>
#include <86box/vid_ddc.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
@@ -208,6 +210,8 @@ typedef struct gd54xx_t
uint32_t extpallook[256];
PALETTE extpal;
void *i2c, *ddc;
} gd54xx_t;
@@ -355,6 +359,10 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p)
if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429)
gd54xx->unlocked = (svga->seqregs[6] == 0x12);
break;
case 0x08:
if (gd54xx->i2c)
i2c_gpio_set(gd54xx->i2c, !!(val & 0x01), !!(val & 0x02));
break;
case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */
gd54xx->vclk_n[svga->seqaddr-0x0b] = val;
break;
@@ -697,6 +705,15 @@ gd54xx_in(uint16_t addr, void *p)
case 6:
ret = svga->seqregs[6];
break;
case 0x08:
if (gd54xx->i2c) {
ret &= 0x7b;
if (i2c_gpio_get_scl(gd54xx->i2c))
ret |= 0x04;
if (i2c_gpio_get_sda(gd54xx->i2c))
ret |= 0x80;
}
break;
case 0x0b: case 0x0c: case 0x0d: case 0x0e:
ret = gd54xx->vclk_n[svga->seqaddr-0x0b];
break;
@@ -3252,6 +3269,11 @@ static void
mca_add(gd5428_mca_read, gd5428_mca_write, gd5428_mca_feedb, NULL, gd54xx);
}
if (gd54xx_is_5434(svga)) {
gd54xx->i2c = i2c_gpio_init("ddc_cl54xx");
gd54xx->ddc = ddc_init(i2c_gpio_get_bus(gd54xx->i2c));
}
return gd54xx;
}
@@ -3359,6 +3381,11 @@ gd54xx_close(void *p)
gd54xx_t *gd54xx = (gd54xx_t *)p;
svga_close(&gd54xx->svga);
if (gd54xx->i2c) {
ddc_close(gd54xx->ddc);
i2c_gpio_close(gd54xx->i2c);
}
free(gd54xx);
}

View File

@@ -26,8 +26,8 @@
#define STD_TIMING(idx, width, aspect_ratio) do { \
edid.std_timings[idx].horiz_pixels = ((width) / 8) - 31; \
edid.std_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \
edid->standard_timings[idx].horiz_pixels = ((width) / 8) - 31; \
edid->standard_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \
} while (0)
enum {
@@ -39,7 +39,7 @@ enum {
typedef struct {
uint8_t horiz_pixels, aspect_ratio_refresh_rate;
} edid_std_timing_t;
} edid_standard_timing_t;
typedef struct {
uint8_t pixel_clock_lsb, pixel_clock_msb, h_active_lsb, h_blank_lsb,
@@ -78,7 +78,7 @@ typedef struct {
} edid_cvt_timings_t;
typedef struct {
uint8_t magic[2], reserved, type, range_limit_offsets;
uint8_t magic[2], reserved, tag, range_limit_offsets;
union {
char ascii[13];
edid_range_limits_t range_limits;
@@ -91,99 +91,111 @@ typedef struct {
uint8_t magic[8], mfg[2], mfg_product[2], serial[4], mfg_week, mfg_year,
edid_version, edid_rev;
uint8_t input_params, horiz_size, vert_size, gamma, features;
uint8_t chromaticity[10], established_timings[3];
edid_std_timing_t std_timings[8];
uint8_t red_green_lsb, blue_white_lsb, red_x_msb, red_y_msb, green_x_msb,
green_y_msb, blue_x_msb, blue_y_msb, white_x_msb, white_y_msb;
uint8_t established_timings[3];
edid_standard_timing_t standard_timings[8];
union {
edid_detailed_timing_t detailed_timings[4];
edid_descriptor_t descriptors[4];
};
uint8_t extensions, checksum;
uint8_t ext_tag, ext_rev, ext_dtd_offset, ext_native_dtds;
union {
edid_detailed_timing_t ext_detailed_timings[6];
edid_descriptor_t ext_descriptors[6];
};
uint8_t padding[15], checksum2;
} edid_t;
static edid_t edid;
void *
ddc_init(void *i2c)
{
memset(&edid.magic[1], 0xff, sizeof(edid.magic) - 2);
edid.magic[0] = edid.magic[7] = 0x00;
edid_t *edid = malloc(sizeof(edid_t));
memset(edid, 0, sizeof(edid_t));
edid.mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */
edid.mfg[1] = 0xf8;
edid.mfg_week = 48;
edid.mfg_year = 2020 - 1990;
edid.edid_version = 0x01;
edid.edid_rev = 0x03; /* EDID 1.3 */
memset(&edid->magic[1], 0xff, sizeof(edid->magic) - 2);
edid.input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */
edid.horiz_size = ((4.0 / 3.0) * 100) - 99; /* landscape 4:3 */
edid.features = 0x09; /* RGB color; CVT */
edid->mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */
edid->mfg[1] = 0xf8;
edid->mfg_week = 48;
edid->mfg_year = 2020 - 1990;
edid->edid_version = 0x01;
edid->edid_rev = 0x04; /* EDID 1.4 */
edid.chromaticity[0] = 0x81;
edid.chromaticity[1] = 0xf1;
edid.chromaticity[2] = 0xa3;
edid.chromaticity[3] = 0x57;
edid.chromaticity[4] = 0x53;
edid.chromaticity[5] = 0x9f;
edid.chromaticity[6] = 0x27;
edid.chromaticity[7] = 0x0a;
edid.chromaticity[8] = 0x50;
edid.chromaticity[9] = 0x00;
edid->input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */
edid->horiz_size = ((4.0 / 3.0) * 100) - 99; /* landscape 4:3 */
edid->features = 0x09; /* RGB color; GTF/CVT */
memset(&edid.established_timings, 0xff, sizeof(edid.established_timings)); /* all enabled */
edid->red_green_lsb = 0x81;
edid->blue_white_lsb = 0xf1;
edid->red_x_msb = 0xa3;
edid->red_y_msb = 0x57;
edid->green_x_msb = 0x53;
edid->green_y_msb = 0x9f;
edid->blue_x_msb = 0x27;
edid->blue_y_msb = 0x0a;
edid->white_x_msb = 0x50;
edid->white_y_msb = 0x00;
memset(&edid.std_timings, 0x01, sizeof(edid.std_timings)); /* pad unused entries with 0x01 */
STD_TIMING(0, 800, STD_ASPECT_4_3); /* 800x600 (preferred) */
STD_TIMING(1, 1280, STD_ASPECT_16_9); /* 1280x720 */
memset(&edid->established_timings, 0xff, sizeof(edid->established_timings)); /* all enabled */
memset(&edid->standard_timings, 0x01, sizeof(edid->standard_timings)); /* pad unused entries */
STD_TIMING(0, 1280, STD_ASPECT_16_9); /* 1280x720 */
STD_TIMING(1, 1280, STD_ASPECT_16_10); /* 1280x800 */
STD_TIMING(2, 1366, STD_ASPECT_16_9); /* 1360x768 (closest to 1366x768) */
STD_TIMING(3, 1600, STD_ASPECT_16_9); /* 1600x900 */
STD_TIMING(4, 1920, STD_ASPECT_16_9); /* 1920x1080 */
STD_TIMING(5, 2048, STD_ASPECT_4_3); /* 2048x1536 */
STD_TIMING(3, 1440, STD_ASPECT_16_10); /* 1440x900 */
STD_TIMING(4, 1600, STD_ASPECT_16_9); /* 1600x900 */
STD_TIMING(5, 1680, STD_ASPECT_16_10); /* 1680x1050 */
STD_TIMING(6, 1920, STD_ASPECT_16_9); /* 1920x1080 */
STD_TIMING(7, 2048, STD_ASPECT_4_3); /* 2048x1536 */
/* Detailed timings for the preferred resolution of 800x600 */
edid.detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */
edid.detailed_timings[0].pixel_clock_msb = 0x0f;
edid.detailed_timings[0].h_active_lsb = 800 & 0xff;
edid.detailed_timings[0].h_blank_lsb = 256 & 0xff;
edid.detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f);
edid.detailed_timings[0].v_active_lsb = 600 & 0xff;
edid.detailed_timings[0].v_blank_lsb = 28;
edid.detailed_timings[0].v_active_blank_msb = (600 >> 4) & 0xf0;
edid.detailed_timings[0].h_front_porch_lsb = 40;
edid.detailed_timings[0].h_sync_pulse_lsb = 128;
edid.detailed_timings[0].v_front_porch_sync_pulse_lsb = (1 << 4) | 4;
/* Detailed timings for the preferred mode of 800x600 */
edid->detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */
edid->detailed_timings[0].pixel_clock_msb = 0x0f;
edid->detailed_timings[0].h_active_lsb = 800 & 0xff;
edid->detailed_timings[0].h_blank_lsb = 256 & 0xff;
edid->detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f);
edid->detailed_timings[0].v_active_lsb = 600 & 0xff;
edid->detailed_timings[0].v_blank_lsb = 28;
edid->detailed_timings[0].v_active_blank_msb = (600 >> 4) & 0xf0;
edid->detailed_timings[0].h_front_porch_lsb = 40;
edid->detailed_timings[0].h_sync_pulse_lsb = 128;
edid->detailed_timings[0].v_front_porch_sync_pulse_lsb = (1 << 4) | 4;
edid.descriptors[1].type = 0xf7; /* established timings 3 */
edid.descriptors[1].established_timings3.version = 0x10;
memset(&edid.descriptors[1].established_timings3.timings, 0xff, sizeof(edid.descriptors[1].established_timings3.timings)); /* all enabled */
edid->descriptors[1].tag = 0xf7; /* established timings 3 */
edid->descriptors[1].established_timings3.version = 0x0a;
memset(&edid->descriptors[1].established_timings3.timings, 0xff, sizeof(edid->descriptors[1].established_timings3.timings)); /* all enabled */
edid.descriptors[2].type = 0xfc; /* display name */
memcpy(&edid.descriptors[2].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */
edid->descriptors[2].tag = 0xfc; /* display name */
memcpy(&edid->descriptors[2].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */
edid.descriptors[3].type = 0xfd; /* range limits */
edid.descriptors[3].range_limits.min_v_field = 1;
edid.descriptors[3].range_limits.max_v_field = -1;
edid.descriptors[3].range_limits.min_h_line = 1;
edid.descriptors[3].range_limits.max_h_line = -1;
edid.descriptors[3].range_limits.max_pixel_clock = -1;
edid.descriptors[3].range_limits.timing_type = 0x00; /* default GTF */
edid.descriptors[3].range_limits.padding[0] = 0x0a;
memset(&edid.descriptors[3].range_limits.padding[1], 0x20, sizeof(edid.descriptors[3].range_limits.padding) - 1);
edid->descriptors[3].tag = 0xfd; /* range limits */
edid->descriptors[3].range_limits.min_v_field = 1;
edid->descriptors[3].range_limits.max_v_field = -1;
edid->descriptors[3].range_limits.min_h_line = 1;
edid->descriptors[3].range_limits.max_h_line = -1;
edid->descriptors[3].range_limits.max_pixel_clock = -1;
edid->descriptors[3].range_limits.timing_type = 0x00; /* default GTF */
edid->descriptors[3].range_limits.padding[0] = 0x0a;
memset(&edid->descriptors[3].range_limits.padding[1], 0x20, sizeof(edid->descriptors[3].range_limits.padding) - 1);
uint8_t *edid_data = (uint8_t *) &edid;
uint8_t *edid_bytes = (uint8_t *) edid;
for (uint8_t c = 0; c < 127; c++)
edid.checksum += edid_data[c];
edid.checksum = 256 - edid.checksum;
edid->checksum += edid_bytes[c];
edid->checksum = 256 - edid->checksum;
for (uint8_t c = 128; c < 255; c++)
edid->checksum2 += edid_bytes[c];
edid->checksum2 = 256 - edid->checksum2;
return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid), 0);
return i2c_eeprom_init(i2c, 0x50, edid_bytes, sizeof(edid_t), 0);
}
void
ddc_close(void *dev_handle)
ddc_close(void *eeprom)
{
i2c_eeprom_close(dev_handle);
i2c_eeprom_close(eeprom);
}

View File

@@ -502,7 +502,7 @@ typedef struct mystique_t
mutex_t *lock;
} dma;
void *i2c, *ddc;
void *i2c, *i2c_ddc, *ddc;
} mystique_t;
@@ -1023,18 +1023,15 @@ mystique_read_xreg(mystique_t *mystique, int reg)
ret = mystique->xgenioctrl;
break;
case XREG_XGENIODATA:
ret = mystique->xgeniodata;
if (!(mystique->xgenioctrl & 0x08)) {
ret &= 0xf7;
if (i2c_gpio_get_scl(mystique->i2c))
ret |= 0x08;
}
if (!(mystique->xgenioctrl & 0x02)) {
ret &= 0xfd;
if (i2c_gpio_get_sda(mystique->i2c))
ret |= 0x02;
}
ret = mystique->xgeniodata & 0xf0;
if (i2c_gpio_get_scl(mystique->i2c_ddc))
ret |= 0x08;
if (i2c_gpio_get_scl(mystique->i2c))
ret |= 0x04;
if (i2c_gpio_get_sda(mystique->i2c_ddc))
ret |= 0x02;
if (i2c_gpio_get_sda(mystique->i2c))
ret |= 0x01;
break;
case XREG_XSYSPLLM:
@@ -1169,7 +1166,8 @@ mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val)
case XREG_XGENIOCTRL:
mystique->xgenioctrl = val;
i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02));
i2c_gpio_set(mystique->i2c_ddc, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02));
i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x04) || (mystique->xgeniodata & 0x04), !(mystique->xgenioctrl & 0x01) || (mystique->xgeniodata & 0x01));
break;
case XREG_XGENIODATA:
mystique->xgeniodata = val;
@@ -5025,8 +5023,9 @@ mystique_init(const device_t *info)
mystique->svga.vsync_callback = mystique_vsync_callback;
mystique->i2c = i2c_gpio_init("ddc_mga");
mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c));
mystique->i2c = i2c_gpio_init("i2c_mga");
mystique->i2c_ddc = i2c_gpio_init("ddc_mga");
mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c_ddc));
return mystique;
}
@@ -5045,6 +5044,7 @@ mystique_close(void *p)
svga_close(&mystique->svga);
ddc_close(mystique->ddc);
i2c_gpio_close(mystique->i2c_ddc);
i2c_gpio_close(mystique->i2c);
free(mystique);

View File

@@ -30,6 +30,8 @@
#include <86box/rom.h>
#include <86box/plat.h>
#include <86box/video.h>
#include <86box/i2c.h>
#include <86box/vid_ddc.h>
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#include "cpu.h"
@@ -266,6 +268,9 @@ typedef struct s3_t
int translate;
int enable_8514;
volatile int busy, force_busy;
uint8_t serialport;
void *i2c, *ddc;
} s3_t;
#define INT_VSY (1 << 0)
@@ -274,6 +279,11 @@ typedef struct s3_t
#define INT_FIFO_EMP (1 << 3)
#define INT_MASK 0xf
#define SERIAL_PORT_SCW (1 << 0)
#define SERIAL_PORT_SDW (1 << 1)
#define SERIAL_PORT_SCR (1 << 2)
#define SERIAL_PORT_SDR (1 << 3)
static void s3_updatemapping(s3_t *s3);
static void s3_accel_write(uint32_t addr, uint8_t val, void *p);
@@ -1051,6 +1061,10 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val)
s3->accel.advfunc_cntl = val;
s3_updatemapping(s3);
break;
case 0xff20:
s3->serialport = val;
i2c_gpio_set(s3->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW));
break;
default:
s3_accel_out_fifo(s3, addr & 0xffff, val);
break;
@@ -1084,7 +1098,10 @@ s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val)
default:
s3_accel_write_fifo(s3, addr, val);
s3_accel_write_fifo(s3, addr + 1, val >> 8);
break;
break;
case 0xff20:
s3_accel_write_fifo(s3, addr, val);
break;
}
}
} else {
@@ -1233,6 +1250,10 @@ s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val)
s3_updatemapping(s3);
break;
case 0xff20:
s3_accel_write_fifo(s3, addr, val);
break;
default:
s3_accel_write_fifo(s3, addr, val);
s3_accel_write_fifo(s3, addr + 1, val >> 8);
@@ -2900,6 +2921,14 @@ s3_accel_in(uint16_t port, void *p)
else if ((s3->accel.cmd & 0x600) == 0x000 && (s3->accel.cmd & 0x100))
s3_accel_start(1, 1, 0xffffffff, 0xff, s3);
return temp;
case 0xff20: case 0xff21:
temp = s3->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR);
if ((s3->serialport & SERIAL_PORT_SCW) && i2c_gpio_get_scl(s3->i2c))
temp |= SERIAL_PORT_SCR;
if ((s3->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(s3->i2c))
temp |= SERIAL_PORT_SDR;
return temp;
}
return 0xff;
@@ -2976,7 +3005,7 @@ s3_accel_read(uint32_t addr, void *p)
case 0x8504:
return s3->subsys_stat;
case 0x8505:
return s3->subsys_cntl;;
return s3->subsys_cntl;
default:
return s3_accel_in(addr & 0xffff, p);
}
@@ -4662,6 +4691,9 @@ static void *s3_init(const device_t *info)
return NULL;
}
s3->i2c = i2c_gpio_init("ddc_s3");
s3->ddc = ddc_init(i2c_gpio_get_bus(s3->i2c));
return s3;
}
@@ -4755,6 +4787,9 @@ static void s3_close(void *p)
thread_destroy_event(s3->wake_fifo_thread);
thread_destroy_event(s3->fifo_not_full_event);
ddc_close(s3->ddc);
i2c_gpio_close(s3->i2c);
free(s3);
}

View File

@@ -447,7 +447,11 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
return;
if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5))
return;
if (svga->crtcreg >= 0x80)
if ((svga->crtcreg >= 0x80)
#if defined(DEV_BRANCH) && defined(USE_S3TRIO3D2X)
&& !((virge->chip == S3_TRIO3D2X) && (svga->crtcreg == 0xaa))
#endif
)
return;
old = svga->crtc[svga->crtcreg];
svga->crtc[svga->crtcreg] = val;
@@ -550,6 +554,12 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p)
default: svga->bpp = 8; break;
}
break;
#if defined(DEV_BRANCH) && defined(USE_S3TRIO3D2X)
case 0xaa:
i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW));
break;
#endif
}
if (old != val)
{
@@ -607,6 +617,18 @@ static uint8_t s3_virge_in(uint16_t addr, void *p)
case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break;
case 0x69: ret = virge->ma_ext; break;
case 0x6a: ret = virge->bank; break;
#if defined(DEV_BRANCH) && defined(USE_S3TRIO3D2X)
case 0xaa: /* Trio3D DDC */
if (virge->chip == S3_TRIO3D2X) {
ret = svga->crtc[0xaa] & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR);
if ((svga->crtc[0xaa] & SERIAL_PORT_SCW) && i2c_gpio_get_scl(virge->i2c))
ret |= SERIAL_PORT_SCR;
if ((svga->crtc[0xaa] & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c))
ret |= SERIAL_PORT_SDR;
break;
}
/* fall-through */
#endif
default: ret = svga->crtc[svga->crtcreg]; break;
}
break;

View File

@@ -2702,7 +2702,7 @@ static void banshee_force_redraw(void *p)
const device_t voodoo_banshee_device =
{
"Voodoo Banshee PCI (reference)",
"3dfx Voodoo Banshee",
DEVICE_PCI,
0,
banshee_init,
@@ -2716,7 +2716,7 @@ const device_t voodoo_banshee_device =
const device_t creative_voodoo_banshee_device =
{
"Creative Labs 3D Blaster Banshee PCI",
"Creative 3D Blaster Banshee",
DEVICE_PCI,
0,
creative_banshee_init,
@@ -2730,7 +2730,7 @@ const device_t creative_voodoo_banshee_device =
const device_t voodoo_3_2000_device =
{
"Voodoo 3 2000 PCI",
"3dfx Voodoo3 2000",
DEVICE_PCI,
0,
v3_2000_init,
@@ -2744,7 +2744,7 @@ const device_t voodoo_3_2000_device =
const device_t voodoo_3_3000_device =
{
"Voodoo 3 3000 PCI",
"3dfx Voodoo3 3000",
DEVICE_PCI,
0,
v3_3000_init,