/****************************************************************************** * 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_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; // 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 ); } }