/* ---------------------------------------------------------------------------- * 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 #include #include #include #include #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)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)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)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)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)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)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)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> 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)); }