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 <string.h>
30 #include "mxc_device.h"
31 #include "mxc_assert.h"
32 #include "mxc_sys.h"
33 #include "mxc_delay.h"
34 #include "lpgcr_regs.h"
35 #include "gcr_regs.h"
36 #include "fcr_regs.h"
37 #include "mcr_regs.h"
38 #include "pwrseq_regs.h"
39 #include "aes.h"
40 #include "flc.h"
41 
42 /**
43  * @ingroup mxc_sys
44  * @{
45  */
46 
47 /* **** Definitions **** */
48 #define MXC_SYS_CLOCK_TIMEOUT MSEC(1)
49 
50 // DAP Lock macros
51 #define INFOBLOCK_DAP_LOCK_OFFSET 0x30
52 #define DAP_LOCK_SEQUENCE_01 0x5A5AA5A5
53 #define DAP_LOCK_SEQUENCE_23 0xFFFFFFFF
54 
55 /* **** Globals **** */
56 
57 /* Symbol defined when loading RISCV image */
58 extern uint32_t _binary_riscv_bin_start;
59 
60 /* **** Functions **** */
61 
62 /* ************************************************************************** */
MXC_SYS_GetUSN(uint8_t * usn,uint8_t * checksum)63 int MXC_SYS_GetUSN(uint8_t *usn, uint8_t *checksum)
64 {
65     int err = E_NO_ERROR;
66     uint32_t *infoblock = (uint32_t *)MXC_INFO0_MEM_BASE;
67 
68     if (usn == NULL) {
69         return E_NULL_PTR;
70     }
71 
72     /* Read the USN from the info block */
73     MXC_FLC_UnlockInfoBlock(MXC_INFO0_MEM_BASE);
74 
75     memset(usn, 0, MXC_SYS_USN_CHECKSUM_LEN);
76 
77     usn[0] = (infoblock[0] & 0x007F8000) >> 15;
78     usn[1] = (infoblock[0] & 0x7F800000) >> 23;
79     usn[2] = (infoblock[1] & 0x0000007F) << 1;
80     usn[2] |= (infoblock[0] & 0x80000000) >> 31;
81     usn[3] = (infoblock[1] & 0x00007F80) >> 7;
82     usn[4] = (infoblock[1] & 0x007F8000) >> 15;
83     usn[5] = (infoblock[1] & 0x7F800000) >> 23;
84     usn[6] = (infoblock[2] & 0x007F8000) >> 15;
85     usn[7] = (infoblock[2] & 0x7F800000) >> 23;
86     usn[8] = (infoblock[3] & 0x0000007F) << 1;
87     usn[8] |= (infoblock[2] & 0x80000000) >> 31;
88     usn[9] = (infoblock[3] & 0x00007F80) >> 7;
89     usn[10] = (infoblock[3] & 0x007F8000) >> 15;
90 
91     /* If requested, verify and return the checksum */
92     if (checksum != NULL) {
93         uint8_t check_csum[MXC_SYS_USN_CHECKSUM_LEN];
94         uint8_t aes_key[MXC_SYS_USN_CHECKSUM_LEN] = { 0 }; // NULL Key (per checksum spec)
95 
96         checksum[0] = ((infoblock[3] & 0x7F800000) >> 23);
97         checksum[1] = ((infoblock[4] & 0x007F8000) >> 15);
98 
99         err = MXC_AES_Init();
100         if (err) {
101             MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE);
102             return err;
103         }
104 
105         // Set NULL Key
106         MXC_AES_SetExtKey((const void *)aes_key, MXC_AES_128BITS);
107 
108         // Compute Checksum
109         mxc_aes_req_t aes_req;
110         aes_req.length = MXC_SYS_USN_CHECKSUM_LEN / 4;
111         aes_req.inputData = (uint32_t *)usn;
112         aes_req.resultData = (uint32_t *)check_csum;
113         aes_req.keySize = MXC_AES_128BITS;
114         aes_req.encryption = MXC_AES_ENCRYPT_EXT_KEY;
115         aes_req.callback = NULL;
116 
117         err = MXC_AES_Generic(&aes_req);
118         if (err) {
119             MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE);
120             return err;
121         }
122 
123         MXC_AES_Shutdown();
124 
125         // Verify Checksum
126         if (check_csum[0] != checksum[1] || check_csum[1] != checksum[0]) {
127             MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE);
128             return E_INVALID;
129         }
130     }
131 
132     /* Add the info block checksum to the USN */
133     usn[11] = ((infoblock[3] & 0x7F800000) >> 23);
134     usn[12] = ((infoblock[4] & 0x007F8000) >> 15);
135 
136     MXC_FLC_LockInfoBlock(MXC_INFO0_MEM_BASE);
137 
138     return err;
139 }
140 
141 /* ************************************************************************** */
MXC_SYS_GetRevision(void)142 int MXC_SYS_GetRevision(void)
143 {
144     return MXC_GCR->revision;
145 }
146 
147 /* ************************************************************************** */
MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock)148 int MXC_SYS_IsClockEnabled(mxc_sys_periph_clock_t clock)
149 {
150     /* The mxc_sys_periph_clock_t enum uses enum values that are the offset by 32 and 64 for the perckcn1 register. */
151     if (clock > 63) {
152         clock -= 64;
153         return !(MXC_LPGCR->pclkdis & (0x1 << clock));
154     } else if (clock > 31) {
155         clock -= 32;
156         return !(MXC_GCR->pclkdis1 & (0x1 << clock));
157     } else {
158         return !(MXC_GCR->pclkdis0 & (0x1 << clock));
159     }
160 }
161 
162 /* ************************************************************************** */
MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock)163 void MXC_SYS_ClockDisable(mxc_sys_periph_clock_t clock)
164 {
165     /* The mxc_sys_periph_clock_t enum uses enum values that are the offset by 32 and 64 for the perckcn1 register. */
166     if (clock > 63) {
167         clock -= 64;
168         MXC_LPGCR->pclkdis |= (0x1 << clock);
169     } else if (clock > 31) {
170         clock -= 32;
171         MXC_GCR->pclkdis1 |= (0x1 << clock);
172     } else {
173         MXC_GCR->pclkdis0 |= (0x1 << clock);
174     }
175 }
176 
177 /* ************************************************************************** */
MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock)178 void MXC_SYS_ClockEnable(mxc_sys_periph_clock_t clock)
179 {
180     /* The mxc_sys_periph_clock_t enum uses enum values that are the offset by 32 and 64 for the perckcn1 register. */
181     if (clock > 63) {
182         clock -= 64;
183         MXC_LPGCR->pclkdis &= ~(0x1 << clock);
184     } else if (clock > 31) {
185         clock -= 32;
186         MXC_GCR->pclkdis1 &= ~(0x1 << clock);
187     } else {
188         MXC_GCR->pclkdis0 &= ~(0x1 << clock);
189     }
190 }
191 /* ************************************************************************** */
MXC_SYS_RTCClockEnable()192 void MXC_SYS_RTCClockEnable()
193 {
194     MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERTCO_EN;
195 }
196 
197 /* ************************************************************************** */
MXC_SYS_RTCClockDisable(void)198 int MXC_SYS_RTCClockDisable(void)
199 {
200     /* Check that the RTC is not the system clock source */
201     if ((MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL) != MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERTCO) {
202         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_ERTCO_EN;
203         return E_NO_ERROR;
204     } else {
205         return E_BAD_STATE;
206     }
207 }
208 
209 #if TARGET_NUM == 32655
210 /******************************************************************************/
MXC_SYS_RTCClockPowerDownEn(void)211 void MXC_SYS_RTCClockPowerDownEn(void)
212 {
213     MXC_MCR->ctrl |= MXC_F_MCR_CTRL_32KOSC_EN;
214 }
215 
216 /******************************************************************************/
MXC_SYS_RTCClockPowerDownDis(void)217 void MXC_SYS_RTCClockPowerDownDis(void)
218 {
219     MXC_MCR->ctrl &= ~MXC_F_MCR_CTRL_32KOSC_EN;
220 }
221 #endif //TARGET_NUM == 32655
222 
223 /******************************************************************************/
MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock)224 int MXC_SYS_ClockSourceEnable(mxc_sys_system_clock_t clock)
225 {
226     switch (clock) {
227     case MXC_SYS_CLOCK_IPO:
228         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IPO_EN;
229         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IPO_RDY);
230         break;
231 
232     case MXC_SYS_CLOCK_IBRO:
233         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IBRO_EN;
234         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IBRO_RDY);
235         break;
236 
237     case MXC_SYS_CLOCK_EXTCLK:
238         // No "RDY" bit to monitor, so just configure the GPIO
239         return MXC_GPIO_Config(&gpio_cfg_extclk);
240         break;
241 
242     case MXC_SYS_CLOCK_INRO:
243         // The 80k clock is always enabled
244         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_INRO_RDY);
245         break;
246 
247     case MXC_SYS_CLOCK_ERFO:
248         MXC_GCR->btleldoctrl |= MXC_F_GCR_BTLELDOCTRL_LDOTXEN | MXC_F_GCR_BTLELDOCTRL_LDORXEN;
249 
250         /* Initialize kickstart circuit
251            Select Kick start circuit clock source- IPO/ISO
252         */
253         MXC_FCR->erfoks = ((MXC_S_FCR_ERFOKS_KSCLKSEL_ISO)
254                            /* Set Drive strengh - 0x1,0x2,0x3 */
255                            | ((0x1) << MXC_F_FCR_ERFOKS_KSERFODRIVER_POS)
256                            /* Set kick count 1-127 */
257                            | (0x8)
258                            /* Set double pulse length  On/Off*/
259                            | (0 & MXC_F_FCR_ERFOKS_KSERFO2X)
260                            /* Enable On/Off */
261                            | (MXC_F_FCR_ERFOKS_KSERFO_EN));
262 
263         /* Enable ERFO */
264         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERFO_EN;
265         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERFO_RDY);
266         break;
267 
268     case MXC_SYS_CLOCK_ERTCO:
269         MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERTCO_EN;
270         return MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERTCO_RDY);
271         break;
272 
273     default:
274         return E_BAD_PARAM;
275         break;
276     }
277 }
278 
279 /******************************************************************************/
MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock)280 int MXC_SYS_ClockSourceDisable(mxc_sys_system_clock_t clock)
281 {
282     uint32_t current_clock;
283 
284     current_clock = MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL;
285 
286     // Don't turn off the clock we're running on
287     if (clock == current_clock) {
288         return E_BAD_PARAM;
289     }
290 
291     switch (clock) {
292     case MXC_SYS_CLOCK_IPO:
293         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_IPO_EN;
294         break;
295 
296     case MXC_SYS_CLOCK_IBRO:
297         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_IBRO_EN;
298         break;
299 
300     case MXC_SYS_CLOCK_EXTCLK:
301         /*
302         There's not a great way to disable the external clock.
303         Deinitializing the GPIO here may have unintended consequences
304         for application code.
305         Selecting a different system clock source is sufficient
306         to "disable" the EXT_CLK source.
307         */
308         break;
309 
310     case MXC_SYS_CLOCK_INRO:
311         // The 80k clock is always enabled
312         break;
313 
314     case MXC_SYS_CLOCK_ERFO:
315         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_ERFO_EN;
316         break;
317 
318     case MXC_SYS_CLOCK_ERTCO:
319         MXC_GCR->clkctrl &= ~MXC_F_GCR_CLKCTRL_ERTCO_EN;
320         break;
321 
322     default:
323         return E_BAD_PARAM;
324     }
325 
326     return E_NO_ERROR;
327 }
328 
329 /* ************************************************************************** */
MXC_SYS_Clock_Timeout(uint32_t ready)330 int MXC_SYS_Clock_Timeout(uint32_t ready)
331 {
332 #ifdef __riscv
333     // The current RISC-V implementation is to block until the clock is ready.
334     // We do not have access to a system tick in the RV core.
335     while (!(MXC_GCR->clkctrl & ready)) {}
336     return E_NO_ERROR;
337 #else
338 #ifndef BOARD_ME17_TESTER
339     // Start timeout, wait for ready
340     MXC_DelayAsync(MXC_SYS_CLOCK_TIMEOUT, NULL);
341 
342     do {
343         if (MXC_GCR->clkctrl & ready) {
344             MXC_DelayAbort();
345             return E_NO_ERROR;
346         }
347     } while (MXC_DelayCheck() == E_BUSY);
348 
349     return E_TIME_OUT;
350 #else
351 
352     return E_NO_ERROR;
353 #endif
354 
355 #endif // __riscv
356 }
357 /* ************************************************************************** */
MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock)358 int MXC_SYS_Clock_Select(mxc_sys_system_clock_t clock)
359 {
360     uint32_t current_clock;
361     int err = E_NO_ERROR;
362 
363     // Save the current system clock
364     current_clock = MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL;
365 
366     switch (clock) {
367     case MXC_SYS_CLOCK_ISO:
368 
369         // Enable ISO clock
370         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_ISO_EN)) {
371             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ISO_EN;
372 
373             // Check if ISO clock is ready
374             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ISO_RDY) != E_NO_ERROR) {
375                 return E_TIME_OUT;
376             }
377         }
378 
379         // Set ISO clock as System Clock
380         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
381                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ISO);
382 
383         break;
384     case MXC_SYS_CLOCK_IPO:
385 
386         // Enable IPO clock
387         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_IPO_EN)) {
388             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IPO_EN;
389 
390             // Check if IPO clock is ready
391             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IPO_RDY) != E_NO_ERROR) {
392                 return E_TIME_OUT;
393             }
394         }
395 
396         // Set IPO clock as System Clock
397         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
398                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IPO);
399 
400         break;
401 
402     case MXC_SYS_CLOCK_IBRO:
403 
404         // Enable IBRO clock
405         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_IBRO_EN)) {
406             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_IBRO_EN;
407 
408             // Check if IBRO clock is ready
409             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_IBRO_RDY) != E_NO_ERROR) {
410                 return E_TIME_OUT;
411             }
412         }
413 
414         // Set IBRO clock as System Clock
415         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
416                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IBRO);
417 
418         break;
419 
420     case MXC_SYS_CLOCK_EXTCLK:
421         /*
422         There's not "EXT_CLK RDY" bit for the ME17, so we'll
423         blindly enable (configure GPIO) the external clock every time.
424         */
425         err = MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_EXTCLK);
426         if (err)
427             return err;
428 
429         // Set EXT clock as System Clock
430         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
431                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_EXTCLK);
432 
433         break;
434 
435     case MXC_SYS_CLOCK_ERFO:
436 
437         // Enable ERFO clock
438         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_ERFO_EN)) {
439             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERFO_EN;
440 
441             // Check if ERFO clock is ready
442             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERFO_RDY) != E_NO_ERROR) {
443                 return E_TIME_OUT;
444             }
445         }
446 
447         // Set ERFO clock as System Clock
448         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
449                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERFO);
450 
451         break;
452 
453     case MXC_SYS_CLOCK_INRO:
454         // Set INRO clock as System Clock
455         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
456                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_INRO);
457 
458         break;
459 
460     case MXC_SYS_CLOCK_ERTCO:
461 
462         // Enable ERTCO clock
463         if (!(MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_ERTCO_EN)) {
464             MXC_GCR->clkctrl |= MXC_F_GCR_CLKCTRL_ERTCO_EN;
465 
466             // Check if ERTCO clock is ready
467             if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_ERTCO_RDY) != E_NO_ERROR) {
468                 return E_TIME_OUT;
469             }
470         }
471 
472         // Set ERTCO clock as System Clock
473         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL,
474                      MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERTCO);
475 
476         break;
477 
478     default:
479         return E_BAD_PARAM;
480     }
481 
482     // Wait for system clock to be ready
483     if (MXC_SYS_Clock_Timeout(MXC_F_GCR_CLKCTRL_SYSCLK_RDY) != E_NO_ERROR) {
484         // Restore the old system clock if timeout
485         MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_SEL, current_clock);
486 
487         return E_TIME_OUT;
488     }
489 
490     // Update the system core clock
491     SystemCoreClockUpdate();
492 
493     return E_NO_ERROR;
494 }
495 
496 /* ************************************************************************** */
MXC_SYS_SetClockDiv(mxc_sys_system_clock_div_t div)497 void MXC_SYS_SetClockDiv(mxc_sys_system_clock_div_t div)
498 {
499     /* Return if this setting is already current */
500     if (div == MXC_SYS_GetClockDiv()) {
501         return;
502     }
503 
504     MXC_SETFIELD(MXC_GCR->clkctrl, MXC_F_GCR_CLKCTRL_SYSCLK_DIV, div);
505 
506     SystemCoreClockUpdate();
507 }
508 
509 /* ************************************************************************** */
MXC_SYS_GetClockDiv(void)510 mxc_sys_system_clock_div_t MXC_SYS_GetClockDiv(void)
511 {
512     return (MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_DIV);
513 }
514 
515 /* ************************************************************************** */
MXC_SYS_Reset_Periph(mxc_sys_reset_t reset)516 void MXC_SYS_Reset_Periph(mxc_sys_reset_t reset)
517 {
518     /* The mxc_sys_reset_t enum uses enum values that are the offset by 32 and 64 for the rst register. */
519     if (reset > 63) {
520         reset -= 64;
521         MXC_LPGCR->rst = (0x1 << reset);
522         while (MXC_LPGCR->rst & (0x1 << reset)) {}
523     } else if (reset > 31) {
524         reset -= 32;
525         MXC_GCR->rst1 = (0x1 << reset);
526         while (MXC_GCR->rst1 & (0x1 << reset)) {}
527     } else {
528         MXC_GCR->rst0 = (0x1 << reset);
529         while (MXC_GCR->rst0 & (0x1 << reset)) {}
530     }
531 }
532 
533 /* ************************************************************************** */
MXC_SYS_RISCVRun(void)534 void MXC_SYS_RISCVRun(void)
535 {
536     /* Disable the the RSCV */
537     MXC_GCR->pclkdis1 |= MXC_F_GCR_PCLKDIS1_CPU1;
538 
539     /* Set the interrupt vector base address */
540     MXC_FCR->urvbootaddr = (uint32_t)&_binary_riscv_bin_start;
541 
542     /* Power up the RSCV */
543     MXC_GCR->pclkdis1 &= ~(MXC_F_GCR_PCLKDIS1_CPU1);
544 
545     /* CPU1 reset */
546     MXC_GCR->rst1 |= MXC_F_GCR_RST1_CPU1;
547 }
548 
549 /* ************************************************************************** */
MXC_SYS_RISCVShutdown(void)550 void MXC_SYS_RISCVShutdown(void)
551 {
552     /* Disable the the RSCV */
553     MXC_GCR->pclkdis1 |= MXC_F_GCR_PCLKDIS1_CPU1;
554 }
555 
556 /* ************************************************************************** */
MXC_SYS_RiscVClockRate(void)557 uint32_t MXC_SYS_RiscVClockRate(void)
558 {
559     // If in LPM mode and the PCLK is selected as the RV32 clock source,
560     if (((MXC_GCR->pm & MXC_F_GCR_PM_MODE) == MXC_S_GCR_PM_MODE_LPM) &&
561         (MXC_PWRSEQ->lpcn & MXC_F_PWRSEQ_LPCN_LPMCLKSEL)) {
562         return ISO_FREQ;
563     } else {
564         return PeripheralClock;
565     }
566 }
567 
568 /* ************************************************************************** */
MXC_SYS_LockDAP_Permanent(void)569 int MXC_SYS_LockDAP_Permanent(void)
570 {
571 #ifdef DEBUG
572     // Locking the DAP is not supported while in DEBUG.
573     // To use this function, build for release ("make release")
574     // or set DEBUG = 0
575     // (see https://analogdevicesinc.github.io/msdk/USERGUIDE/#build-tables)
576     return E_NOT_SUPPORTED;
577 #else
578     int err;
579     uint32_t info_blk_addr;
580     uint32_t lock_sequence[4];
581 
582     // Infoblock address to write lock sequence to
583     info_blk_addr = MXC_INFO_MEM_BASE + INFOBLOCK_DAP_LOCK_OFFSET;
584 
585     // Set lock sequence
586     lock_sequence[0] = DAP_LOCK_SEQUENCE_01;
587     lock_sequence[1] = DAP_LOCK_SEQUENCE_01;
588     lock_sequence[2] = DAP_LOCK_SEQUENCE_23;
589     lock_sequence[3] = DAP_LOCK_SEQUENCE_23;
590 
591     // Initialize FLC
592     MXC_FLC_Init();
593 
594     // Unlock infoblock
595     MXC_FLC_UnlockInfoBlock(info_blk_addr);
596 
597     // Write DAP lock sequence to infoblock
598     err = MXC_FLC_Write128(info_blk_addr, lock_sequence);
599 
600     // Re-lock infoblock
601     MXC_FLC_LockInfoBlock(info_blk_addr);
602 
603     return err;
604 #endif
605 }
606 
607 /**@} end of mxc_sys */
608