/****************************************************************************** * Filename: sys_ctrl.c * Revised: 2018-06-26 15:19:11 +0200 (Tue, 26 Jun 2018) * Revision: 52220 * * Description: Driver for the System Control. * * Copyright (c) 2015 - 2017, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2) Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3) Neither the name of the ORGANIZATION nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. * ******************************************************************************/ // Hardware headers #include "../inc/hw_types.h" #include "../inc/hw_ccfg.h" #include "../inc/hw_adi.h" // Driverlib headers #include "aon_batmon.h" #include "setup_rom.h" #include "sys_ctrl.h" //***************************************************************************** // // Handle support for DriverLib in ROM: // This section will undo prototype renaming made in the header file // //***************************************************************************** #if !defined(DOXYGEN) #undef SysCtrlSetRechargeBeforePowerDown #define SysCtrlSetRechargeBeforePowerDown NOROM_SysCtrlSetRechargeBeforePowerDown #undef SysCtrlAdjustRechargeAfterPowerDown #define SysCtrlAdjustRechargeAfterPowerDown NOROM_SysCtrlAdjustRechargeAfterPowerDown #undef SysCtrl_DCDC_VoltageConditionalControl #define SysCtrl_DCDC_VoltageConditionalControl NOROM_SysCtrl_DCDC_VoltageConditionalControl #undef SysCtrlResetSourceGet #define SysCtrlResetSourceGet NOROM_SysCtrlResetSourceGet #endif //***************************************************************************** // // Recharge calculator defines and globals // //***************************************************************************** #define PD_STATE_CACHE_RET 1 #define PD_STATE_RFMEM_RET 2 #define PD_STATE_XOSC_LPM 4 #define PD_STATE_EXT_REG_MODE 8 typedef struct { uint32_t pdTime ; uint16_t pdRechargePeriod ; uint8_t pdState ; int8_t pdTemp ; } PowerQualGlobals_t; static PowerQualGlobals_t powerQualGlobals; //***************************************************************************** // // SysCtrlSetRechargeBeforePowerDown( xoscPowerMode ) // //***************************************************************************** void SysCtrlSetRechargeBeforePowerDown( uint32_t xoscPowerMode ) { int32_t curTemp ; int32_t shiftedTemp ; int32_t deltaVddrSleepTrim ; int32_t vddrTrimSleep ; int32_t vddrTrimActve ; int32_t diffVddrActiveSleep ; uint32_t ccfg_ModeConfReg ; uint32_t curState ; uint32_t prcmRamRetention ; uint32_t di ; uint32_t dii ; uint32_t ti ; uint32_t cd ; uint32_t cl ; uint32_t load ; uint32_t k ; uint32_t vddrCap ; uint32_t newRechargePeriod ; uint32_t perE ; uint32_t perM ; const uint32_t * pLookupTable ; // If external regulator mode we shall: // - Disable adaptive recharge (bit[31]=0) in AON_WUC_O_RECHARGECFG // - Set recharge period to approximately 500 mS (perM=31, perE=5 => 0xFD) // - Make sure you get a recalculation if leaving external regulator mode by setting powerQualGlobals.pdState accordingly if ( HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_PWRCTL ) & AON_SYSCTL_PWRCTL_EXT_REG_MODE ) { powerQualGlobals.pdState = PD_STATE_EXT_REG_MODE; HWREG( AON_WUC_BASE + AON_WUC_O_RECHARGECFG ) = 0x00A4FDFD; return; } //--- Spec. point 1 --- curTemp = AONBatMonTemperatureGetDegC(); curState = 0; // read the MODE_CONF register in CCFG ccfg_ModeConfReg = HWREG( CCFG_BASE + CCFG_O_MODE_CONF ); // Get VDDR_TRIM_SLEEP_DELTA + 1 (sign extended) deltaVddrSleepTrim = ((((int32_t) ccfg_ModeConfReg ) << ( 32 - CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_W - CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_S )) >> ( 32 - CCFG_MODE_CONF_VDDR_TRIM_SLEEP_DELTA_W )) + 1; // Do temperature compensation if enabled if (( ccfg_ModeConfReg & CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC ) == 0 ) { int32_t tcDelta = ( 62 - curTemp ) >> 3; if ( tcDelta > 8 ) tcDelta = 8; if ( tcDelta > deltaVddrSleepTrim ) deltaVddrSleepTrim = tcDelta; } { vddrTrimSleep = SetupSignExtendVddrTrimValue(( HWREG( FCFG1_BASE + FCFG1_O_LDO_TRIM ) & FCFG1_LDO_TRIM_VDDR_TRIM_SLEEP_M ) >> FCFG1_LDO_TRIM_VDDR_TRIM_SLEEP_S ) ; vddrTrimActve = SetupSignExtendVddrTrimValue(( HWREG( FCFG1_BASE + FCFG1_O_SHDW_ANA_TRIM ) & FCFG1_SHDW_ANA_TRIM_VDDR_TRIM_M ) >> FCFG1_SHDW_ANA_TRIM_VDDR_TRIM_S ) ; } vddrTrimSleep += deltaVddrSleepTrim; if ( vddrTrimSleep > 21 ) vddrTrimSleep = 21; if ( vddrTrimSleep < -10 ) vddrTrimSleep = -10; // Write adjusted value using MASKED write (MASK8) HWREGH( ADI3_BASE + ADI_O_MASK8B + ( ADI_3_REFSYS_O_DCDCCTL1 * 2 )) = (( ADI_3_REFSYS_DCDCCTL1_VDDR_TRIM_SLEEP_M << 8 ) | (( vddrTrimSleep << ADI_3_REFSYS_DCDCCTL1_VDDR_TRIM_SLEEP_S ) & ADI_3_REFSYS_DCDCCTL1_VDDR_TRIM_SLEEP_M )); prcmRamRetention = HWREG( PRCM_BASE + PRCM_O_RAMRETEN ); if ( prcmRamRetention & PRCM_RAMRETEN_VIMS_M ) { curState |= PD_STATE_CACHE_RET; } if ( prcmRamRetention & PRCM_RAMRETEN_RFC ) { curState |= PD_STATE_RFMEM_RET; } if ( xoscPowerMode != XOSC_IN_HIGH_POWER_MODE ) { curState |= PD_STATE_XOSC_LPM; } //--- Spec. point 2 --- if ((( curTemp - powerQualGlobals.pdTemp ) >= 5 ) || ( curState != powerQualGlobals.pdState )) { //--- Spec. point 3 --- shiftedTemp = curTemp - 15; //--- Spec point 4 --- //4. Check for external VDDR load option (may not be supported): ext_load = (VDDR_EXT_LOAD=0 in CCFG) // Currently not implementing external load handling // if ( __ccfg.ulModeConfig & MODE_CONF_VDDR_EXT_LOAD ) { // } pLookupTable = (uint32_t *)( FCFG1_BASE + FCFG1_O_PWD_CURR_20C ); //--- Spec point 5 --- di = 0; ti = 0; if ( shiftedTemp >= 0 ) { //--- Spec point 5.a --- shiftedTemp += ( shiftedTemp << 4 ); //--- Spec point 5.b --- ti = ( shiftedTemp >> 8 ); if ( ti > 7 ) { ti = 7; } dii = ti; if ( dii > 6 ) { dii = 6; } //--- Spec point 5.c --- cd = pLookupTable[ dii + 1 ] - pLookupTable[ dii ]; //--- Spec point 5.d --- di = cd & 0xFF; //--- Spec point 5.e --- if ( curState & PD_STATE_XOSC_LPM ) { di += (( cd >> 8 ) & 0xFF ); } if ( curState & PD_STATE_RFMEM_RET ) { di += (( cd >> 16 ) & 0xFF ); } if ( curState & PD_STATE_CACHE_RET ) { di += (( cd >> 24 ) & 0xFF ); } //--- Spec point 5.f --- // Currently not implementing external load handling } //--- Spec. point 6 --- cl = pLookupTable[ ti ]; //--- Spec. point 7 --- load = cl & 0xFF; //--- Spec. point 8 --- if ( curState & PD_STATE_XOSC_LPM ) { load += (( cl >> 8 ) & 0xFF ); } if ( curState & PD_STATE_RFMEM_RET ) { load += (( cl >> 16 ) & 0xFF ); } if ( curState & PD_STATE_CACHE_RET ) { load += (( cl >> 24 ) & 0xFF ); } //--- Spec. point 9 --- load += ((( di * ( shiftedTemp - ( ti << 8 ))) + 128 ) >> 8 ); // Currently not implementing external load handling // if ( __ccfg.ulModeConfig & MODE_CONF_VDDR_EXT_LOAD ) { //--- Spec. point 10 --- // } else { //--- Spec. point 11 --- diffVddrActiveSleep = ( vddrTrimActve - vddrTrimSleep ); if ( diffVddrActiveSleep < 1 ) diffVddrActiveSleep = 1; k = ( diffVddrActiveSleep * 52 ); // } //--- Spec. point 12 --- vddrCap = ( ccfg_ModeConfReg & CCFG_MODE_CONF_VDDR_CAP_M ) >> CCFG_MODE_CONF_VDDR_CAP_S; newRechargePeriod = ( vddrCap * k ) / load; if ( newRechargePeriod > 0xFFFF ) { newRechargePeriod = 0xFFFF; } powerQualGlobals.pdRechargePeriod = newRechargePeriod; //--- Spec. point 13 --- if ( curTemp > 127 ) curTemp = 127; if ( curTemp < -128 ) curTemp = -128; powerQualGlobals.pdTemp = curTemp; powerQualGlobals.pdState = curState; } powerQualGlobals.pdTime = HWREG( AON_RTC_BASE + AON_RTC_O_SEC ); // Calculate PER_E and PER_M (based on powerQualGlobals.pdRechargePeriod) // Round downwards but make sure PER_E=0 and PER_M=1 is the minimum possible setting. // (assuming that powerQualGlobals.pdRechargePeriod always are <= 0xFFFF) perE = 0; perM = powerQualGlobals.pdRechargePeriod; if ( perM < 31 ) { perM = 31; powerQualGlobals.pdRechargePeriod = 31; } while ( perM > 511 ) { perM >>= 1; perE += 1; } perM = ( perM - 15 ) >> 4; HWREG( AON_WUC_BASE + AON_WUC_O_RECHARGECFG ) = ( 0x80A4E700 ) | ( perM << AON_WUC_RECHARGECFG_PER_M_S ) | ( perE << AON_WUC_RECHARGECFG_PER_E_S ) ; HWREG( AON_WUC_BASE + AON_WUC_O_RECHARGESTAT ) = 0; } //***************************************************************************** // // SysCtrlAdjustRechargeAfterPowerDown() // //***************************************************************************** void SysCtrlAdjustRechargeAfterPowerDown( uint32_t vddrRechargeMargin ) { int32_t curTemp ; uint32_t longestRechargePeriod ; uint32_t deltaTime ; uint32_t newRechargePeriod ; //--- Spec. point 2 --- longestRechargePeriod = ( HWREG( AON_WUC_BASE + AON_WUC_O_RECHARGESTAT ) & AON_WUC_RECHARGESTAT_MAX_USED_PER_M ) >> AON_WUC_RECHARGESTAT_MAX_USED_PER_S ; if ( longestRechargePeriod != 0 ) { //--- Spec. changed (originally point 1) --- curTemp = AONBatMonTemperatureGetDegC(); if ( curTemp < powerQualGlobals.pdTemp ) { if ( curTemp < -128 ) { curTemp = -128; } powerQualGlobals.pdTemp = curTemp; } // Add some margin between the longest previous recharge period and the // next initial recharge period. Since it is a fixed margin, it will have a // higher impact as a fraction of the converged recharge period at higher temperatures // where it is needed more due to higher leakage. if (longestRechargePeriod > vddrRechargeMargin) { longestRechargePeriod -= vddrRechargeMargin; } else { longestRechargePeriod = 1; } //--- Spec. point 4 --- if ( longestRechargePeriod < powerQualGlobals.pdRechargePeriod ) { powerQualGlobals.pdRechargePeriod = longestRechargePeriod; } else { //--- Spec. point 5 --- deltaTime = HWREG( AON_RTC_BASE + AON_RTC_O_SEC ) - powerQualGlobals.pdTime + 2; if ( deltaTime > 31 ) { deltaTime = 31; } newRechargePeriod = powerQualGlobals.pdRechargePeriod + (( longestRechargePeriod - powerQualGlobals.pdRechargePeriod ) >> (deltaTime>>1)); if ( newRechargePeriod > 0xFFFF ) { newRechargePeriod = 0xFFFF; } powerQualGlobals.pdRechargePeriod = newRechargePeriod; } } } //***************************************************************************** // // SysCtrl_DCDC_VoltageConditionalControl() // //***************************************************************************** void SysCtrl_DCDC_VoltageConditionalControl( void ) { uint32_t batThreshold ; // Fractional format with 8 fractional bits. uint32_t aonBatmonBat ; // Fractional format with 8 fractional bits. uint32_t ccfg_ModeConfReg ; // Holds a copy of the CCFG_O_MODE_CONF register. uint32_t aonSysctlPwrctl ; // Reflect whats read/written to the AON_SYSCTL_O_PWRCTL register. // We could potentially call this function before any battery voltage measurement // is made/available. In that case we must make sure that we do not turn off the DCDC. // This can be done by doing nothing as long as the battery voltage is 0 (Since the // reset value of the battery voltage register is 0). aonBatmonBat = HWREG( AON_BATMON_BASE + AON_BATMON_O_BAT ); if ( aonBatmonBat != 0 ) { // Check if Voltage Conditional Control is enabled // It is enabled if all the following are true: // - DCDC in use (either in active or recharge mode), (in use if one of the corresponding CCFG bits are zero). // - Alternative DCDC settings are enabled ( DIS_ALT_DCDC_SETTING == 0 ) // - Not in external regulator mode ( EXT_REG_MODE == 0 ) ccfg_ModeConfReg = HWREG( CCFG_BASE + CCFG_O_MODE_CONF ); if (((( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0 ) || (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M ) == 0 ) ) && (( HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_PWRCTL ) & AON_SYSCTL_PWRCTL_EXT_REG_MODE ) == 0 ) && (( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING ) == 0 ) ) { aonSysctlPwrctl = HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_PWRCTL ); batThreshold = (((( HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 ) & CCFG_MODE_CONF_1_ALT_DCDC_VMIN_M ) >> CCFG_MODE_CONF_1_ALT_DCDC_VMIN_S ) + 28 ) << 4 ); if ( aonSysctlPwrctl & ( AON_SYSCTL_PWRCTL_DCDC_EN_M | AON_SYSCTL_PWRCTL_DCDC_ACTIVE_M )) { // DCDC is ON, check if it should be switched off if ( aonBatmonBat < batThreshold ) { aonSysctlPwrctl &= ~( AON_SYSCTL_PWRCTL_DCDC_EN_M | AON_SYSCTL_PWRCTL_DCDC_ACTIVE_M ); HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_PWRCTL ) = aonSysctlPwrctl; } } else { // DCDC is OFF, check if it should be switched on if ( aonBatmonBat > batThreshold ) { if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0 ) aonSysctlPwrctl |= AON_SYSCTL_PWRCTL_DCDC_EN_M ; if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M ) == 0 ) aonSysctlPwrctl |= AON_SYSCTL_PWRCTL_DCDC_ACTIVE_M ; HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_PWRCTL ) = aonSysctlPwrctl; } } } } } //***************************************************************************** // // SysCtrlResetSourceGet() // //***************************************************************************** uint32_t SysCtrlResetSourceGet( void ) { uint32_t aonSysctlResetCtl = HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_RESETCTL ); if ( aonSysctlResetCtl & AON_SYSCTL_RESETCTL_WU_FROM_SD_M ) { return ( RSTSRC_WAKEUP_FROM_SHUTDOWN ); } else { return (( aonSysctlResetCtl & AON_SYSCTL_RESETCTL_RESET_SRC_M ) >> AON_SYSCTL_RESETCTL_RESET_SRC_S ) ; } }