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;
}