1 /**
2  * @file    mxc_sys.h
3  * @brief   System level header file.
4  */
5 
6 /******************************************************************************
7  *
8  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
9  * Analog Devices, Inc.),
10  * Copyright (C) 2023-2024 Analog Devices, Inc.
11  *
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  *
24  ******************************************************************************/
25 
26 #ifndef LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32572_MXC_SYS_H_
27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32572_MXC_SYS_H_
28 
29 #include "mxc_device.h"
30 #include "gcr_regs.h"
31 #include "mcr_regs.h"
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 /**
38  * @defgroup mxc_sys System Configuration (MXC_SYS)
39  * @ingroup syscfg
40  * @details API for system configuration including clock source selection and entering critical sections of code.
41  * @{
42  */
43 
44 /** @brief System reset0 and reset1 enumeration. Used in MXC_SYS_PeriphReset0 function */
45 typedef enum {
46     MXC_SYS_RESET0_DMA = MXC_F_GCR_RST0_DMA_POS, /**< Reset DMA */
47     MXC_SYS_RESET0_WDT = MXC_F_GCR_RST0_WDT0_POS, /**< Reset WDT */
48     MXC_SYS_RESET0_GPIO0 = MXC_F_GCR_RST0_GPIO0_POS, /**< Reset GPIO0 */
49     MXC_SYS_RESET0_GPIO1 = MXC_F_GCR_RST0_GPIO1_POS, /**< Reset GPIO1 */
50     MXC_SYS_RESET0_TMR0 = MXC_F_GCR_RST0_TMR0_POS, /**< Reset TMR0 */
51     MXC_SYS_RESET0_TMR1 = MXC_F_GCR_RST0_TMR1_POS, /**< Reset TMR1 */
52     MXC_SYS_RESET0_TMR2 = MXC_F_GCR_RST0_TMR2_POS, /**< Reset TMR2 */
53     MXC_SYS_RESET0_TMR3 = MXC_F_GCR_RST0_TMR3_POS, /**< Reset TMR3 */
54     MXC_SYS_RESET0_TMR4 = MXC_F_GCR_RST0_TMR4_POS, /**< Reset TMR4 */
55     MXC_SYS_RESET0_TMR5 = MXC_F_GCR_RST0_TMR5_POS, /**< Reset TMR5 */
56     MXC_SYS_RESET0_UART0 = MXC_F_GCR_RST0_UART0_POS, /**< Reset UART0 */
57     MXC_SYS_RESET0_UART1 = MXC_F_GCR_RST0_UART1_POS, /**< Reset UART1 */
58     MXC_SYS_RESET0_SPI0 = MXC_F_GCR_RST0_SPI0_POS, /**< Reset SPI0 */
59     MXC_SYS_RESET0_SPI1 = MXC_F_GCR_RST0_SPI1_POS, /**< Reset SPI1 */
60     MXC_SYS_RESET0_I2C0 = MXC_F_GCR_RST0_I2C0_POS, /**< Reset I2C0 */
61     MXC_SYS_RESET0_RTC = MXC_F_MCR_RST_RTC, /**< Reset RTC */
62     MXC_SYS_RESET0_CTB = MXC_F_GCR_RST0_CRYPTO_POS, /**< Reset CRYPTO */
63     MXC_SYS_RESET0_USB = MXC_F_GCR_RST0_USB_POS, /**< Reset USB */
64     MXC_SYS_RESET0_TRNG = MXC_F_GCR_RST0_TRNG_POS, /**< Reset TRNG */
65     MXC_SYS_RESET0_ADC = MXC_F_GCR_RST0_ADC_POS, /**< Reset ADC */
66     MXC_SYS_RESET0_UART2 = MXC_F_GCR_RST0_UART2_POS, /**< Reset UART2 */
67     MXC_SYS_RESET0_SRST = MXC_F_GCR_RST0_SOFT_POS, /**< Soft reset */
68     MXC_SYS_RESET0_PRST = MXC_F_GCR_RST0_PERIPH_POS, /**< Peripheral reset */
69     MXC_SYS_RESET0_SYS = MXC_F_GCR_RST0_SYS_POS, /**< System reset */
70     /* RESET1 Below this line we add 32 to separate RESET0 and RESET1 */
71     MXC_SYS_RESET1_I2C1 = (MXC_F_GCR_RST1_I2C1_POS + 32), /**< Reset I2C1 */
72     MXC_SYS_RESET1_PT = (MXC_F_GCR_RST1_PT_POS + 32), /**< Reset PT */
73     MXC_SYS_RESET1_SPIXIP = (MXC_F_GCR_RST1_SPIXIP_POS + 32), /**< Reset SPIXIP */
74     MXC_SYS_RESET1_SPIXIPM = (MXC_F_GCR_RST1_SPIXIPM_POS + 32), /**< Reset SPIXIPM */
75     MXC_SYS_RESET1_WDT1 = (MXC_F_GCR_RST1_WDT1_POS + 32), /**< Reset WDT1 */
76     MXC_SYS_RESET1_SPI3 = (MXC_F_GCR_RST1_SPI3_POS + 32), /**< Reset SPI3 */
77     MXC_SYS_RESET1_AC = (MXC_F_GCR_RST1_AC_POS + 32), /**< Reset AC */
78     MXC_SYS_RESET1_UART3 = (MXC_F_GCR_RST1_UART3_POS + 32), /**< Reset UART3 */
79     MXC_SYS_RESET1_SKBD = (MXC_F_GCR_RST1_SKBD_POS + 32), /**< Reset SKBD */
80     MXC_SYS_RESET1_MSRADC = (MXC_F_GCR_RST1_MSRADC_POS + 32), /**< Reset MSRADC */
81     MXC_SYS_RESET1_SC0 = (MXC_F_GCR_RST1_SC0_POS + 32), /**< Reset SC0 */
82     MXC_SYS_RESET1_SC1 = (MXC_F_GCR_RST1_SC1_POS + 32), /**< Reset SC1 */
83     MXC_SYS_RESET1_HTMR0 = (MXC_F_GCR_RST1_HTMR0_POS + 32), /**< Reset HTMR0 */
84     MXC_SYS_RESET1_HTMR1 = (MXC_F_GCR_RST1_HTMR1_POS + 32), /**< Reset HTMR1 */
85     MXC_SYS_RESET1_CPU1 = (MXC_F_GCR_RST1_CPU1_POS + 32), /**< Reset CPU1 */
86 } mxc_sys_reset_t;
87 
88 /** @brief System clock disable enumeration. Used in MXC_SYS_ClockDisable and MXC_SYS_ClockEnable functions */
89 typedef enum {
90     MXC_SYS_PERIPH_CLOCK_GPIO0 =
91         MXC_F_GCR_PCLKDIS0_GPIO0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO0 clock */
92     MXC_SYS_PERIPH_CLOCK_GPIO1 =
93         MXC_F_GCR_PCLKDIS0_GPIO1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO1 clock */
94     MXC_SYS_PERIPH_CLOCK_USB =
95         MXC_F_GCR_PCLKDIS0_USB_POS, /**< Disable MXC_F_GCR_PCLKDIS0_USB clock */
96     MXC_SYS_PERIPH_CLOCK_DMA =
97         MXC_F_GCR_PCLKDIS0_DMA_POS, /**< Disable MXC_F_GCR_PCLKDIS0_DMA clock */
98     MXC_SYS_PERIPH_CLOCK_SPI0 =
99         MXC_F_GCR_PCLKDIS0_SPI0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI0 clock */
100     MXC_SYS_PERIPH_CLOCK_SPI1 =
101         MXC_F_GCR_PCLKDIS0_SPI1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI1 clock */
102     MXC_SYS_PERIPH_CLOCK_UART0 =
103         MXC_F_GCR_PCLKDIS0_UART0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART0 clock */
104     MXC_SYS_PERIPH_CLOCK_UART1 =
105         MXC_F_GCR_PCLKDIS0_UART1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART1 clock */
106     MXC_SYS_PERIPH_CLOCK_I2C0 =
107         MXC_F_GCR_PCLKDIS0_I2C0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C0 clock */
108     MXC_SYS_PERIPH_CLOCK_CTB =
109         MXC_F_GCR_PCLKDIS0_CRYPTO_POS, /**< Disable MXC_F_GCR_PCLKDIS0_CRYPTO clock */
110     MXC_SYS_PERIPH_CLOCK_TMR0 =
111         MXC_F_GCR_PCLKDIS0_TMR0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR0 clock */
112     MXC_SYS_PERIPH_CLOCK_TMR1 =
113         MXC_F_GCR_PCLKDIS0_TMR1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR1 clock */
114     MXC_SYS_PERIPH_CLOCK_TMR2 =
115         MXC_F_GCR_PCLKDIS0_TMR2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR2 clock */
116     MXC_SYS_PERIPH_CLOCK_TMR3 =
117         MXC_F_GCR_PCLKDIS0_TMR3_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR3 clock */
118     MXC_SYS_PERIPH_CLOCK_TMR4 =
119         MXC_F_GCR_PCLKDIS0_TMR4_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR4 clock */
120     MXC_SYS_PERIPH_CLOCK_TMR5 =
121         MXC_F_GCR_PCLKDIS0_TMR5_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR5 clock */
122     MXC_SYS_PERIPH_CLOCK_SKBD =
123         MXC_F_GCR_PCLKDIS0_SKBD_POS, /**< Disable MXC_F_GCR_PCLKDIS0_ADC clock */
124     MXC_SYS_PERIPH_CLOCK_ADC =
125         MXC_F_GCR_PCLKDIS0_ADC_POS, /**< Disable MXC_F_GCR_PCLKDIS0_ADC clock */
126     MXC_SYS_PERIPH_CLOCK_HTMR0 =
127         MXC_F_GCR_PCLKDIS0_HTMR0_POS, /**< Disable MXC_F_GCR_PCLKDIS1_HTMR0 clock */
128     MXC_SYS_PERIPH_CLOCK_HTMR1 =
129         MXC_F_GCR_PCLKDIS0_HTMR1_POS, /**< Disable MXC_F_GCR_PCLKDIS1_HTMR1 clock */
130     MXC_SYS_PERIPH_CLOCK_I2C1 =
131         MXC_F_GCR_PCLKDIS0_I2C1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C1 clock */
132     MXC_SYS_PERIPH_CLOCK_PT = MXC_F_GCR_PCLKDIS0_PT_POS, /**< Disable MXC_F_GCR_PCLKDIS0_PT clock */
133     MXC_SYS_PERIPH_CLOCK_SPIXIP =
134         MXC_F_GCR_PCLKDIS0_SPIXIP_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPIXIP clock */
135     MXC_SYS_PERIPH_CLOCK_SPIXFC =
136         MXC_F_GCR_PCLKDIS0_SPIXIPC_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPIXIPC clock */
137     /* PCLKDIS1 Below this line we add 32 to separate PCLKDIS0 and PCLKDIS1 */
138     MXC_SYS_PERIPH_CLOCK_UART2 =
139         (MXC_F_GCR_PCLKDIS1_UART2_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_UART2 clock */
140     MXC_SYS_PERIPH_CLOCK_TRNG =
141         (MXC_F_GCR_PCLKDIS1_TRNG_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_TRNG clock */
142     MXC_SYS_PERIPH_CLOCK_OTP =
143         (MXC_F_GCR_PCLKDIS1_OTP_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_OTP clock */
144     MXC_SYS_PERIPH_CLOCK_WDT0 =
145         (MXC_F_GCR_PCLKDIS1_WDT0_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_WDT0 clock */
146     MXC_SYS_PERIPH_CLOCK_WDT1 =
147         (MXC_F_GCR_PCLKDIS1_WDT1_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_WDT1 clock */
148     MXC_SYS_PERIPH_CLOCK_SPI3 =
149         (MXC_F_GCR_PCLKDIS1_SPI3_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_SPI3 clock */
150     MXC_SYS_PERIPH_CLOCK_UART3 =
151         (MXC_F_GCR_PCLKDIS1_UART3_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_UART3 clock */
152     MXC_SYS_PERIPH_CLOCK_MSRADC =
153         (MXC_F_GCR_PCLKDIS1_MSRADC_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_MSRADC clock */
154     MXC_SYS_PERIPH_CLOCK_SC0 =
155         (MXC_F_GCR_PCLKDIS1_SC0_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_SC0 clock */
156     MXC_SYS_PERIPH_CLOCK_SC1 =
157         (MXC_F_GCR_PCLKDIS1_SC1_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_SC1 clock */
158     MXC_SYS_PERIPH_CLOCK_CPU1 =
159         (MXC_F_GCR_PCLKDIS1_CPU1_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_CPU1 clock */
160 } mxc_sys_periph_clock_t;
161 
162 /** @brief Enumeration to select System Clock source */
163 typedef enum {
164     MXC_SYS_CLOCK_IPO =
165         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IPO, /**< Select the Internal Primary Oscillator (IPO) */
166     MXC_SYS_CLOCK_IBRO =
167         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IBRO, /**< Select the Internal Baud Rate Oscillator (IBRO) */
168     MXC_SYS_CLOCK_ISO =
169         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ISO, /**< Select the Internal Secondary Oscillator (ISO) */
170     MXC_SYS_CLOCK_ERFO =
171         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERFO, /**< Select the External RF Crystal Oscillator */
172     MXC_SYS_CLOCK_INRO =
173         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_INRO, /**< Select the Internal Nanoring Oscillator (INRO) */
174     MXC_SYS_CLOCK_ERTCO =
175         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERTCO, /**< Select the External RTC Crystal Oscillator */
176 } mxc_sys_system_clock_t;
177 
178 #define MXC_SYS_SCACHE_CLK 1 // Enable SCACHE CLK
179 #define MXC_SYS_CTB_CLK 1 // Enable CTB CLK
180 
181 #define MXC_SYS_USN_CHECKSUM_LEN 16 // Length of the USN + padding for checksum compute
182 #define MXC_SYS_USN_CSUM_FIELD_LEN 2 // Size of the checksum field in the USN
183 #define MXC_SYS_USN_LEN 13 // Size of the USN including the checksum
184 
185 /***** Function Prototypes *****/
186 
187 typedef struct {
188     int ie_status;
189     int in_critical;
190 } mxc_crit_state_t;
191 
192 static mxc_crit_state_t _state = { .ie_status = (int)0xFFFFFFFF, .in_critical = 0 };
193 
_mxc_crit_get_state(void)194 static inline void _mxc_crit_get_state(void)
195 {
196 #ifndef __riscv
197     /*
198         On ARM M the 0th bit of the Priority Mask register indicates
199         whether interrupts are enabled or not.
200 
201         0 = enabled
202         1 = disabled
203     */
204     uint32_t primask = __get_PRIMASK();
205     _state.ie_status = (primask == 0);
206 #else
207     /*
208         On RISC-V bit position 3 (Machine Interrupt Enable) of the
209         mstatus register indicates whether interrupts are enabled.
210 
211         0 = disabled
212         1 = enabled
213     */
214     uint32_t mstatus = get_mstatus();
215     _state.ie_status = ((mstatus & (1 << 3)) != 0);
216 #endif
217 }
218 
219 /**
220  * @brief Enter a critical section of code that cannot be interrupted.  Call @ref MXC_SYS_Crit_Exit to exit the critical section.
221  * @details Ex:
222  * @code
223  * MXC_SYS_Crit_Enter();
224  * printf("Hello critical section!\n");
225  * MXC_SYS_Crit_Exit();
226  * @endcode
227  * The @ref MXC_CRITICAL macro is also provided as a convencience macro for wrapping a code section in this way.
228  * @returns None
229  */
MXC_SYS_Crit_Enter(void)230 static inline void MXC_SYS_Crit_Enter(void)
231 {
232     _mxc_crit_get_state();
233     if (_state.ie_status)
234         __disable_irq();
235     _state.in_critical = 1;
236 }
237 
238 /**
239  * @brief Exit a critical section of code from @ref MXC_SYS_Crit_Enter
240  * @returns None
241  */
MXC_SYS_Crit_Exit(void)242 static inline void MXC_SYS_Crit_Exit(void)
243 {
244     if (_state.ie_status) {
245         __enable_irq();
246     }
247     _state.in_critical = 0;
248     _mxc_crit_get_state();
249     /*
250         ^ Reset the state again to prevent edge case
251         where interrupts get disabled, then Crit_Exit() gets
252         called, which would inadvertently re-enable interrupts
253         from old state.
254     */
255 }
256 
257 /**
258  * @brief Polls whether code is currently executing from a critical section.
259  * @returns 1 if code is currently in a critical section (interrupts are disabled).
260  *          0 if code is not in a critical section.
261  */
MXC_SYS_In_Crit_Section(void)262 static inline int MXC_SYS_In_Crit_Section(void)
263 {
264     return _state.in_critical;
265 }
266 
267 // clang-format off
268 /**
269  * @brief Macro for wrapping a section of code to make it critical (interrupts disabled).  Note: this macro
270  * does not support nesting.
271  * @details
272  * Ex:
273  * \code
274  * MXC_CRITICAL(
275  *      printf("Hello critical section!\n");
276  * )
277  * \endcode
278  * This macro places a call to @ref MXC_SYS_Crit_Enter before the code, and a call to @ref MXC_SYS_Crit_Exit after.
279  * @param code The code section to wrap.
280  */
281 #define MXC_CRITICAL(code) {\
282     MXC_SYS_Crit_Enter();\
283     code;\
284     MXC_SYS_Crit_Exit();\
285 }
286 // clang-format on
287 
288 /**
289  * @brief Determines if the selected peripheral clock is enabled.
290  * @param clock   Enumeration for desired clock.
291  * @returns       0 is the clock is disabled, non 0 if the clock is enabled.
292  */
293 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock);
294 
295 /**
296  * @brief Disables the selected peripheral clock.
297  * @param clock   Enumeration for desired clock.
298  */
299 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock);
300 
301 /**
302  * @brief Enables the selected peripheral clock.
303  * @param clock   Enumeration for desired clock.
304  */
305 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock);
306 
307 /**
308  * @brief Enables the 32kHz oscillator
309  * @param mxc_sys_cfg   Not used, may be NULL.
310  */
311 void MXC_SYS_RTCClockEnable(void);
312 
313 /**
314  * @brief Disables the 32kHz oscillator
315  * @returns         E_NO_ERROR if everything is successful
316  */
317 int MXC_SYS_RTCClockDisable(void);
318 
319 /**
320  * @brief Enable System Clock Source without switching to it
321  * @param      clock The clock to enable
322  * @return     E_NO_ERROR if everything is successful
323  */
324 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock);
325 
326 /**
327  * @brief Disable System Clock Source
328  * @param      clock The clock to disable
329  * @return     E_NO_ERROR if everything is successful
330  */
331 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock);
332 
333 /**
334  * @brief Select the system clock.
335  * @param clock     Enumeration for desired clock.
336  * @returns         E_NO_ERROR if everything is successful.
337  */
338 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock);
339 
340 /**
341  * @brief Wait for a clock to enable with timeout
342  * @param      ready The clock to wait for
343  * @return     E_NO_ERROR if ready, E_TIME_OUT if timeout
344  */
345 int MXC_SYS_Clock_Timeout(uint32_t ready);
346 
347 /**
348  * @brief Reset the peripherals and/or CPU in the RST0 or RST1 register.
349  * @param           Enumeration for what to reset. Can reset multiple items at once.
350  */
351 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset);
352 
353 /**
354  * @brief      Get the revision of the chip
355  * @returns    the chip revision
356  */
357 uint8_t MXC_SYS_GetRev(void);
358 
359 /**
360  * @brief Reads the device USN and verifies the checksum.
361  * @param usn       Pointer to store the USN. Array must be at least MXC_SYS_USN_LEN bytes long.
362  * @param checksum  Optional pointer to store the AES checksum. If not NULL, checksum is verified with AES engine.
363  * @returns         E_NO_ERROR if everything is successful.
364  */
365 int MXC_SYS_GetUSN(uint8_t *usn, uint8_t *checksum);
366 
367 #ifdef __cplusplus
368 }
369 #endif
370 
371 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32572_MXC_SYS_H_
372