/************************************************************************************* * resetRod.c * * synopsis: A collection of routines which use the general purpose pins on the * serial ports to tell the program reset manager FPGA to reset a part * of the board, and associated clock testing routines. These routines are primarily * used to force all the slave's clocks to be in sync, which is necessary for the * router. * * in this file: resetSlave, resetSlaveSync, resetRod, waitPRMAck, waitRodBusy ************************************************************************************/ #include #include #include #include #include #include #include "resources.h" #include "registerIndices.h" #pragma CODE_SECTION(resetSlave, "xcode"); #pragma CODE_SECTION(resetSlaveSync, "xcode"); #pragma CODE_SECTION(resetRod, "xcode"); #pragma CODE_SECTION(waitPRMAck, "xcode"); #pragma CODE_SECTION(waitRodBusy, "xcode"); extern char genStr[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ /* Program Reset Manager pulse series meanings: */ #define PRM_RESET_SLAVE(x) (1 +(x)) #define PRM_RESET_BOARD 5 #define PRM_RECONFIG_ROUTER 6 #define PRM_RECONFIG_EFB 7 #define PRM_RECONFIG_FORMATTERS 8 #define PRM_RECONFIG_CONTROLLER 9 #define ROD_BUSY_TIMEOUT 300000000 /* in 1/10th microseconds */ /************************************************************************************ * resetSlave * synopsis: Sends a request via the serial port receiver (which is held in reset * and thus available for general purpose I/O -- fsr 1 is used) to the Program Reset * Manager. The PRM responds by resetting the requested chip(s), and sends an * acknowledgement signal back through another serial port receiver pin when this * is accomplished. ************************************************************************************/ void resetSlave(UINT8 slave) { //UINT32 x; /* Before resetting the SDSP on a Rev. E ROD, the 162245 (bus-hold 16 bit transceiver) chip on the ROD should be placed in a state where all the lines are held high; this will guarantee that the DSP mode select bits are read correctly at DSP reset. This can be accomplished by writing to the HPIA register before resetting the SDSP. */ if (getRodRev() == 0xe) writeSlvHPIA(slave, 0xffffffff); resetRod(PRM_RESET_SLAVE(slave)); } /************************************************************************************ * resetSlaveSync * synopsis: Resets a slave DSP and then checks to make sure its clock is in * sychronization; re-tries up to the input limit if not. After slave * is up and running, configures its EMIF registers. The clock synchronization * is only really possible on a Rev. C ROD. Rev. B Rods have clocks which cannot * be synchronized due to a manufacturing error, and Rev. E RODs have enough * global clocks on the router that all the clocks are synchronized at start. * Registers on these RODs will indicate that the clocks are already in sync * (the Rev. B ROD is lying); this is done so that this routine, which is called * from a primitive, will work on any ROD without requiring separate compilations * for each. * * arguments: see the primitive dspReset (which is a wrapper for this routine) ************************************************************************************/ INT32 resetSlaveSync(UINT8 slave, UINT8 forceSync, UINT32 nAttemptsTot, UINT32 timeOut, UINT8 info) { INT32 returnCode= SUCCESS, errorCode; UINT32 initTime, dt; UINT32 attempt, nAttempts= 0, sync; if (info) { sprintf(genStr, "Inputs: fS= %d, nAT= %d, timeOut= 0x%08x.\n", forceSync, nAttemptsTot, timeOut); newInformation(__FILE__, __LINE__, genStr); } /* wait while the ROD BUSY signal is active, with a timeout. The timeout uses timer 1; this *must* be run after that has been set up. */ initTime= TIMER_getCount(timer1); while ( (MCBSP_FGET(PCR1, DRSTAT)) &&((dt= delta_t(initTime)) < ROD_BUSY_TIMEOUT) ); if (MCBSP_FGET(PCR1, DRSTAT)) { sprintf(genStr, "%s0x%08x%s","The ROD BUSY signal is still set after ", ROD_BUSY_TIMEOUT," timer counts!\n"); newError(&returnCode, ROD_BUSY_ERR, FATAL_ERR, "resetSlaveSync", genStr, __FILE__, __LINE__); return returnCode; } else { if (info) { sprintf(genStr, "%s0x%08x, 0x%08x%s", "\n\nROD BUSY signal: init timer count, final polled dt= ", initTime, (dt/10000)," (dt in ms)\n"); newInformation(__FILE__, __LINE__, genStr); } } errorCode= readRegister(RTR_TRAP_STATUS(slave), 1, RTR_SLAVE_CLK_SYNC_O, &sync); if ((forceSync)&&(sync)) { if (info) { sprintf(genStr, "Slave DSP #%d clock is already in sync.\n", slave); newInformation(__FILE__, __LINE__, genStr); } return returnCode; } do { ++nAttempts; if (info) { sprintf(genStr, "Resetting DSP #%d.\n", slave); newInformation(__FILE__, __LINE__, genStr); } resetSlave(slave); errorCode= waitPRMAck(timeOut, info); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "resetSlaveSync", "waitPRMAck", __FILE__, __LINE__); return returnCode; } if (!forceSync) { attempt= FALSE; } else { errorCode= readRegister(RTR_TRAP_STATUS(slave), 1, RTR_SLAVE_CLK_SYNC_O, &sync); if ((!sync)&&(nAttempts < nAttemptsTot)) { attempt= TRUE; } else { attempt= FALSE; if (!sync) { sprintf(genStr, "%s%d%s%d%s", "Phase/delay lock on DSP #", slave, " still fails after ",nAttempts, " attempts.\n"); newError(&returnCode, LIMIT_EXCEEDED, FATAL_ERR, "resetSlaveSync", genStr, __FILE__, __LINE__); } else if (info) { sprintf(genStr, "%s%d%s%d%s", "Phase/delay lock on DSP #", slave, " corrected after ",nAttempts, " attempts.\n"); newInformation(__FILE__, __LINE__, genStr); } } } } while (attempt); /* Now re-load the slaves's EMIF registers, and (for a rev. E ROD), set the clock to run at 220 MHz (routine does nothing on a Rev. C ROD). Setting the EMIF is also done in the SDSP's routine initEmif; however the code will not be running yet & access to the external memory is needed to load the external code. Note that the EMIF must be set before setting the clock. Before any of this is done, a Rev. E ROD ought to be told that the SDSP clock is currently running at 40 MHz; this is done using the SLOW_SDSP_CLOCK_ENABLE bit in RRIF cmnd. 0 */ if (getRodRev() == 0xe) writeRegister(RRIF_CMND_0, 1, SLOW_SDSP_CLOCK_ENABLE, 1); errorCode = initSlvEmif(slave); //dpsf SDSP -> 160 MHz by default; Rev. E claimed unstable at 220? //errorCode|= setSlvClk(slave, 11); errorCode|= setSlvClk(slave, 8); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "resetSlaveSync", "initSlvEmif", __FILE__, __LINE__); } if (getRodRev() == 0xe) writeRegister(RRIF_CMND_0, 1, SLOW_SDSP_CLOCK_ENABLE, 0); return returnCode; } /************************************************************************************ * resetRod * synopsis: Resets the whole board, or one of the chips. ************************************************************************************/ void resetRod(UINT8 pulseSeries) { UINT8 i; MCBSP_FSET(PCR1, FSRP, 1); MCBSP_FSET(PCR1, FSRP, 0); asm(" nop 9"); asm(" nop 9"); for (i= 0; i < pulseSeries; ++i) { MCBSP_FSET(PCR1, FSRP, 1); MCBSP_FSET(PCR1, FSRP, 0); } } /************************************************************************************ * waitPRMAck * synopsis: Waits for the acknowledgement pulse from the PRM, with a time-out (in * micro-seconds). Exits with an error if the ack does not come by then. * * modifications/bugs: * - Replaced call to startUserTimer with a measurement of the time at * init-- the user timer is now started in main() with the maximal period * and left running. Successive calls to TIMER_getCount will subtract * correctly. 09.01.03 dpsf ************************************************************************************/ INT32 waitPRMAck(UINT32 timeOut, UINT8 info) { INT32 returnCode= SUCCESS; UINT8 timedOut= FALSE; UINT32 timeoutInTmrUnits, timerCnt, initTime; initTime= TIMER_getCount(timer1); /* Get the time-out delay in timer units. */ timeoutInTmrUnits= timeOut * (DSPClockInMHz()/4); /* The acknowledgement begins upon reception of the DSP serial port string and lasts until the end of the reset (several micro-seconds long); this amount is large enough that it will be caught even if the routine is running out of SDRAM. */ while ((MCBSP_FGET(PCR0, DRSTAT))&&(!timedOut)) { if ((timerCnt= TIMER_getCount(timer1) -initTime) > timeoutInTmrUnits) { sprintf(genStr, "%s%s0x%08x %s0x%08x %s0x%08x, 0x%08x%s", " Timer timed out waiting for PRM Ack!\n", " Init count: ", initTime, " Final polled timer count: ", timerCnt, " (timeOuts: ", timeOut, timeoutInTmrUnits, ").\n"); newError(&returnCode, TIMEOUT_ERR, FATAL_ERR, "waitPRMAck", genStr, __FILE__, __LINE__); timedOut= TRUE; } } if ((!timedOut)&&(info)) { sprintf(genStr, "%s0x%08x %s0x%08x %s0x%08x%s", " init count: ", initTime, " Final polled timer count: ", timerCnt, " (timeOut: ", timeoutInTmrUnits, ").\n"); newInformation(__FILE__, __LINE__, genStr); } return returnCode; } /************************************************************************************ * waitRodBusy: * synopsis: Waits for the ROD busy signal to clear, with a timeout. ROD Busy is * sent to the MDSP using the MCBSP DRSTAT1 register (the serial port * receivers are used as general purpose I/O). ************************************************************************************/ INT32 waitRodBusy() { INT32 returnCode= SUCCESS; UINT32 initTime, dt; /* wait while the ROD BUSY signal is active, with a timeout. The timeout uses timer 1; this *must* be run after that has been set up. */ initTime= TIMER_getCount(timer1); while ( (MCBSP_FGET(PCR1, DRSTAT)) &&((dt= delta_t(initTime)) < ROD_BUSY_TIMEOUT) ); if (MCBSP_FGET(PCR1, DRSTAT)) { sprintf(genStr, "%s0x%08x%s","The ROD BUSY signal is still set after ", ROD_BUSY_TIMEOUT," timer counts!\n"); newError(&returnCode, ROD_BUSY_ERR, FATAL_ERR, "waitRodBusy", genStr, __FILE__, __LINE__); } return returnCode; }