1
|
#include <stdio.h>
|
2
|
#include <stdlib.h>
|
3
|
#include <unistd.h>
|
4
|
#include <fcntl.h>
|
5
|
#include <sys/mman.h>
|
6
|
#include <errno.h>
|
7
|
#include <string.h>
|
8
|
|
9
|
#include "osal/osal.h"
|
10
|
#include "osal/regs_sysconfig.h"
|
11
|
|
12
|
|
13
|
#define FPGA_BASE_ADDR (0x66000000) /* ARM side interface, CS5 */
|
14
|
#define GPIO_REG_BASE (0x01E26000)
|
15
|
|
16
|
|
17
|
typedef struct GpioBankPair
|
18
|
{
|
19
|
volatile uint32_t DIR;
|
20
|
volatile uint32_t OUT_DATA;
|
21
|
volatile uint32_t SET_DATA;
|
22
|
volatile uint32_t CLR_DATA;
|
23
|
volatile uint32_t IN_DATA;
|
24
|
volatile uint32_t SET_RIS_TRIG;
|
25
|
volatile uint32_t CLR_RIS_TRIG;
|
26
|
volatile uint32_t SET_FAL_TRIG;
|
27
|
volatile uint32_t CLR_FAL_TRIG;
|
28
|
volatile uint32_t INTSTAT;
|
29
|
} tsGpioBankPair;
|
30
|
|
31
|
typedef struct GpioRegs
|
32
|
{
|
33
|
volatile uint32_t REVID;
|
34
|
volatile uint32_t reserved1;
|
35
|
volatile uint32_t BINTEN;
|
36
|
volatile uint32_t reserved2;
|
37
|
tsGpioBankPair BANKPAIR[4];
|
38
|
} tsGpioRegs;
|
39
|
|
40
|
static tsGpioRegs *mpGpioRegs;
|
41
|
static const unsigned int gnNUMBANKS = 8;
|
42
|
static const unsigned int gnIOPERBANK = 16;
|
43
|
|
44
|
// GPIO Access Functions
|
45
|
static void GPIO_SetPinValue(unsigned int Bank, unsigned int Offset)
|
46
|
{
|
47
|
int bankpair = Bank >> 1;
|
48
|
int shift = (Bank&1)*16+Offset;
|
49
|
|
50
|
mpGpioRegs->BANKPAIR[bankpair].SET_DATA = 1<<shift;
|
51
|
}
|
52
|
|
53
|
|
54
|
static void GPIO_ClearPinValue(unsigned int Bank, unsigned int Offset)
|
55
|
{
|
56
|
int bankpair = Bank >> 1;
|
57
|
int shift = (Bank&1)*16+Offset;
|
58
|
|
59
|
mpGpioRegs->BANKPAIR[bankpair].CLR_DATA = 1<<shift;
|
60
|
}
|
61
|
|
62
|
static int GPIO_GetPinValue(unsigned int Bank, unsigned int Offset)
|
63
|
{
|
64
|
int bankpair = Bank>>1;
|
65
|
int shift = (Bank&1)*16+Offset;
|
66
|
return (mpGpioRegs->BANKPAIR[bankpair].IN_DATA & (1<<shift)) ? 1 : 0;
|
67
|
}
|
68
|
|
69
|
static void GPIO_SetPinDirection(unsigned int Bank, unsigned int Offset, int IsOutput, unsigned int Value)
|
70
|
{
|
71
|
int bankpair = Bank >> 1;
|
72
|
int shift = (Bank&1)*16+Offset;
|
73
|
|
74
|
// ASSERT(Bank < 8);
|
75
|
// ASSERT(Offset < 16);
|
76
|
|
77
|
if (IsOutput)
|
78
|
{
|
79
|
if (Value)
|
80
|
GPIO_SetPinValue(Bank,Offset);
|
81
|
else
|
82
|
GPIO_ClearPinValue(Bank,Offset);
|
83
|
mpGpioRegs->BANKPAIR[bankpair].DIR &= ~(1<<shift);
|
84
|
}
|
85
|
else
|
86
|
{
|
87
|
mpGpioRegs->BANKPAIR[bankpair].DIR |= (1<<shift);
|
88
|
}
|
89
|
}
|
90
|
|
91
|
|
92
|
static void FPGA_ResetEnable(void)
|
93
|
{
|
94
|
GPIO_ClearPinValue(6, 15);
|
95
|
}
|
96
|
|
97
|
static void FPGA_ResetDisable(void)
|
98
|
{
|
99
|
GPIO_SetPinValue(6, 15);
|
100
|
}
|
101
|
|
102
|
static void FPGA_WriteEnable(void)
|
103
|
{
|
104
|
GPIO_ClearPinValue(3, 9);
|
105
|
}
|
106
|
|
107
|
static void FPGA_WriteDisable(void)
|
108
|
{
|
109
|
GPIO_SetPinValue(3, 9);
|
110
|
}
|
111
|
|
112
|
static int FPGA_InitResponse(void)
|
113
|
{
|
114
|
return (GPIO_GetPinValue(3, 9));
|
115
|
}
|
116
|
|
117
|
static void GPIO_Init(void)
|
118
|
{
|
119
|
// Setup GPIO pin directions
|
120
|
GPIO_SetPinDirection(6, 15, True, 1); // output: PROGRAM_B (/resetout GP6[15])
|
121
|
GPIO_SetPinDirection(3, 9, True, 1); // output: RDWR_B (/EMA_RW GP3[9] )
|
122
|
GPIO_SetPinDirection(1, 15, False, 0); // input: INIT_B (init GP1[15])
|
123
|
}
|
124
|
|
125
|
|
126
|
|
127
|
// FPGA Load Routine
|
128
|
// returns 0 on success
|
129
|
int32_t loadFpga (const char_t *filename, bool reset_only=false, const char_t * board="")
|
130
|
{
|
131
|
FILE *file;
|
132
|
uint8_t *filedata;
|
133
|
long filesize, i;
|
134
|
uint8_t *fpgamem;
|
135
|
bool_t boBitSwap;
|
136
|
sysconfig_regs_t *mpSysRegs;
|
137
|
uint32_t w32;
|
138
|
|
139
|
// Open memory device (O_SYNC option disables cache)
|
140
|
int fd;
|
141
|
fd = open("/dev/mem", O_RDWR | O_SYNC);
|
142
|
if (fd < 0)
|
143
|
{
|
144
|
printf("Failed to open /dev/mem\n");
|
145
|
return -1;
|
146
|
}
|
147
|
|
148
|
// Get access to GPIO memory area (MMU) - getpagesize()
|
149
|
mpGpioRegs = (tsGpioRegs *) mmap(0, sizeof(tsGpioRegs), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_REG_BASE);
|
150
|
if (mpGpioRegs == NULL)
|
151
|
{
|
152
|
printf("mmap Failed for mpGpioRegs\n");
|
153
|
close(fd);
|
154
|
return -1;
|
155
|
}
|
156
|
|
157
|
// Get access to FPGA memory address space for programming
|
158
|
fpgamem = (uint8_t *) mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, FPGA_BASE_ADDR);
|
159
|
if (fpgamem == NULL)
|
160
|
{
|
161
|
printf("mmap Failed for fpgamem\n");
|
162
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
163
|
close(fd);
|
164
|
return -1;
|
165
|
}
|
166
|
|
167
|
|
168
|
// Get access to the syscfg registers
|
169
|
// mpSysRegs = (sysconfig_regs_t *) mmap(0, sizeof(sysconfig_regs_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, SYSCFG0_REG_BASE);
|
170
|
// Only read access (write access to the sys cfg registers is only possible from kernel space - by chip design)
|
171
|
mpSysRegs = (sysconfig_regs_t *) mmap(0, sizeof(sysconfig_regs_t), PROT_READ, MAP_SHARED, fd, SYSCFG0_REG_BASE);
|
172
|
if (mpSysRegs == NULL)
|
173
|
{
|
174
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
175
|
munmap(fpgamem, getpagesize());
|
176
|
printf("mmap Failed for mpSysRegs\n");
|
177
|
close(fd);
|
178
|
return -1;
|
179
|
}
|
180
|
|
181
|
// Check pin mux configuration for EMA_A_Rw must be GPIO to enable fpga load
|
182
|
w32 = mpSysRegs->PINMUX[7] & 0x0F000000;
|
183
|
if (w32 != 0x08000000)
|
184
|
{
|
185
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
186
|
munmap(fpgamem, getpagesize());
|
187
|
munmap(mpSysRegs, sizeof(sysconfig_regs_t));
|
188
|
printf("Pin EMA_A_Rw not configured as GPIO, fpga will not be loaded\n");
|
189
|
printf("pinmux7: %08X\n", w32);
|
190
|
close(fd);
|
191
|
return -1;
|
192
|
}
|
193
|
|
194
|
#if 0
|
195
|
printf("PINMUX[7] = 0x%08X\n", w32);
|
196
|
w32 &= 0xF0FFFFFF; // Set EMA_A_Rw pin to work as GPIO required for fpga loading (else used as GPIO in fpga loader on ARM!)
|
197
|
w32 |= 0x08000000;
|
198
|
mpSysRegs->PINMUX[7] = w32;
|
199
|
printf("PINMUX[7] = 0x%08X\n", w32);
|
200
|
printf("PINMUX[7] = 0x%08X\n", mpSysRegs->PINMUX[7]);
|
201
|
#endif
|
202
|
|
203
|
// Unmap access to SYS CONFIG registers
|
204
|
munmap(mpSysRegs, sizeof(sysconfig_regs_t));
|
205
|
|
206
|
// Done using the filedescriptor
|
207
|
close(fd);
|
208
|
|
209
|
if (reset_only)
|
210
|
{
|
211
|
GPIO_Init();
|
212
|
FPGA_ResetEnable();
|
213
|
munmap(fpgamem, getpagesize());
|
214
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
215
|
return 0;
|
216
|
}
|
217
|
|
218
|
// Open fpga file
|
219
|
file = fopen(filename, "r");
|
220
|
if (file == NULL)
|
221
|
{
|
222
|
printf("Failed to open fpga file\n");
|
223
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
224
|
munmap(fpgamem, getpagesize());
|
225
|
return (errno);
|
226
|
}
|
227
|
|
228
|
//Extract header
|
229
|
long offset = 0;
|
230
|
if(strlen(board) != 0)
|
231
|
{
|
232
|
char header_buf[50]; // max header size is 50 char
|
233
|
int header_size = 0;
|
234
|
while(header_size <= 50)
|
235
|
{
|
236
|
header_buf[header_size] = fgetc(file);
|
237
|
if(header_buf[header_size] == ':')
|
238
|
{
|
239
|
header_size ++;
|
240
|
break;
|
241
|
}
|
242
|
header_size ++;
|
243
|
}
|
244
|
header_buf[header_size]='\0';
|
245
|
offset = (long)header_size;
|
246
|
printf("header: '%s'\n",header_buf);
|
247
|
|
248
|
// Extract version from header
|
249
|
char * version = strtok(header_buf,"v=");
|
250
|
// Remove end marker ':' from version string
|
251
|
version[strlen(version)-1] = '\0';
|
252
|
|
253
|
printf("FPGA version: %s\n",version);
|
254
|
|
255
|
// Compare board version and FPGA version
|
256
|
if(strcmp(board,version) != 0)
|
257
|
{
|
258
|
printf("Error: FPGA version doesn't match Board \"%s\" != \"%s\"\n",version, board);
|
259
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
260
|
munmap(fpgamem, getpagesize());
|
261
|
return (-1);
|
262
|
}
|
263
|
}
|
264
|
|
265
|
// return -1; //Debug dont load new fpga
|
266
|
|
267
|
|
268
|
// Get file size
|
269
|
fseek(file, 0L, SEEK_END);
|
270
|
filesize = ftell(file);
|
271
|
printf("filesize %ld\n",filesize);
|
272
|
filesize = filesize - offset;
|
273
|
if (filesize < 0)
|
274
|
{
|
275
|
printf("Error reading fpga filesize\n");
|
276
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
277
|
munmap(fpgamem, getpagesize());
|
278
|
return (errno);
|
279
|
}
|
280
|
|
281
|
// Verify max filesize
|
282
|
if (filesize > (4 * 1024 * 1024))
|
283
|
{
|
284
|
printf("Error too large fpga filesize, max. 4MB\n");
|
285
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
286
|
munmap(fpgamem, getpagesize());
|
287
|
return (-1);
|
288
|
}
|
289
|
|
290
|
// Verify in filesize
|
291
|
if (filesize < (200 * 1024))
|
292
|
{
|
293
|
printf("FPGA Bin file too small\n");
|
294
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
295
|
munmap(fpgamem, getpagesize());
|
296
|
return (-1);
|
297
|
}
|
298
|
|
299
|
// Allocate memory for file
|
300
|
filedata = (uint8_t*) malloc(filesize);
|
301
|
if (filedata == NULL)
|
302
|
{
|
303
|
printf("Error allocating memory for fpga file\n");
|
304
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
305
|
munmap(fpgamem, getpagesize());
|
306
|
return (-1);
|
307
|
}
|
308
|
|
309
|
// Read fpga file
|
310
|
fseek(file, offset, SEEK_SET);
|
311
|
if (fread(filedata, 1, filesize, file) != (size_t) filesize)
|
312
|
{
|
313
|
printf("Error reading fpga file\n");
|
314
|
free(filedata);
|
315
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
316
|
munmap(fpgamem, getpagesize());
|
317
|
return (-1);
|
318
|
}
|
319
|
|
320
|
// Close file
|
321
|
fclose(file);
|
322
|
|
323
|
// Initialize fpga interface gpios
|
324
|
GPIO_Init();
|
325
|
|
326
|
// Reset fpga TPROGRAM low pulse time, must be above 500ns, hmmm we are way over the top here
|
327
|
FPGA_ResetEnable();
|
328
|
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));
|
329
|
|
330
|
// Stop resetting
|
331
|
FPGA_ResetDisable();
|
332
|
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));
|
333
|
|
334
|
// Verify reset OK
|
335
|
if (FPGA_InitResponse() == 0)
|
336
|
{
|
337
|
printf("FPGA reset timeout\n");
|
338
|
free(filedata);
|
339
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
340
|
munmap(fpgamem, getpagesize());
|
341
|
return (-1);
|
342
|
}
|
343
|
|
344
|
// Read 32bit pattern 55 99 AA 66, if AA 99 55 66 we need to bit swap, else abort
|
345
|
switch (*((uint32_t*) &filedata[0x10]))
|
346
|
{
|
347
|
case 0x665599AA: // actually => 0xAA995566
|
348
|
boBitSwap = True;
|
349
|
break;
|
350
|
|
351
|
// Already swapped
|
352
|
case 0x66AA9955: // actually => 0x5599AA66
|
353
|
default:
|
354
|
boBitSwap = False;
|
355
|
break;
|
356
|
}
|
357
|
|
358
|
// Enable writing program to fpga
|
359
|
FPGA_WriteEnable();
|
360
|
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));
|
361
|
|
362
|
// Send program to fpga
|
363
|
for (i = 0; i < filesize; i++)
|
364
|
{
|
365
|
byte_t bIn = filedata[i];
|
366
|
byte_t bOut = 0;
|
367
|
int bit;
|
368
|
|
369
|
if (boBitSwap)
|
370
|
{
|
371
|
for (bit = 0; bit <= 7; bit++)
|
372
|
{
|
373
|
bOut <<= 1;
|
374
|
bOut |= (bIn & 0x01);
|
375
|
bIn >>= 1;
|
376
|
}
|
377
|
}
|
378
|
else
|
379
|
{
|
380
|
bOut = bIn;
|
381
|
}
|
382
|
*fpgamem = bOut;
|
383
|
}
|
384
|
|
385
|
// Done programming
|
386
|
FPGA_WriteDisable();
|
387
|
OSAL_TaskSleep(OSAL_SEC_TO_TICK(0.01));
|
388
|
|
389
|
// Verify programming done (CRC) ok
|
390
|
if (FPGA_InitResponse() == 0)
|
391
|
{
|
392
|
printf("FPGA programming failed\n");
|
393
|
free(filedata);
|
394
|
return (-1);
|
395
|
}
|
396
|
|
397
|
// Cleanup
|
398
|
munmap(fpgamem, getpagesize());
|
399
|
munmap(mpGpioRegs, sizeof(tsGpioRegs));
|
400
|
free(filedata);
|
401
|
|
402
|
return 0;
|
403
|
}
|