From ec0cf28d25dfc7c71228d4fd52bb7885db3a7644 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Tue, 31 Dec 2024 19:59:33 +0000 Subject: [PATCH] Implement some basic i2c shit and more SVGA shit, so that the drivers don't magically explode. LOL --- src/include/86box/nv/vid_nv.h | 17 ++++-- src/include/86box/nv/vid_nv3.h | 5 +- src/video/nv/nv3/nv3_core.c | 84 +++++++++++++++++++++++---- src/video/nv/nv3/subsystems/nv3_pmc.c | 2 +- 4 files changed, 90 insertions(+), 18 deletions(-) diff --git a/src/include/86box/nv/vid_nv.h b/src/include/86box/nv/vid_nv.h index 39e9a68d0..06c545fc7 100644 --- a/src/include/86box/nv/vid_nv.h +++ b/src/include/86box/nv/vid_nv.h @@ -28,6 +28,8 @@ //TODO: split this all into nv1, nv3, nv4... +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/timer.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> @@ -68,16 +70,19 @@ void nv_log(const char *fmt, ...); typedef enum nv_bus_generation_e { + // NV1 - Prototype version + nv_bus_vlb = 0, + // NV1 // NV3 - nv_bus_pci = 0, + nv_bus_pci = 1, // NV3 - nv_bus_agp_1x = 1, + nv_bus_agp_1x = 2, // NV3T // NV4 - nv_bus_agp_2x = 2, + nv_bus_agp_2x = 3, } nv_bus_generation; @@ -103,11 +108,13 @@ typedef struct nv_base_s nv_bus_generation bus_generation; // current bus (see nv_bus_generation documentation) uint32_t gpu_revision; // GPU Stepping double pixel_clock_period; // Period in seconds for pixel clock - rivatimer_t* pixel_clock_timer; + rivatimer_t* pixel_clock_timer; // Timer for measuring pixel clock bool pixel_clock_enabled; // Pixel Clock Enabled - stupid crap used to prevent us enabling the timer multiple times double memory_clock_period; // Period in seconds for pixel clock - rivatimer_t* memory_clock_timer; + rivatimer_t* memory_clock_timer; // Timer for measuring memory/gpu clock bool memory_clock_enabled; // Memory Clock Enabled - stupid crap used to prevent us eanbling the timer multiple times + void* i2c; // I2C for monitor EDID + void* ddc; } nv_base_t; #define NV_REG_LIST_END 0xD15EA5E diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index b17423305..5aa0e6c79 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -568,7 +568,10 @@ extern const device_config_t nv3_config[]; #define NV3_CRTC_REGISTER_PIXELMODE_16BPP 0x02 #define NV3_CRTC_REGISTER_PIXELMODE_32BPP 0x03 -#define NV3_CRTC_REGISTER_RMA 0x38 // REAL MODE ACCESS! +#define NV3_CRTC_REGISTER_RL0 0x34 +#define NV3_CRTC_REGISTER_RL1 0x35 +#define NV3_CRTC_REGISTER_RMA 0x38 // REAL MODE ACCESS! +#define NV3_CRTC_REGISTER_I2C 0x3F // where the fuck is GDC? #define NV3_CRTC_BANKED_128K_A0000 0x00 diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index a7caa0b2b..cfbb0c324 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -243,7 +243,7 @@ uint8_t nv3_pci_read(int32_t func, int32_t addr, void* priv) break; case PCI_REG_COMMAND_H: - ret = nv3->pci_config.pci_regs[PCI_REG_COMMAND_H] | NV3_PCI_COMMAND_H_FAST_BACK2BACK; // always enable fast back2back + ret = nv3->pci_config.pci_regs[PCI_REG_COMMAND_H] & NV3_PCI_COMMAND_H_FAST_BACK2BACK; // always enable fast back2back break; // pci status register @@ -447,15 +447,6 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) } } -void nv3_close(void* priv) -{ - rivatimer_destroy(nv3->nvbase.pixel_clock_timer); - rivatimer_destroy(nv3->nvbase.memory_clock_timer); - svga_close(&nv3->nvbase.svga); - free(nv3); - nv3 = NULL; -} - // // SVGA functions @@ -575,6 +566,18 @@ uint8_t nv3_svga_in(uint16_t addr, void* priv) // Support the extended NVIDIA CRTC register range switch (nv3->nvbase.svga.crtcreg) { + case NV3_CRTC_REGISTER_RL0: + ret = nv3->nvbase.svga.displine & 0xFF; + break; + /* Is rl1?*/ + case NV3_CRTC_REGISTER_RL1: + ret = (nv3->nvbase.svga.displine >> 8) & 7; + break; + case NV3_CRTC_REGISTER_I2C: + ret = i2c_gpio_get_sda((nv3->nvbase.i2c) << 3) + | i2c_gpio_get_scl((nv3->nvbase.i2c) << 2); + + break; default: ret = nv3->nvbase.svga.crtc[nv3->nvbase.svga.crtcreg]; } @@ -641,6 +644,8 @@ void nv3_svga_out(uint16_t addr, uint8_t val, void* priv) val = (nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_OVERFLOW] & ~0x10) | (val & 0x10); // set the register value... + uint8_t old_value = nv3->nvbase.svga.crtc[crtcreg]; + nv3->nvbase.svga.crtc[crtcreg] = val; // ...now act on it @@ -664,6 +669,27 @@ void nv3_svga_out(uint16_t addr, uint8_t val, void* priv) case NV3_CRTC_REGISTER_RMA: nv3->pbus.rma.mode = val & NV3_CRTC_REGISTER_RMA_MODE_MAX; break; + case NV3_CRTC_REGISTER_I2C: + uint8_t scl = !!(val & 0x20); + uint8_t sda = !!(val & 0x10); + // Set an I2C GPIO register + i2c_gpio_set(nv3->nvbase.i2c, scl, sda); + break; + } + + /* Recalculate the timings if we actually changed them + Additionally only do it if the value actually changed*/ + if (old_value != val) + { + // Thx to Fuel who basically wrote all the SVGA compatibility code already (although I fixed some issues), because VGA is boring + // and in the words of an ex-Rendition/3dfx/NVIDIA engineer, "VGA was basically an undocumented bundle of steaming you-know-what. + // And it was essential that any cores the PC 3D startups acquired had to work with all the undocumented modes and timing tweaks (mode X, etc.)" + if (nv3->nvbase.svga.crtcreg < 0xE + && nv3->nvbase.svga.crtcreg > 0x10) + { + nv3->nvbase.svga.fullchange = changeframecount; + svga_recalctimings(&nv3->nvbase.svga); + } } break; @@ -937,7 +963,9 @@ void* nv3_init(const device_t *info) nv3_ptimer_init(); // Initialise programmable interval timer nv3_pvideo_init(); // Initialise video overlay engine - nv_log("NV3: Initialising timers...\n"); + nv_log("NV3: Initialising I2C..."); + nv3->nvbase.i2c = i2c_gpio_init("nv3_i2c"); + nv3->nvbase.ddc = ddc_init(i2c_gpio_get_bus(nv3->nvbase.i2c)); return nv3; } @@ -958,6 +986,38 @@ void* nv3_init_agp(const device_t* info) nv3_init(info); } +void nv3_close(void* priv) +{ + // Shut down I2C and the DDC + i2c_gpio_close(nv3->nvbase.i2c); + ddc_close(nv3->nvbase.ddc); + + // Destroy the Rivatimers. (It doesn't matter if they are running.) + rivatimer_destroy(nv3->nvbase.pixel_clock_timer); + rivatimer_destroy(nv3->nvbase.memory_clock_timer); + + // Shut down SVGA + svga_close(&nv3->nvbase.svga); + free(nv3); + nv3 = NULL; +} + +// See if the bios rom is available. +void nv3_available() +{ + return rom_present(NV3_VBIOS_ASUS_V3000_V151) + || rom_present(NV3_VBIOS_DIAMOND_V330_V162) + || rom_present(NV3_VBIOS_ERAZOR_V14700) + || rom_present(NV3_VBIOS_ERAZOR_V15403) + || rom_present(NV3_VBIOS_ERAZOR_V15500) + || rom_present(NV3_VBIOS_STB_V128_V182) + || rom_present(NV3_VBIOS_STB_V128_V182) + || rom_present(NV3T_VBIOS_ASUS_V170) + || rom_present(NV3T_VBIOS_DIAMOND_V330_V182B) + || rom_present(NV3T_VBIOS_REFERENCE_CEK_V171) + || rom_present(NV3T_VBIOS_REFERENCE_CEK_V172); +} + // NV3 (RIVA 128) // PCI // 2MB or 4MB VRAM @@ -971,6 +1031,7 @@ const device_t nv3_device_pci = .close = nv3_close, .speed_changed = nv3_speed_changed, .force_redraw = nv3_force_redraw, + .available = nv3_available, .config = nv3_config, }; @@ -987,5 +1048,6 @@ const device_t nv3_device_agp = .close = nv3_close, .speed_changed = nv3_speed_changed, .force_redraw = nv3_force_redraw, + .available = nv3_available, .config = nv3_config, }; \ No newline at end of file diff --git a/src/video/nv/nv3/subsystems/nv3_pmc.c b/src/video/nv/nv3/subsystems/nv3_pmc.c index d32738a5e..7313a7554 100644 --- a/src/video/nv/nv3/subsystems/nv3_pmc.c +++ b/src/video/nv/nv3/subsystems/nv3_pmc.c @@ -72,7 +72,7 @@ uint32_t nv3_pmc_handle_interrupts(bool send_now) // PGRAPH DMA INTR_EN (there is no DMA engine yet) // PRM Real-Mode Compatibility Interrupts - uint32_t new_intr_value; + uint32_t new_intr_value = 0x00; // set the new interrupt value // PAUDIO not used