1 /***************************************************************************//**
2  * @file
3  * @brief Reset Management Unit (RMU) peripheral module peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #include "em_rmu.h"
32 #if (defined(RMU_COUNT) && (RMU_COUNT > 0)) || (_EMU_RSTCTRL_MASK)
33 
34 #include "sl_common.h"
35 #include "em_emu.h"
36 #include "em_bus.h"
37 
38 /***************************************************************************//**
39  * @addtogroup rmu RMU - Reset Management Unit
40  * @brief Reset Management Unit (RMU) Peripheral API
41  * @details
42  *  This module contains functions to control the RMU peripheral of Silicon
43  *  Labs 32-bit MCUs and SoCs. RMU ensures correct reset operation and is
44  *  responsible for connecting the different reset sources to the reset lines of
45  *  the MCU or SoC.
46  * @{
47  ******************************************************************************/
48 
49 /*******************************************************************************
50  *****************************     DEFINES     *********************************
51  ******************************************************************************/
52 
53 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
54 
55 #if defined(_RMU_RSTCAUSE_MASK)
56 
57 /** Reset cause XMASKS for series-0 and series-1 devices.
58     Reset cause zero and "don't care" bit definitions (XMASKs).
59     An XMASK 1 bit marks a bit that must be zero in RMU_RSTCAUSE. A 0 in XMASK
60     is a "don't care" bit in RMU_RSTCAUSE if also 0 in resetCauseMask
61     in @ref RMU_ResetCauseMasks_Typedef. */
62 
63 /* EFM32G */
64 #if (_RMU_RSTCAUSE_MASK == 0x0000007FUL)
65 #define RMU_RSTCAUSE_PORST_XMASK         0x00000000UL /** 0000000000000000  < Power On Reset */
66 #define RMU_RSTCAUSE_BODUNREGRST_XMASK   0x00000001UL /** 0000000000000001  < Brown Out Detector Unregulated Domain Reset */
67 #define RMU_RSTCAUSE_BODREGRST_XMASK     0x0000001BUL /** 0000000000011011  < Brown Out Detector Regulated Domain Reset */
68 #define RMU_RSTCAUSE_EXTRST_XMASK        0x00000003UL /** 0000000000000011  < External Pin Reset */
69 #define RMU_RSTCAUSE_WDOGRST_XMASK       0x00000003UL /** 0000000000000011  < Watchdog Reset */
70 #define RMU_RSTCAUSE_LOCKUPRST_XMASK     0x0000001FUL /** 0000000000011111  < LOCKUP Reset */
71 #define RMU_RSTCAUSE_SYSREQRST_XMASK     0x0000001FUL /** 0000000000011111  < System Request Reset */
72 #define NUM_RSTCAUSES                               7
73 
74 /* EFM32TG, EFM32HG, EZR32HG, EFM32ZG */
75 #elif (_RMU_RSTCAUSE_MASK == 0x000007FFUL)
76 #define RMU_RSTCAUSE_PORST_XMASK         0x00000000UL /** 0000000000000000  < Power On Reset */
77 #define RMU_RSTCAUSE_BODUNREGRST_XMASK   0x00000081UL /** 0000000010000001  < Brown Out Detector Unregulated Domain Reset */
78 #define RMU_RSTCAUSE_BODREGRST_XMASK     0x00000091UL /** 0000000010010001  < Brown Out Detector Regulated Domain Reset */
79 #define RMU_RSTCAUSE_EXTRST_XMASK        0x00000001UL /** 0000000000000001  < External Pin Reset */
80 #define RMU_RSTCAUSE_WDOGRST_XMASK       0x00000003UL /** 0000000000000011  < Watchdog Reset */
81 #define RMU_RSTCAUSE_LOCKUPRST_XMASK     0x0000EFDFUL /** 1110111111011111  < LOCKUP Reset */
82 #define RMU_RSTCAUSE_SYSREQRST_XMASK     0x0000EF9FUL /** 1110111110011111  < System Request Reset */
83 #define RMU_RSTCAUSE_EM4RST_XMASK        0x00000719UL /** 0000011100011001  < EM4 Reset */
84 #define RMU_RSTCAUSE_EM4WURST_XMASK      0x00000619UL /** 0000011000011001  < EM4 Wake-up Reset */
85 #define RMU_RSTCAUSE_BODAVDD0_XMASK      0x0000041FUL /** 0000010000011111  < AVDD0 Bod Reset. */
86 #define RMU_RSTCAUSE_BODAVDD1_XMASK      0x0000021FUL /** 0000001000011111  < AVDD1 Bod Reset. */
87 #define NUM_RSTCAUSES                              11
88 
89 /* EFM32GG, EFM32LG, EZR32LG, EFM32WG, EZR32WG */
90 #elif (_RMU_RSTCAUSE_MASK == 0x0000FFFFUL)
91 #define RMU_RSTCAUSE_PORST_XMASK         0x00000000UL /** 0000000000000000  < Power On Reset */
92 #define RMU_RSTCAUSE_BODUNREGRST_XMASK   0x00000081UL /** 0000000010000001  < Brown Out Detector Unregulated Domain Reset */
93 #define RMU_RSTCAUSE_BODREGRST_XMASK     0x00000091UL /** 0000000010010001  < Brown Out Detector Regulated Domain Reset */
94 #define RMU_RSTCAUSE_EXTRST_XMASK        0x00000001UL /** 0000000000000001  < External Pin Reset */
95 #define RMU_RSTCAUSE_WDOGRST_XMASK       0x00000003UL /** 0000000000000011  < Watchdog Reset */
96 #define RMU_RSTCAUSE_LOCKUPRST_XMASK     0x0000EFDFUL /** 1110111111011111  < LOCKUP Reset */
97 #define RMU_RSTCAUSE_SYSREQRST_XMASK     0x0000EF9FUL /** 1110111110011111  < System Request Reset */
98 #define RMU_RSTCAUSE_EM4RST_XMASK        0x00000719UL /** 0000011100011001  < EM4 Reset */
99 #define RMU_RSTCAUSE_EM4WURST_XMASK      0x00000619UL /** 0000011000011001  < EM4 Wake-up Reset */
100 #define RMU_RSTCAUSE_BODAVDD0_XMASK      0x0000041FUL /** 0000010000011111  < AVDD0 Bod Reset */
101 #define RMU_RSTCAUSE_BODAVDD1_XMASK      0x0000021FUL /** 0000001000011111  < AVDD1 Bod Reset */
102 #define RMU_RSTCAUSE_BUBODVDDDREG_XMASK  0x00000001UL /** 0000000000000001  < Backup Brown Out Detector, VDD_DREG */
103 #define RMU_RSTCAUSE_BUBODBUVIN_XMASK    0x00000001UL /** 0000000000000001  < Backup Brown Out Detector, BU_VIN */
104 #define RMU_RSTCAUSE_BUBODUNREG_XMASK    0x00000001UL /** 0000000000000001  < Backup Brown Out Detector Unregulated Domain */
105 #define RMU_RSTCAUSE_BUBODREG_XMASK      0x00000001UL /** 0000000000000001  < Backup Brown Out Detector Regulated Domain */
106 #define RMU_RSTCAUSE_BUMODERST_XMASK     0x00000001UL /** 0000000000000001  < Backup mode reset */
107 #define NUM_RSTCAUSES                              16
108 
109 /* EFM32xG1, EFM32xG12, EFM32xG13 */
110 #elif ((_RMU_RSTCAUSE_MASK & 0x0FFFFFFF) == 0x00010F1DUL)
111 #define RMU_RSTCAUSE_PORST_XMASK         0x00000000UL /** 0000000000000000  < Power On Reset */
112 #define RMU_RSTCAUSE_BODAVDD_XMASK       0x00000001UL /** 0000000000000001  < AVDD BOD Reset */
113 #define RMU_RSTCAUSE_BODDVDD_XMASK       0x00000001UL /** 0000000000000001  < DVDD BOD Reset */
114 #define RMU_RSTCAUSE_BODREGRST_XMASK     0x00000001UL /** 0000000000000001  < Regulated Domain (DEC) BOD Reset */
115 #define RMU_RSTCAUSE_EXTRST_XMASK        0x00000001UL /** 0000000000000001  < External Pin Reset */
116 #define RMU_RSTCAUSE_LOCKUPRST_XMASK     0x0000001DUL /** 0000000000011101  < LOCKUP Reset */
117 #define RMU_RSTCAUSE_SYSREQRST_XMASK     0x0000001DUL /** 0000000000011101  < System Request Reset */
118 #define RMU_RSTCAUSE_WDOGRST_XMASK       0x0000001DUL /** 0000000000011101  < Watchdog Reset */
119 #define RMU_RSTCAUSE_EM4RST_XMASK        0x0000001DUL /** 0000000000011101  < EM4H/S Reset */
120 #define NUM_RSTCAUSES                               9
121 
122 /* EFM32GG11 */
123 #elif ((_RMU_RSTCAUSE_MASK & 0x0FFFFFFF) == 0x00011F1DUL)
124 #define RMU_RSTCAUSE_PORST_XMASK         0x00000000UL /** 0000000000000000  < Power On Reset */
125 #define RMU_RSTCAUSE_BODAVDD_XMASK       0x00000001UL /** 0000000000000001  < AVDD BOD Reset */
126 #define RMU_RSTCAUSE_BODDVDD_XMASK       0x00000001UL /** 0000000000000001  < DVDD BOD Reset */
127 #define RMU_RSTCAUSE_BODREGRST_XMASK     0x00000001UL /** 0000000000000001  < Regulated Domain (DEC) BOD Reset */
128 #define RMU_RSTCAUSE_EXTRST_XMASK        0x00000001UL /** 0000000000000001  < External Pin Reset */
129 #define RMU_RSTCAUSE_LOCKUPRST_XMASK     0x0000001DUL /** 0000000000011101  < LOCKUP Reset */
130 #define RMU_RSTCAUSE_SYSREQRST_XMASK     0x0000001DUL /** 0000000000011101  < System Request Reset */
131 #define RMU_RSTCAUSE_WDOGRST_XMASK       0x0000001DUL /** 0000000000011101  < Watchdog Reset */
132 #define RMU_RSTCAUSE_BUMODERST_XMASK     0x0000001DUL /** 0000000000011101  < Backup mode reset */
133 #define RMU_RSTCAUSE_EM4RST_XMASK        0x0000001DUL /** 0000000000011101  < EM4H/S Reset */
134 #define NUM_RSTCAUSES                              10
135 
136 #else
137 #error "RMU_RSTCAUSE XMASKs are not defined for this family."
138 #endif
139 
140 /* Pin reset definitions. */
141 #define LB_CLW0           (*((volatile uint32_t *)(LOCKBITS_BASE) +122))
142 #define LB_CLW0_PINRESETSOFT    (1 << 2)
143 
144 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
145 /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H. */
146 #define ERRATA_FIX_EMU_E208_EN
147 #endif
148 
149 #endif /* #if defined(_RMU_RSTCAUSE_MASK) */
150 
151 /*******************************************************************************
152  *******************************   STRUCTS   ***********************************
153  ******************************************************************************/
154 
155 #if defined(_RMU_RSTCAUSE_MASK)
156 /** Reset cause mask type for series-0 and series-1 devices. */
157 typedef struct {
158   /** Reset cause 1 bits. */
159   uint32_t resetCauseMask;
160   /** Reset cause 0 and "don't care" bits. */
161   uint32_t resetCauseZeroXMask;
162 } RMU_ResetCauseMasks_Typedef;
163 #endif
164 
165 /*******************************************************************************
166  *******************************   TYPEDEFS   **********************************
167  ******************************************************************************/
168 
169 #if defined(_RMU_RSTCAUSE_MASK)
170 /** Reset cause mask table. */
171 static const RMU_ResetCauseMasks_Typedef  resetCauseMasks[NUM_RSTCAUSES] =
172 {
173   { RMU_RSTCAUSE_PORST, RMU_RSTCAUSE_PORST_XMASK },
174 #if defined(RMU_RSTCAUSE_BODUNREGRST)
175   { RMU_RSTCAUSE_BODUNREGRST, RMU_RSTCAUSE_BODUNREGRST_XMASK },
176 #endif
177 #if defined(RMU_RSTCAUSE_BODREGRST)
178   { RMU_RSTCAUSE_BODREGRST, RMU_RSTCAUSE_BODREGRST_XMASK },
179 #endif
180 #if defined(RMU_RSTCAUSE_AVDDBOD)
181   { RMU_RSTCAUSE_AVDDBOD, RMU_RSTCAUSE_BODAVDD_XMASK },
182 #endif
183 #if defined(RMU_RSTCAUSE_DVDDBOD)
184   { RMU_RSTCAUSE_DVDDBOD, RMU_RSTCAUSE_BODDVDD_XMASK },
185 #endif
186 #if defined(RMU_RSTCAUSE_DECBOD)
187   { RMU_RSTCAUSE_DECBOD, RMU_RSTCAUSE_BODREGRST_XMASK },
188 #endif
189   { RMU_RSTCAUSE_EXTRST, RMU_RSTCAUSE_EXTRST_XMASK },
190   { RMU_RSTCAUSE_WDOGRST, RMU_RSTCAUSE_WDOGRST_XMASK },
191   { RMU_RSTCAUSE_LOCKUPRST, RMU_RSTCAUSE_LOCKUPRST_XMASK },
192   { RMU_RSTCAUSE_SYSREQRST, RMU_RSTCAUSE_SYSREQRST_XMASK },
193 #if defined(RMU_RSTCAUSE_EM4RST)
194   { RMU_RSTCAUSE_EM4RST, RMU_RSTCAUSE_EM4RST_XMASK },
195 #endif
196 #if defined(RMU_RSTCAUSE_EM4WURST)
197   { RMU_RSTCAUSE_EM4WURST, RMU_RSTCAUSE_EM4WURST_XMASK },
198 #endif
199 #if defined(RMU_RSTCAUSE_BODAVDD0)
200   { RMU_RSTCAUSE_BODAVDD0, RMU_RSTCAUSE_BODAVDD0_XMASK },
201 #endif
202 #if defined(RMU_RSTCAUSE_BODAVDD1)
203   { RMU_RSTCAUSE_BODAVDD1, RMU_RSTCAUSE_BODAVDD1_XMASK },
204 #endif
205 #if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_0)
206   { RMU_RSTCAUSE_BUBODVDDDREG, RMU_RSTCAUSE_BUBODVDDDREG_XMASK },
207   { RMU_RSTCAUSE_BUBODBUVIN, RMU_RSTCAUSE_BUBODBUVIN_XMASK },
208   { RMU_RSTCAUSE_BUBODUNREG, RMU_RSTCAUSE_BUBODUNREG_XMASK },
209   { RMU_RSTCAUSE_BUBODREG, RMU_RSTCAUSE_BUBODREG_XMASK },
210   { RMU_RSTCAUSE_BUMODERST, RMU_RSTCAUSE_BUMODERST_XMASK },
211 #elif defined(RMU_RSTCAUSE_BUMODERST)
212   { RMU_RSTCAUSE_BUMODERST, RMU_RSTCAUSE_BUMODERST_XMASK },
213 #endif
214 };
215 #endif /* #if defined(_RMU_RSTCAUSE_MASK) */
216 
217 /*******************************************************************************
218  ********************************     TEST     ********************************
219  ******************************************************************************/
220 #if defined(EMLIB_REGRESSION_TEST)
221 /* A test variable that replaces the RSTCAUSE cause register when testing
222    the RMU_ResetCauseGet function. */
223 extern uint32_t rstCause;
224 #else
225 static uint32_t rstCause = UINT32_MAX;
226 #endif
227 
228 /** @endcond */
229 
230 /*******************************************************************************
231  **************************   GLOBAL FUNCTIONS   *******************************
232  ******************************************************************************/
233 
234 /***************************************************************************//**
235  * @brief
236  *   Disable/enable reset for various peripherals and signal sources.
237  *
238  * @param[in] reset Reset types to enable/disable.s
239  *
240  * @param[in] mode  Reset mode.
241  ******************************************************************************/
242 #if defined(__GNUC__) && __GNUC__ >= 11
243 #pragma GCC diagnostic push
244 #pragma GCC diagnostic ignored "-Wanalyzer-shift-count-overflow"
245 #endif
RMU_ResetControl(RMU_Reset_TypeDef reset,RMU_ResetMode_TypeDef mode)246 void RMU_ResetControl(RMU_Reset_TypeDef reset, RMU_ResetMode_TypeDef mode)
247 {
248   /* Note that the RMU supports bit-band access, but not peripheral bit-field set/clear. */
249 #if defined(_RMU_CTRL_PINRMODE_MASK)
250   uint32_t val;
251 #endif
252   uint32_t shift;
253 
254   shift = SL_CTZ((uint32_t)reset);
255 #if defined(_EMU_RSTCTRL_MASK)
256   BUS_RegBitWrite(&EMU->RSTCTRL, (uint32_t)shift, mode ? 1 : 0);
257 #elif defined(_RMU_CTRL_PINRMODE_MASK)
258   EFM_ASSERT(shift < 32);
259   val = (uint32_t)mode << shift;
260   RMU->CTRL = (RMU->CTRL & ~reset) | val;
261 #else
262   BUS_RegBitWrite(&RMU->CTRL, (uint32_t)shift, mode ? 1 : 0);
263 #endif
264 }
265 #if defined(__GNUC__) && __GNUC__ >= 11
266 #pragma GCC diagnostic pop
267 #endif
268 
269 /***************************************************************************//**
270  * @brief
271  *   Clear the reset cause register.
272  *
273  * @details
274  *   This function clears all the reset cause bits of the RSTCAUSE register.
275  *   The reset cause bits must be cleared by software before a new reset occurs.
276  *   Otherwise, reset causes may accumulate. See @ref RMU_ResetCauseGet().
277  ******************************************************************************/
RMU_ResetCauseClear(void)278 void RMU_ResetCauseClear(void)
279 {
280 #if defined(_EMU_RSTCTRL_MASK)
281   EMU->CMD_SET = EMU_CMD_RSTCAUSECLR;
282 #else
283   RMU->CMD = RMU_CMD_RCCLR;
284 #endif
285 
286 #if defined(EMU_AUXCTRL_HRCCLR)
287   {
288     uint32_t locked;
289 
290     /* Clear reset causes not cleared with the RMU CMD register. */
291     /* (If EMU registers are locked, they must be unlocked first) */
292     locked = EMU->LOCK & EMU_LOCK_LOCKKEY_LOCKED;
293     if (locked) {
294       EMU_Unlock();
295     }
296 
297     BUS_RegBitWrite(&(EMU->AUXCTRL), _EMU_AUXCTRL_HRCCLR_SHIFT, 1);
298     BUS_RegBitWrite(&(EMU->AUXCTRL), _EMU_AUXCTRL_HRCCLR_SHIFT, 0);
299 
300     if (locked) {
301       EMU_Lock();
302     }
303   }
304 #endif
305 }
306 
307 /***************************************************************************//**
308  * @brief
309  *   Get the cause of the last reset.
310  *
311  * @details
312  *   To be useful, the reset cause must be cleared by software before a new
313  *   reset occurs. Otherwise, reset causes may accumulate. See @ref
314  *   RMU_ResetCauseClear(). This function call will return the main cause for
315  *   reset, which can be a bit mask (several causes) and clear away "noise".
316  *
317  * @return
318  *   A reset cause mask. See the reference manual for a description
319  *   of the reset cause mask.
320  ******************************************************************************/
RMU_ResetCauseGet(void)321 uint32_t RMU_ResetCauseGet(void)
322 {
323 #if !defined(EMLIB_REGRESSION_TEST)
324   if (rstCause != UINT32_MAX) {
325     // RMU_ResetCauseGet() has already been called since boot. Return what was already obtained.
326     return rstCause;
327   }
328 #endif
329 
330 #if defined(_EMU_RSTCAUSE_MASK)
331 #if !defined(EMLIB_REGRESSION_TEST)
332   rstCause = EMU->RSTCAUSE;
333 #endif
334   return rstCause;
335 #endif
336 
337 #if defined(_RMU_RSTCAUSE_MASK)
338 #if !defined(EMLIB_REGRESSION_TEST)
339   rstCause = RMU->RSTCAUSE;
340 #endif
341   uint32_t validRstCause = 0;
342   uint32_t zeroXMask;
343   uint32_t i;
344 
345   for (i = 0; i < NUM_RSTCAUSES; i++) {
346     zeroXMask = resetCauseMasks[i].resetCauseZeroXMask;
347 #if defined(_SILICON_LABS_32B_SERIES_1)
348     /* Handle soft/hard pin reset. */
349     if (!(LB_CLW0 & LB_CLW0_PINRESETSOFT)) {
350       /* RSTCAUSE_EXTRST must be 0 if pin reset is configured as hard reset. */
351       switch (resetCauseMasks[i].resetCauseMask) {
352         case RMU_RSTCAUSE_LOCKUPRST:
353         /* Fallthrough */
354         case RMU_RSTCAUSE_SYSREQRST:
355         /* Fallthrough */
356         case RMU_RSTCAUSE_WDOGRST:
357         /* Fallthrough */
358         case RMU_RSTCAUSE_EM4RST:
359           zeroXMask |= RMU_RSTCAUSE_EXTRST;
360           break;
361         default:
362           /* MISRA requires a default case. */
363           break;
364       }
365     }
366 #endif
367 
368 #if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_EN)
369     /* Ignore BOD flags impacted by EMU_E208. */
370     if (*(volatile uint32_t *)(EMU_BASE + 0x88) & (0x1 << 8)) {
371       zeroXMask &= ~(RMU_RSTCAUSE_DECBOD
372                      | RMU_RSTCAUSE_DVDDBOD
373                      | RMU_RSTCAUSE_AVDDBOD);
374     }
375 #endif
376 
377     /* Check reset cause requirements. Note that a bit is "don't care" if 0 in
378        both resetCauseMask and resetCauseZeroXMask. */
379     if ((rstCause & resetCauseMasks[i].resetCauseMask)
380         && !(rstCause & zeroXMask)) {
381       /* Add this reset-cause to the mask of qualified reset-causes. */
382       validRstCause |= resetCauseMasks[i].resetCauseMask;
383     }
384   }
385 #if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_EN)
386   /* Clear BOD flags impacted by EMU_E208. */
387   if (validRstCause & RMU_RSTCAUSE_EM4RST) {
388     validRstCause &= ~(RMU_RSTCAUSE_DECBOD
389                        | RMU_RSTCAUSE_DVDDBOD
390                        | RMU_RSTCAUSE_AVDDBOD);
391   }
392 #endif
393 #if !defined(EMLIB_REGRESSION_TEST)
394   // keep validRstCause in the static local variable for future calls
395   rstCause = validRstCause
396 #endif
397   return validRstCause;
398 #endif
399 }
400 
401 /** @} (end addtogroup rmu) */
402 #endif /* defined(RMU_COUNT) && (RMU_COUNT > 0) */
403