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