mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
7db791476e
Signed-off-by: Jean Pierre Dudey <me@jeandudey.tech>
424 lines
17 KiB
C
424 lines
17 KiB
C
/******************************************************************************
|
|
* 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 ) ;
|
|
}
|
|
}
|