1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************************/
20 
21 /**
22  * @file mxc_sys.c
23  * @brief      System layer driver.
24  * @details    This driver is used to control the system layer of the device.
25  */
26 
27 /* **** Includes **** */
28 #include <stddef.h>
29 #include "mxc_device.h"
30 #include "mxc_assert.h"
31 #include "mxc_sys.h"
32 #include "mxc_delay.h"
33 #include "gcr_regs.h"
34 #include "fcr_regs.h"
35 #include "mcr_regs.h"
36 
37 /**
38  * @ingroup mxc_sys
39  * @{
40  */
41 
42 /* **** Definitions **** */
43 #define MXC_SYS_CLOCK_TIMEOUT MSEC(160)
44 
45 /* **** Globals **** */
46 
47 /* **** Functions **** */
48 
49 /* ************************************************************************** */
MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock)50 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock)
51 {
52     /* The mxc_sys_periph_clock_t enum uses enum values that are the offset by 32 for the pclkdis1 register. */
53     if (clock > 31) {
54         clock -= 32;
55         return !(MXC_GCR->pclkdis1 & (0x1 << clock));
56     } else {
57         return !(MXC_GCR->pclkdis0 & (0x1 << clock));
58     }
59 }
60 
61 /* ************************************************************************** */
MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock)62 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock)
63 {
64     /* The mxc_sys_periph_clock_t enum uses enum values that are the offset by 32 for the pclkdis1 register. */
65     if (clock > 31) {
66         clock -= 32;
67         MXC_GCR->pclkdis1 |= (0x1 << clock);
68     } else {
69         MXC_GCR->pclkdis0 |= (0x1 << clock);
70     }
71 }
72 
73 /* ************************************************************************** */
MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock)74 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock)
75 {
76     /* The mxc_sys_periph_clock_t enum uses enum values that are the offset by 32 for the pclkdis1 register. */
77     if (clock > 31) {
78         clock -= 32;
79         MXC_GCR->pclkdis1 &= ~(0x1 << clock);
80     } else {
81         MXC_GCR->pclkdis0 &= ~(0x1 << clock);
82     }
83 }
84 /* ************************************************************************** */
MXC_SYS_RTCClockEnable()85 void MXC_SYS_RTCClockEnable()
86 {
87     MXC_MCR->clkctrl &= ~MXC_F_MCR_CLKCTRL_ERTCO_PD;
88     MXC_MCR->clkctrl |= MXC_F_MCR_CLKCTRL_ERTCO_EN;
89 }
90 
91 /* ************************************************************************** */
MXC_SYS_RTCClockDisable(void)92 int MXC_SYS_RTCClockDisable(void)
93 {
94     /* Check that the RTC is not the system clock source */
95     if ((MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL) != MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERTCO) {
96         MXC_MCR->clkctrl &= ~MXC_F_MCR_CLKCTRL_ERTCO_EN;
97         return E_NO_ERROR;
98     } else {
99         return E_BAD_STATE;
100     }
101 }
102 
103 /******************************************************************************/
MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock)104 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock)
105 {
106     switch (clock) {
107     case MXC_SYS_CLOCK_IPO:
108         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IPO_EN;
109         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IPO_RDY);
110         break;
111 
112     case MXC_SYS_CLOCK_IBRO:
113         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IBRO_EN;
114         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IBRO_RDY);
115         break;
116 
117     case MXC_SYS_CLOCK_ISO:
118         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ISO_EN;
119         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ISO_RDY);
120         break;
121 
122     case MXC_SYS_CLOCK_INRO:
123         // The nano ring clock is always enabled
124         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_INRO_RDY);
125         break;
126 
127     case MXC_SYS_CLOCK_ERFO:
128         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERFO_EN;
129         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERFO_RDY);
130         break;
131 
132     case MXC_SYS_CLOCK_ERTCO:
133         MXC_MCR->clkctrl &= ~MXC_F_MCR_CLKCTRL_ERTCO_PD;
134         MXC_MCR->clkctrl |= MXC_F_MCR_CLKCTRL_ERTCO_EN;
135         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERTCO_RDY);
136         break;
137 
138     default:
139         return E_BAD_PARAM;
140         break;
141     }
142 }
143 
144 /******************************************************************************/
MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock)145 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock)
146 {
147     uint32_t current_clock;
148 
149     current_clock = MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL;
150 
151     // Don't turn off the clock we're running on
152     if (clock == current_clock) {
153         return E_BAD_PARAM;
154     }
155 
156     switch (clock) {
157     case MXC_SYS_CLOCK_IPO:
158         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_IPO_EN;
159         break;
160 
161     case MXC_SYS_CLOCK_IBRO:
162         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_IBRO_EN;
163         break;
164 
165     case MXC_SYS_CLOCK_ISO:
166         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_ISO_EN;
167         break;
168 
169     case MXC_SYS_CLOCK_INRO:
170         // The 8k clock is always enabled
171         break;
172 
173     case MXC_SYS_CLOCK_ERFO:
174         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_ERFO_EN;
175         break;
176 
177     case MXC_SYS_CLOCK_ERTCO:
178         MXC_MCR->clkctrl &= ~MXC_F_MCR_CLKCTRL_ERTCO_EN;
179         break;
180 
181     default:
182         return E_BAD_PARAM;
183     }
184 
185     return E_NO_ERROR;
186 }
187 
188 /* ************************************************************************** */
MXC_SYS_Clock_Timeout(uint32_t ready)189 int MXC_SYS_Clock_Timeout(uint32_t ready)
190 {
191     // Start timeout, wait for ready
192     MXC_DelayAsync(MXC_SYS_CLOCK_TIMEOUT, NULL);
193 
194     do {
195         if (MXC_GCR->clkctrl & ready) {
196             MXC_DelayAbort();
197             return E_NO_ERROR;
198         }
199     } while (MXC_DelayCheck() == E_BUSY);
200 
201     return E_TIME_OUT;
202 }
203 
204 /* ************************************************************************** */
MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock)205 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock)
206 {
207     uint32_t current_clock;
208 
209     // Save the current system clock
210     current_clock = MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL;
211 
212     switch (clock) {
213     case MXC_SYS_CLOCK_IPO:
214 
215         // Enable IPO clock
216         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_IPO_EN)) {
217             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IPO_EN;
218 
219             // Check if IPO clock is ready
220             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IPO_RDY) != E_NO_ERROR) {
221                 return E_TIME_OUT;
222             }
223         }
224 
225         // Set IPO clock as System Clock
226         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
227                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IPO);
228 
229         break;
230 
231     case MXC_SYS_CLOCK_IBRO:
232 
233         // Enable IBRO clock
234         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_IBRO_EN)) {
235             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IBRO_EN;
236 
237             // Check if IBRO clock is ready
238             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IBRO_RDY) != E_NO_ERROR) {
239                 return E_TIME_OUT;
240             }
241         }
242 
243         // Set IBRO clock as System Clock
244         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
245                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IBRO);
246 
247         break;
248 
249     case MXC_SYS_CLOCK_ISO:
250 
251         // Enable ISO clock
252         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_ISO_EN)) {
253             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ISO_EN;
254 
255             // Check if ISO clock is ready
256             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ISO_RDY) != E_NO_ERROR) {
257                 return E_TIME_OUT;
258             }
259         }
260 
261         // Set ISO clock as System Clock
262         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
263                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ISO);
264 
265         break;
266 
267     case MXC_SYS_CLOCK_ERFO:
268 
269         // Enable XRFO clock
270         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_ERFO_EN)) {
271             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERFO_EN;
272 
273             // Check if XRFO clock is ready
274             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERFO_RDY) != E_NO_ERROR) {
275                 return E_TIME_OUT;
276             }
277         }
278 
279         // Set XFRO clock as System Clock
280         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
281                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERFO);
282 
283         break;
284 
285     case MXC_SYS_CLOCK_INRO:
286         // Set INRO clock as System Clock
287         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
288                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_INRO);
289 
290         break;
291 
292     case MXC_SYS_CLOCK_ERTCO:
293 
294         // Enable XRTCO clock
295         if (!(MXC_MCR->clkctrl & MXC_F_MCR_CLKCTRL_ERTCO_EN)) {
296             MXC_MCR->clkctrl &= ~MXC_F_MCR_CLKCTRL_ERTCO_PD;
297             MXC_MCR->clkctrl |= MXC_F_MCR_CLKCTRL_ERTCO_EN;
298 
299             // Check if XRTCO clock is ready
300             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERTCO_RDY) != E_NO_ERROR) {
301                 return E_TIME_OUT;
302             }
303         }
304 
305         // Set XRTCO clock as System Clock
306         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
307                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERTCO);
308 
309         break;
310 
311     default:
312         return E_BAD_PARAM;
313     }
314 
315     // Wait for system clock to be ready
316     if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_SYSCLK_RDY) != E_NO_ERROR) {
317         // Restore the old system clock if timeout
318         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL, current_clock);
319 
320         return E_TIME_OUT;
321     }
322 
323     // Update the system core clock
324     SystemCoreClockUpdate();
325 
326     return E_NO_ERROR;
327 }
328 
329 /* ************************************************************************** */
MXC_SYS_Reset_Periph(mxc_sys_reset_t reset)330 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset)
331 {
332     /* The mxc_sys_reset_t enum uses enum values that are the offset by 32 for the rst1 register. */
333     if (reset > 31) {
334         reset -= 32;
335         MXC_GCR->rst1 = (0x1 << reset);
336     } else {
337         MXC_GCR->rst0 = (0x1 << reset);
338     }
339 }
340 
341 /* ************************************************************************** */
MXC_SYS_GetUSN(uint8_t * usn,uint8_t * checksum)342 int MXC_SYS_GetUSN(uint8_t *usn, uint8_t *checksum)
343 {
344     //FIXME: No flash for ME55
345     return E_NOT_SUPPORTED;
346 
347     // if (usn == NULL) {
348     //     return E_NOT_SUPPORTED;
349     // }
350 
351     // uint32_t *infoblock = (uint32_t *)MXC_INFO0_MEM_BASE;
352 
353     // /* Read the USN from the info block */
354     // MXC_FLC_UnlockInfoBlock(MXC_INFO0_MEM_BASE);
355 
356     // memset(usn, 0, MXC_SYS_CHECKSUM_LEN);
357 
358     // usn[0] = (infoblock[0] & 0x007F8000) >> 15;
359     // usn[1] = (infoblock[0] & 0x7F800000) >> 23;
360     // usn[2] = (infoblock[1] & 0x0000007F) << 1;
361     // usn[2] |= (infoblock[0] & 0x80000000) >> 31;
362     // usn[3] = (infoblock[1] & 0x00007F80) >> 7;
363     // usn[4] = (infoblock[1] & 0x007F8000) >> 15;
364     // usn[5] = (infoblock[1] & 0x7F800000) >> 23;
365     // usn[6] = (infoblock[2] & 0x007F8000) >> 15;
366     // usn[7] = (infoblock[2] & 0x7F800000) >> 23;
367     // usn[8] = (infoblock[3] & 0x0000007F) << 1;
368     // usn[8] |= (infoblock[2] & 0x80000000) >> 31;
369     // usn[9] = (infoblock[3] & 0x00007F80) >> 7;
370     // usn[10] = (infoblock[3] & 0x007F8000) >> 15;
371 
372     // // Compute the checksum
373     // if (checksum != NULL) {
374     //     uint32_t key[4];
375     //     uint32_t pt32[4];
376     //     uint32_t check_csum32[4];
377     //     uint8_t check_csum[MXC_SYS_CHECKSUM_LEN];
378 
379     //     /* Initialize key and plaintext */
380     //     memset(key, 0, MXC_SYS_CHECKSUM_LEN);
381     //     memset(pt32, 0, MXC_SYS_CHECKSUM_LEN);
382     //     memcpy(pt32, usn, MXC_SYS_CHECKSUM_LEN);
383 
384     //     /* Read the checksum from the info block */
385     //     checksum[0] = ((infoblock[3] & 0x7F800000) >> 23);
386     //     checksum[1] = ((infoblock[4] & 0x007F8000) >> 15);
387 
388     //     MXC_CTB_Init(MXC_CTB_FEATURE_CIPHER);
389 
390     //     /* Reset the CTB */
391     //     MXC_CTB->ctrl = MXC_F_CTB_CTRL_RST;
392 
393     //     /* Set the legacy bit */
394     //     MXC_CTB->ctrl |= MXC_F_CTB_CTRL_FLAG_MODE;
395 
396     //     /* Clear interrupt flags */
397     //     MXC_CTB->ctrl |= MXC_F_CTB_CTRL_CPH_DONE;
398 
399     //     /* Setup the key source */
400     //     MXC_CTB->cipher_ctrl = MXC_S_CTB_CIPHER_CTRL_SRC_CIPHERKEY;
401 
402     //     /* Setup the CT calculation */
403     //     MXC_CTB->cipher_ctrl |= MXC_S_CTB_CIPHER_CTRL_CIPHER_AES128;
404 
405     //     /* Load the key */
406     //     MXC_CTB->cipher_key[0] = key[0];
407     //     MXC_CTB->cipher_key[1] = key[1];
408     //     MXC_CTB->cipher_key[2] = key[2];
409     //     MXC_CTB->cipher_key[3] = key[3];
410 
411     //     /* Wait for the ready flag */
412     //     while (!(MXC_CTB->ctrl & MXC_F_CTB_CTRL_RDY)) {}
413 
414     //     /* Copy data to start the operation */
415     //     MXC_CTB->din[0] = pt32[0];
416     //     MXC_CTB->din[1] = pt32[1];
417     //     MXC_CTB->din[2] = pt32[2];
418     //     MXC_CTB->din[3] = pt32[3];
419 
420     //     /* Wait for and clear the done flag */
421     //     while (!(MXC_CTB->ctrl & MXC_F_CTB_CTRL_CPH_DONE)) {}
422     //     MXC_CTB->ctrl |= MXC_F_CTB_CTRL_CPH_DONE;
423 
424     //     /* Copy out the cipher text */
425     //     check_csum32[0] = MXC_CTB->dout[0];
426     //     check_csum32[1] = MXC_CTB->dout[1];
427     //     check_csum32[2] = MXC_CTB->dout[2];
428     //     check_csum32[3] = MXC_CTB->dout[3];
429 
430     //     memcpy(check_csum, check_csum32, MXC_SYS_CHECKSUM_LEN);
431 
432     //     /* Verify the checksum */
433     //     if ((checksum[1] != check_csum[0]) || (checksum[0] != check_csum[1])) {
434     //         MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE);
435     //         return E_UNKNOWN;
436     //     }
437     // }
438 
439     // /* Add the info block checksum to the USN */
440     // usn[11] = ((infoblock[3] & 0x7F800000) >> 23);
441     // usn[12] = ((infoblock[4] & 0x007F8000) >> 15);
442 
443     // MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE);
444 
445     // return E_NO_ERROR;
446 }
447 
448 /* ************************************************************************** */
MXC_SYS_GetRev(void)449 uint8_t MXC_SYS_GetRev(void)
450 {
451     //FIXME: Same as above^^^
452     return E_NOT_SUPPORTED;
453 
454     // uint8_t serialNumber[13];
455     // MXC_SYS_GetUSN(serialNumber, 13); <<<<<<<<
456 
457     // if ((serialNumber[0] < 0x9F) | ((serialNumber[0] & 0x0F) > 0x09)) {
458     //     // Fail back to the hardware register
459     //     return MXC_GCR->revision & 0xFF;
460     // }
461 
462     // return serialNumber[0];
463 }
464 
465 /* ************************************************************************** */
MXC_SYS_RiscVClockRate(void)466 uint32_t MXC_SYS_RiscVClockRate(void)
467 {
468     // // If in LPM mode and the PCLK is selected as the RV32 clock source,
469     // if(((MXC_GCR->pm & MXC_F_GCR_PM_MODE) == MXC_S_GCR_PM_MODE_LPM) &&
470     //    (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_LPMCLKSEL)) {
471     //     return ISO_FREQ;
472     // } else {
473     // return PeripheralClock;
474     return SystemCoreClock;
475     // }
476 }
477 
478 /**@} end of mxc_sys */
479