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