voodoo/main.c

254 lines
7.2 KiB
C

#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include "voodoo2.h"
#include "voodoo2_bits.h"
#include "voodoo2_config.h"
#include "voodoo2_config_bits.h"
#include "ics5342.h"
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 = 0;
} else {
cnt += 1;
}
if (cnt >= 3)
return true;
}
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)
{
voodoo2->dacData
= DACDATA__WRITE_DATA(data)
| DACDATA__ADDRESS_2_0(rs >> 0)
| DACDATA__READ_COMMAND
| DACDATA__ADDRESS_4_3(rs >> 3)
;
}
static inline void dac_data_write(voodoo2_reg * voodoo2,
int data,
int rs)
{
voodoo2->dacData
= DACDATA__WRITE_DATA(data)
| DACDATA__ADDRESS_2_0(rs >> 0)
| DACDATA__ADDRESS_4_3(rs >> 3)
;
}
static inline void dac_write_pll_8(voodoo2_reg * voodoo2,
int address,
int parameter_m)
{
dac_data_write(voodoo2, address, DAC__RS__PLL_ADDRESS_WRITE);
wait_graphics_busy(voodoo2);
dac_data_write(voodoo2, parameter_m, DAC__RS__PLL_PARAMETER);
wait_graphics_busy(voodoo2);
}
static inline void dac_write_pll_16(voodoo2_reg * voodoo2,
int address,
int parameter_m,
int parameter_n)
{
dac_data_write(voodoo2, address, DAC__RS__PLL_ADDRESS_WRITE);
wait_graphics_busy(voodoo2);
dac_data_write(voodoo2, parameter_m, DAC__RS__PLL_PARAMETER);
wait_graphics_busy(voodoo2);
dac_data_write(voodoo2, parameter_n, DAC__RS__PLL_PARAMETER);
wait_graphics_busy(voodoo2);
}
typedef struct mn {
uint8_t m;
uint8_t n;
} mn_t;
static inline mn_t dac_read_pll_16(voodoo2_reg * voodoo2,
int address)
{
dac_data_write(voodoo2, address, DAC__RS__PLL_ADDRESS_READ);
wait_graphics_busy(voodoo2);
dac_data_read(voodoo2, 0, DAC__RS__PLL_PARAMETER);
wait_graphics_busy(voodoo2);
int m = voodoo2->fbiInit2 & 0xff;
dac_data_read(voodoo2, 0, DAC__RS__PLL_PARAMETER);
wait_graphics_busy(voodoo2);
int n = voodoo2->fbiInit2 & 0xff;
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 config_fd = open(config_path, O_RDWR | O_SYNC);
assert(config_fd >= 0);
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);
////////////////////////////////////////////////////////////////////////
// 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);
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);
}
////////////////////////////////////////////////////////////////////////
// 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);
/*
pixel clock: 40MHz
graphics/memory clock: 44.6MHz
*/
int m = 54;
int n = 67;
dac_write_pll_16(voodoo2, DAC__PLL_PARAMETER__CLK0_f0_PLL, m, n);
mn_t clk0_f0_res = dac_read_pll_16(voodoo2, DAC__PLL_PARAMETER__CLK0_f0_PLL);
printf("dac read: DAC__PLL_PARAMETER__CLK0_f0_PLL: m: %02x n: %02x\n",
clk0_f0_res.m, clk0_f0_res.n);
int pll_control
= DAC__PLL_CONTROL__CLK0_SELECT(0) // f0
| DAC__PLL_CONTROL__CLK1_SELECT(0) // fA
| DAC__PLL_CONTROL__ENABLE_INTERNAL_CLOCK_SELECT;
dac_write_pll_8(voodoo2, DAC__PLL_PARAMETER__PLL_CONTROL, pll_control);
mn_t pll_control_res = dac_read_pll_16(voodoo2, DAC__PLL_PARAMETER__PLL_CONTROL);
printf("dac read: DAC__PLL_PARAMETER__PLL_CONTROL: m: %02x\n",
pll_control_res.m);
////////////////////////////////////////////////////////////////////////
// cleanup
////////////////////////////////////////////////////////////////////////
close(config_fd);
close(resource0_fd);
return 0;
}