1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
|
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/*
Title: FPGA / CAP synchronization routines
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include <board.h>
#include <rtt/rtt.h>
#include <slck/slck.h>
#include <pio/pio.h>
#include <utility/trace.h>
#include "board_fpga_init.h"
//------------------------------------------------------------------------------
// FPGA Config done on PC13 (CAP9S3-DKZ only)
//------------------------------------------------------------------------------
#define PIN_FPGA_CONFDONE {1 << 13, AT91C_BASE_PIOC, AT91C_ID_PIOABCD, PIO_INPUT, PIO_DEGLITCH}
static const Pin pinPC13 = PIN_FPGA_CONFDONE;
//------------------------------------------------------------------------------
// Prototype of internal functions
//------------------------------------------------------------------------------
unsigned int fpga_synchro_newIF(void);
unsigned int init_mpblock_revC(unsigned char mode);
unsigned int fpga_synchro_revC(void);
void init_mpbs_revC(volatile unsigned int* mpbs,char pun,char lp,char sup);
unsigned int init_mpblock_revB(void);
unsigned int fpga_synchro_revB(void);
void init_mpbs_revB(volatile unsigned int* mpbs,char pun,char lp,char sup);
void wait_slck_periods(int periods);
void wait_for_FPGA_config(void);
void wait_for_FPGA_config_CAP9S3(void);
unsigned int search_last_match(void);
unsigned int search_first_match(void);
int fpga_pattern_ok(void);
//------------------------------------------------------------------------------
// Globlal variables
//------------------------------------------------------------------------------
int delay_status, master_cnt_hold, master_cnt;
//------------------------------------------------------------------------------
// FPGA access initialization
// Returns : programmed clk out delay if success
// error code with pattern CACAB0Fx if fail
//------------------------------------------------------------------------------
unsigned int BOARD_InitMPBlock(unsigned char mode)
{
// Switch to external 32KHz if not done
if(!SLCK_Is32k())SLCK_RCto32k();
// Wait 1 second
wait_slck_periods(32768);
if (!(RSTC_SR_REG&0x00000600)){
wait_for_FPGA_config_CAP9S3(); // if POR, wait until FPGA is ready
}
if(CAP9_CHECK_REVISION_REG == REV_B_CHECK_VALUE) {
TRACE_INFO("Init MPBlock rev B\n\r");
return(init_mpblock_revB()); // CAP9 revB detected
}
else {
if(EXTENDED_CHIP_ID_REG) {
TRACE_INFO("No init MPBlock : it is not a dev chip\n\r");
return(NOT_A_DEV_CHIP_ERROR); // not a dev chip
}
else {
TRACE_INFO("Init MPBlock rev C\n\r");
return(init_mpblock_revC(mode)); // CAP9 revC detected
}
}
}
//------------------------------------------------------------------------------
// CAP9 / FPGA synchronization loop - CAP9 RevC / new interface
//------------------------------------------------------------------------------
unsigned int fpga_synchro_newIF (void)
{
unsigned int time = 0;
unsigned int wait_loop1;
unsigned int wait_loop2;
unsigned int wait_loop3;
unsigned int delay_ctrl, clkin_delay, clkin_delay_max,dw_width;
//-- Write in CONFIG_INIT register
//-- - dllin_used bit = 0 (used clock coming from FPGA)
//-- - dllout_used bit = 0 (bypass the DelayLine OUT)
//-- - drive_pad_by_sfr = - (drive pad by register)
CONFIG_INIT_REG &= 0xFFFFFE7F; //outi(0xFDF00000+0x28, (ini(0xFDF00000+0x28) & 0xFFFFFE7F));
// clk_in setup
delay_status = DELAY_STATUS_REG; //-- read in DELAY_STATUS register
master_cnt_hold = ((delay_status & 0xFF00) >> 8) + 6;
master_cnt = (delay_status & 0xFF0000) >> 16;
//ERr
//clkin_delay = (master_cnt_hold >> 2)-2; //start in data window
clkin_delay = 0;
DELAY_CTRL_REG=(clkin_delay << 16)|0x1;
//-- FPGA I/F INIT
INIT_ARG_REG = 0x5C00;
INIT_CMD_REG = 0x01; // INIT_CMD = INIT_CMD_START_INIT
wait_loop1 = 5000000;while(wait_loop1--);
wait_loop2 = 5000000;while(wait_loop2--);
wait_loop3 = 5000000;while(wait_loop3--);
if (fpga_pattern_ok()){ // already in data window
clkin_delay_max = search_last_match();
clkin_delay = search_first_match();
dw_width = clkin_delay_max + master_cnt_hold-clkin_delay;
//ERr debug purppose
printf("-I- Data window : 0x%02X to 0x%02X\n\r", clkin_delay,clkin_delay_max);
clkin_delay = (clkin_delay+dw_width/2)%master_cnt_hold;
}
else{ // not in data window
clkin_delay = search_first_match();
clkin_delay_max = search_last_match();
dw_width = clkin_delay_max-clkin_delay;
//ERr debug purppose
printf("-I- Data window : 0x%02X to 0x%02X\n\r", clkin_delay,clkin_delay_max);
clkin_delay = (clkin_delay+dw_width/2)%master_cnt_hold;
}
// debug purppose
printf("-I- Master count : 0x%02X\n\r", master_cnt);
//clkin_delay = (master_cnt_hold >> 2)-2; //start in data window
printf("-I- clk_in delay : 0x%02X\n\r", clkin_delay);
printf("-I- data window width : 0x%02X (%dns)\n\r", dw_width,(dw_width*10/master_cnt));
// Set clk in delay
delay_ctrl = DELAY_CTRL_REG;
DELAY_CTRL_REG=((delay_ctrl & ~(0xFF << 16)) | clkin_delay << 16);
DELAY_CTRL_REG|=0x1;
// Cycle index select
time = 0;
while((CYCLE_IDX_RESP_R_LSB_REG != 0x0A7014E0)&&time++<FPGA_SYNCHRO_TIMEOUT3){
INIT_ARG_REG = 0x02; // INIT_ARG = 2
INIT_CMD_REG = 0x02; // INIT_CMD = INIT_CMD_ADD_CYCLE
}
if(time>FPGA_SYNCHRO_TIMEOUT3)return(FPGA_SYNCHRO_ERROR3);
// Return the number of iterations
return(time);
}
//------------------------------------------------------------------------------
// FPGA access initialization - CAP9 RevC
//------------------------------------------------------------------------------
unsigned int init_mpblock_revC(unsigned char mode)
{
// AT91PS_CCFG pCCFG = (AT91PS_CCFG) AT91C_BASE_CCFG; //not used
unsigned int ret_value;
// Enable clk
*((unsigned int*)0xFFFFFC00)|=0x4;
init_mpbs_revC(MPBS0,PULLUP_ON,MPIO_LP,MPIO_SUPPLY);
// User IF pad config
/*
*((unsigned int*)0xFDF00028)&=0xFFFFFFFD; // Drive pad by user if
*((unsigned int*)0xFDF00034)=0x01000000; // MPIOB SUP
*((unsigned int*)0xFDF00038)=0x00000000; // MPIOB SUP
*((unsigned int*)0xFDF0003C)=0x00000000; // MPIOA SUP
*((unsigned int*)0xFDF00040)=0x01000000; // MPIOB LP1
*((unsigned int*)0xFDF00044)=0x00000000; // MPIOB LP2
*((unsigned int*)0xFDF00048)=0x00000000; // MPIOA LP
*((unsigned int*)0xFDF0004C)=0x00000000; // MPIOB PU1
*((unsigned int*)0xFDF00050)=0x00000000; // MPIOB PU2
*((unsigned int*)0xFDF00054)=0x00000000; // MPIOA PU
*/
#ifdef __FPGA_IF_TYPE_DIV3
FPGA_IF_TYPE_REG = 0x01;
#endif
// DELAY LINE SETUP
DELAY_CTRL_REG = 0x03; // write in DELAY_CTRL register enable_delay = 1 and update_delay = 1
while (!(DELAY_STATUS_REG & 0x1)){} // wait master_is_locked = 1
// FPGA IF synchronization loop
TRACE_INFO("FPGA IF synchro loop...\n\r");
//#ifdef NEW_INTERFACE
if (mode==NEW_IF){
ret_value = fpga_synchro_newIF();
if(ret_value>FPGA_SYNCHRO_TIMEOUT3)return(FPGA_SYNCHRO_ERROR3);
}
else{
ret_value = fpga_synchro_revC();
if ((ret_value&0xFFFF0000) == 0xCACA0000)return(ret_value);
}
//#endif
TRACE_INFO("Synchro done\n\r");
// Switch to functionnal mode
//outi(0x30DC00, 0xDC00);
INIT_ARG_REG = 0x4C727354; // INIT_ARG = INIT_CMD_START_INIT
INIT_ARG_REG = 0x4C6F634B; // INIT_ARG = INIT_CMD_START_INIT
INIT_CMD_REG = 0x03; // INIT_CMD = INIT_CMD_CYCLE_IDX_LOCKED
// Return the programmed clock_out_delay value
return(ret_value);
}
//------------------------------------------------------------------------------
// FPGA access initialization - CAP9 RevC
//------------------------------------------------------------------------------
unsigned int fpga_synchro_revC(void)
{
unsigned char clk_out_delay_mean;
unsigned char clk_out_delay = 0;
unsigned int time = 0;
INIT_ARG_REG = 0x5C00; //
wait_slck_periods(1); // about 30us (wait 10us for FPGA PLL relock)
INIT_CMD_REG = 0x01; // INIT_CMD = INIT_CMD_START_INIT
//Search first match value
time = 0;
while(((CYCLE_IDX_RESP_R_LSB_REG != CYCLE_IDX_RESP_F_LSB_REG)||(CYCLE_IDX_RESP_R_MSB_REG != ~CYCLE_IDX_RESP_F_MSB_REG))&&time++<FPGA_SYNCHRO_TIMEOUT1)DELAY_CTRL_REG=(clk_out_delay++ << 8)|0x1;
if(time > FPGA_SYNCHRO_TIMEOUT1)return(FPGA_SYNCHRO_ERROR1);
clk_out_delay_mean = clk_out_delay;
//Search last match value
DELAY_CTRL_REG=(clk_out_delay++ << 8)|0x1;
while(((CYCLE_IDX_RESP_R_LSB_REG == CYCLE_IDX_RESP_F_LSB_REG)&&(CYCLE_IDX_RESP_R_MSB_REG == ~CYCLE_IDX_RESP_F_MSB_REG))&&time++<FPGA_SYNCHRO_TIMEOUT2)DELAY_CTRL_REG=(clk_out_delay++ << 8)|0x1;
if(time>FPGA_SYNCHRO_TIMEOUT2)return(FPGA_SYNCHRO_ERROR2);
clk_out_delay_mean = (clk_out_delay_mean + clk_out_delay)/2;
// Setup to middle match value
DELAY_CTRL_REG = (clk_out_delay_mean << 8) | 0x1;
// Cycle index select
time = 0;
while((CYCLE_IDX_RESP_R_LSB_REG != 0x0A7014E0)&&time++<FPGA_SYNCHRO_TIMEOUT3) {
INIT_ARG_REG = 0x02; // INIT_ARG = 2
INIT_CMD_REG = 0x02; // INIT_CMD = INIT_CMD_ADD_CYCLE
}
if(time>FPGA_SYNCHRO_TIMEOUT3)return(FPGA_SYNCHRO_ERROR3);
// Return the programmed clock_out_delay value
return ((unsigned int)clk_out_delay_mean);
}
//------------------------------------------------------------------------------
// Enable CAP to FPGA clock, and configure pads - CAP9 RevC
//------------------------------------------------------------------------------
// Updated for UMC pads
void init_mpbs_revC(volatile unsigned int* mpbs,char pun,char lp,char sup)
{
unsigned int value;
if (mpbs!=MPBS0 && mpbs!=MPBS1 && mpbs!=MPBS2 && mpbs!=MPBS3)
return;
value = *mpbs | MPBS_ENABLE_BIT;
if (pun==PULLUP_ON) value&= ~(MPIOB_PUN_BIT|MPIOA_PUN_BIT);
else if (pun==PULLUP_OFF) value|= (MPIOB_PUN_BIT|MPIOA_PUN_BIT);
if (lp==LOWPOWER_OFF) value|= (MPIOB_LP_BIT|MPIOA_LP_BIT);
else if(lp==LOWPOWER_ON)value&= ~(MPIOB_LP_BIT|MPIOA_LP_BIT);
if (sup==SUPPLY_18) value|= (MPIOB_SUP_BIT|MPIOA_SUP_BIT);
else if(sup==SUPPLY_33)value&= ~(MPIOB_SUP_BIT|MPIOA_SUP_BIT);
*mpbs = value;
}
//------------------------------------------------------------------------------
// FPGA access initialization - CAP9 RevB
//------------------------------------------------------------------------------
unsigned int init_mpblock_revB(void)
{
// AT91PS_CCFG pCCFG = (AT91PS_CCFG) AT91C_BASE_CCFG; // not used
unsigned int ret_value;
// Enable clk
init_mpbs_revB(MPBS0,PULLUP_ON,MPIO_LP,MPIO_SUPPLY);
TRACE_INFO("FPGA IF synchro loop...\n\r");
#ifdef __FPGA_IF_TYPE_DIV3
FPGA_IF_TYPE_REG = 0x01;
#endif
// DELAY LINE SETUP
DELAY_CTRL_REG = 0x03; // write in DELAY_CTRL register enable_delay = 1 and update_delay = 1
while (!(DELAY_STATUS_REG & 0x1)){} // wait master_is_locked = 1
// FPGA IF synchronization loop
//ret_value = fpga_synchro_old();
ret_value = fpga_synchro_revB();
if ((ret_value&0xFFFF0000) == 0xCACA0000)return(ret_value);
TRACE_INFO("Synchro done\n\r");
// Switch to functionnal mode
//outi(0x30DC00, 0xDC00);
INIT_ARG_REG = 0x4C727354; // INIT_ARG = INIT_CMD_START_INIT
INIT_ARG_REG = 0x4C6F634B; // INIT_ARG = INIT_CMD_START_INIT
INIT_CMD_REG = 0x03; // INIT_CMD = INIT_CMD_CYCLE_IDX_LOCKED
// Return the programmed clock_out_delay value
return(ret_value);
}
//------------------------------------------------------------------------------
// CAP9 / FPGA synchronization loop - CAP9 RevB
//------------------------------------------------------------------------------
unsigned int fpga_synchro_revB(void)
{
unsigned char clk_out_delay_mean;
unsigned char clk_out_delay = 0;
unsigned int time = 0;
INIT_ARG_REG = 0x5C00; //
wait_slck_periods(1); // about 30us (wait 10us for FPGA PLL relock)
INIT_CMD_REG = 0x01; // INIT_CMD = INIT_CMD_START_INIT
//Search first match value
time = 0;
while(((CYCLE_IDX_RESP_R_LSB_REG != CYCLE_IDX_RESP_F_LSB_REG)||(CYCLE_IDX_RESP_R_MSB_REG != ~CYCLE_IDX_RESP_F_MSB_REG))&&time++<FPGA_SYNCHRO_TIMEOUT1)DELAY_CTRL_REG=(clk_out_delay++ << 8)|0x1;
if(time > FPGA_SYNCHRO_TIMEOUT1)return(FPGA_SYNCHRO_ERROR1);
clk_out_delay_mean = clk_out_delay;
//Search last match value
DELAY_CTRL_REG=(clk_out_delay++ << 8)|0x1;
while(((CYCLE_IDX_RESP_R_LSB_REG == CYCLE_IDX_RESP_F_LSB_REG)&&(CYCLE_IDX_RESP_R_MSB_REG == ~CYCLE_IDX_RESP_F_MSB_REG))&&time++<FPGA_SYNCHRO_TIMEOUT2)DELAY_CTRL_REG=(clk_out_delay++ << 8)|0x1;
if(time>FPGA_SYNCHRO_TIMEOUT2)return(FPGA_SYNCHRO_ERROR2);
clk_out_delay_mean = (clk_out_delay_mean + clk_out_delay)/2;
// Setup to middle match value
DELAY_CTRL_REG = (clk_out_delay_mean << 8) | 0x1;
// Cycle index select
time = 0;
while((CYCLE_IDX_RESP_R_LSB_REG != 0x0A7014E0)&&time++<FPGA_SYNCHRO_TIMEOUT3) {
INIT_ARG_REG = 0x02; // INIT_ARG = 2
INIT_CMD_REG = 0x02; // INIT_CMD = INIT_CMD_ADD_CYCLE
}
if(time>FPGA_SYNCHRO_TIMEOUT3)return(FPGA_SYNCHRO_ERROR3);
// Return the programmed clock_out_delay value
return ((unsigned int)clk_out_delay_mean);
}
//------------------------------------------------------------------------------
// Enable CAP to FPGA clock, and configure pads - CAP9 RevB
//------------------------------------------------------------------------------
void init_mpbs_revB(volatile unsigned int* mpbs,char pun,char lp,char sup)
{
//AT91PS_CCFG pCCFG = (AT91PS_CCFG) AT91C_BASE_CCFG;
//pCCFG->CCFG_MPBS0 |= (1<<31) | (1<<16) | (1<<24);
unsigned int value;
if (mpbs!=MPBS0 && mpbs!=MPBS1 && mpbs!=MPBS2 && mpbs!=MPBS3)
return;
value = *mpbs | MPBS_ENABLE_BIT;
if (pun==PULLUP_ON) value&= ~(MPIOB_PUN_BIT|MPIOA_PUN_BIT);
else if (pun==PULLUP_OFF) value|= (MPIOB_PUN_BIT|MPIOA_PUN_BIT);
if (lp==LOWPOWER_ON) value|= (MPIOB_LP_BIT|MPIOA_LP_BIT);
else if(lp==LOWPOWER_OFF)value&= ~(MPIOB_LP_BIT|MPIOA_LP_BIT);
if (sup==SUPPLY_33) value|= (MPIOB_SUP_BIT|MPIOA_SUP_BIT);
else if(sup==SUPPLY_18)value&= ~(MPIOB_SUP_BIT|MPIOA_SUP_BIT);
*mpbs = value;
}
//------------------------------------------------------------------------------
/// Wait specified number of slow clock periods (30.52uS if external 32KHz)
//------------------------------------------------------------------------------
void wait_slck_periods(int periods)
{
RTT_SetPrescaler(AT91C_BASE_RTTC, 1);
while(RTT_GetTime(AT91C_BASE_RTTC)!=periods);
}
//------------------------------------------------------------------------------
/// Wait for correct FPGA configuration (used after POR)
//------------------------------------------------------------------------------
void wait_for_FPGA_config()
{
int i;
for(i=0;i<POWER_ON_TEMPO;++i);
}
//------------------------------------------------------------------------------
/// Wait for correct FPGA configuration (used after POR) / CAP9S3-DKZ
//------------------------------------------------------------------------------
void wait_for_FPGA_config_CAP9S3()
{
PIO_Configure(&pinPC13, 1);
while(!PIO_Get(&pinPC13)); // Wait for config_done
wait_slck_periods(4); // Wait 100us more for user mode
}
//------------------------------------------------------------------------------
// FPGA pattern checking
//------------------------------------------------------------------------------
unsigned int search_last_match()
{
unsigned int clkin_delay;
clkin_delay = (DELAY_CTRL_REG >> 16)&(0xFF);
while (fpga_pattern_ok() && (clkin_delay++ < master_cnt_hold))
DELAY_CTRL_REG=(clkin_delay << 16)|0x1;
return clkin_delay;
}
unsigned int search_first_match()
{
unsigned int clkin_delay;
clkin_delay = (DELAY_CTRL_REG >> 16)&(0xFF);
while (!fpga_pattern_ok() && (clkin_delay++ < master_cnt_hold))
DELAY_CTRL_REG=(clkin_delay << 16)|0x1;
return clkin_delay;
}
int fpga_pattern_ok()
{
return((CYCLE_IDX_RESP_R_LSB_REG == CYCLE_IDX_RESP_F_LSB_REG)&&(CYCLE_IDX_RESP_R_MSB_REG == ~CYCLE_IDX_RESP_F_MSB_REG));
}
|