//------------------------------------------------------------------------------ // // Function: UpdatePeriod // VOID UpdatePeriod( UINT32 periodMSec ) { UINT32 period, match; INT32 delta; UINT64 offsetMSec = periodMSec; UINT64 tickCount = OALGetTickCount(); INT nDelay; // Calculate count difference period = (UINT32)MSEC_TO_TICK(offsetMSec); nDelay = min(period, DELTA_TIME); // This is compare value match = ((UINT32)MSEC_TO_TICK(tickCount)) + nDelay; delta = (INT32)(OALTimerGetCount()+ g_oalTimerContext.margin - match); // If we are behind, issue interrupt as soon as possible if (delta > 0) { match += MSEC_TO_TICK(1); } // Save off match value g_oalTimerContext.match = match; // Set timer match value OALTimerSetCompare(match); }
//------------------------------------------------------------------------------ // // Function: OALTimerReduceSysTick // UINT32 OALTimerReduceSysTick(UINT32 count, UINT32 margin) { UINT32 rc, edge, compare; edge = OALTimerGetCount(); compare = OALTimerGetCompare(); // Update the countdown value OALTimerSetCompare(count); if (edge > margin) { // We are far enough from the interrupt that we should return the // number of ticks that would have occurred since the last tick based // on the new number of counts per tick. We will avoid the interrupt and // just start fresh. rc = (compare - edge) / count; OALTimerSetCount(count); } else { // We are close enough to the next interrupt that we will let the // interrupt occur. We will also return the number of counts that would // have happened since the last tick based on the new number of counts // per tick, but we will subtract one because another is just about to // happen. rc = (compare / count) - 1; } return rc; }
//------------------------------------------------------------------------------ // // Function: OALTimerUpdate // // This function is called to change length of actual system timer period. // When end of new period is closer to actual time than margin period end // is shifted by margin (but next period should fix this shift - this is // reason why OALTimerRecharge doesn't read back compare register and it // uses saved value instead). // UINT32 OALTimerUpdate(UINT32 period, UINT32 margin) { UINT32 edge; // New compare value is base plus period g_timer.compare = g_timer.base + period; // Are we more than margin before new compare? edge = OALTimerGetCount() + margin; if ((INT32)(g_timer.compare - edge) > 0) { // Yes, then use calculated value OALTimerSetCompare(g_timer.compare); } else { // No, shift real compare value OALTimerSetCompare(edge); } return 0; }
//------------------------------------------------------------------------------ // // Function: OALTimerExtendSysTick // VOID OALTimerExtendSysTick(UINT32 count, UINT32 margin, UINT32 offset) { UINT32 compare, edge; edge = OALTimerGetCount(); compare = OALTimerGetCompare(); if (edge > ((count - compare) + margin + offset)) { // We are far enough away from the interrupt that we should just // increase the time it will take to hit the next interrupt taking into // account the offset provided. OALTimerSetCount(edge - (count - offset - compare)); } OALTimerSetCompare(count); }
//------------------------------------------------------------------------------ // // Function: OALTimerRecharge // // This function recharge count/compare timer. In case that we are late more // than margin value we will use count as new counter base. Under // normal conditions previous compare value stored in global variable is used. // Using global variable instead reading compare register allows compensate // offset when we reduce system tick to value which can cause hazard. // VOID OALTimerRecharge(UINT32 period, UINT32 margin) { UINT32 count; count = OALTimerGetCount(); // Check if recharge was called in required margin if ((INT32)(count - OALTimerGetCompare() - margin) < 0) { // Yes, base new period on previous (no shift) g_timer.base = g_timer.compare; g_timer.compare += period; } else { // No, base new period on actual counter value (shift) g_timer.base = count; g_timer.compare = g_timer.base + period; } OALTimerSetCompare(g_timer.compare); }
//------------------------------------------------------------------------------ // // Function: OALTimerInitCount // // This function initialize count/compare timer. // VOID OALTimerInitCount(UINT32 period) { g_timer.base = OALTimerGetCount(); g_timer.compare = g_timer.base + period; OALTimerSetCompare(g_timer.compare); }
//------------------------------------------------------------------------------ // // Function: OEMIdle // // This function is called by the kernel when there are no threads ready to // run. The CPU should be put into a reduced power mode if possible and halted. // It is important to be able to resume execution quickly upon receiving an // interrupt. // // Interrupts are disabled when OEMIdle is called and when it returns. // // This implementation doesn't change system tick. It is intend to be used // with variable tick implementation. However it should work with fixed // variable tick implementation also (with lower efficiency because maximal // idle time is 1 ms). // // WARNING: This function is called from deep within the kernel, it cannot make // any system calls, use any critical sections, or debug messages. // VOID OEMIdle( DWORD idleParam ) { static UINT _max = 0; static UINT _count = 0; INT delta; UINT tcrrTemp; UINT tcrrEnter, tcrrExit; UINT idleDelta, newIdleLow; INT wakeupDelay; INT maxDelay; DWORD latencyState; UNREFERENCED_PARAMETER(idleParam); PrcmInitializePrevPowerState(); // How far are we from next timer interrupt // If we are really near to timer interrupt do nothing... latencyState = OALWakeupLatency_GetCurrentState(); tcrrEnter = OALTimerGetReg(&g_pTimerRegs->TCRR); delta = g_oalTimerContext.match - tcrrEnter; if (delta < (INT32)g_oalTimerContext.margin) goto cleanUp; // get latency time... // // check if current latency is greater than current requirements maxDelay = min(delta, g_wakeupLatencyConstraintTickCount); wakeupDelay = OALWakeupLatency_GetDelayInTicks(latencyState); if (maxDelay < wakeupDelay) { // check if current state meets timing constraint latencyState = OALWakeupLatency_FindStateByMaxDelayInTicks(maxDelay); wakeupDelay = OALWakeupLatency_GetDelayInTicks(latencyState); } // check one last time to make sure we aren't going to sleep longer than if (maxDelay >= wakeupDelay) { // Indicate in idle OALLED(LED_IDX_IDLE, 1); if (OALWakeupLatency_IsChipOff(latencyState)) { if (!OALContextSave()) { // Context Save Failed goto cleanUp; } } // account for wakeup latency OALWakeupLatency_PushState(latencyState); g_oalTimerContext.match -= wakeupDelay; OALTimerSetCompare(g_oalTimerContext.match); } else { goto cleanUp; } // Move SoC/CPU to idle mode fnOALCPUIdle(g_pCPUInfo); // restore latency state OALWakeupLatency_PopState(); PrcmCapturePrevPowerState(); // get current TCRR value: workaround for errata 1.35 OALTimerGetReg(&g_pTimerRegs->TCRR); tcrrExit = OALTimerGetReg(&g_pTimerRegs->TCRR); PrcmProcessPostMpuWakeup(); // ERRATA 1.31 workaround do { tcrrTemp = OALTimerGetReg(&g_pTimerRegs->TCRR); } while (tcrrTemp == tcrrExit); PrcmProfilePrevPowerState(tcrrTemp, wakeupDelay); // Update idle counter idleDelta = OALTimerGetReg(&g_pTimerRegs->TCRR) - tcrrEnter; newIdleLow = curridlelow + idleDelta; if (newIdleLow < curridlelow) curridlehigh++; curridlelow = newIdleLow; cleanUp: OALLED(LED_IDX_IDLE, 0); return; }
//------------------------------------------------------------------------------ // VOID OALTimerInitCount(UINT32 count) { OALTimerSetCompare(count); OALTimerSetCount(count); }