//------------------------------------------------------------------------------ // // 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: OEMGetTickCount // // This returns the number of milliseconds that have elapsed since Windows // CE was started. If the system timer period is 1ms the function simply // returns the value of CurMSec. If the system timer period is greater then // 1 ms, the HiRes offset is added to the value of CurMSec. // UINT32 OEMGetTickCount( ) { UINT64 baseCounts; UINT32 offset; // This code adjusts the accuracy of the returned value to the nearest // MSec when the system tick exceeds 1 ms. The following code checks if // a system timer interrupt occurred between reading the CurMSec value // and the call to fetch the HiResTicksSinceSysTick. If so, the value of // CurMSec and Offset is re-read, with the certainty that a system timer // interrupt will not occur again. do { baseCounts = g_oalTimerContext.curCounts; offset = OALTimerGetCount() - g_oalTimerContext.base; } while (baseCounts != g_oalTimerContext.curCounts); // Update CurMSec (kernel uses both CurMSec and GetTickCount() at different places) and return msec tick count CurMSec = (UINT32)TICK_TO_MSEC(baseCounts + offset); return CurMSec; }
//------------------------------------------------------------------------------ // // 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: 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: 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: 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: OALTimerUpdateRescheduleTime // // This function is called by kernel to set next reschedule time. // VOID OALTimerUpdateRescheduleTime( DWORD timeMSec ) { UINT32 baseMSec, periodMSec; INT32 delta; // Get current system timer counter baseMSec = CurMSec; // How far we are from next tick delta = (INT32)(g_oalTimerContext.match - OALTimerGetCount()); if( delta < 0 ) { UpdatePeriod(0); goto cleanUp; } // If timer interrupts occurs, or we are within 1 ms of the scheduled // interrupt, just return - timer ISR will take care of it. if ((baseMSec != CurMSec) || (delta < MSEC_TO_TICK(1))) goto cleanUp; // Calculate the distance between the new time and the last timer interrupt periodMSec = timeMSec - OEMGetTickCount(); // Trying to set reschedule time prior or equal to CurMSec - this could // happen if a thread is on its way to sleep while preempted before // getting into the Sleep Queue if ((INT32)periodMSec < 0) { periodMSec = 0; } else if (periodMSec > g_oalTimerContext.maxPeriodMSec) { periodMSec = g_oalTimerContext.maxPeriodMSec; } // Now we find new period, so update timer UpdatePeriod(periodMSec); cleanUp: return; }
//------------------------------------------------------------------------------ // // Function: OALTimerCountsSinceSysTick // INT32 OALTimerCountsSinceSysTick() { return OALTimerGetCount() - g_timer.base; }
//------------------------------------------------------------------------------ // // 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); }
/** * PrcmVoltScaleVoltageABB - controls ABB ldo during voltage scaling * @target_volt: target voltage determines if ABB ldo is active or bypassed * * Adaptive Body-Bias is a technique in all OMAP silicon that uses the 45nm * process. ABB can boost voltage in high OPPs for silicon with weak * characteristics (forward Body-Bias) as well as lower voltage in low OPPs * for silicon with strong characteristics (Reverse Body-Bias). * * Only Foward Body-Bias for operating at high OPPs is implemented below, per * recommendations from silicon team. * Reverse Body-Bias for saving power in active cases and sleep cases is not * yet implemented. */ int PrcmVoltScaleVoltageABB(UINT32 target_opp_no) { UINT32 sr2en_enabled; UINT32 timeout; int sr2_wtcnt_value; UINT32 regVal =0; UINT32 tcrr; /* calculate SR2_WTCNT_VALUE settling time */ sr2_wtcnt_value = (ABB_MAX_SETTLING_TIME * (PrcmClockGetClockRate(SYS_CLK)) / 8); /* has SR2EN been enabled previously? */ sr2en_enabled = INREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_CTRL) & SMPS_SR2EN; // enable voltage processor PrcmVoltEnableVp(kVDD1, TRUE); /* select fast, nominal or slow OPP for ABB ldo */ if (target_opp_no >= ABB_FAST_OPP_VAL) { /* program for fast opp - enable FBB */ regVal = INREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_SETUP); regVal = (regVal & ~(SMPS_OPP_SEL_MASK)) | (ABB_FAST_OPP << SMPS_OPP_SEL_SHIFT); OUTREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_SETUP,regVal); /* enable the ABB ldo if not done already */ if (!sr2en_enabled) SETREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_CTRL,SMPS_SR2EN); } else if (sr2en_enabled) { /* program for nominal opp - bypass ABB ldo */ regVal = INREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_SETUP); regVal = (regVal & ~(SMPS_OPP_SEL_MASK)) | (ABB_NOMINAL_OPP << SMPS_OPP_SEL_SHIFT); OUTREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_SETUP,regVal); } else { /* nothing to do here yet... might enable RBB here someday */ goto cleanUp; } /* set ACTIVE_FBB_SEL for all 45nm silicon */ SETREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_CTRL,SMPS_ACTIVE_FBB_SEL); /* program settling time of 30us for ABB ldo transition */ regVal = INREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_CTRL); regVal = (regVal & ~(SMPS_SR2_WTCNT_VALUE_MASK)) | (sr2_wtcnt_value << SMPS_SR2_WTCNT_VALUE_SHIFT); OUTREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_CTRL,regVal); /* clear ABB ldo interrupt status */ OUTREG32(&g_pPrcmPrm->pOMAP_OCP_SYSTEM_PRM->PRM_IRQSTATUS_MPU, PRM_IRQENABLE_ABB_LDO_TRANXDONE_ST); /* enable ABB LDO OPP change */ SETREG32(&g_pPrcmPrm->pOMAP_GLOBAL_PRM->PRM_LDO_ABB_SETUP,SMPS_OPP_CHANGE); /* wait until OPP change completes */ timeout=tcrr=OALTimerGetCount(); while (((INREG32(&g_pPrcmPrm->pOMAP_OCP_SYSTEM_PRM->PRM_IRQSTATUS_MPU) & PRM_IRQENABLE_ABB_LDO_TRANXDONE_ST) == 0) && ((timeout - tcrr) < ABB_MAX_SETTLING_TIME_IN_TICKS)) { timeout=OALTimerGetCount(); } if (timeout >= tcrr+ABB_MAX_SETTLING_TIME_IN_TICKS) RETAILMSG(0,(L"ABB: TRANXDONE timed out waiting for OPP change\r\n")); timeout=tcrr=OALTimerGetCount(); /* Clear all pending TRANXDONE interrupts/status */ while ((timeout - tcrr) < ABB_MAX_SETTLING_TIME_IN_TICKS) { OUTREG32(&g_pPrcmPrm->pOMAP_OCP_SYSTEM_PRM->PRM_IRQSTATUS_MPU, PRM_IRQENABLE_ABB_LDO_TRANXDONE_ST); if (!(INREG32(&g_pPrcmPrm->pOMAP_OCP_SYSTEM_PRM->PRM_IRQSTATUS_MPU) & PRM_IRQENABLE_ABB_LDO_TRANXDONE_ST)) break; timeout=OALTimerGetCount(); } if (timeout >= tcrr+ABB_MAX_SETTLING_TIME_IN_TICKS) RETAILMSG(0,(L"ABB: TRANXDONE timed out trying to clear status\n")); cleanUp: // disable the voltage processor sub-chip PrcmVoltEnableVp(kVDD1, FALSE); return 0; }
//------------------------------------------------------------------------------ // // Function: OALTimerIntrHandler // // This function implement timer interrupt handler. It is called from common // ARM interrupt handler. // UINT32 OALTimerIntrHandler() { UINT32 count; INT32 period, delta; UINT32 sysIntr = SYSINTR_NOP; // allow bsp to process timer interrupt first sysIntr = OALTickTimerIntr(); if (sysIntr != SYSINTR_NOP) return sysIntr; // Clear interrupt OALTimerSetReg(&g_pTimerRegs->TISR, GPTIMER_TIER_MATCH); // How far from interrupt we are? count = OALTimerGetCount(); delta = count - g_oalTimerContext.match; // If delta is negative, timer fired for some reason // To be safe, reprogram the timer for minimum delta if (delta < 0) { delta = 0; goto cleanUp; } #ifdef OAL_ILTIMING if (g_oalILT.active) { g_oalILT.isrTime1 = delta; } #endif // Find how long period was period = count - g_oalTimerContext.base; g_oalTimerContext.curCounts += period; g_oalTimerContext.base += period; // Calculate actual CurMSec CurMSec = (UINT32) TICK_TO_MSEC(g_oalTimerContext.curCounts); OALLED(LED_IDX_TIMER, CurMSec >> 10); // Reschedule? delta = dwReschedTime - CurMSec; if (delta <= 0) { sysIntr = SYSINTR_RESCHED; delta = g_oalTimerContext.maxPeriodMSec; } cleanUp: // Set new period UpdatePeriod(delta); #ifdef OAL_ILTIMING if (g_oalILT.active) { if (--g_oalILT.counter == 0) { sysIntr = SYSINTR_TIMING; g_oalILT.counter = g_oalILT.counterSet; g_oalILT.isrTime2 = 0; } } #endif return sysIntr; }
//------------------------------------------------------------------------------ // // Function: OALTimerCountsSinceSysTick // INT32 OALTimerCountsSinceSysTick() { return OALTimerGetCompare() - OALTimerGetCount(); }