/* * ======== Watchdog_init ======== */ Void Watchdog_init( Void (*timerFxn)(Void) ) { Hwi_Params hwiParams; UInt key; Timer_Handle tHandle; Types_FreqHz tFreq; Watchdog_TimerRegs *timer; Int i; tHandle = Timer_Object_get(NULL, 0); Timer_getFreq(tHandle, &tFreq); /* get timer frequency */ for (i = 0; i < Watchdog_module->wdtCores; i++) { /* loop for SMP cores */ timer = (Watchdog_TimerRegs *) Watchdog_module->device[i].baseAddr; /* Check if timer is enabled by host-side */ if ((REG32(Watchdog_module->device[i].clkCtrl) & WATCHDOG_WDT_CLKCTRL_IDLEST_MASK) == WATCHDOG_WDT_CLKCTRL_IDLEST_MASK) { System_printf("Watchdog disabled: TimerBase = 0x%x ClkCtrl = 0x%x\n", timer, Watchdog_module->device[i].clkCtrl); continue; /* for next core */ } /* Configure the timer */ initTimer(timer, TRUE); /* Enable interrupt in BIOS */ Hwi_Params_init(&hwiParams); hwiParams.priority = 1; hwiParams.eventId = Watchdog_module->device[i].eventId; hwiParams.maskSetting = Hwi_MaskingOption_LOWER; key = Hwi_disable(); Hwi_create(Watchdog_module->device[i].intNum, (Hwi_FuncPtr) timerFxn, &hwiParams, NULL); Hwi_enableInterrupt(Watchdog_module->device[i].intNum); Hwi_restore(key); /* Enable timer */ while (timer->twps & WATCHDOG_TIMER_TWPS_W_PEND_TCLR); timer->tclr |= 1; Watchdog_module->status[i] = Watchdog_Mode_ENABLED; #ifdef SMP System_printf("Watchdog enabled: TimerBase = 0x%x SMP-Core = %d " "Freq = %d\n", timer, i, tFreq.lo); #else System_printf("Watchdog enabled: TimerBase = 0x%x Freq = %d\n", timer, tFreq.lo); #endif } /* Register callback function */ if (!IpcPower_registerCallback(IpcPower_Event_RESUME, Watchdog_restore, NULL)) { System_printf("Watchdog_restore registered as a resume callback\n"); } return; }
/* * ======== Timer_trigger ======== */ Void Timer_trigger(Timer_Object *obj, UInt32 insts) { UInt64 cpuCounts, timerCounts; Types_FreqHz timerfreq, cpufreq; UInt32 ratio; UInt32 period; UInt32 count; UInt key; /* get CPU frequency */ BIOS_getCpuFreq(&cpufreq); cpuCounts = (cpufreq.hi * (1 < 0xffffffff)) + cpufreq.lo; /* get Timer frequency */ Timer_getFreq(obj, &timerfreq); timerCounts = (timerfreq.hi * (1 < 0xffffffff)) + timerfreq.lo; ratio = cpuCounts/timerCounts; period = insts / ratio; count = ratio - (insts % ratio); if (period == 0) { period = 1; } /* follow proper procedure for dynamic period change */ key = Hwi_disable(); Timer_setPeriod(obj, period); Timer_start(obj); Timer_spinLoop(count); Hwi_restore(key); }
/* * ======== Timer_setPeriodMicroSecs ======== * 1. stop timer * 2. compute counts * 3. set period register * * For Davinci, the timer needs to be stopped for the new value to * be written (otherwise it gets dropped). */ Bool Timer_setPeriodMicroSecs(Timer_Object *obj, UInt32 period) { Types_FreqHz freqHz; UInt64 counts; UInt32 prdCounts; UInt32 freqKHz; TimerRegs *timer; UInt32 roundUp; timer = (TimerRegs *)Timer_module->device[obj->id].baseAddr; Timer_stop(obj); /* Today c64 supports less than 4.2GHz */ Timer_getFreq(obj, &freqHz); roundUp = ((freqHz.lo % 1000) >= 500) ? 1 : 0; freqKHz = (freqHz.lo / 1000) + roundUp; if (Timer_checkOverflow(freqKHz, period/1000)) { return (FALSE); } counts = ((UInt64)freqKHz * (UInt64)period) / (UInt64)1000; if (counts > 0xffffffff) { return (FALSE); } else { prdCounts = counts - 1; } obj->period = prdCounts; obj->periodType = Timer_PeriodType_COUNTS; if (obj->runMode != Timer_RunMode_DYNAMIC) { timer->tcrr = Timer_MAX_PERIOD - prdCounts; while (timer->twps & TIMER_TWPS_W_PEND_TCRR) ; timer->tldr = Timer_MAX_PERIOD - prdCounts; while (timer->twps & TIMER_TWPS_W_PEND_TLDR) ; } else { timer->tcrr = 0; while (timer->twps & TIMER_TWPS_W_PEND_TCRR) ; timer->tmar = prdCounts; while (timer->twps & TIMER_TWPS_W_PEND_TMAR) ; } return(TRUE); }
/* * ======== Timer_setPeriodMicroSecs ======== * 1. stop timer * 2. compute counts * 3. set period */ Bool Timer_setPeriodMicroSecs(Timer_Object *obj, UInt32 period) { Types_FreqHz freqHz; UInt64 counts; UInt32 freqKHz; Timer_stop(obj); Timer_getFreq(obj, &freqHz); freqKHz = freqHz.lo / 1000; counts = ((UInt64)freqKHz * (UInt64)period) / (UInt64)1000; obj->period = counts; obj->periodType = Timer_PeriodType_COUNTS; return(TRUE); }
/* * ======== Timer_setPeriodMicroSecs ======== * 1. stop timer * 2. compute counts * 3. set period register */ Bool Timer_setPeriodMicroSecs(Timer_Object *obj, UInt32 period) { Types_FreqHz freqHz; UInt64 counts; UInt32 freqKHz; Timer_stop(obj); Timer_getFreq(obj, &freqHz); freqKHz = freqHz.lo / 1000; counts = (freqKHz * period) / 1000; obj->period = counts; obj->periodType = Timer_PeriodType_COUNTS; timerDevices[obj->id].load = counts; return(TRUE); }
/* * ======== Timer_setPeriodMicroSecs ======== * * 1. Stop timer * 2. Compute counts * 3. Set new period value in timer obj * */ Bool Timer_setPeriodMicroSecs(Timer_Object *obj, UInt32 period) { Types_FreqHz freqHz; UInt32 counts; UInt32 freqKHz; Timer_stop(obj); Timer_getFreq(obj, &freqHz); freqKHz = freqHz.lo / 1000; if (checkOverflow(freqKHz, period/1000)) { return (FALSE); } else { counts = (freqKHz * period) / 1000; obj->period = counts; obj->periodType = Timer_PeriodType_COUNTS; return(TRUE); } }
/* * ======== initTimer ======== */ static Void initTimer(Watchdog_TimerRegs *timer, Bool boot) { Timer_Handle tHandle; Types_FreqHz tFreq; /* Get timer frequency */ tHandle = Timer_Object_get(NULL, 0); Timer_getFreq(tHandle, &tFreq); timer->tisr = ~0; timer->tier = 2; timer->twer = 2; timer->tldr = (0 - (tFreq.lo * Watchdog_TIME_SEC)); /* Booting can take more time, so set CRR to WDT_BOOT_TIME */ if (boot) { timer->tcrr = (0 - (tFreq.lo * Watchdog_BOOT_TIME_SEC)); } else { timer->tcrr = (0 - (tFreq.lo * Watchdog_TIME_SEC)); } timer->tsicr |= 4; /* enable posted write mode */ }
/* * ======== TimestampProvider_getFreq ======== */ Void TimestampProvider_getFreq(Types_FreqHz *freq) { Timer_getFreq(MOD->timer, freq); }
/* * ======== Timer_checkFreq ======== */ Void Timer_checkFreq(Timer_Object *obj) { UInt key; UInt32 timerCountStart, timerCountEnd, tsCountStart, tsCountEnd; UInt32 deltaTs, deltaCnt; Types_FreqHz timerFreq, timestampFreq; UInt freqRatio; UInt32 actualFrequency; Timer_Object tempObj; /* * Make a temporary copy of 'obj' and modify it to be used for the timer * frequency check. Set the period to Timer_MAX_PERIOD to ensure that * the timer does not roll over while performing the check. */ memcpy((void *)&tempObj, (void *)obj, sizeof(Timer_Object)); tempObj.period = Timer_MAX_PERIOD; tempObj.periodType = Timer_PeriodType_COUNTS; tempObj.runMode = Timer_RunMode_ONESHOT; tempObj.startMode = Timer_StartMode_USER; /* Initialize the timer registers */ Timer_deviceConfig(&tempObj, NULL); /* Get the frequencies of the Timer and the Timestamp */ Timer_getFreq(&tempObj, &timerFreq); Timestamp_getFreq(×tampFreq); /* Assume that timer frequency is less than 2^32 Hz */ Assert_isTrue(timestampFreq.hi == 0 && timerFreq.hi == 0, NULL); freqRatio = timestampFreq.lo / timerFreq.lo; key = Hwi_disable(); /* * Warning: halting the core between Timer_start and the point of * code indicated below can cause the frequency check to fail. This is * is because the DMTimer will continue to run while this core is halted, * this causing the ratio between timer counts to change */ Timer_start(&tempObj); /* Record the initial timer & timestamp counts */ timerCountStart = Timer_getCount(&tempObj); tsCountStart = Timestamp_get32(); /* Wait for 'TIMERCOUNTS' timer counts to elapse */ while (Timer_getCount(&tempObj) < timerCountStart + TIMERCOUNTS); timerCountEnd = Timer_getCount(&tempObj); /* Record the timestamp ticks that have elapsed during the above loop */ tsCountEnd = Timestamp_get32(); /* End of code segment where core should not be halted */ Hwi_restore(key); deltaTs = tsCountEnd - tsCountStart; deltaCnt = timerCountEnd - timerCountStart; /* Check the timer frequency. Allow a margin of error. */ if (((deltaTs / deltaCnt) > freqRatio * 2) || ((deltaTs / deltaCnt) < freqRatio / 2)) { actualFrequency = ((UInt64)timestampFreq.lo * (UInt64)deltaCnt) / (UInt64)deltaTs; Error_raise(NULL, Timer_E_freqMismatch, Timer_module->intFreqs[obj->id].lo, actualFrequency); } }