TS-4400 GPIO
From embeddedTS Manuals
The TS-4400 provides the downstream developer with 70 total FPGA-based GPIO on the PCI Express bus. TODO: Add pinout and simple DOS blinky example.
To gain access to these, first you need to get the address of the TS-4400's PCI, in specific PCIe BAR 0.
#include <bios.h> //
#include <stdio.h> // printf()
#include <conio.h> // inp() and outp()
#include <i86.h> //
#include <assert.h> // assert() used.
#include <unistd.h> // usleep()
#include "pcicfg.h"
#include "rdtsc.h"
extern int InitFlatMem(void);
extern void SetGSto4G(void);
extern uint32_t flatrealmode_readd(uint32_t addr);
#pragma aux flatrealmode_readd = \
".386p" \
"push ecx" \
"push edx" \
"push eax" \
"xor cx,cx" \
"mov gs,cx" \
"shl edx,16" \
"movzx eax,ax" \
"lea ecx,[eax+edx]" \
"pop eax" \
"pop edx" \
"mov ecx,gs:[ecx]" \
"mov ax,cx" \
"shr ecx,16" \
"mov dx,cx" \
"pop ecx" \
modify [cx] \
parm [dx ax] \
value [dx ax]
extern void flatrealmode_writed(uint32_t addr,uint32_t c);
#pragma aux flatrealmode_writed = \
".386p" \
"push edx" \
"push ebx" \
"push eax" \
"push ecx" \
"push cx" \
"xor cx,cx" \
"mov es,cx" \
"pop cx" \
"shl edx,16" \
"movzx eax,ax" \
"shl ecx,16" \
"movzx ebx,bx" \
"add ebx,ecx" \
"pop ecx" \
"mov gs:[eax+edx],ebx" \
"pop eax" \
"pop ebx" \
"pop edx" \
modify [bx cx dx] \
parm [dx ax] [cx bx]
extern uint16_t htons( uint16_t );
#pragma aux htons = \
"xchg al, ah" \
parm [ax] \
modify [ax] \
value [ax];
#define ntohs( x ) htons( x )
static inline void outpd(uint16_t port, uint32_t v);
#pragma aux outpd = \
".386" \
"shl eax, 16" \
"mov ax, dx" \
"out cx, eax" \
parm [cx] [ax dx]
uint32_t fpga_base;
uint32_t fpga_io_base;
void init4400(void) {
int i, r;
uint8_t b, d, f;
delay(10);
for (i = 0; i < 10; i++) outpd(0xc00 + (i*4), 0);
for (i = 0; i < 16; i++) inp(0x3f8);
r = pci_find(0x17f3, 0x6011, 0, &b, &d, &f); /* south bridge */ // RDC Semiconducter, ISA bridge
assert(r == 0);
/* disable usb/eth/pci irqs */
pci_cfg_write(b, d, f, 0x58, 0x0);
outp(0x4d0, inp(0x4d0) & ~0xe0); /* irq 5-7 to edge trigger */
r = pci_find(0x1172, 0x0004, 0, &b, &d, &f); /* fpga */ // Altera, undefined
fpga_io_base = pci_cfg_read(b, d, f, 0x14) & ~0x3; // do '& ~0x3' because the lowest 2 bits are statuses not part of the address.
printf("pci io at 0x%X\n", fpga_io_base);
fpga_base = pci_cfg_read(b, d, f, 0x10) & ~0xf;
printf("fpga_base at 0x%X\n", fpga_base);
r = InitFlatMem();
assert(r != 0);
}
// gpio bank in/out configuration
// is at io base + 0, 4, and 8
// for gpio 0:31, 32:63, and 64:68.
// 0 is input, 1 is output.
// output values (1 is high, 0 is low)
// gpio 0:31 are at io base + 0xc
// gpio 32:63 are at io base + 0x10
// gpio 64:68 are at io base + 0x14
void pcie_gpiotest()
{
outp(fpga_io_base + 0x0, 0xff); // FPGA GPIO bank 0 set to output.
printf("Starting square wave generation on ALL GPIO.\n");
sleep(1);
for(;;){
outp(fpga_io_base + 0xc, 0xAA); // Set GPIO 0:31 high.
outp(fpga_io_base + 0xc, 0x55); // Turn GPIO 0:31 off.
}
}
int main()
{
uint16_t i,j;
init4400();
printf("FPGA Base Address from global: 0x%X\n", fpga_base);
sleep(1);
pcie_gpiotest();
printf("Done.\n");
return 0;
}