1 /******************************************************************************
2 *  Filename:       sys_ctrl.c
3 *
4 *  Description:    Driver for the System Control.
5 *
6 *  Copyright (c) 2015 - 2022, Texas Instruments Incorporated
7 *  All rights reserved.
8 *
9 *  Redistribution and use in source and binary forms, with or without
10 *  modification, are permitted provided that the following conditions are met:
11 *
12 *  1) Redistributions of source code must retain the above copyright notice,
13 *     this list of conditions and the following disclaimer.
14 *
15 *  2) Redistributions in binary form must reproduce the above copyright notice,
16 *     this list of conditions and the following disclaimer in the documentation
17 *     and/or other materials provided with the distribution.
18 *
19 *  3) Neither the name of the ORGANIZATION nor the names of its contributors may
20 *     be used to endorse or promote products derived from this software without
21 *     specific prior written permission.
22 *
23 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 *  POSSIBILITY OF SUCH DAMAGE.
34 *
35 ******************************************************************************/
36 
37 // Hardware headers
38 #include "../inc/hw_types.h"
39 #include "../inc/hw_ccfg.h"
40 #include "../inc/hw_ioc.h"
41 // Driverlib headers
42 #include "aon_batmon.h"
43 #include "flash.h"
44 #include "gpio.h"
45 #include "setup_rom.h"
46 #include "sys_ctrl.h"
47 
48 
49 //*****************************************************************************
50 //
51 // Handle support for DriverLib in ROM:
52 // This section will undo prototype renaming made in the header file
53 //
54 //*****************************************************************************
55 #if !defined(DOXYGEN)
56     #undef  SysCtrlIdle
57     #define SysCtrlIdle                     NOROM_SysCtrlIdle
58     #undef  SysCtrlShutdownWithAbort
59     #define SysCtrlShutdownWithAbort        NOROM_SysCtrlShutdownWithAbort
60     #undef  SysCtrlShutdown
61     #define SysCtrlShutdown                 NOROM_SysCtrlShutdown
62     #undef  SysCtrlStandby
63     #define SysCtrlStandby                  NOROM_SysCtrlStandby
64     #undef  SysCtrlSetRechargeBeforePowerDown
65     #define SysCtrlSetRechargeBeforePowerDown NOROM_SysCtrlSetRechargeBeforePowerDown
66     #undef  SysCtrlAdjustRechargeAfterPowerDown
67     #define SysCtrlAdjustRechargeAfterPowerDown NOROM_SysCtrlAdjustRechargeAfterPowerDown
68     #undef  SysCtrl_DCDC_VoltageConditionalControl
69     #define SysCtrl_DCDC_VoltageConditionalControl NOROM_SysCtrl_DCDC_VoltageConditionalControl
70     #undef  SysCtrlResetSourceGet
71     #define SysCtrlResetSourceGet           NOROM_SysCtrlResetSourceGet
72 #endif
73 
74 
75 //*****************************************************************************
76 //
77 // Force the system in to idle mode
78 //
79 //*****************************************************************************
SysCtrlIdle(uint32_t vimsPdMode)80 void SysCtrlIdle(uint32_t vimsPdMode)
81 {
82     // Configure the VIMS mode
83     HWREG(PRCM_BASE + NONSECURE_OFFSET + PRCM_O_PDCTL1VIMS) = vimsPdMode;
84 
85     // Always keep cache retention ON in IDLE
86     PRCMCacheRetentionEnable();
87 
88     // Turn off the CPU power domain, will take effect when PRCMDeepSleep() executes
89     PRCMPowerDomainOff(PRCM_DOMAIN_CPU);
90 
91     // Ensure any possible outstanding AON writes complete
92     SysCtrlAonSync();
93 
94     // Invoke deep sleep to go to IDLE
95     PRCMDeepSleep();
96 }
97 
98 //*****************************************************************************
99 //
100 // Try to enter shutdown but abort if wakeup event happened before shutdown
101 //
102 //*****************************************************************************
SysCtrlShutdownWithAbort(void)103 void SysCtrlShutdownWithAbort(void)
104 {
105     uint32_t wakeupDetected = 0;
106     uint32_t ioIndex = 0;
107 
108     uint32_t ioCount = (( HWREG( FCFG1_BASE + FCFG1_O_IOCONF ) &
109             FCFG1_IOCONF_GPIO_CNT_M ) >> FCFG1_IOCONF_GPIO_CNT_S ) ;
110 
111     // Wakeup events are detected when pads are in sleep mode
112     PowerCtrlPadSleepEnable();
113 
114     // Make sure all potential events have propagated before checking event flags
115     SysCtrlAonUpdate();
116     SysCtrlAonUpdate();
117 
118     // For all IO CFG registers check if wakeup detect is enabled
119     for(ioIndex = 0; ioIndex < ioCount; ioIndex++)
120     {
121         // Read MSB from WU_CFG bit field
122         if( HWREG(IOC_BASE + IOC_O_IOCFG0 + (ioIndex * 4) ) & (1 << (IOC_IOCFG0_WU_CFG_S + IOC_IOCFG0_WU_CFG_W - 1)) )
123         {
124             if (GPIO_getEventDio(ioIndex))
125             {
126                 wakeupDetected = 1;
127                 break;
128             }
129         }
130     }
131 
132     // If no edge detect flags for wakeup enabled IOs are set then shut down the device
133     if( wakeupDetected == 0 )
134     {
135         SysCtrlShutdown();
136     }
137     else
138     {
139         PowerCtrlPadSleepDisable();
140     }
141 }
142 
143 //*****************************************************************************
144 //
145 // Force the system into shutdown mode
146 //
147 //*****************************************************************************
SysCtrlShutdown(void)148 void SysCtrlShutdown(void)
149 {
150     // Request shutdown mode
151     HWREG(AON_PMCTL_BASE + AON_PMCTL_O_SHUTDOWN) = AON_PMCTL_SHUTDOWN_EN;
152 
153     // Make sure System CPU does not continue beyond this point.
154     // Shutdown happens when all shutdown conditions are met.
155     while(1);
156 }
157 
158 //*****************************************************************************
159 //
160 // Force the system in to standby mode
161 //
162 //*****************************************************************************
SysCtrlStandby(bool retainCache,uint32_t vimsPdMode,uint32_t rechargeMode)163 void SysCtrlStandby(bool retainCache, uint32_t vimsPdMode, uint32_t rechargeMode)
164 {
165     uint32_t modeVIMS;
166 
167     // In external regulator mode:
168     // Set static recharge timing to approximately 500 milliseconds
169     // Else:
170     // Handle compensation for improving RCOSC_LF stability at low temperatures
171     // as configured in CCFG
172     SysCtrlSetRechargeBeforePowerDown(XOSC_IN_HIGH_POWER_MODE);
173 
174     // Freeze the IOs on the boundary between MCU and AON
175     AONIOCFreezeEnable();
176 
177     // Ensure any possible outstanding AON writes complete before turning off the power domains
178     SysCtrlAonSync();
179 
180     // Request power off of domains in the MCU voltage domain
181     PRCMPowerDomainOff(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH | PRCM_DOMAIN_CPU);
182 
183     // Ensure that no clocks are forced on in any modes for Crypto, DMA and I2S
184     HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) &= (~PRCM_SECDMACLKGR_CRYPTO_AM_CLK_EN & ~PRCM_SECDMACLKGR_DMA_AM_CLK_EN);
185     HWREG(PRCM_BASE + PRCM_O_I2SCLKGR)    &= ~PRCM_I2SCLKGR_AM_CLK_EN;
186 
187     // Gate running deep sleep clocks for Crypto, DMA and I2S
188     PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_CRYPTO);
189     PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_UDMA);
190     PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_I2S);
191 
192     // Load the new clock settings
193     PRCMLoadSet();
194 
195     // Configure the VIMS power domain mode
196     HWREG(PRCM_BASE + PRCM_O_PDCTL1VIMS) = vimsPdMode;
197 
198     // Request uLDO during standby
199     PRCMMcuUldoConfigure(1);
200 
201     // In external regulator mode:
202     // - Setting the AON_PMCTL_O_RECHARGECFG register is already handled above.
203     //   (in function SysCtrlSetRechargeBeforePowerDown() )
204     // Else:
205     // - Set the AON_PMCTL_O_RECHARGECFG register as described below.
206     if ((HWREG(AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL) & AON_PMCTL_PWRCTL_EXT_REG_MODE)==0)
207     {
208         // In internal regulator mode the recharge functionality is set up with
209         // adaptive recharge mode and fixed parameter values
210         if(rechargeMode == SYSCTRL_PREFERRED_RECHARGE_MODE)
211         {
212             // Enable the Recharge Comparator
213             HWREG(AON_PMCTL_BASE + AON_PMCTL_O_RECHARGECFG) = AON_PMCTL_RECHARGECFG_MODE_COMPARATOR;
214         }
215         else
216         {
217             // Set requested recharge mode
218             HWREG(AON_PMCTL_BASE + AON_PMCTL_O_RECHARGECFG) = rechargeMode;
219         }
220     }
221 
222     // Ensure all writes have taken effect
223     SysCtrlAonSync();
224 
225     // Ensure UDMA, Crypto and I2C clocks are turned off
226     while (!PRCMLoadGet()) {;}
227 
228     // Ensure power domains have been turned off.
229     // CPU power domain will power down when PRCMDeepSleep() executes.
230     while (PRCMPowerDomainsAllOff(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH) != PRCM_DOMAIN_POWER_OFF) {;}
231 
232     // Turn off cache retention if requested
233     if (retainCache == false) {
234 
235         // Get the current VIMS mode
236         do {
237             modeVIMS = VIMSModeGet(VIMS_BASE);
238         } while (modeVIMS == VIMS_MODE_CHANGING);
239 
240         // If in a cache mode, turn VIMS off
241         if (modeVIMS == VIMS_MODE_ENABLED) {
242            VIMSModeSet(VIMS_BASE, VIMS_MODE_OFF);
243         }
244 
245         // Disable retention of cache RAM
246         PRCMCacheRetentionDisable();
247     }
248 
249     // Invoke deep sleep to go to STANDBY
250     PRCMDeepSleep();
251 }
252 
253 //*****************************************************************************
254 //
255 // SysCtrlSetRechargeBeforePowerDown( xoscPowerMode )
256 //
257 //*****************************************************************************
258 void
SysCtrlSetRechargeBeforePowerDown(uint32_t xoscPowerMode)259 SysCtrlSetRechargeBeforePowerDown( uint32_t xoscPowerMode )
260 {
261 
262    // If external regulator mode we shall:
263    // - Set static recharge timing in AON_PMCTL_RECHARGECFG (MODE_STATIC)
264    // - Set recharge period to approximately 500 mS (perM=31, perE=5 => 0xFD)
265    if ( HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) & AON_PMCTL_PWRCTL_EXT_REG_MODE ) {
266       HWREG( AON_PMCTL_BASE + AON_PMCTL_O_RECHARGECFG ) = ( AON_PMCTL_RECHARGECFG_MODE_STATIC | 0x000000FD );
267       return;
268    }
269 
270 }
271 
272 
273 //*****************************************************************************
274 //
275 // SysCtrlAdjustRechargeAfterPowerDown()
276 //
277 //*****************************************************************************
278 void
SysCtrlAdjustRechargeAfterPowerDown(uint32_t vddrRechargeMargin)279 SysCtrlAdjustRechargeAfterPowerDown( uint32_t vddrRechargeMargin )
280 {
281    // Nothing to be done but keeping this function for platform compatibility.
282 }
283 
284 
285 //*****************************************************************************
286 //
287 // SysCtrl_DCDC_VoltageConditionalControl()
288 //
289 //*****************************************************************************
290 void
SysCtrl_DCDC_VoltageConditionalControl(void)291 SysCtrl_DCDC_VoltageConditionalControl( void )
292 {
293    uint32_t batThreshold     ;  // Fractional format with 8 fractional bits.
294    uint32_t aonBatmonBat     ;  // Fractional format with 8 fractional bits.
295    uint32_t ccfg_ModeConfReg ;  // Holds a copy of the CCFG_O_MODE_CONF register.
296    uint32_t aonPmctlPwrctl   ;  // Reflect whats read/written to the AON_PMCTL_O_PWRCTL register.
297 
298    // We could potentially call this function before any battery voltage measurement
299    // is made/available. In that case we must make sure that we do not turn off the DCDC.
300    // This can be done by doing nothing as long as the battery voltage is 0 (Since the
301    // reset value of the battery voltage register is 0).
302    aonBatmonBat = HWREG( AON_BATMON_BASE + AON_BATMON_O_BAT );
303    if ( aonBatmonBat != 0 ) {
304       // Check if Voltage Conditional Control is enabled
305       // It is enabled if all the following are true:
306       // - DCDC in use (either in active or recharge mode), (in use if one of the corresponding CCFG bits are zero).
307       // - Alternative DCDC settings are enabled ( DIS_ALT_DCDC_SETTING == 0 )
308       // - Not in external regulator mode ( EXT_REG_MODE == 0 )
309       ccfg_ModeConfReg = HWREG( CCFG_BASE + CCFG_O_MODE_CONF );
310 
311       if (((( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0                                            ) ||
312            (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M   ) == 0                                            )    ) &&
313           (( HWREG( AON_PMCTL_BASE  + AON_PMCTL_O_PWRCTL  ) & AON_PMCTL_PWRCTL_EXT_REG_MODE  )               == 0      ) &&
314           (( HWREG( CCFG_BASE + CCFG_O_SIZE_AND_DIS_FLAGS ) & CCFG_SIZE_AND_DIS_FLAGS_DIS_ALT_DCDC_SETTING ) == 0      )    )
315       {
316          aonPmctlPwrctl = HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL );
317          batThreshold   = (((( HWREG( CCFG_BASE + CCFG_O_MODE_CONF_1 ) &
318             CCFG_MODE_CONF_1_ALT_DCDC_VMIN_M ) >>
319             CCFG_MODE_CONF_1_ALT_DCDC_VMIN_S ) + 28 ) << 4 );
320 
321          if ( aonPmctlPwrctl & ( AON_PMCTL_PWRCTL_DCDC_EN_M | AON_PMCTL_PWRCTL_DCDC_ACTIVE_M )) {
322             // DCDC is ON, check if it should be switched off
323             if ( aonBatmonBat < batThreshold ) {
324                aonPmctlPwrctl &= ~( AON_PMCTL_PWRCTL_DCDC_EN_M | AON_PMCTL_PWRCTL_DCDC_ACTIVE_M );
325 
326                HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) = aonPmctlPwrctl;
327             }
328          } else {
329             // DCDC is OFF, check if it should be switched on
330             if ( aonBatmonBat > batThreshold ) {
331                if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_RECHARGE_M ) == 0 ) aonPmctlPwrctl |= AON_PMCTL_PWRCTL_DCDC_EN_M     ;
332                if (( ccfg_ModeConfReg & CCFG_MODE_CONF_DCDC_ACTIVE_M   ) == 0 ) aonPmctlPwrctl |= AON_PMCTL_PWRCTL_DCDC_ACTIVE_M ;
333 
334                HWREG( AON_PMCTL_BASE + AON_PMCTL_O_PWRCTL ) = aonPmctlPwrctl;
335             }
336          }
337       }
338    }
339 }
340 
341 
342 //*****************************************************************************
343 //
344 // SysCtrlResetSourceGet()
345 //
346 //*****************************************************************************
347 uint32_t
SysCtrlResetSourceGet(void)348 SysCtrlResetSourceGet( void )
349 {
350    uint32_t aonPmctlResetCtl = HWREG( AON_PMCTL_BASE + AON_PMCTL_O_RESETCTL );
351 
352    if ( aonPmctlResetCtl & AON_PMCTL_RESETCTL_WU_FROM_SD_M ) {
353       if ( aonPmctlResetCtl & AON_PMCTL_RESETCTL_GPIO_WU_FROM_SD_M ) {
354          return ( RSTSRC_WAKEUP_FROM_SHUTDOWN );
355       } else {
356          return ( RSTSRC_WAKEUP_FROM_TCK_NOISE );
357       }
358    } else {
359       return (( aonPmctlResetCtl & AON_PMCTL_RESETCTL_RESET_SRC_M ) >> AON_PMCTL_RESETCTL_RESET_SRC_S );
360    }
361 }
362