diff --git a/.gitignore b/.gitignore index ac215f6..6c7dcd2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,12 @@ *.pyc __pycache__ *.gch +*.o +*.mod +*.ko +*~ +*.symvers +.* +*.cmd +*.order +*.mod.c \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..26c5873 --- /dev/null +++ b/main.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} + +int main() +{ + 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); +} diff --git a/pci/Makefile b/pci/Makefile new file mode 100644 index 0000000..4178392 --- /dev/null +++ b/pci/Makefile @@ -0,0 +1,19 @@ +BINARY := test_pci_module +KERNEL := /lib/modules/$(shell uname -r)/build +ARCH := x86 +C_FLAGS := -Wall +KMOD_DIR := $(shell pwd) + +OBJECTS := main.o + +ccflags-y += $(C_FLAGS) + +obj-m += $(BINARY).o + +$(BINARY)-y := $(OBJECTS) + +$(BINARY).ko: + make -C $(KERNEL) M=$(KMOD_DIR) modules + +clean: + rm -f $(BINARY).ko diff --git a/pci/main.c b/pci/main.c new file mode 100644 index 0000000..690d87b --- /dev/null +++ b/pci/main.c @@ -0,0 +1,548 @@ +#include +#include +#include + +#define VOODOO2 "voodoo2" + +static struct pci_device_id voodoo2_id_table[] = { + { PCI_DEVICE(0x121a, 0x0002) }, + { 0,} +}; + +MODULE_DEVICE_TABLE(pci, voodoo2_id_table); + +static int voodoo2_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void voodoo2_remove(struct pci_dev *pdev); + +/* Module registration structure */ +static struct pci_driver voodoo2 = { + .name = VOODOO2, + .id_table = voodoo2_id_table, + .probe = voodoo2_probe, + .remove = voodoo2_remove +}; + +/* This is a "private" data structure */ +/* You can store there any data that should be passed between module's functions */ +struct voodoo2_priv { + volatile u32 __iomem *hwmem; +}; + +/* */ + +static int __init voodoo2_module_init(void) +{ + return pci_register_driver(&voodoo2); +} + +static void __exit voodoo2_module_exit(void) +{ + pci_unregister_driver(&voodoo2); +} + +void release_device(struct pci_dev *pdev); + +void release_device(struct pci_dev *pdev) +{ + /* Free memory region */ + pci_release_region(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); + /* And disable device */ + pci_disable_device(pdev); +} + +struct name_int { + const char * name; + int offset; +}; + +#define STATUS 0x000 +#define FBIINIT0 0x210 +#define FBIINIT1 0x214 +#define FBIINIT2 0x218 +#define FBIINIT3 0x21c +#define FBIINIT4 0x200 +#define FBIINIT5 0x244 +#define FBIINIT6 0x248 +#define FBIINIT7 0x24c +#define DACDATA 0x22c + +#define LFBMODE 0x114 + +#define BACKPORCH 0x208 +#define VIDEODIMENSIONS 0x20c +#define HSYNC 0x220 +#define VSYNC 0x224 + +const struct name_int registers[] = { + {"status", STATUS}, + {"fbiInit0", FBIINIT0}, + {"fbiInit1", FBIINIT1}, + {"fbiInit2", FBIINIT2}, + {"fbiInit3", FBIINIT3}, + {"fbiInit4", FBIINIT4}, + {"fbiInit5", FBIINIT5}, + {"fbiInit6", FBIINIT6}, + {"fbiInit7", FBIINIT7}, + // + {"backPorch", BACKPORCH}, + {"videoDimensions", VIDEODIMENSIONS}, + {"hSync", HSYNC}, + {"vSync", VSYNC}, +}; + +static inline void dac_data(volatile uint32_t * base, int data, int rs, int read) +{ + int value = 0 + | ((data & 0xff) << 0) + | ((rs & 0b111) << 8) + | ((read & 0b1) << 11); + + //printk(KERN_INFO "DACDATA = %08x\n", value); + base[DACDATA / 4] = value; +} + +#define DAC__RS__PIXEL_ADDRESS_WRITE 0b000 // TDV_GENDAC_WR +#define DAC__RS__PIXEL_ADDRESS_READ 0b011 // TDV_GENDAC_RD +#define DAC__RS__COLOR_VALUE 0b001 // TDV_GENDAC_LUT +#define DAC__RS__PIXEL_MASK 0b010 // TDV_GENDAC_PIXMASK +#define DAC__RS__PLL_ADDRESS_WRITE 0b100 // TDV_GENDAC_PLLWR +#define DAC__RS__PLL_PARAMETER 0b101 // TDV_GENDAC_PLLDATA +#define DAC__RS__COMMAND 0b110 // TDV_GENDAC_CMD +#define DAC__RS__PLL_ADDRESS_READ 0b111 // TDV_GENDAC_PLLRD + +#define CLK0_f0_PLL 0x00 +#define CLK0_f1_PLL 0x01 +#define CLK0_f2_PLL 0x02 +#define CLK0_f3_PLL 0x03 +#define CLK0_f4_PLL 0x04 +#define CLK0_f5_PLL 0x05 +#define CLK0_f6_PLL 0x06 +#define CLK0_f7_PLL 0x07 +#define CLK1_fA_PLL 0x0A +#define CLK1_fB_PLL 0x0B +#define PLL_CONTROL 0x0E + +const struct name_int dac_registers[] = { + {"CLK0_f0_PLL", CLK0_f0_PLL}, + {"CLK0_f1_PLL", CLK0_f1_PLL}, + {"CLK0_f2_PLL", CLK0_f2_PLL}, + {"CLK0_f3_PLL", CLK0_f3_PLL}, + {"CLK0_f4_PLL", CLK0_f4_PLL}, + {"CLK0_f5_PLL", CLK0_f5_PLL}, + {"CLK0_f6_PLL", CLK0_f6_PLL}, + {"CLK0_f7_PLL", CLK0_f7_PLL}, + {"CLK1_fA_PLL", CLK1_fA_PLL}, + {"CLK1_fB_PLL", CLK1_fB_PLL}, + {"PLL_CONTROL", PLL_CONTROL}, +}; + +#define MAXLOOP 4096 + +static void +busy_wait(volatile uint32_t * base) +{ + uint32_t x, cnt; + cnt = 0; + for (x = 0; x < MAXLOOP; x++) { + if (base[STATUS / 4] & (1 << 7)) // busy + cnt = 0; + else + cnt++; + + if (cnt >= 5) /* Voodoo2 specs suggest at least 3 */ + break; + } + + if (x == MAXLOOP) + printk(KERN_INFO "wait timeout\n"); +} + +static inline void dac_write_8(volatile uint32_t * base, int param_address, int m) +{ + dac_data(base, param_address, DAC__RS__PLL_ADDRESS_WRITE, 0); + busy_wait(base); + + dac_data(base, m, DAC__RS__PLL_PARAMETER, 0); + busy_wait(base); +} + +static inline void dac_write_16(volatile uint32_t * base, int param_address, int m, int n) +{ + dac_data(base, param_address, DAC__RS__PLL_ADDRESS_WRITE, 0); + busy_wait(base); + + dac_data(base, m, DAC__RS__PLL_PARAMETER, 0); + busy_wait(base); + + dac_data(base, n, DAC__RS__PLL_PARAMETER, 0); + busy_wait(base); +} + + +struct m_n { + uint8_t m; + uint8_t n; +}; + +static inline struct m_n dac_read_16(volatile uint32_t * base, int param_address) +{ + dac_data(base, param_address, DAC__RS__PLL_ADDRESS_READ, 0); + busy_wait(base); + + dac_data(base, 0, DAC__RS__PLL_PARAMETER, 1); + busy_wait(base); + uint32_t m = base[FBIINIT2 / 4] & 0xff; + + dac_data(base, 0, DAC__RS__PLL_PARAMETER, 1); + busy_wait(base); + uint32_t n = base[FBIINIT2 / 4] & 0xff; + + return (struct m_n){ m, n }; +} + +/* This function is called by the kernel */ +static int voodoo2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int bar, err; + u16 vendor, device; + unsigned long mmio_start, mmio_len; + struct voodoo2_priv *drv_priv; + + /* Let's read data from the PCI device configuration registers */ + pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor); + pci_read_config_word(pdev, PCI_DEVICE_ID, &device); + + printk(KERN_INFO "vid: %04x pid: %04x\n", vendor, device); + + uint32_t init_enable; + init_enable = 0 + | (1 << 2) // enable writes to hardware initialization registers + | (1 << 0); // remap fbiinit2, fbiinit3 to dacread, videochecksum + pci_write_config_dword(pdev, 0x40, init_enable); + pci_read_config_dword(pdev, 0x40, &init_enable); + printk(KERN_INFO "init_enable: %08x\n", init_enable); + + /* Request IO BAR */ + bar = pci_select_bars(pdev, IORESOURCE_MEM); + + /* Enable device memory */ + err = pci_enable_device_mem(pdev); + if (err) { + printk(KERN_INFO "pci_enable_device_mem error\n"); + return err; + } + + /* Request memory region for the BAR */ + err = pci_request_region(pdev, bar, VOODOO2); + if (err) { + printk(KERN_INFO "pci_request_region error\n"); + pci_disable_device(pdev); + return err; + } + + /* Get start and stop memory offsets */ + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + printk(KERN_INFO "mmio_start %p mmio_len %p\n", (void*)mmio_start, (void*)mmio_len); + + /* Allocate memory for the module private data */ + drv_priv = kzalloc(sizeof(struct voodoo2_priv), GFP_KERNEL); + + if (!drv_priv) { + release_device(pdev); + return -ENOMEM; + } + + /* Remap BAR to the local pointer */ + drv_priv->hwmem = ioremap(mmio_start, mmio_len); + if (!drv_priv->hwmem) { + release_device(pdev); + return -EIO; + } + + /* Set module private data */ + /* Now we can access mapped "hwmem" from the any module's function */ + pci_set_drvdata(pdev, drv_priv); + + for (int i = 0; i < (sizeof (registers)) / (sizeof (registers[0])); i++) { + printk(KERN_INFO "%s %08x\n", + registers[i].name, + drv_priv->hwmem[registers[i].offset / 4]); + } + + //return 0; + + init_enable = 0 + | (1 << 0); // enable writes to hardware initialization registers + pci_write_config_dword(pdev, 0x40, init_enable); + busy_wait(drv_priv->hwmem); + + drv_priv->hwmem[FBIINIT1 / 4] = (1 << 8); // 8: Video Timing Reset (0=run, 1=reset). + busy_wait(drv_priv->hwmem); + drv_priv->hwmem[FBIINIT0 / 4] = (1 << 1) // 1: Chuck Graphics Reset + | (1 << 2); // 2: Chuck FIFO Reset + busy_wait(drv_priv->hwmem); + + drv_priv->hwmem[FBIINIT2 / 4] &= (1 << 22); // 22: dram refresh disable + busy_wait(drv_priv->hwmem); + + init_enable = 0 + | (1 << 2) // remap fbiinit2, fbiinit3 to dacread, videochecksum + | (1 << 0); // enable writes to hardware initialization registers + pci_write_config_dword(pdev, 0x40, init_enable); + busy_wait(drv_priv->hwmem); + + for (int i = 0; i < (sizeof (dac_registers)) / (sizeof (dac_registers[0])); i++) { + struct m_n res = dac_read_16(drv_priv->hwmem, dac_registers[i].offset); + printk(KERN_INFO "dac read1: %s: m: %02x n: %02x\n", dac_registers[i].name, res.m, res.n); + } + + /* pixel clock: 40MHz + graphics/memory clock: 44.6MHz + */ + dac_data(drv_priv->hwmem, (0b0101 << 4), DAC__RS__COMMAND, 0); //write + busy_wait(drv_priv->hwmem); + dac_data(drv_priv->hwmem, 0, DAC__RS__COMMAND, 1); //read + busy_wait(drv_priv->hwmem); + uint32_t command = drv_priv->hwmem[FBIINIT2 / 4] & 0xff; + printk(KERN_INFO "dac read2: RS__COMMAND: m: %02x\n", command); + + int m = 54; + int n = 67; + dac_write_16(drv_priv->hwmem, CLK0_f0_PLL, m, n); + struct m_n res0 = dac_read_16(drv_priv->hwmem, CLK0_f0_PLL); + printk(KERN_INFO "dac read2: CLK0_f0_PLL: m: %02x n: %02x\n", res0.m, res0.n); + + uint8_t pll_control = 0 + | (0 << 0) // internal select: f0 + | (0 << 4) // clk1 sel: fA + | (1 << 5); // enable incs: 1 + dac_write_8(drv_priv->hwmem, PLL_CONTROL, pll_control); + struct m_n res = dac_read_16(drv_priv->hwmem, PLL_CONTROL); + printk(KERN_INFO "dac read2: PLL_CONTROL: m: %02x n: %02x\n", res.m, res.n); + + /* + fbiInit0 00000410 + 4: Stall PCI enable for High Water Mark + 6: (0x10) PCI FIFO Empty Entries Low Water Mark + fbiInit1 00201102 + 1: One wait state + 8: Video Timing Reset + 12: Software Blanking Enable + 20: (0x2) vid_clk_2x_sel + fbiInit2 80000002 + 1: DRAM banking configuration (0=128Kx16 banking, 1=256Kx16 banking) + 23: 0x100 Refresh_Load value + fbiInit3 00000000 + fbiInit4 00000001 + 0: Wait state cycles for PCI read accesses (0=1 ws, 1=2 ws). + fbiInit5 00000128 + + fbiInit6 001e6000 + fbiInit7 000000aa + */ + + int x_tiles = 832 / 32; + + // fbinit0 + int fbiinit0 = 0 + | (1 << 0) // no VGA passthrough + | (0 << 1) // no chuck graphics reset + | (0 << 2) // no chuck fifo reset + | (0 << 3) // no byte swizzle + | (1 << 4) // Stall PCI enable for High Water Mark + | (0x10 << 6) // PCI FIFO Empty Entries Low Water Mark + ; + + // fbiinit1 + int fbiinit1 = 0 + //| (1 << 1) // one wait state + | (1 << 3) // enable linear framebuffer reads + | (((x_tiles >> 1) & 0b1111) << 4) // tiles x [4:1] + | (1 << 13) // drive data output + | (1 << 14) // drive blank output + | (1 << 15) // drive hsync/vsync output + | (1 << 16) // drive dclk output + | (0 << 17) // Video timing vclk input select : vid_clk_2x + | (0x2 << 20) // Video timing vclk source select : vid_clk_2x + | (((x_tiles >> 5) & 0b1) << 24) // tiles x [5] + ; + + int fbiinit2 = 0 + | (1 << 1) // DRAM banking configuration (0=128Kx16 banking, 1=256Kx16 banking) + | (1 << 5) // fast RAS + | (1 << 6) // DRAM_OE + | (247 << 11) // video buffer offset + | (1 << 21) // FIFO RDA + | (1 << 22) // Refresh Enable (0=disable, 1=enable). Default is 0. + | (0x30 << 23) // Refresh_Load Value. + ; + + int fbiinit3 = 0 + | (1 << 6) // trex dis + ; + + int fbiinit4 = 0 + | (1 << 1) // lfb rda + ; + + int fbiinit5 = 0 + | 0x00000128 + | (1 << 23) + | (1 << 24) + ; + + int fbiinit6 = 0 + | (x_tiles & 1) << 30; // tiles x [0] + + int yHeight = 600; + int xWidth = 800; + + // sc->sc_videomode->vtotal - sc->sc_videomode->vsync_end + int vBackPorch = 628 - 605; + // sc->sc_videomode->htotal - sc->sc_videomode->hsync_end + int hBackPorch = 1056 - 968; + + // sc->sc_videomode->vsync_end - sc->sc_videomode->vsync_start + int vSyncOn = 605 - 601; + // sc->sc_videomode->hsync_end - sc->sc_videomode->hsync_start + int hSyncOn = 968 - 840; + + // sc->sc_videomode->vtotal - vsyncon + int vSyncOff = 628 - vSyncOn; + // sc->sc_videomode->htotal - hsyncon + int hSyncOff = 1056 - hSyncOn; + + int hSync = 0 + | (((hSyncOn - 1) & 0x1ff) << 0) + | ((hSyncOff & 0x3ff) << 16) + ; + + int vSync = 0 + | ((vSyncOn & 0x1fff) << 0) + | ((vSyncOff & 0x1fff) << 16) + ; + + int backPorch = 0 + | (((hBackPorch - 2) & 0x1ff) << 0) + | ((vBackPorch & 0x1ff) << 16) + ; + + int videoDimensions = 0 + | (((xWidth - 1) & 0x7ff) << 0) + | ((yHeight & 0x7ff) << 16) + ; + + drv_priv->hwmem[HSYNC / 4] = hSync; + busy_wait(drv_priv->hwmem); + drv_priv->hwmem[VSYNC / 4] = vSync; + busy_wait(drv_priv->hwmem); + drv_priv->hwmem[BACKPORCH / 4] = backPorch; + busy_wait(drv_priv->hwmem); + drv_priv->hwmem[VIDEODIMENSIONS / 4] = videoDimensions; + busy_wait(drv_priv->hwmem); + + int lfbMode = 0; + + drv_priv->hwmem[LFBMODE / 4] = lfbMode; + busy_wait(drv_priv->hwmem); + + init_enable = 0 + | (1 << 0); // enable writes to hardware initialization registers + pci_write_config_dword(pdev, 0x40, init_enable); + busy_wait(drv_priv->hwmem); + + drv_priv->hwmem[FBIINIT0 / 4] = fbiinit0; + drv_priv->hwmem[FBIINIT1 / 4] = fbiinit1; + drv_priv->hwmem[FBIINIT2 / 4] = fbiinit2; + drv_priv->hwmem[FBIINIT3 / 4] = fbiinit3; + drv_priv->hwmem[FBIINIT4 / 4] = fbiinit4; + drv_priv->hwmem[FBIINIT5 / 4] = fbiinit5; + drv_priv->hwmem[FBIINIT6 / 4] = fbiinit6; + busy_wait(drv_priv->hwmem); + + init_enable = 0 + | (1 << 1); // Enable writes to PCI FIFO + pci_write_config_dword(pdev, 0x40, init_enable); + busy_wait(drv_priv->hwmem); + pci_write_config_dword(pdev, 0xC0, 0); // VCLK_ENABLE_REG + + for (int i = 0; i < (sizeof (registers)) / (sizeof (registers[0])); i++) { + printk(KERN_INFO "read2: %s %08x\n", + registers[i].name, + drv_priv->hwmem[registers[i].offset / 4]); + } + printk(KERN_INFO "hsync: %08x vsync: %08x\n", hSync, vSync); + +#define rgb(r, g, b) (((r) << 11) | ((g) << 5) | ((b) << 0)) + static const uint16_t panda[] __attribute__((aligned(4))) = { + //#embed "panda.rgb565.txt" + #include "panda.txt" + }; + + const int colors[] = { + rgb(31, 0, 0), + rgb(0, 63, 0), + rgb(0, 0, 31), + rgb(31, 63, 0), // yellow + rgb(31, 0, 31), // magenta + rgb(0, 63, 31), // cyan + rgb(31, 31, 0), // orange + rgb(31, 0, 15), // pink + rgb(0, 31, 31), // light blue + rgb(0, 63, 15), // light green + }; + + if (0) { + for (int y = 0; y < 600; y++) { + for (int x = 0; x < 1024; x++) { + ((volatile uint16_t *)drv_priv->hwmem)[(0x0400000 / 2) + y * 1024 + x] = 0 + | colors[(y / 32) % 10]; + + if (0) { + ((volatile uint16_t *)drv_priv->hwmem)[(0x0400000 / 2) + y * 1024 + x] = 0 + | rgb(0, 63, 0); + } + } + busy_wait(drv_priv->hwmem); + } + for (int y = 0; y < 600; y++) { + ((volatile uint16_t *)drv_priv->hwmem)[(0x0400000 / 2) + y * 1024 + 10] = 0 + | rgb(0, 0, 31); + ((volatile uint16_t *)drv_priv->hwmem)[(0x0400000 / 2) + y * 1024 + 790] = 0 + | rgb(0, 63, 0); + } + } + + for (int y = 0; y < 600; y++) { + for (int x = 0; x < 800; x++) { + ((volatile uint16_t *)drv_priv->hwmem)[(0x0400000 / 2) + y * 1024 + x] = ((uint16_t*)panda)[y * 800 + x]; + } + } + + return 0; +} + +/* Clean up */ +static void voodoo2_remove(struct pci_dev *pdev) +{ + struct voodoo2_priv *drv_priv = pci_get_drvdata(pdev); + + if (drv_priv) { + if (drv_priv->hwmem) { + iounmap(drv_priv->hwmem); + } + + kfree(drv_priv); + } + + release_device(pdev); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zachary Buhman "); +MODULE_DESCRIPTION("Voodoo2 module"); +MODULE_VERSION("0.1"); + +module_init(voodoo2_module_init); +module_exit(voodoo2_module_exit); diff --git a/pci/mode.c b/pci/mode.c new file mode 100644 index 0000000..42e501f --- /dev/null +++ b/pci/mode.c @@ -0,0 +1,46 @@ +int dot_clock; /* Dot clock frequency in kHz. */ +int hdisplay; // hr +int hsync_start; // hs +int hsync_end; // he +int htotal; // ht +int vdisplay; // vr +int vsync_start; // vs +int vsync_end; // ve +int vtotal; // vt +int flags; // f /* Video mode flags; see below. */ +const char *name; + +// name hr vr clk hs he ht vs ve vt f +// M("800x600x60",800,600,40000,840,968,1056,601,605,628,HP|VP), + +/* dac write */ +// 0x04 0x0a +//tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_0); + +{ + // TDV_GENDAC_ADDRMASK 0x07 + wreg = ((reg & TDV_GENDAC_ADDRMASK) << 8) | val; + // TDV_OFF_DAC_DATA 0x22c + tdvfb_cvg_write(sc, TDV_OFF_DAC_DATA, wreg); + tdvfb_wait(sc); +} + +/* dac read */ +{ + // reg = TDV_GENDAC_PLLWR 0x4 "PLL Address (write mode)" + // reg = TDV_GENDAC_PLLDATA 0x5 "PLL Parameter" + // reg = TDV_GENDAC_CMD 0x6 "Command" + // reg = TDV_GENDAC_PLLRD 0x7 "PLL Address (read mode)" + // TDV_DAC_DATA_READ (1 << 11) 0x800 + tdvfb_cvg_dac_write(sc, reg, TDV_DAC_DATA_READ); + + /* When fbiinit2/fbiinit3 address remapping is enabled (PCI Configuration + register initEnable bit(2)=1), reading from fbiinit2 bits (7:0) returns the last + value read from the external DAC (fbiinit2 bits(31:8) are undefined when address + remapping is enabled). + */ + + // TDV_OFF_DAC_READ 0x0218 fbiInit2 + rv = tdvfb_cvg_read(sc, TDV_OFF_DAC_READ); + return rv & 0xFF; +} diff --git a/pci/panda.py b/pci/panda.py new file mode 100644 index 0000000..add5fbb --- /dev/null +++ b/pci/panda.py @@ -0,0 +1,14 @@ +import sys +import struct + +with open(sys.argv[1], 'rb') as f: + buf = f.read() + +mem = memoryview(buf) + +for i in range(len(mem) // 2): + n, = struct.unpack("