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_MAX32675_MXC_SYS_H_
27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32675_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_WDT0 = 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 TIMER0 */
51     MXC_SYS_RESET0_TMR1 = MXC_F_GCR_RST0_TMR1_POS, /**< Reset TIMER1 */
52     MXC_SYS_RESET0_TMR2 = MXC_F_GCR_RST0_TMR2_POS, /**< Reset TIMER2 */
53     MXC_SYS_RESET0_TMR3 = MXC_F_GCR_RST0_TMR3_POS, /**< Reset TIMER3 */
54     MXC_SYS_RESET0_UART0 = MXC_F_GCR_RST0_UART0_POS, /**< Reset UART0 */
55     MXC_SYS_RESET0_UART1 = MXC_F_GCR_RST0_UART1_POS, /**< Reset UART1 */
56     MXC_SYS_RESET0_SPI0 = MXC_F_GCR_RST0_SPI0_POS, /**< Reset SPI0 */
57     MXC_SYS_RESET0_SPI1 = MXC_F_GCR_RST0_SPI1_POS, /**< Reset SPI1 */
58     MXC_SYS_RESET0_SPI2 = MXC_F_GCR_RST0_SPI2_POS, /**< Reset SPI2 */
59     MXC_SYS_RESET0_I2C0 = MXC_F_GCR_RST0_I2C0_POS, /**< Reset I2C0 */
60     MXC_SYS_RESET0_RTC = MXC_F_GCR_RST0_RTC_POS, /**< Reset RTC */
61     MXC_SYS_RESET0_TRNG = MXC_F_GCR_RST0_TRNG_POS, /**< Reset TRNG */
62     MXC_SYS_RESET0_UART2 = MXC_F_GCR_RST0_UART2_POS, /**< Reset UART2 */
63     MXC_SYS_RESET0_SRST = MXC_F_GCR_RST0_SOFT_POS, /**< Soft reset */
64     MXC_SYS_RESET0_PRST = MXC_F_GCR_RST0_PERIPH_POS, /**< Peripheral reset */
65     MXC_SYS_RESET0_SYS = MXC_F_GCR_RST0_SYS_POS, /**< System reset */
66     /* RESET1 Below this line we add 32 to separate RESET0 and RESET1 */
67     MXC_SYS_RESET1_I2C1 = (MXC_F_GCR_RST1_I2C1_POS + 32), /**< Reset I2C1 */
68     MXC_SYS_RESET1_WDT1 = (MXC_F_GCR_RST1_WDT1_POS + 32), /**< Reset WDT1 */
69     MXC_SYS_RESET1_AES = (MXC_F_GCR_RST1_AES_POS + 32), /**< Reset WDT1 */
70     MXC_SYS_RESET1_CRC = (MXC_F_GCR_RST1_CRC_POS + 32), /**< Reset WDT1 */
71     MXC_SYS_RESET1_I2C2 = (MXC_F_GCR_RST1_I2C2_POS + 32), /**< Reset */
72     MXC_SYS_RESET1_I2S = (MXC_F_GCR_RST1_I2S_POS + 32), /**< Reset */
73     /* LPGCR RESET Below this line we add 64 to separate LPGCR and GCR */
74     MXC_SYS_RESET_TMR4 = (MXC_F_MCR_RST_LPTMR0 + 64), /**< Reset TMR4 */
75     MXC_SYS_RESET_TMR5 = (MXC_F_MCR_RST_LPTMR1 + 64), /**< Reset TMR5 */
76     MXC_SYS_RESET_UART3 = (MXC_F_MCR_RST_LPUART0 + 64), /**< Reset UART3 */
77 } mxc_sys_reset_t;
78 
79 /** @brief System clock disable enumeration. Used in MXC_SYS_ClockDisable and MXC_SYS_ClockEnable functions */
80 typedef enum {
81     MXC_SYS_PERIPH_CLOCK_GPIO0 =
82         MXC_F_GCR_PCLKDIS0_GPIO0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO0 clock */
83     MXC_SYS_PERIPH_CLOCK_GPIO1 =
84         MXC_F_GCR_PCLKDIS0_GPIO1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_GPIO1 clock */
85     MXC_SYS_PERIPH_CLOCK_DMA =
86         MXC_F_GCR_PCLKDIS0_DMA_POS, /**< Disable MXC_F_GCR_PCLKDIS0_DMA clock */
87     MXC_SYS_PERIPH_CLOCK_SPI0 =
88         MXC_F_GCR_PCLKDIS0_SPI0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI0 clock */
89     MXC_SYS_PERIPH_CLOCK_SPI1 =
90         MXC_F_GCR_PCLKDIS0_SPI1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI1 clock */
91     MXC_SYS_PERIPH_CLOCK_SPI2 =
92         MXC_F_GCR_PCLKDIS0_SPI2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_SPI2 clock */
93     MXC_SYS_PERIPH_CLOCK_UART0 =
94         MXC_F_GCR_PCLKDIS0_UART0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART0 clock */
95     MXC_SYS_PERIPH_CLOCK_UART1 =
96         MXC_F_GCR_PCLKDIS0_UART1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_UART1 clock */
97     MXC_SYS_PERIPH_CLOCK_I2C0 =
98         MXC_F_GCR_PCLKDIS0_I2C0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C0 clock */
99     MXC_SYS_PERIPH_CLOCK_TMR0 =
100         MXC_F_GCR_PCLKDIS0_TMR0_POS, /**< Disable MXC_F_GCR_PCLKDIS0_T0 clock */
101     MXC_SYS_PERIPH_CLOCK_TMR1 =
102         MXC_F_GCR_PCLKDIS0_TMR1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_T1 clock */
103     MXC_SYS_PERIPH_CLOCK_TMR2 =
104         MXC_F_GCR_PCLKDIS0_TMR2_POS, /**< Disable MXC_F_GCR_PCLKDIS0_T2 clock */
105     MXC_SYS_PERIPH_CLOCK_TMR3 =
106         MXC_F_GCR_PCLKDIS0_TMR3_POS, /**< Disable MXC_F_GCR_PCLKDIS0_T3 clock */
107     MXC_SYS_PERIPH_CLOCK_I2C1 =
108         MXC_F_GCR_PCLKDIS0_I2C1_POS, /**< Disable MXC_F_GCR_PCLKDIS0_I2C1 clock */
109     /* PCLKDIS1 Below this line we add 32 to separate PCLKDIS0 and PCLKDIS1 */
110     MXC_SYS_PERIPH_CLOCK_UART2 =
111         (MXC_F_GCR_PCLKDIS1_UART2_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_UART2 clock */
112     MXC_SYS_PERIPH_CLOCK_TRNG =
113         (MXC_F_GCR_PCLKDIS1_TRNG_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_TRNG clock */
114     MXC_SYS_PERIPH_CLOCK_WDT0 =
115         (MXC_F_GCR_PCLKDIS1_WWDT0_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_WDT0 clock */
116     MXC_SYS_PERIPH_CLOCK_WDT1 =
117         (MXC_F_GCR_PCLKDIS1_WWDT1_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_WDT1 clock */
118     MXC_SYS_PERIPH_CLOCK_ICACHE =
119         (MXC_F_GCR_PCLKDIS1_ICC0_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_ICACHE clock */
120     MXC_SYS_PERIPH_CLOCK_CRC =
121         (MXC_F_GCR_PCLKDIS1_CRC_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_CRC clock */
122     MXC_SYS_PERIPH_CLOCK_AES =
123         (MXC_F_GCR_PCLKDIS1_AES_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_AES clock */
124     MXC_SYS_PERIPH_CLOCK_I2C2 =
125         (MXC_F_GCR_PCLKDIS1_I2C2_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_I2C2 clock */
126     MXC_SYS_PERIPH_CLOCK_I2S =
127         (MXC_F_GCR_PCLKDIS1_I2S_POS + 32), /**< Disable MXC_F_GCR_PCLKDIS1_I2S clock */
128     /* LPGCR PCLKDIS Below this line we add 64 to seperate GCR and LPGCR registers */
129     MXC_SYS_PERIPH_CLOCK_TMR4 =
130         (MXC_F_MCR_CLKDIS_LPTMR0_POS + 64), /**< Disable MXC_F_LPGCR_PCLKDIS_TMR4 clock */
131     MXC_SYS_PERIPH_CLOCK_UART3 =
132         (MXC_F_MCR_CLKDIS_LPUART0_POS + 64), /**< Disable MXC_F_LPGCR_PCLKDIS_UART3 clock */
133 } mxc_sys_periph_clock_t;
134 
135 /** @brief Enumeration to select System Clock source */
136 typedef enum {
137     MXC_SYS_CLOCK_IPO =
138         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IPO, /**< Select the Internal Primary Oscillator (IPO) */
139     MXC_SYS_CLOCK_IBRO =
140         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_IBRO, /**< Select the Internal Baud Rate Oscillator (IBRO) */
141     MXC_SYS_CLOCK_ERFO =
142         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERFO, /**< Select the External RF Crystal Oscillator */
143     MXC_SYS_CLOCK_INRO =
144         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_INRO, /**< Select the Internal Nanoring Oscillator (INRO) */
145     MXC_SYS_CLOCK_ERTCO =
146         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_ERTCO, /**< Select the External RTC Crystal Oscillator */
147     MXC_SYS_CLOCK_EXTCLK =
148         MXC_V_GCR_CLKCTRL_SYSCLK_SEL_EXTCLK /**< Select the External RTC Crystal Oscillator */
149 } mxc_sys_system_clock_t;
150 
151 typedef enum {
152     MXC_SYS_CLOCK_DIV_1 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV1,
153     MXC_SYS_CLOCK_DIV_2 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV2,
154     MXC_SYS_CLOCK_DIV_4 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV4,
155     MXC_SYS_CLOCK_DIV_8 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV8,
156     MXC_SYS_CLOCK_DIV_16 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV16,
157     MXC_SYS_CLOCK_DIV_32 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV32,
158     MXC_SYS_CLOCK_DIV_64 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV64,
159     MXC_SYS_CLOCK_DIV_128 = MXC_S_GCR_CLKCTRL_SYSCLK_DIV_DIV128
160 } mxc_sys_system_clock_div_t;
161 
162 #define MXC_SYS_USN_CHECKSUM_LEN 16 // Length of the USN + padding for checksum compute
163 #define MXC_SYS_USN_CSUM_FIELD_LEN 2 // Size of the checksum field in the USN
164 #define MXC_SYS_USN_LEN 13 // Size of the USN including the checksum
165 
166 /***** Function Prototypes *****/
167 
168 typedef struct {
169     int ie_status;
170     int in_critical;
171 } mxc_crit_state_t;
172 
173 static mxc_crit_state_t _state = { .ie_status = (int)0xFFFFFFFF, .in_critical = 0 };
174 
_mxc_crit_get_state(void)175 static inline void _mxc_crit_get_state(void)
176 {
177 #ifndef __riscv
178     /*
179         On ARM M the 0th bit of the Priority Mask register indicates
180         whether interrupts are enabled or not.
181 
182         0 = enabled
183         1 = disabled
184     */
185     uint32_t primask = __get_PRIMASK();
186     _state.ie_status = (primask == 0);
187 #else
188     /*
189         On RISC-V bit position 3 (Machine Interrupt Enable) of the
190         mstatus register indicates whether interrupts are enabled.
191 
192         0 = disabled
193         1 = enabled
194     */
195     uint32_t mstatus = get_mstatus();
196     _state.ie_status = ((mstatus & (1 << 3)) != 0);
197 #endif
198 }
199 
200 /**
201  * @brief Enter a critical section of code that cannot be interrupted.  Call @ref MXC_SYS_Crit_Exit to exit the critical section.
202  * @details Ex:
203  * @code
204  * MXC_SYS_Crit_Enter();
205  * printf("Hello critical section!\n");
206  * MXC_SYS_Crit_Exit();
207  * @endcode
208  * The @ref MXC_CRITICAL macro is also provided as a convencience macro for wrapping a code section in this way.
209  * @returns None
210  */
MXC_SYS_Crit_Enter(void)211 static inline void MXC_SYS_Crit_Enter(void)
212 {
213     _mxc_crit_get_state();
214     if (_state.ie_status)
215         __disable_irq();
216     _state.in_critical = 1;
217 }
218 
219 /**
220  * @brief Exit a critical section of code from @ref MXC_SYS_Crit_Enter
221  * @returns None
222  */
MXC_SYS_Crit_Exit(void)223 static inline void MXC_SYS_Crit_Exit(void)
224 {
225     if (_state.ie_status) {
226         __enable_irq();
227     }
228     _state.in_critical = 0;
229     _mxc_crit_get_state();
230     /*
231         ^ Reset the state again to prevent edge case
232         where interrupts get disabled, then Crit_Exit() gets
233         called, which would inadvertently re-enable interrupts
234         from old state.
235     */
236 }
237 
238 /**
239  * @brief Polls whether code is currently executing from a critical section.
240  * @returns 1 if code is currently in a critical section (interrupts are disabled).
241  *          0 if code is not in a critical section.
242  */
MXC_SYS_In_Crit_Section(void)243 static inline int MXC_SYS_In_Crit_Section(void)
244 {
245     return _state.in_critical;
246 }
247 
248 // clang-format off
249 /**
250  * @brief Macro for wrapping a section of code to make it critical (interrupts disabled).  Note: this macro
251  * does not support nesting.
252  * @details
253  * Ex:
254  * \code
255  * MXC_CRITICAL(
256  *      printf("Hello critical section!\n");
257  * )
258  * \endcode
259  * This macro places a call to @ref MXC_SYS_Crit_Enter before the code, and a call to @ref MXC_SYS_Crit_Exit after.
260  * @param code The code section to wrap.
261  */
262 #define MXC_CRITICAL(code) {\
263     MXC_SYS_Crit_Enter();\
264     code;\
265     MXC_SYS_Crit_Exit();\
266 }
267 // clang-format on
268 
269 /**
270  * @brief Reads the device USN and verifies the checksum.
271  * @param usn       Pointer to store the USN. Array must be at least MXC_SYS_USN_LEN bytes long.
272  * @param checksum  Optional pointer to store the AES checksum. If not NULL, checksum is verified with AES engine.
273  * @returns         E_NO_ERROR if everything is successful.
274  */
275 int MXC_SYS_GetUSN(uint8_t *usn, uint8_t *checksum);
276 
277 /**
278  * @brief Determines if the selected peripheral clock is enabled.
279  * @param clock   Enumeration for desired clock.
280  * @returns       0 is the clock is disabled, non 0 if the clock is enabled.
281  */
282 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock);
283 
284 /**
285  * @brief Disables the selected peripheral clock.
286  * @param clock   Enumeration for desired clock.
287  */
288 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock);
289 
290 /**
291  * @brief Enables the selected peripheral clock.
292  * @param clock   Enumeration for desired clock.
293  */
294 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock);
295 
296 /**
297  * @brief Enables the 32kHz oscillator
298  * @param mxc_sys_cfg   Not used, may be NULL.
299  */
300 void MXC_SYS_RTCClockEnable(void);
301 
302 /**
303  * @brief Disables the 32kHz oscillator
304  * @returns         E_NO_ERROR if everything is successful
305  */
306 int MXC_SYS_RTCClockDisable(void);
307 
308 /**
309  * @brief Enable System Clock Source without switching to it
310  * @param      clock The clock to enable
311  * @return     E_NO_ERROR if everything is successful
312  */
313 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock);
314 
315 /**
316  * @brief Disable System Clock Source
317  * @param      clock The clock to disable
318  * @return     E_NO_ERROR if everything is successful
319  */
320 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock);
321 
322 /**
323  * @brief Select the system clock.
324  * @param clock     Enumeration for desired clock.  Note:  If using the external clock input be sure to define EXTCLK_FREQ correctly.
325  *                  The default EXTCLK_FREQ value is defined in the system_max32675.h file and can be overridden at compile time.
326  * @returns         E_NO_ERROR if everything is successful.
327  */
328 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock);
329 
330 /**
331  * @brief Set the system clock divider.
332  * @param div       Enumeration for desired clock divider.
333  */
334 void MXC_SYS_SetClockDiv(mxc_sys_system_clock_div_t div);
335 
336 /**
337  * @brief Get the system clock divider.
338  * @returns         System clock divider.
339  */
340 mxc_sys_system_clock_div_t MXC_SYS_GetClockDiv(void);
341 
342 /**
343  * @brief Wait for a clock to enable with timeout
344  * @param      ready The clock to wait for
345  * @return     E_NO_ERROR if ready, E_TIME_OUT if timeout
346  */
347 int MXC_SYS_Clock_Timeout(uint32_t ready);
348 
349 /**
350  * @brief Reset the peripherals and/or CPU in the rstr0 or rstr1 register.
351  * @param           Enumeration for what to reset. Can reset multiple items at once.
352  */
353 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset);
354 
355 /**
356  * @brief This function PERMANENTLY locks the Debug Access Port.
357  *
358  * @warning After executing this function you will never be able
359  *          to reprogram the target micro.
360  */
361 int MXC_SYS_LockDAP_Permanent(void);
362 
363 #ifdef __cplusplus
364 }
365 #endif
366 
367 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32675_MXC_SYS_H_
368