Project

General

Profile

RE: Changes on MityDSP-L138 L138-DM-336-RI-J ยป fpga_loader.cpp

Kim Nielsen, 04/26/2023 12:40 PM

 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>

#include "osal/osal.h"
#include "osal/regs_sysconfig.h"


#define FPGA_BASE_ADDR (0x66000000) /* ARM side interface, CS5 */
#define GPIO_REG_BASE (0x01E26000)


typedef struct GpioBankPair
{
volatile uint32_t DIR;
volatile uint32_t OUT_DATA;
volatile uint32_t SET_DATA;
volatile uint32_t CLR_DATA;
volatile uint32_t IN_DATA;
volatile uint32_t SET_RIS_TRIG;
volatile uint32_t CLR_RIS_TRIG;
volatile uint32_t SET_FAL_TRIG;
volatile uint32_t CLR_FAL_TRIG;
volatile uint32_t INTSTAT;
} tsGpioBankPair;

typedef struct GpioRegs
{
volatile uint32_t REVID;
volatile uint32_t reserved1;
volatile uint32_t BINTEN;
volatile uint32_t reserved2;
tsGpioBankPair BANKPAIR[4];
} tsGpioRegs;

static tsGpioRegs *mpGpioRegs;
static const unsigned int gnNUMBANKS = 8;
static const unsigned int gnIOPERBANK = 16;

// GPIO Access Functions
static void GPIO_SetPinValue(unsigned int Bank, unsigned int Offset)
{
int bankpair = Bank >> 1;
int shift = (Bank&1)*16+Offset;

mpGpioRegs->BANKPAIR[bankpair].SET_DATA = 1<<shift;
}


static void GPIO_ClearPinValue(unsigned int Bank, unsigned int Offset)
{
int bankpair = Bank >> 1;
int shift = (Bank&1)*16+Offset;

mpGpioRegs->BANKPAIR[bankpair].CLR_DATA = 1<<shift;
}

static int GPIO_GetPinValue(unsigned int Bank, unsigned int Offset)
{
int bankpair = Bank>>1;
int shift = (Bank&1)*16+Offset;
return (mpGpioRegs->BANKPAIR[bankpair].IN_DATA & (1<<shift)) ? 1 : 0;
}

static void GPIO_SetPinDirection(unsigned int Bank, unsigned int Offset, int IsOutput, unsigned int Value)
{
int bankpair = Bank >> 1;
int shift = (Bank&1)*16+Offset;

// ASSERT(Bank < 8);
// ASSERT(Offset < 16);

if (IsOutput)
{
if (Value)
GPIO_SetPinValue(Bank,Offset);
else
GPIO_ClearPinValue(Bank,Offset);
mpGpioRegs->BANKPAIR[bankpair].DIR &= ~(1<<shift);
}
else
{
mpGpioRegs->BANKPAIR[bankpair].DIR |= (1<<shift);
}
}


static void FPGA_ResetEnable(void)
{
GPIO_ClearPinValue(6, 15);
}

static void FPGA_ResetDisable(void)
{
GPIO_SetPinValue(6, 15);
}

static void FPGA_WriteEnable(void)
{
GPIO_ClearPinValue(3, 9);
}

static void FPGA_WriteDisable(void)
{
GPIO_SetPinValue(3, 9);
}

static int FPGA_InitResponse(void)
{
return (GPIO_GetPinValue(3, 9));
}

static void GPIO_Init(void)
{
// Setup GPIO pin directions
GPIO_SetPinDirection(6, 15, True, 1); // output: PROGRAM_B (/resetout GP6[15])
GPIO_SetPinDirection(3, 9, True, 1); // output: RDWR_B (/EMA_RW GP3[9] )
GPIO_SetPinDirection(1, 15, False, 0); // input: INIT_B (init GP1[15])
}



// FPGA Load Routine
// returns 0 on success
int32_t loadFpga (const char_t *filename, bool reset_only=false, const char_t * board="")
{
FILE *file;
uint8_t *filedata;
long filesize, i;
uint8_t *fpgamem;
bool_t boBitSwap;
sysconfig_regs_t *mpSysRegs;
uint32_t w32;

// Open memory device (O_SYNC option disables cache)
int fd;
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0)
{
printf("Failed to open /dev/mem\n");
return -1;
}

// Get access to GPIO memory area (MMU) - getpagesize()
mpGpioRegs = (tsGpioRegs *) mmap(0, sizeof(tsGpioRegs), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_REG_BASE);
if (mpGpioRegs == NULL)
{
printf("mmap Failed for mpGpioRegs\n");
close(fd);
return -1;
}

// Get access to FPGA memory address space for programming
fpgamem = (uint8_t *) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, FPGA_BASE_ADDR);
if (fpgamem == NULL)
{
printf("mmap Failed for fpgamem\n");
munmap(mpGpioRegs, sizeof(tsGpioRegs));
close(fd);
return -1;
}


// Get access to the syscfg registers
// mpSysRegs = (sysconfig_regs_t *) mmap(0, sizeof(sysconfig_regs_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, SYSCFG0_REG_BASE);
// Only read access (write access to the sys cfg registers is only possible from kernel space - by chip design)
mpSysRegs = (sysconfig_regs_t *) mmap(0, sizeof(sysconfig_regs_t), PROT_READ, MAP_SHARED, fd, SYSCFG0_REG_BASE);
if (mpSysRegs == NULL)
{
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
printf("mmap Failed for mpSysRegs\n");
close(fd);
return -1;
}

