From 6a097f78b496e9bc84a32e902e8d05fffa78e5d2 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 25 Nov 2020 19:10:15 -0300 Subject: [PATCH] Add high refresh rate and 1366x768 modes to DDC --- src/video/vid_ddc.c | 88 ++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index afe80b9ef..64483feec 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -25,10 +25,29 @@ #include <86box/i2c.h> -#define STD_TIMING(idx, width, aspect_ratio) do { \ - edid->standard_timings[idx].horiz_pixels = ((width) >> 3) - 31; \ - edid->standard_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \ - } while (0) +#define PIXEL_MM(px) ((uint16_t) (((px) * 25.4) / 96)) +#define STANDARD_TIMING(slot, width, aspect_ratio, refresh) do { \ + edid->slot.horiz_pixels = ((width) >> 3) - 31; \ + edid->slot.aspect_ratio_refresh_rate = ((aspect_ratio) << 6) | ((refresh) - 60); \ + } while (0) +#define DETAILED_TIMING(slot, clk, width, height, hblank, vblank, hfp, hsp, vfp, vsp) do { \ + edid->slot.pixel_clock_lsb = ((clk) / 10) & 0xff; \ + edid->slot.pixel_clock_msb = ((clk) / 10) >> 8; \ + edid->slot.h_active_lsb = (width) & 0xff; \ + edid->slot.h_blank_lsb = (hblank) & 0xff; \ + edid->slot.h_active_blank_msb = (((width) >> 4) & 0xf0) | (((hblank) >> 8) & 0x0f); \ + edid->slot.v_active_lsb = (height) & 0xff; \ + edid->slot.v_blank_lsb = (vblank) & 0xff; \ + edid->slot.v_active_blank_msb = (((height) >> 4) & 0xf0) | (((vblank) >> 8) & 0x0f); \ + edid->slot.h_front_porch_lsb = (hfp) & 0xff; \ + edid->slot.h_sync_pulse_lsb = (hsp) & 0xff; \ + edid->slot.v_front_porch_sync_pulse_lsb = (((vfp) & 0x0f) << 4) | ((vsp) & 0x0f); \ + edid->slot.hv_front_porch_sync_pulse_msb = (((hfp) >> 2) & 0x03) | (((hsp) >> 4) & 0x03) | (((vfp) >> 6) & 0x03) | (((vsp) >> 8) & 0x03); \ + edid->slot.h_size_lsb = PIXEL_MM(width) & 0xff; \ + edid->slot.v_size_lsb = PIXEL_MM(height) & 0xff; \ + edid->slot.hv_size_msb = ((PIXEL_MM(width) >> 4) & 0xf0) | ((PIXEL_MM(height) >> 8) & 0x0f); \ + } while (0) + enum { STD_ASPECT_16_10 = 0x0, @@ -112,6 +131,7 @@ void * ddc_init(void *i2c) { edid_t *edid = malloc(sizeof(edid_t)); + uint8_t *edid_bytes = (uint8_t *) edid; memset(edid, 0, sizeof(edid_t)); memset(&edid->magic[1], 0xff, sizeof(edid->magic) - 2); @@ -140,34 +160,23 @@ ddc_init(void *i2c) memset(&edid->established_timings, 0xff, sizeof(edid->established_timings)); /* all enabled */ -#if 0 - memset(&edid->standard_timings, 0x01, sizeof(edid->standard_timings)); /* pad unused entries */ -#endif - 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, 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 */ + /* 60 Hz timings */ + STANDARD_TIMING(standard_timings[0], 1280, STD_ASPECT_16_9, 60); /* 1280x720 */ + STANDARD_TIMING(standard_timings[1], 1280, STD_ASPECT_16_10, 60); /* 1280x800 */ + STANDARD_TIMING(standard_timings[2], 1366, STD_ASPECT_16_9, 60); /* 1360x768 (closest to 1366x768) */ + STANDARD_TIMING(standard_timings[3], 1440, STD_ASPECT_16_10, 60); /* 1440x900 */ + STANDARD_TIMING(standard_timings[4], 1600, STD_ASPECT_16_9, 60); /* 1600x900 */ + STANDARD_TIMING(standard_timings[5], 1680, STD_ASPECT_16_10, 60); /* 1680x1050 */ + STANDARD_TIMING(standard_timings[6], 1920, STD_ASPECT_16_9, 60); /* 1920x1080 */ + STANDARD_TIMING(standard_timings[7], 2048, STD_ASPECT_4_3, 60); /* 2048x1536 */ - /* Detailed timings for the preferred mode of 800x600 @ 60 Hz */ - edid->detailed_timings[0].pixel_clock_lsb = 4000 & 0xff; /* 40.000 MHz */ - edid->detailed_timings[0].pixel_clock_msb = 4000 >> 8; - 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 timing for the preferred mode of 800x600 @ 60 Hz */ + DETAILED_TIMING(detailed_timings[0], 40000, 800, 600, 256, 28, 40, 128, 1, 4); 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[1].established_timings3.timings[5] &= 0xf0; /* reserved bits */ 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) */ @@ -182,14 +191,37 @@ ddc_init(void *i2c) 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_bytes = (uint8_t *) edid; + edid->extensions = 1; for (uint8_t c = 0; c < 127; c++) edid->checksum += edid_bytes[c]; edid->checksum = 256 - edid->checksum; + + edid->ext_tag = 0x02; + edid->ext_rev = 0x03; + edid->ext_dtd_offset = 0x04; + + /* Detailed timing for 1366x768 */ + DETAILED_TIMING(ext_detailed_timings[0], 85500, 1366, 768, 426, 30, 70, 143, 3, 3); + + /* High refresh rate timings (VGA is limited to 85 Hz) */ + edid->ext_descriptors[1].tag = 0xfa; /* standard timing identifiers */ +#define ext_standard_timings0 ext_descriptors[1].ext_standard_timings.timings + STANDARD_TIMING(ext_standard_timings0[0], 640, STD_ASPECT_4_3, 90); /* 640x480 @ 90 Hz */ + STANDARD_TIMING(ext_standard_timings0[1], 640, STD_ASPECT_4_3, 120); /* 640x480 @ 120 Hz */ + STANDARD_TIMING(ext_standard_timings0[2], 800, STD_ASPECT_4_3, 90); /* 800x600 @ 90 Hz */ + STANDARD_TIMING(ext_standard_timings0[3], 800, STD_ASPECT_4_3, 120); /* 800x600 @ 120 Hz */ + STANDARD_TIMING(ext_standard_timings0[4], 1024, STD_ASPECT_4_3, 90); /* 1024x768 @ 90 Hz */ + STANDARD_TIMING(ext_standard_timings0[5], 1280, STD_ASPECT_5_4, 90); /* 1280x1024 @ 90 Hz */ + edid->ext_descriptors[1].ext_standard_timings.padding = 0x0a; + for (uint8_t c = 128; c < 255; c++) edid->checksum2 += edid_bytes[c]; edid->checksum2 = 256 - edid->checksum2; + FILE *f = fopen("C:\\Users\\Richard\\Desktop\\86boxedid.bin", "wb"); + fwrite(edid_bytes, 1, sizeof(edid_t), f); + fclose(f); + return i2c_eeprom_init(i2c, 0x50, edid_bytes, sizeof(edid_t), 0); }