1 //*****************************************************************************
2 //
3 //! @file am_hal_sysctrl.c
4 //!
5 //! @brief Functions for interfacing with the M4F system control registers
6 //!
7 //! @addtogroup sysctrl3 SYSCTRL - System Control
8 //! @ingroup apollo3_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 
53 //*****************************************************************************
54 //
55 //  Globals
56 //
57 //*****************************************************************************
58 uint32_t g_am_hal_sysctrl_sleep_count = 0;
59 
60 //*****************************************************************************
61 //
62 // @brief Place the core into sleep or deepsleep.
63 //
64 // @param bSleepDeep - False for Normal or True Deep sleep.
65 //
66 // This function puts the MCU to sleep or deepsleep depending on bSleepDeep.
67 //
68 // Valid values for bSleepDeep are:
69 //
70 //     AM_HAL_SYSCTRL_SLEEP_NORMAL
71 //     AM_HAL_SYSCTRL_SLEEP_DEEP
72 //
73 //*****************************************************************************
74 void
am_hal_sysctrl_sleep(bool bSleepDeep)75 am_hal_sysctrl_sleep(bool bSleepDeep)
76 {
77     //
78     // Disable interrupts and save the previous interrupt state.
79     //
80     AM_CRITICAL_BEGIN
81 
82     g_am_hal_sysctrl_sleep_count++;
83 
84     //
85     // If the user selected DEEPSLEEP and the TPIU is off, attempt to enter
86     // DEEP SLEEP.
87     //
88     if ( (bSleepDeep == AM_HAL_SYSCTRL_SLEEP_DEEP)    &&
89          (MCUCTRL->TPIUCTRL_b.ENABLE == MCUCTRL_TPIUCTRL_ENABLE_DIS) )
90     {
91 
92         //
93         // Retrieve the reset generator status bits
94         // This gets reset on Deep Sleep, so we take a snapshot here
95         //
96         if (!gAmHalResetStatus)
97         {
98             gAmHalResetStatus = RSTGEN->STAT;
99         }
100 
101         //
102         // save original SIMOBUCK1 value, it will be restored
103         //
104         uint32_t ui32Simobuck1Backup = MCUCTRL->SIMOBUCK1;
105 
106         //
107         // increase VDDC by 9 counts
108         //
109         uint32_t ui32Vddc = _FLD2VAL( MCUCTRL_SIMOBUCK1_MEMACTIVETRIM, ui32Simobuck1Backup );
110         ui32Vddc += 9;
111 
112         //
113         // check for overflow and limit
114         //
115         ui32Vddc =  ui32Vddc > (MCUCTRL_SIMOBUCK1_MEMACTIVETRIM_Msk>>MCUCTRL_SIMOBUCK1_MEMACTIVETRIM_Pos) ?
116                     (MCUCTRL_SIMOBUCK1_MEMACTIVETRIM_Msk>>MCUCTRL_SIMOBUCK1_MEMACTIVETRIM_Pos) :
117                     ui32Vddc;
118 
119         ui32Vddc = _VAL2FLD(MCUCTRL_SIMOBUCK1_MEMACTIVETRIM, ui32Vddc );
120 
121         //
122         // increase VDDF by 24 counts
123         //
124         uint32_t ui32Vddf = _FLD2VAL( MCUCTRL_SIMOBUCK1_COREACTIVETRIM, ui32Simobuck1Backup ) ;
125         ui32Vddf += 24 ;
126 
127         //
128         // check for overflow and limit
129         //
130         ui32Vddf    = ui32Vddf > (MCUCTRL_SIMOBUCK1_COREACTIVETRIM_Msk >> MCUCTRL_SIMOBUCK1_COREACTIVETRIM_Pos) ?
131                       (MCUCTRL_SIMOBUCK1_COREACTIVETRIM_Msk >> MCUCTRL_SIMOBUCK1_COREACTIVETRIM_Pos) :
132                       ui32Vddf;
133         ui32Vddf = _VAL2FLD(MCUCTRL_SIMOBUCK1_COREACTIVETRIM, ui32Vddf );
134 
135         //
136         // remove original values of vddc and vddf and replace with modified values
137         //
138         uint32_t  ui32VddVffMask = MCUCTRL_SIMOBUCK1_MEMACTIVETRIM_Msk | MCUCTRL_SIMOBUCK1_COREACTIVETRIM_Msk;
139         uint32_t  ui32SimoBuck1Working =
140                       (ui32Simobuck1Backup & ~ui32VddVffMask) | ui32Vddc | ui32Vddf;
141 
142         //
143         // write updated vddc and vddf to SIMOBUCK1 and wait for 20 microseconds
144         //
145         MCUCTRL->SIMOBUCK1 = ui32SimoBuck1Working;
146 
147         //
148         // 20 micosecond delay
149         //
150         am_hal_flash_delay(FLASH_CYCLES_US(20));
151 
152         //
153         // just before sleep, restore SIMONBUCK1 to original value
154         //
155         MCUCTRL->SIMOBUCK1 = ui32Simobuck1Backup;
156 
157         //
158         // Prepare the core for deepsleep (write 1 to the DEEPSLEEP bit).
159         //
160         SCB->SCR |= _VAL2FLD(SCB_SCR_SLEEPDEEP, 1);
161     }
162     else
163     {
164         //
165         // Prepare the core for normal sleep (write 0 to the DEEPSLEEP bit).
166         //
167         SCB->SCR &= ~_VAL2FLD(SCB_SCR_SLEEPDEEP, 1);
168     }
169 
170     //
171     // Before executing WFI, flush any buffered core and peripheral writes.
172     //
173     __DSB();
174     am_hal_sysctrl_bus_write_flush();
175 
176     //
177     // Execute the sleep instruction.
178     //
179     __WFI();
180 
181     //
182     // Upon wake, execute the Instruction Sync Barrier instruction.
183     //
184     __ISB();
185 
186     //
187     // Restore the interrupt state.
188     //
189     AM_CRITICAL_END
190 }
191 
192 //*****************************************************************************
193 //
194 // @brief Enable the floating point module.
195 //
196 // Call this function to enable the ARM hardware floating point module.
197 //
198 //*****************************************************************************
199 void
am_hal_sysctrl_fpu_enable(void)200 am_hal_sysctrl_fpu_enable(void)
201 {
202     //
203     // Enable access to the FPU in both privileged and user modes.
204     // NOTE: Write 0s to all reserved fields in this register.
205     //
206     SCB->CPACR = _VAL2FLD(SCB_CPACR_CP11, 0x3) |
207                  _VAL2FLD(SCB_CPACR_CP10, 0x3);
208 }
209 
210 //*****************************************************************************
211 //
212 // @brief Disable the floating point module.
213 //
214 // Call this function to disable the ARM hardware floating point module.
215 //
216 //*****************************************************************************
217 void
am_hal_sysctrl_fpu_disable(void)218 am_hal_sysctrl_fpu_disable(void)
219 {
220     //
221     // Disable access to the FPU in both privileged and user modes.
222     // NOTE: Write 0s to all reserved fields in this register.
223     //
224     SCB->CPACR = 0x00000000                         &
225                  ~(_VAL2FLD(SCB_CPACR_CP11, 0x3) |
226                    _VAL2FLD(SCB_CPACR_CP10, 0x3));
227 }
228 
229 //*****************************************************************************
230 //
231 // @brief Enable stacking of FPU registers on exception entry.
232 //
233 // @param bLazy - Set to "true" to enable "lazy stacking".
234 //
235 // This function allows the core to save floating-point information to the
236 // stack on exception entry. Setting the bLazy option enables "lazy stacking"
237 // for interrupt handlers.  Normally, mixing floating-point code and interrupt
238 // driven routines causes increased interrupt latency, because the core must
239 // save extra information to the stack upon exception entry. With the lazy
240 // stacking option enabled, the core will skip the saving of floating-point
241 // registers when possible, reducing average interrupt latency.
242 //
243 // @note At reset of the Cortex M4, the ASPEN and LSPEN bits are set to 1,
244 // enabling Lazy mode by default. Therefore this function will generally
245 // only have an affect when setting for full-context save (or when switching
246 // from full-context to lazy mode).
247 //
248 // @note See also:
249 // infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0298a/DAFGGBJD.html
250 //
251 // @note Three valid FPU context saving modes are possible.
252 // 1. Lazy           ASPEN=1 LSPEN=1 am_hal_sysctrl_fpu_stacking_enable(true)
253 //                                   and default.
254 // 2. Full-context   ASPEN=1 LSPEN=0 am_hal_sysctrl_fpu_stacking_enable(false)
255 // 3. No FPU state   ASPEN=0 LSPEN=0 am_hal_sysctrl_fpu_stacking_disable()
256 // 4. Invalid        ASPEN=0 LSPEN=1
257 //
258 //*****************************************************************************
259 void
am_hal_sysctrl_fpu_stacking_enable(bool bLazy)260 am_hal_sysctrl_fpu_stacking_enable(bool bLazy)
261 {
262     uint32_t ui32fpccr;
263 
264     //
265     // Set the requested FPU stacking mode in ISRs.
266     //
267     AM_CRITICAL_BEGIN
268 #define SYSCTRL_FPCCR_LAZY  (FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk)
269     ui32fpccr  = FPU->FPCCR;
270     ui32fpccr &= ~SYSCTRL_FPCCR_LAZY;
271     ui32fpccr |= (bLazy ? SYSCTRL_FPCCR_LAZY : FPU_FPCCR_ASPEN_Msk);
272     FPU->FPCCR = ui32fpccr;
273     AM_CRITICAL_END
274 }
275 
276 //*****************************************************************************
277 //
278 // @brief Disable FPU register stacking on exception entry.
279 //
280 // This function disables all stacking of floating point registers for
281 // interrupt handlers.  This mode should only be used when it is absolutely
282 // known that no FPU instructions will be executed in an ISR.
283 //
284 //*****************************************************************************
285 void
am_hal_sysctrl_fpu_stacking_disable(void)286 am_hal_sysctrl_fpu_stacking_disable(void)
287 {
288     //
289     // Completely disable FPU context save on entry to ISRs.
290     //
291     AM_CRITICAL_BEGIN
292     FPU->FPCCR &= ~SYSCTRL_FPCCR_LAZY;
293     AM_CRITICAL_END
294 }
295 
296 //*****************************************************************************
297 //
298 // @brief Issue a system wide reset using the AIRCR bit in the M4 system ctrl.
299 //
300 // This function issues a system wide reset (Apollo POR level reset).
301 //
302 //*****************************************************************************
303 void
am_hal_sysctrl_aircr_reset(void)304 am_hal_sysctrl_aircr_reset(void)
305 {
306     //
307     // Set the system reset bit in the AIRCR register
308     //
309     __NVIC_SystemReset();
310 }
311 
312 //*****************************************************************************
313 //
314 // End Doxygen group.
315 //! @}
316 //
317 //*****************************************************************************
318