// Check pin mux configuration for EMA_A_Rw must be GPIO to enable fpga load
w32 = mpSysRegs->PINMUX[7] & 0x0F000000;
if (w32 != 0x08000000)
{
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
munmap(mpSysRegs, sizeof(sysconfig_regs_t));
printf("Pin EMA_A_Rw not configured as GPIO, fpga will not be loaded\n");
printf("pinmux7: %08X\n", w32);
close(fd);
return -1;
}

#if 0
printf("PINMUX[7] = 0x%08X\n", w32);
w32 &= 0xF0FFFFFF; // Set EMA_A_Rw pin to work as GPIO required for fpga loading (else used as GPIO in fpga loader on ARM!)
w32 |= 0x08000000;
mpSysRegs->PINMUX[7] = w32;
printf("PINMUX[7] = 0x%08X\n", w32);
printf("PINMUX[7] = 0x%08X\n", mpSysRegs->PINMUX[7]);
#endif

// Unmap access to SYS CONFIG registers
munmap(mpSysRegs, sizeof(sysconfig_regs_t));

// Done using the filedescriptor
close(fd);

if (reset_only)
{
GPIO_Init();
FPGA_ResetEnable();
munmap(fpgamem, getpagesize());
munmap(mpGpioRegs, sizeof(tsGpioRegs));
return 0;
}

// Open fpga file
file = fopen(filename, "r");
if (file == NULL)
{
printf("Failed to open fpga file\n");
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (errno);
}

//Extract header
long offset = 0;
if(strlen(board) != 0)
{
char header_buf[50]; // max header size is 50 char
int header_size = 0;
while(header_size <= 50)
{
header_buf[header_size] = fgetc(file);
if(header_buf[header_size] == ':')
{
header_size ++;
break;
}
header_size ++;
}
header_buf[header_size]='\0';
offset = (long)header_size;
printf("header: '%s'\n",header_buf);

// Extract version from header
char * version = strtok(header_buf,"v=");
// Remove end marker ':' from version string
version[strlen(version)-1] = '\0';

printf("FPGA version: %s\n",version);

// Compare board version and FPGA version
if(strcmp(board,version) != 0)
{
printf("Error: FPGA version doesn't match Board \"%s\" != \"%s\"\n",version, board);
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (-1);
}
}

// return -1; //Debug dont load new fpga


// Get file size
fseek(file, 0L, SEEK_END);
filesize = ftell(file);
printf("filesize %ld\n",filesize);
filesize = filesize - offset;
if (filesize < 0)
{
printf("Error reading fpga filesize\n");
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (errno);
}

// Verify max filesize
if (filesize > (4 * 1024 * 1024))
{
printf("Error too large fpga filesize, max. 4MB\n");
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (-1);
}

// Verify in filesize
if (filesize < (200 * 1024))
{
printf("FPGA Bin file too small\n");
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (-1);
}

// Allocate memory for file
filedata = (uint8_t*) malloc(filesize);
if (filedata == NULL)
{
printf("Error allocating memory for fpga file\n");
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (-1);
}

// Read fpga file
fseek(file, offset, SEEK_SET);
if (fread(filedata, 1, filesize, file) != (size_t) filesize)
{
printf("Error reading fpga file\n");
free(filedata);
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (-1);
}

// Close file
fclose(file);

// Initialize fpga interface gpios
GPIO_Init();

// Reset fpga TPROGRAM low pulse time, must be above 500ns, hmmm we are way over the top here
FPGA_ResetEnable();
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));

// Stop resetting
FPGA_ResetDisable();
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));

// Verify reset OK
if (FPGA_InitResponse() == 0)
{
printf("FPGA reset timeout\n");
free(filedata);
munmap(mpGpioRegs, sizeof(tsGpioRegs));
munmap(fpgamem, getpagesize());
return (-1);
}

// Read 32bit pattern 55 99 AA 66, if AA 99 55 66 we need to bit swap, else abort
switch (*((uint32_t*) &filedata[0x10]))
{
case 0x665599AA: // actually => 0xAA995566
boBitSwap = True;
break;

// Already swapped
case 0x66AA9955: // actually => 0x5599AA66
default:
boBitSwap = False;
break;
}

// Enable writing program to fpga
FPGA_WriteEnable();
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));

// Send program to fpga
for (i = 0; i < filesize; i++)
{
byte_t bIn = filedata[i];
byte_t bOut = 0;
int bit;

if (boBitSwap)
{
for (bit = 0; bit <= 7; bit++)
{
bOut <<= 1;
bOut |= (bIn & 0x01);
bIn >>= 1;
}
}
else
{
bOut = bIn;
}
*fpgamem = bOut;
}

// Done programming
FPGA_WriteDisable();
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));

// Verify programming done (CRC) ok
if (FPGA_InitResponse() == 0)
{
printf("FPGA programming failed\n");
free(filedata);
return (-1);
}

// Cleanup
munmap(fpgamem, getpagesize());
munmap(mpGpioRegs, sizeof(tsGpioRegs));
free(filedata);

return 0;
}
    (1-1/1)