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_MAX32520_MXC_SYS_H_
27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32520_MXC_SYS_H_
28
29 #include "mxc_device.h"
30 #include "gcr_regs.h"
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 /**
37 * @defgroup mxc_sys System Configuration (MXC_SYS)
38 * @ingroup syscfg
39 * @details API for system configuration including clock source selection and entering critical sections of code.
40 * @{
41 */
42
43 /** @brief System reset0 and reset1 enumeration. Used in MXC_SYS_PeriphReset0 function */
44 typedef enum {
45 MXC_SYS_RESET_DMA = MXC_F_GCR_RST0_DMA_POS, /**< Reset DMA */
46 MXC_SYS_RESET_WDT0 = MXC_F_GCR_RST0_WDT0_POS, /**< Reset WDT */
47 MXC_SYS_RESET_GPIO0 = MXC_F_GCR_RST0_GPIO0_POS, /**< Reset GPIO0 */
48 MXC_SYS_RESET_GPIO1 = MXC_F_GCR_RST0_GPIO1_POS, /**< Reset GPIO1 */
49 MXC_SYS_RESET_TMR0 = MXC_F_GCR_RST0_TMR0_POS, /**< Reset TMR0 */
50 MXC_SYS_RESET_TMR1 = MXC_F_GCR_RST0_TMR1_POS, /**< Reset TMR1 */
51 MXC_SYS_RESET_TMR2 = MXC_F_GCR_RST0_TMR2_POS, /**< Reset TMR2 */
52 MXC_SYS_RESET_TMR3 = MXC_F_GCR_RST0_TMR3_POS, /**< Reset TMR3 */
53 MXC_SYS_RESET_UART0 = MXC_F_GCR_RST0_UART0_POS, /**< Reset UART0 */
54 MXC_SYS_RESET_SPI0 = MXC_F_GCR_RST0_SPI0_POS, /**< Reset SPI0 */
55 MXC_SYS_RESET_SPI1 = MXC_F_GCR_RST0_SPI1_POS, /**< Reset SPI1 */
56 MXC_SYS_RESET_I2C0 = MXC_F_GCR_RST0_I2C0_POS, /**< Reset I2C0 */
57 MXC_SYS_RESET_CTB = MXC_F_GCR_RST0_CRYPTO_POS, /**< Reset CRYPTO */
58 MXC_SYS_RESET_SRST = MXC_F_GCR_RST0_SOFT_POS, /**< Soft reset */
59 MXC_SYS_RESET_PRST = MXC_F_GCR_RST0_PERIPH_POS, /**< Peripheral reset */
60 MXC_SYS_RESET_SYS = MXC_F_GCR_RST0_SYS_POS, /**< System reset */
61 /* RESET1 Below this line we add 32 to separate RESET0 and RESET1 */
62 MXC_SYS_RESET_WDT1 = (MXC_F_GCR_RST1_WDT1_POS + 32), /**< Reset WDT1 */
63 MXC_SYS_RESET_SFES = (MXC_F_GCR_RST1_SFES_POS + 32), /**< Reset SFES */
64 } mxc_sys_reset_t;
65
66 /** @brief System clock disable enumeration. Used in MXC_SYS_ClockDisable and MXC_SYS_ClockEnable functions */
67 typedef enum {
68 MXC_SYS_PERIPH_CLOCK_GPIO0 =
69 MXC_F_GCR_PCLKDIS0_GPIO0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO0 clock */
70 MXC_SYS_PERIPH_CLOCK_GPIO1 =
71 MXC_F_GCR_PCLKDIS0_GPIO1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO1 clock */
72 MXC_SYS_PERIPH_CLOCK_DMA =
73 MXC_F_GCR_PCLKDIS0_DMA_POS, /**< Disable MXC_F_GCR_PCLKDIS0_DMA clock */
74 MXC_SYS_PERIPH_CLOCK_SPI0 =
75 MXC_F_GCR_PCLKDIS0_SPI0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI0 clock */
76 MXC_SYS_PERIPH_CLOCK_SPI1 =
77 MXC_F_GCR_PCLKDIS0_SPI1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI1 clock */
78 MXC_SYS_PERIPH_CLOCK_UART0 =
79 MXC_F_GCR_PCLKDIS0_UART0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART0 clock */
80 MXC_SYS_PERIPH_CLOCK_I2C0 =
81 MXC_F_GCR_PCLKDIS0_I2C0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C0 clock */
82 MXC_SYS_PERIPH_CLOCK_CTB =
83 MXC_F_GCR_PCLKDIS0_CRYPTO_POS, /**< Disable MXC_F_GCR_PCLKDIS0_CRYPTO clock */
84 MXC_SYS_PERIPH_CLOCK_TMR0 =
85 MXC_F_GCR_PCLKDIS0_TMR0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR0 clock */
86 MXC_SYS_PERIPH_CLOCK_TMR1 =
87 MXC_F_GCR_PCLKDIS0_TMR1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR1 clock */
88 MXC_SYS_PERIPH_CLOCK_TMR2 =
89 MXC_F_GCR_PCLKDIS0_TMR2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR2 clock */
90 MXC_SYS_PERIPH_CLOCK_TMR3 =
91 MXC_F_GCR_PCLKDIS0_TMR3_POS, /**< Disable MXC_F_GCR_PCLKDIS0_TMR3 clock */
92 /* PCLKDIS1 Below this line we add 32 to separate PCLKDIS0 and PCLKDIS1 */
93 MXC_SYS_PERIPH_CLOCK_TRNG =
94 (MXC_F_GCR_PCLKDIS1_TRNG_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_TRNG clock */
95 MXC_SYS_PERIPH_CLOCK_WDT0 =
96 (MXC_F_GCR_PCLKDIS1_WDT0_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_WDT0 clock */
97 MXC_SYS_PERIPH_CLOCK_WDT1 =
98 (MXC_F_GCR_PCLKDIS1_WDT1_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_WDT1 clock */
99 MXC_SYS_PERIPH_CLOCK_SFES =
100 (MXC_F_GCR_PCLKDIS1_SFES_POS + 32), /**<Disable MXC_F_GCR_PCLKDIS1_SFES clock */
101 } mxc_sys_periph_clock_t;
102
103 /** @brief Enumeration to select System Clock source */
104 typedef enum {
105 MXC_SYS_CLOCK_IPO =
106 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IPO, /**< Select the Internal Primary Oscillator (IPO) */
107 MXC_SYS_CLOCK_IBRO =
108 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IBRO, /**< Select the Internal Baud Rate Oscillator (IBRO) */
109 MXC_SYS_CLOCK_INRO =
110 MXC_V_GCR_CLKCTRL_SYSCLK_SEL_INRO, /**< Select the Internal Nanoring Oscillator (INRO) */
111 } mxc_sys_system_clock_t;
112
113 typedef enum {
114 MXC_SYS_CLOCK_DIV_1 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV1,
115 MXC_SYS_CLOCK_DIV_2 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV2,
116 MXC_SYS_CLOCK_DIV_4 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV4,
117 MXC_SYS_CLOCK_DIV_8 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV8,
118 MXC_SYS_CLOCK_DIV_16 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV16,
119 MXC_SYS_CLOCK_DIV_32 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV32,
120 MXC_SYS_CLOCK_DIV_64 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV64,
121 MXC_SYS_CLOCK_DIV_128 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV128
122 } mxc_sys_system_clock_div_t;
123
124 #define MXC_SYS_SCACHE_CLK 1 // Enable SCACHE CLK
125 #define MXC_SYS_CTB_CLK 1 // Enable CTB CLK
126
127 /***** Function Prototypes *****/
128
129 typedef struct {
130 int ie_status;
131 int in_critical;
132 } mxc_crit_state_t;
133
134 static mxc_crit_state_t _state = { .ie_status = (int)0xFFFFFFFF, .in_critical = 0 };
135
_mxc_crit_get_state(void)136 static inline void _mxc_crit_get_state(void)
137 {
138 #ifndef __riscv
139 /*
140 On ARM M the 0th bit of the Priority Mask register indicates
141 whether interrupts are enabled or not.
142
143 0 = enabled
144 1 = disabled
145 */
146 uint32_t primask = __get_PRIMASK();
147 _state.ie_status = (primask == 0);
148 #else
149 /*
150 On RISC-V bit position 3 (Machine Interrupt Enable) of the
151 mstatus register indicates whether interrupts are enabled.
152
153 0 = disabled
154 1 = enabled
155 */
156 uint32_t mstatus = get_mstatus();
157 _state.ie_status = ((mstatus & (1 << 3)) != 0);
158 #endif
159 }
160
161 /**
162 * @brief Enter a critical section of code that cannot be interrupted. Call @ref MXC_SYS_Crit_Exit to exit the critical section.
163 * @details Ex:
164 * @code
165 * MXC_SYS_Crit_Enter();
166 * printf("Hello critical section!\n");
167 * MXC_SYS_Crit_Exit();
168 * @endcode
169 * The @ref MXC_CRITICAL macro is also provided as a convencience macro for wrapping a code section in this way.
170 * @returns None
171 */
MXC_SYS_Crit_Enter(void)172 static inline void MXC_SYS_Crit_Enter(void)
173 {
174 _mxc_crit_get_state();
175 if (_state.ie_status)
176 __disable_irq();
177 _state.in_critical = 1;
178 }
179
180 /**
181 * @brief Exit a critical section of code from @ref MXC_SYS_Crit_Enter
182 * @returns None
183 */
MXC_SYS_Crit_Exit(void)184 static inline void MXC_SYS_Crit_Exit(void)
185 {
186 if (_state.ie_status) {
187 __enable_irq();
188 }
189 _state.in_critical = 0;
190 _mxc_crit_get_state();
191 /*
192 ^ Reset the state again to prevent edge case
193 where interrupts get disabled, then Crit_Exit() gets
194 called, which would inadvertently re-enable interrupts
195 from old state.
196 */
197 }
198
199 /**
200 * @brief Polls whether code is currently executing from a critical section.
201 * @returns 1 if code is currently in a critical section (interrupts are disabled).
202 * 0 if code is not in a critical section.
203 */
MXC_SYS_In_Crit_Section(void)204 static inline int MXC_SYS_In_Crit_Section(void)
205 {
206 return _state.in_critical;
207 }
208
209 // clang-format off
210 /**
211 * @brief Macro for wrapping a section of code to make it critical (interrupts disabled). Note: this macro
212 * does not support nesting.
213 * @details
214 * Ex:
215 * \code
216 * MXC_CRITICAL(
217 * printf("Hello critical section!\n");
218 * )
219 * \endcode
220 * This macro places a call to @ref MXC_SYS_Crit_Enter before the code, and a call to @ref MXC_SYS_Crit_Exit after.
221 * @param code The code section to wrap.
222 */
223 #define MXC_CRITICAL(code) {\
224 MXC_SYS_Crit_Enter();\
225 code;\
226 MXC_SYS_Crit_Exit();\
227 }
228 // clang-format on
229
230 /**
231 * @brief Determines if the selected peripheral clock is enabled.
232 * @param clock Enumeration for desired clock.
233 * @returns 0 is the clock is disabled, non 0 if the clock is enabled.
234 */
235 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock);
236
237 /**
238 * @brief Disables the selected peripheral clock.
239 * @param clock Enumeration for desired clock.
240 */
241 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock);
242
243 /**
244 * @brief Enables the selected peripheral clock.
245 * @param clock Enumeration for desired clock.
246 */
247 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock);
248
249 /**
250 * @brief Enables the 32kHz oscillator
251 * @param mxc_sys_cfg Not used, may be NULL.
252 */
253 void MXC_SYS_RTCClockEnable(void);
254
255 /**
256 * @brief Disables the 32kHz oscillator
257 * @returns E_NO_ERROR if everything is successful
258 */
259 int MXC_SYS_RTCClockDisable(void);
260
261 /**
262 * @brief Enable System Clock Source without switching to it
263 * @param clock The clock to enable
264 * @return E_NO_ERROR if everything is successful
265 */
266 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock);
267
268 /**
269 * @brief Disable System Clock Source
270 * @param clock The clock to disable
271 * @return E_NO_ERROR if everything is successful
272 */
273 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock);
274
275 /**
276 * @brief Select the system clock.
277 * @param clock Enumeration for desired clock.
278 * @returns E_NO_ERROR if everything is successful.
279 */
280 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock);
281
282 /**
283 * @brief Wait for a clock to enable with timeout
284 * @param ready The clock to wait for
285 * @return E_NO_ERROR if ready, E_TIME_OUT if timeout
286 */
287 int MXC_SYS_Clock_Timeout(uint32_t ready);
288
289 /**
290 * @brief Set the system clock divider.
291 * @param div Enumeration for desired clock divider.
292 */
293 void MXC_SYS_SetClockDiv(mxc_sys_system_clock_div_t div);
294
295 /**
296 * @brief Get the system clock divider.
297 * @returns System clock divider.
298 */
299 mxc_sys_system_clock_div_t MXC_SYS_GetClockDiv(void);
300
301 /**
302 * @brief Reset the peripherals and/or CPU in the rstr0 or rstr1 register.
303 * @param Enumeration for what to reset. Can reset multiple items at once.
304 */
305 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset);
306
307 /**
308 * @brief Get the revision of the chip
309 * @returns the chip revision
310 */
311 uint8_t MXC_SYS_GetRev(void);
312
313 /**
314 * @brief Get the USN of the chip
315 * @param serialNumber buffer to store the USN
316 * @param len length of the USN buffer
317 * @returns #E_NO_ERROR if everything is successful.
318 */
319 int MXC_SYS_GetUSN(uint8_t *serialNumber, int len);
320
321 /**
322 * @brief This function PERMANENTLY locks the Debug Access Port.
323 *
324 * @warning After executing this function you will never be able
325 * to reprogram the target micro.
326 */
327 int MXC_SYS_LockDAP_Permanent(void);
328
329 #ifdef __cplusplus
330 }
331 #endif
332
333 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32520_MXC_SYS_H_
334