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