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