blob: 4474725f81674dd4838fef5be5a7601e5c70ef15 [file] [log] [blame]
/******************************************************************************
* Filename: sys_ctrl.c
* Revised: 2016-05-25 14:45:26 +0200 (Wed, 25 May 2016)
* Revision: 46492
*
* Description: Driver for the System Control.
*
* Copyright (c) 2015 - 2016, 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>
// Driverlib headers
#include <driverlib/aon_batmon.h>
#include <driverlib/sys_ctrl.h>
#include <driverlib/setup.h>
//*****************************************************************************
//
// Handle support for DriverLib in ROM:
// This section will undo prototype renaming made in the header file
//
//*****************************************************************************
#if !defined(DOXYGEN)
#undef SysCtrlPowerEverything
#define SysCtrlPowerEverything NOROM_SysCtrlPowerEverything
#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;
//*****************************************************************************
//
// Arrays that maps the "peripheral set" number (which is stored in the
// third nibble of the PRCM_PERIPH_* defines) to the PRCM register that
// contains the relevant bit for that peripheral.
//
//*****************************************************************************
// Run mode registers
static const uint32_t g_pui32ModuleCG[] =
{
PRCM_PERIPH_TIMER0,
PRCM_PERIPH_TIMER1,
PRCM_PERIPH_TIMER2,
PRCM_PERIPH_TIMER3,
PRCM_PERIPH_SSI0,
PRCM_PERIPH_SSI1,
PRCM_PERIPH_UART0,
PRCM_PERIPH_I2C0,
PRCM_PERIPH_UDMA,
PRCM_PERIPH_TRNG,
PRCM_PERIPH_CRYPTO,
PRCM_PERIPH_GPIO,
PRCM_PERIPH_I2S
};
//*****************************************************************************
//
// Power up everything
//
//*****************************************************************************
void
SysCtrlPowerEverything(void)
{
uint32_t ui32Idx;
uint32_t ui32AuxClocks;
//
// Force power on AUX
//
AONWUCAuxWakeupEvent(AONWUC_AUX_WAKEUP);
while(!(AONWUCPowerStatusGet() & AONWUC_AUX_POWER_ON))
{ }
//
// Enable all the AUX domain clocks and wait for them to be ready
//
ui32AuxClocks = AUX_WUC_ADI_CLOCK | AUX_WUC_OSCCTRL_CLOCK |
AUX_WUC_TDCIF_CLOCK | AUX_WUC_ANAIF_CLOCK |
AUX_WUC_TIMER_CLOCK | AUX_WUC_AIODIO0_CLOCK |
AUX_WUC_AIODIO1_CLOCK | AUX_WUC_SMPH_CLOCK |
AUX_WUC_TDC_CLOCK | AUX_WUC_ADC_CLOCK |
AUX_WUC_REF_CLOCK;
AUXWUCClockEnable(ui32AuxClocks);
while(AUXWUCClockStatus(ui32AuxClocks) != AUX_WUC_CLOCK_READY)
{ }
//
// Request to switch to the crystal to enable radio operation.
// It takes a while for the XTAL to be ready so it is possible to
// perform other tasks while waiting.
OSCClockSourceSet(OSC_SRC_CLK_MF | OSC_SRC_CLK_HF, OSC_XOSC_HF);
OSCClockSourceSet(OSC_SRC_CLK_LF, OSC_XOSC_LF);
//
// Switch the HF source to XTAL - must be performed safely out of ROM to
// avoid flash issues when switching the clock.
//
// NB. If already running XTAL on HF clock source the ROM will wait forever
// on a flag that will never be set - need to check.
//
if(OSCClockSourceGet(OSC_SRC_CLK_HF) != OSC_XOSC_HF) {
OSCHfSourceSwitch();
}
//
// Turn on all the MCU power domains
// If the CPU is running and executing code the SYSBUS, VIMS and CPU are
// automatically on as well.
//
PRCMPowerDomainOn(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL |
PRCM_DOMAIN_PERIPH);
//
// Wait for power to be on
//
while(PRCMPowerDomainStatus(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL |
PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_ON);
PRCMLoadSet();
while(!PRCMLoadGet());
//
// Ensure the domain clocks are running and wait for the clock settings to
// take effect
//
PRCMDomainEnable(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_VIMS);
PRCMLoadSet();
while(!PRCMLoadGet())
{ }
//
// Enable all the RF Core clocks
//
// Do not read back to check, for two reasons:
// 1. CPE will update the PWMCLKENABLE register right after boot
// 2. The PWMCLKENABLE register always reads back what is written
HWREG(RFC_PWR_NONBUF_BASE + RFC_PWR_O_PWMCLKEN) = 0x7FF;
//
// Enable all peripheral clocks in System CPU run/sleep/deep-sleep mode.
//
for(ui32Idx = 0; ui32Idx < sizeof(g_pui32ModuleCG) / sizeof(uint32_t);
ui32Idx++)
{
PRCMPeripheralRunEnable(g_pui32ModuleCG[ui32Idx]);
PRCMPeripheralSleepEnable(g_pui32ModuleCG[ui32Idx]);
PRCMPeripheralDeepSleepEnable(g_pui32ModuleCG[ui32Idx]);
}
PRCMLoadSet();
while(!PRCMLoadGet())
{ }
}
//*****************************************************************************
//
// 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( void )
{
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 (originaly point 1) ---
curTemp = AONBatMonTemperatureGetDegC();
if ( curTemp < powerQualGlobals.pdTemp ) {
if ( curTemp < -128 ) {
curTemp = -128;
}
powerQualGlobals.pdTemp = curTemp;
}
//--- 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 )
{
if ( HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_RESETCTL ) & AON_SYSCTL_RESETCTL_WU_FROM_SD_M ) {
return ( RSTSRC_WAKEUP_FROM_SHUTDOWN );
} else {
return (( HWREG( AON_SYSCTL_BASE + AON_SYSCTL_O_RESETCTL ) &
AON_SYSCTL_RESETCTL_RESET_SRC_M ) >>
AON_SYSCTL_RESETCTL_RESET_SRC_S ) ;
}
}