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