150 lines
3.7 KiB
C
150 lines
3.7 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"
|
|
|
|
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)
|
|
{
|
|
int cnt = 0;
|
|
for (int i = 0; i < 4096; i++) {
|
|
if (voodoo2->status & STATUS__GRAPHICS_BUSY) {
|
|
cnt += 1;
|
|
} else {
|
|
cnt = 0;
|
|
}
|
|
if (cnt >= 3)
|
|
return;
|
|
}
|
|
|
|
assert(!"busy wait timeout");
|
|
}
|
|
|
|
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, 0);
|
|
wait_graphics_busy(voodoo2);
|
|
|
|
dac_data_write(voodoo2, parameter_m, DAC__RS__PLL_PARAMETER, 0);
|
|
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, 0);
|
|
wait_graphics_busy(voodoo2);
|
|
|
|
dac_data_write(voodoo2, parameter_m, DAC__RS__PLL_PARAMETER, 0);
|
|
wait_graphics_busy(voodoo2);
|
|
|
|
dac_data_write(voodoo2, parameter_n, DAC__RS__PLL_PARAMETER, 0);
|
|
wait_graphics_busy(voodoo2);
|
|
}
|
|
|
|
typedef struct mn {
|
|
uint8_t m;
|
|
uint8_t n;
|
|
} mn_t;
|
|
|
|
static inline struct mn_t dac_read_16(voodoo2_reg * voodoo,
|
|
int address)
|
|
{
|
|
dac_data_write(base, address, DAC__RS__PLL_ADDRESS_READ);
|
|
wait_graphics_busy(base);
|
|
|
|
dac_data_read(base, 0, DAC__RS__PLL_PARAMETER);
|
|
wait_graphics_busy(base);
|
|
int m = voodoo2->fbiInit2 & 0xff;
|
|
|
|
dac_data_read(base, 0, DAC__RS__PLL_PARAMETER);
|
|
wait_graphics_busy(base);
|
|
int n = voodoo2->fbiInit2 & 0xff;
|
|
|
|
return (struct m_n){ m, n };
|
|
}
|
|
|
|
int main()
|
|
{
|
|
const char * config = "/sys/bus/pci/devices/0000:02:0a.0/config";
|
|
int fd = open(config, O_RDWR | O_SYNC);
|
|
assert(fd >= 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;
|
|
|
|
off_t target_base = 0;
|
|
void * map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target_base);
|
|
assert(map_base != MAP_FAILED);
|
|
|
|
struct voodoo2_reg * reg = (struct voodoo2_reg *)map_base;
|
|
print_registers(reg);
|
|
|
|
close(fd);
|
|
}
|