From 60ccbef127305e7e4221f33e66332a4557350a32 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 16 Sep 2025 23:56:49 -0500 Subject: [PATCH] main: write to pci config registers --- gen/voodoo2_config.py | 24 +++++- dac.h => ics5342.h | 10 +++ main.c | 191 ++++++++++++++++++++++++++++-------------- voodoo2_config.h | 68 +++++---------- voodoo2_config_bits.h | 5 ++ 5 files changed, 185 insertions(+), 113 deletions(-) rename dac.h => ics5342.h (54%) create mode 100644 voodoo2_config_bits.h diff --git a/gen/voodoo2_config.py b/gen/voodoo2_config.py index 954484e..b67b5b3 100644 --- a/gen/voodoo2_config.py +++ b/gen/voodoo2_config.py @@ -1,5 +1,6 @@ import sys from generate import renderer +import string with open(sys.argv[1], 'r') as f: buf = f.read() @@ -54,6 +55,18 @@ def reg_type(length): return "reg32" assert False, length + +def format_name(s): + def do(): + prev_lower = False + for i, c in enumerate(s): + if prev_lower and i > 0 and c in string.ascii_uppercase: + yield "_" + prev_lower = c in string.ascii_lowercase + yield c.upper() + + return "".join(do()) + def render_struct(buf): next_address = 0 reserved_ix = 0 @@ -65,14 +78,19 @@ def render_struct(buf): reserved_ix += 1 length = bits_length(bits) arr = "" if length != 3 else "[3]" - yield f"{reg_type(length)} {register_name}{arr};" + yield f"{reg_type(length)} {format_name(register_name)}{arr};" next_address = addr + length yield "};" yield "" for register_name, addr, bits, description in lines: length = bits_length(bits) arr = "" if length != 3 else "[0]" - yield f"static_assert((offsetof (struct voodoo2_config, {register_name}{arr})) == 0x{addr:02x});" + yield f"static_assert((offsetof (struct voodoo2_config, {format_name(register_name)}{arr})) == 0x{addr:02x});" + +def render_macros(buf): + lines = list(parse_lines(buf)) + for register_name, addr, bits, description in lines: + yield f"#define PCI__CONFIG__{format_name(register_name)} (0x{addr:02x})" def render_all(buf): yield "#pragma once" @@ -82,7 +100,7 @@ def render_all(buf): yield "" yield '#include "reg.h"' yield "" - yield from render_struct(buf) + yield from render_macros(buf) yield "" yield "typedef struct voodoo2_config voodoo2_config;" diff --git a/dac.h b/ics5342.h similarity index 54% rename from dac.h rename to ics5342.h index 849c667..30a47ba 100644 --- a/dac.h +++ b/ics5342.h @@ -18,3 +18,13 @@ #define DAC__PLL_PARAMETER__CLK1_fA_PLL 0x0a #define DAC__PLL_PARAMETER__CLK1_fB_PLL 0x0b #define DAC__PLL_PARAMETER__PLL_CONTROL 0x0e + +#define DAC__COMMAND__COLOR_MODE__MULTIPLEXED_16BIT_PSUEDO_COLOR_WITH_PALETTE (0b0001 << 4) // mode 4 +#define DAC__COMMAND__COLOR_MODE__15BIT_DIRECT_COLOR_WITH_BYPASS (0b0011 << 4) // mode 5 +#define DAC__COMMAND__COLOR_MODE__16BIT_DIRECT_COLOR_WITH_BYPASS (0b0101 << 4) // mode 6 +#define DAC__COMMAND__COLOR_MODE__24BIT_TRUE_COLOR_WITH_BYPASS (0b0111 << 4) // mode 7 +#define DAC__COMMAND__COLOR_MODE__24BIT_PACKED_TRUE_COLOR_WITH_BYPASS (0b1011 << 4) // mode 8 + +#define DAC__PLL_CONTROL__CLK0_SELECT(n) (((n) & 0b111) << 0) +#define DAC__PLL_CONTROL__CLK1_SELECT(n) (((n) & 0b1) << 4) +#define DAC__PLL_CONTROL__ENABLE_INTERNAL_CLOCK_SELECT (1 << 5) diff --git a/main.c b/main.c index 6d3a766..ac3d5c4 100644 --- a/main.c +++ b/main.c @@ -10,53 +10,26 @@ #include "voodoo2.h" #include "voodoo2_bits.h" #include "voodoo2_config.h" -#include "dac.h" +#include "voodoo2_config_bits.h" +#include "ics5342.h" -struct name_int { - const char * name; - uint32_t value; -}; - -void print_registers(struct voodoo2_reg * reg) -{ - const struct name_int registers[] = { - {"status", reg->status}, - {"fbiInit0", reg->fbiInit0}, - {"fbiInit1", reg->fbiInit1}, - {"fbiInit2", reg->fbiInit2}, - {"fbiInit3", reg->fbiInit3}, - {"fbiInit4", reg->fbiInit4}, - {"fbiInit5", reg->fbiInit5}, - {"fbiInit6", reg->fbiInit6}, - {"fbiInit7", reg->fbiInit7}, - // - {"backPorch", reg->backPorch}, - {"videoDimensions", reg->videoDimensions}, - {"hSync", reg->hSync}, - {"vSync", reg->vSync}, - }; - - for (int i = 0; i < (sizeof (registers)) / (sizeof (registers[0])); i++) { - printf("%s %08x\n", registers[i].name, registers[i].value); - } -} - -static inline void wait_graphics_busy(voodoo2_reg * voodoo2) +static inline bool _wait_graphics_busy(voodoo2_reg * voodoo2) { int cnt = 0; for (int i = 0; i < 4096; i++) { if (voodoo2->status & STATUS__GRAPHICS_BUSY) { - cnt += 1; - } else { cnt = 0; + } else { + cnt += 1; } if (cnt >= 3) - return; + return true; } - - assert(!"busy wait timeout"); + return false; } +#define wait_graphics_busy(voodoo2) assert(_wait_graphics_busy(voodoo2)); + static inline void dac_data_read(voodoo2_reg * voodoo2, int data, int rs) @@ -128,40 +101,132 @@ static inline mn_t dac_read_pll_16(voodoo2_reg * voodoo2, return (mn_t){ m, n }; } +uint8_t read_fd_u8(int fd, uint32_t offset) +{ + off_t ret = lseek(fd, offset, SEEK_SET); + assert(ret == offset); + uint8_t value; + ssize_t len = read(fd, &value, 1); + assert(len == 1); + return value; +} + +uint16_t read_fd_u16(int fd, uint32_t offset) +{ + off_t ret = lseek(fd, offset, SEEK_SET); + assert(ret == offset); + uint16_t value; + ssize_t len = read(fd, &value, 2); + assert(len == 2); + return value; +} + +void write_fd_u8(int fd, uint32_t offset, uint8_t value) +{ + off_t ret = lseek(fd, offset, SEEK_SET); + assert(ret == offset); + ssize_t len = write(fd, &value, 1); + assert(len == 1); +} + +void write_fd_u32(int fd, uint32_t offset, uint32_t value) +{ + off_t ret = lseek(fd, offset, SEEK_SET); + assert(ret == offset); + ssize_t len = write(fd, &value, 4); + assert(len == 4); +} + int main() { const char * config_path = "/sys/bus/pci/devices/0000:02:0a.0/config"; - int fd = open(config_path, O_RDWR | O_SYNC); - assert(fd >= 0); + int config_fd = open(config_path, O_RDWR | O_SYNC); + assert(config_fd >= 0); - uint32_t config_size = (sizeof (struct voodoo2_config)); + uint16_t vendor_id = read_fd_u16(config_fd, PCI__CONFIG__VENDOR_ID); + uint16_t device_id = read_fd_u16(config_fd, PCI__CONFIG__DEVICE_ID); + printf("Vendor ID: %04x\n", vendor_id); + printf("Device ID: %04x\n", device_id); + assert(vendor_id == 0x121a); + assert(device_id == 0x0002); - void * config_base = mmap(0, config_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - assert(config_base != MAP_FAILED); - voodoo2_config * config = (voodoo2_config *)config_base; + //////////////////////////////////////////////////////////////////////// + // PCI enable + //////////////////////////////////////////////////////////////////////// + { + const char * enable_path = "/sys/bus/pci/devices/0000:02:0a.0/enable"; + int enable_fd = open(enable_path, O_RDWR | O_SYNC); + assert(enable_fd >= 0); - printf("Vendor ID: %04x\n", config->Vendor_ID); - printf("Device ID: %04x\n", config->Device_ID); + if (read_fd_u8(enable_fd, 0) == '0') { + write_fd_u8(enable_fd, 0, '1'); // enable + assert(read_fd_u8(enable_fd, 0) != '0'); + } + close(enable_fd); + } - munmap(config_base, config_size); - close(fd); + //////////////////////////////////////////////////////////////////////// + // PCI resource0 + //////////////////////////////////////////////////////////////////////// + const char * resource0_path = "/sys/bus/pci/devices/0000:02:0a.0/resource0"; + int resource0_fd = open(resource0_path, O_RDWR | O_SYNC); + assert(resource0_fd >= 0); + + uint32_t resource0_size = 16 * 1024 * 1024; + void * resource0_base = mmap(0, resource0_size, PROT_READ | PROT_WRITE, MAP_SHARED, resource0_fd, 0); + assert(resource0_base != MAP_FAILED); + + voodoo2_reg * voodoo2 = (voodoo2_reg *)resource0_base; + + int init_enable; + + //////////////////////////////////////////////////////////////////////// + // reset + //////////////////////////////////////////////////////////////////////// + + init_enable + = INIT_ENABLE__ENABLE_WRITES_TO_HARDWARE_REGISTERS; + write_fd_u32(config_fd, PCI__CONFIG__INIT_ENABLE, init_enable); + //wait_graphics_busy(voodoo2); + + voodoo2->fbiInit0 + = FBIINIT0__CHUCK_GRAPHICS_RESET + | FBIINIT0__CHUCK_FIFO_RESET + ; + wait_graphics_busy(voodoo2); + + voodoo2->fbiInit1 + = FBIINIT1__VIDEO_TIMING_RESET + ; + wait_graphics_busy(voodoo2); + + voodoo2->fbiInit2 + = 0; // disable DRAM refresh + wait_graphics_busy(voodoo2); + + //////////////////////////////////////////////////////////////////////// + // DAC initialization + //////////////////////////////////////////////////////////////////////// + + init_enable + = INIT_ENABLE__ENABLE_WRITES_TO_HARDWARE_REGISTERS + | INIT_ENABLE__REMAP_FBIINIT2_FBIINIT3_TO_DACREAD_VIDEOCHECKSUM; + write_fd_u32(config_fd, PCI__CONFIG__INIT_ENABLE, init_enable); + wait_graphics_busy(voodoo2); + + int command = DAC__COMMAND__COLOR_MODE__16BIT_DIRECT_COLOR_WITH_BYPASS; + dac_data_write(voodoo2, command, DAC__RS__COMMAND); + wait_graphics_busy(voodoo2); + dac_data_read(voodoo2, command, DAC__RS__COMMAND); + wait_graphics_busy(voodoo2); + int command_read = voodoo2->fbiInit2 & 0xff; + printf("dac read: DAC__RS__COMMAND: m: %02x\n", command_read); + + //////////////////////////////////////////////////////////////////////// + // cleanup + //////////////////////////////////////////////////////////////////////// + close(config_fd); + close(resource0_fd); return 0; - - /* - const char * filename = "/sys/bus/pci/devices/0000:02:0a.0/resource0"; - - int fd = open(filename, O_RDWR | O_SYNC); - assert(fd >= 0); - - uint32_t map_size = 0x4000; - - void * map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - assert(map_base != MAP_FAILED); - - struct voodoo2_reg * reg = (struct voodoo2_reg *)map_base; - print_registers(reg); - - close(fd); - */ } diff --git a/voodoo2_config.h b/voodoo2_config.h index 2475bd8..2130abd 100644 --- a/voodoo2_config.h +++ b/voodoo2_config.h @@ -5,53 +5,27 @@ #include "reg.h" -struct voodoo2_config { - reg16 Vendor_ID; - reg16 Device_ID; - reg16 Command; - reg16 Status; - reg8 Revision_ID; - reg8 Class_code[3]; - reg8 Cache_line_size; - reg8 Latency_timer; - reg8 Header_type; - reg8 BIST; - reg32 memBaseAddr; - reg8 _reserved0[40]; - reg8 Interrupt_line; - reg8 Interrupt_pin; - reg8 Min_gnt; - reg8 Max_lat; - reg32 initEnable; - reg32 busSnoop0; - reg32 busSnoop1; - reg32 cfgStatus; - reg32 cfgScratch; - reg32 siProcess; -}; - - -static_assert((offsetof (struct voodoo2_config, Vendor_ID)) == 0x00); -static_assert((offsetof (struct voodoo2_config, Device_ID)) == 0x02); -static_assert((offsetof (struct voodoo2_config, Command)) == 0x04); -static_assert((offsetof (struct voodoo2_config, Status)) == 0x06); -static_assert((offsetof (struct voodoo2_config, Revision_ID)) == 0x08); -static_assert((offsetof (struct voodoo2_config, Class_code[0])) == 0x09); -static_assert((offsetof (struct voodoo2_config, Cache_line_size)) == 0x0c); -static_assert((offsetof (struct voodoo2_config, Latency_timer)) == 0x0d); -static_assert((offsetof (struct voodoo2_config, Header_type)) == 0x0e); -static_assert((offsetof (struct voodoo2_config, BIST)) == 0x0f); -static_assert((offsetof (struct voodoo2_config, memBaseAddr)) == 0x10); -static_assert((offsetof (struct voodoo2_config, Interrupt_line)) == 0x3c); -static_assert((offsetof (struct voodoo2_config, Interrupt_pin)) == 0x3d); -static_assert((offsetof (struct voodoo2_config, Min_gnt)) == 0x3e); -static_assert((offsetof (struct voodoo2_config, Max_lat)) == 0x3f); -static_assert((offsetof (struct voodoo2_config, initEnable)) == 0x40); -static_assert((offsetof (struct voodoo2_config, busSnoop0)) == 0x44); -static_assert((offsetof (struct voodoo2_config, busSnoop1)) == 0x48); -static_assert((offsetof (struct voodoo2_config, cfgStatus)) == 0x4c); -static_assert((offsetof (struct voodoo2_config, cfgScratch)) == 0x50); -static_assert((offsetof (struct voodoo2_config, siProcess)) == 0x54); +#define PCI__CONFIG__VENDOR_ID (0x00) +#define PCI__CONFIG__DEVICE_ID (0x02) +#define PCI__CONFIG__COMMAND (0x04) +#define PCI__CONFIG__STATUS (0x06) +#define PCI__CONFIG__REVISION_ID (0x08) +#define PCI__CONFIG__CLASS_CODE (0x09) +#define PCI__CONFIG__CACHE_LINE_SIZE (0x0c) +#define PCI__CONFIG__LATENCY_TIMER (0x0d) +#define PCI__CONFIG__HEADER_TYPE (0x0e) +#define PCI__CONFIG__BIST (0x0f) +#define PCI__CONFIG__MEM_BASE_ADDR (0x10) +#define PCI__CONFIG__INTERRUPT_LINE (0x3c) +#define PCI__CONFIG__INTERRUPT_PIN (0x3d) +#define PCI__CONFIG__MIN_GNT (0x3e) +#define PCI__CONFIG__MAX_LAT (0x3f) +#define PCI__CONFIG__INIT_ENABLE (0x40) +#define PCI__CONFIG__BUS_SNOOP0 (0x44) +#define PCI__CONFIG__BUS_SNOOP1 (0x48) +#define PCI__CONFIG__CFG_STATUS (0x4c) +#define PCI__CONFIG__CFG_SCRATCH (0x50) +#define PCI__CONFIG__SI_PROCESS (0x54) typedef struct voodoo2_config voodoo2_config; diff --git a/voodoo2_config_bits.h b/voodoo2_config_bits.h new file mode 100644 index 0000000..0cc90b3 --- /dev/null +++ b/voodoo2_config_bits.h @@ -0,0 +1,5 @@ +#pragma once + +#define INIT_ENABLE__ENABLE_WRITES_TO_HARDWARE_REGISTERS (1 << 0) +#define INIT_ENABLE__ENABLE_WRITES_TO_PCI_FIFO (1 << 1) +#define INIT_ENABLE__REMAP_FBIINIT2_FBIINIT3_TO_DACREAD_VIDEOCHECKSUM (1 << 2)