380 lines
15 KiB
C
380 lines
15 KiB
C
/******************************************************************************
|
|
* Filename: sys_ctrl.c
|
|
* Revised: 2020-02-18 14:05:12 +0100 (Tue, 18 Feb 2020)
|
|
* Revision: 56796
|
|
*
|
|
* 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_ioc.h"
|
|
// Driverlib headers
|
|
#include "aon_batmon.h"
|
|
#include "flash.h"
|
|
#include "gpio.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 SysCtrlIdle
|
|
#define SysCtrlIdle NOROM_SysCtrlIdle
|
|
#undef SysCtrlShutdownWithAbort
|
|
#define SysCtrlShutdownWithAbort NOROM_SysCtrlShutdownWithAbort
|
|
#undef SysCtrlShutdown
|
|
#define SysCtrlShutdown NOROM_SysCtrlShutdown
|
|
#undef SysCtrlStandby
|
|
#define SysCtrlStandby NOROM_SysCtrlStandby
|
|
#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
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Force the system in to idle mode
|
|
//
|
|
//*****************************************************************************
|
|
void SysCtrlIdle(uint32_t vimsPdMode)
|
|
{
|
|
// Configure the VIMS mode
|
|
HWREG(PRCM_BASE + PRCM_O_PDCTL1VIMS) = vimsPdMode;
|
|
|
|
// Always keep cache retention ON in IDLE
|
|
PRCMCacheRetentionEnable();
|
|
|
|
// Turn off the CPU power domain, will take effect when PRCMDeepSleep() executes
|
|
PRCMPowerDomainOff(PRCM_DOMAIN_CPU);
|
|
|
|
// Ensure any possible outstanding AON writes complete
|
|
SysCtrlAonSync();
|
|
|
|
// Invoke deep sleep to go to IDLE
|
|
PRCMDeepSleep();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Try to enter shutdown but abort if wakeup event happened before shutdown
|
|
//
|
|
//*****************************************************************************
|
|
void SysCtrlShutdownWithAbort(void)
|
|
{
|
|
uint32_t wu_detect_vector = 0;
|
|
uint32_t io_num = 0;
|
|
|
|
// For all IO CFG registers check if wakeup detect is enabled
|
|
for(io_num = 0; io_num < 32; io_num++)
|
|
{
|
|
// Read MSB from WU_CFG bit field
|
|
if( HWREG(IOC_BASE + IOC_O_IOCFG0 + (io_num * 4) ) & (1 << (IOC_IOCFG0_WU_CFG_S + IOC_IOCFG0_WU_CFG_W - 1)) )
|
|
{
|
|
wu_detect_vector |= (1 << io_num);
|
|
}
|
|
}
|
|
|
|
// Wakeup events are detected when pads are in sleep mode
|
|
PowerCtrlPadSleepEnable();
|
|
|
|
// Make sure all potential events have propagated before checking event flags
|
|
SysCtrlAonUpdate();
|
|
SysCtrlAonUpdate();
|
|
|
|
// If no edge detect flags for wakeup enabled IOs are set then shut down the device
|
|
if( GPIO_getEventMultiDio(wu_detect_vector) == 0 )
|
|
{
|
|
SysCtrlShutdown();
|
|
}
|
|
else
|
|
{
|
|
PowerCtrlPadSleepDisable();
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Force the system into shutdown mode
|
|
//
|
|
//*****************************************************************************
|
|
void SysCtrlShutdown(void)
|
|
{
|
|
// Request shutdown mode
|
|
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_SHUTDOWN) = AON_PMCTL_SHUTDOWN_EN;
|
|
|
|
// Make sure System CPU does not continue beyond this point.
|
|
// Shutdown happens when all shutdown conditions are met.
|
|
while(1);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Force the system in to standby mode
|
|
//
|
|
//*****************************************************************************
|
|
void SysCtrlStandby(bool retainCache, uint32_t vimsPdMode, uint32_t rechargeMode)
|
|
{
|
|
uint32_t modeVIMS;
|
|
|
|
// Handle compensation for improving RCOSC_LF stability at low temperatures
|
|
// as configured in CCFG
|
|
SysCtrlSetRechargeBeforePowerDown(XOSC_IN_HIGH_POWER_MODE);
|
|
|
|
// Freeze the IOs on the boundary between MCU and AON
|
|
AONIOCFreezeEnable();
|
|
|
|
// Ensure any possible outstanding AON writes complete before turning off the power domains
|
|
SysCtrlAonSync();
|
|
|
|
// Request power off of domains in the MCU voltage domain
|
|
PRCMPowerDomainOff(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH | PRCM_DOMAIN_CPU);
|
|
|
|
// Ensure that no clocks are forced on in any modes for Crypto, DMA and I2S
|
|
HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) &= (~PRCM_SECDMACLKGR_CRYPTO_AM_CLK_EN & ~PRCM_SECDMACLKGR_DMA_AM_CLK_EN);
|
|
HWREG(PRCM_BASE + PRCM_O_I2SCLKGR) &= ~PRCM_I2SCLKGR_AM_CLK_EN;
|
|
|
|
// Gate running deep sleep clocks for Crypto, DMA and I2S
|
|
PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_CRYPTO);
|
|
PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_UDMA);
|
|
PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_I2S);
|
|
|
|
// Load the new clock settings
|
|
PRCMLoadSet();
|
|
|
|
// Configure the VIMS power domain mode
|
|
HWREG(PRCM_BASE + PRCM_O_PDCTL1VIMS) = vimsPdMode;
|
|
|
|
// Request uLDO during standby
|
|
PRCMMcuUldoConfigure(1);
|
|
|
|
// Check the regulator mode
|
|
if (HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & AON_PMCTL_PWRCTL_EXT_REG_MODE)
|
|
{
|
|
// In external regulator mode the recharge functionality is disabled
|
|
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_RECHARGECFG) = 0x00000000;
|
|
}
|
|
else
|
|
{
|
|
// In internal regulator mode the recharge functionality is set up with
|
|
// adaptive recharge mode and fixed parameter values
|
|
if(rechargeMode == SYSCTRL_PREFERRED_RECHARGE_MODE)
|
|
{
|
|
// Enable the Recharge Comparator
|
|
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_RECHARGECFG) = AON_PMCTL_RECHARGECFG_MODE_COMPARATOR;
|
|
}
|
|
else
|
|
{
|
|
// Set requested recharge mode
|
|
HWREG(AON_PMCTL_BASE + AON_PMCTL_O_RECHARGECFG) = rechargeMode;
|
|
}
|
|
}
|
|
|
|
// Ensure all writes have taken effect
|
|
SysCtrlAonSync();
|
|
|
|
// Ensure UDMA, Crypto and I2C clocks are turned off
|
|
while (!PRCMLoadGet()) {;}
|
|
|
|
// Ensure power domains have been turned off.
|
|
// CPU power domain will power down when PRCMDeepSleep() executes.
|
|
while (PRCMPowerDomainStatus(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_OFF) {;}
|
|
|
|
// Turn off cache retention if requested
|
|
if (retainCache == false) {
|
|
|
|
// Get the current VIMS mode
|
|
do {
|
|
modeVIMS = VIMSModeGet(VIMS_BASE);
|
|
} while (modeVIMS == VIMS_MODE_CHANGING);
|
|
|
|
// If in a cache mode, turn VIMS off
|
|
if (modeVIMS == VIMS_MODE_ENABLED) {
|
|
VIMSModeSet(VIMS_BASE, VIMS_MODE_OFF);
|
|
}
|
|
|
|
// Disable retention of cache RAM
|
|
PRCMCacheRetentionDisable();
|
|
}
|
|
|
|
// Invoke deep sleep to go to STANDBY
|
|
PRCMDeepSleep();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// SysCtrlSetRechargeBeforePowerDown( xoscPowerMode )
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
SysCtrlSetRechargeBeforePowerDown( uint32_t xoscPowerMode )
|
|
{
|
|
uint32_t ccfg_ModeConfReg ;
|
|
|
|
// read the MODE_CONF register in CCFG
|
|
ccfg_ModeConfReg = HWREG( CCFG_BASE + CCFG_O_MODE_CONF );
|
|
// Do temperature compensation if enabled
|
|
if (( ccfg_ModeConfReg & CCFG_MODE_CONF_VDDR_TRIM_SLEEP_TC ) == 0 ) {
|
|
int32_t vddrSleepDelta ;
|
|
int32_t curTemp ;
|
|
int32_t tcDelta ;
|
|
int32_t vddrSleepTrim ;
|
|
|
|
// Get VDDR_TRIM_SLEEP_DELTA + 1 (sign extended) ==> vddrSleepDelta = -7..+8
|
|
vddrSleepDelta = (((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 ;
|
|
curTemp = AONBatMonTemperatureGetDegC();
|
|
tcDelta = ( 62 - curTemp ) >> 3;
|
|
if ( tcDelta > 7 ) {
|
|
tcDelta = 7 ;
|
|
}
|
|
if ( tcDelta > vddrSleepDelta ) {
|
|
vddrSleepDelta = tcDelta ;
|
|
}
|
|
vddrSleepTrim = (( HWREG( FLASH_CFG_BASE + FCFG1_OFFSET + FCFG1_O_MISC_TRIM ) & FCFG1_MISC_TRIM_TRIM_RECHARGE_COMP_REFLEVEL_M ) >>
|
|
FCFG1_MISC_TRIM_TRIM_RECHARGE_COMP_REFLEVEL_S ) ;
|
|
vddrSleepTrim -= vddrSleepDelta ;
|
|
if ( vddrSleepTrim > 15 ) vddrSleepTrim = 15 ;
|
|
if ( vddrSleepTrim < 1 ) vddrSleepTrim = 1 ;
|
|
// Write adjusted value using MASKED write (MASK8)
|
|
HWREGB( ADI3_BASE + ADI_O_MASK4B + ( ADI_3_REFSYS_O_CTL_RECHARGE_CMP0 * 2 )) = (( ADI_3_REFSYS_CTL_RECHARGE_CMP0_TRIM_RECHARGE_COMP_REFLEVEL_M << 4 ) |
|
|
(( vddrSleepTrim << ADI_3_REFSYS_CTL_RECHARGE_CMP0_TRIM_RECHARGE_COMP_REFLEVEL_S ) & ADI_3_REFSYS_CTL_RECHARGE_CMP0_TRIM_RECHARGE_COMP_REFLEVEL_M ) );
|
|
// Make a dummy read in order to make sure the write above is done before going into standby
|
|
HWREGB( ADI3_BASE + ADI_3_REFSYS_O_CTL_RECHARGE_CMP0 );
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// SysCtrlAdjustRechargeAfterPowerDown()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
SysCtrlAdjustRechargeAfterPowerDown( uint32_t vddrRechargeMargin )
|
|
{
|
|
// Nothing to be done but keeping this function for platform compatibility.
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// 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 aonPmctlPwrctl ; // Reflect whats read/written to the AON_PMCTL_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_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) & AON_PMCTL_PWRCTL_EXT_REG_MODE ) == 0 ) &&
|
|
(( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING ) == 0 ) )
|
|
{
|
|
aonPmctlPwrctl = HWREG( AON_PMCTL_BASE + AON_PMCTL_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 ( aonPmctlPwrctl & ( AON_PMCTL_PWRCTL_DCDC_EN_M | AON_PMCTL_PWRCTL_DCDC_ACTIVE_M )) {
|
|
// DCDC is ON, check if it should be switched off
|
|
if ( aonBatmonBat < batThreshold ) {
|
|
aonPmctlPwrctl &= ~( AON_PMCTL_PWRCTL_DCDC_EN_M | AON_PMCTL_PWRCTL_DCDC_ACTIVE_M );
|
|
|
|
HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) = aonPmctlPwrctl;
|
|
}
|
|
} else {
|
|
// DCDC is OFF, check if it should be switched on
|
|
if ( aonBatmonBat > batThreshold ) {
|
|
if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0 ) aonPmctlPwrctl |= AON_PMCTL_PWRCTL_DCDC_EN_M ;
|
|
if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M ) == 0 ) aonPmctlPwrctl |= AON_PMCTL_PWRCTL_DCDC_ACTIVE_M ;
|
|
|
|
HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) = aonPmctlPwrctl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// SysCtrlResetSourceGet()
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
SysCtrlResetSourceGet( void )
|
|
{
|
|
uint32_t aonPmctlResetCtl = HWREG( AON_PMCTL_BASE + AON_PMCTL_O_RESETCTL );
|
|
|
|
if ( aonPmctlResetCtl & AON_PMCTL_RESETCTL_WU_FROM_SD_M ) {
|
|
if ( aonPmctlResetCtl & AON_PMCTL_RESETCTL_GPIO_WU_FROM_SD_M ) {
|
|
return ( RSTSRC_WAKEUP_FROM_SHUTDOWN );
|
|
} else {
|
|
return ( RSTSRC_WAKEUP_FROM_TCK_NOISE );
|
|
}
|
|
} else {
|
|
return (( aonPmctlResetCtl & AON_PMCTL_RESETCTL_RESET_SRC_M ) >> AON_PMCTL_RESETCTL_RESET_SRC_S );
|
|
}
|
|
}
|