1 /**
2 * @file system_max32662.c
3 * @brief System-level initialization implementation file
4 */
5 /******************************************************************************
6 *
7 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
8 * Analog Devices, Inc.),
9 * Copyright (C) 2023-2024 Analog Devices, Inc.
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 *
23 ******************************************************************************/
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include "max32662.h"
29 #include "gcr_regs.h"
30 #include "pwrseq_regs.h"
31 #include "mxc_sys.h"
32
33 extern void (*const __isr_vector[])(void);
34
35 uint32_t SystemCoreClock = HIRC_FREQ;
36
37 /*
38 The libc implementation from GCC 11+ depends on _getpid and _kill in some places.
39 There is no concept of processes/PIDs in the baremetal PeriphDrivers, therefore
40 we implement stub functions that return an error code to resolve linker warnings.
41 */
_getpid(void)42 __weak int _getpid(void)
43 {
44 return E_NOT_SUPPORTED;
45 }
46
_kill(void)47 __weak int _kill(void)
48 {
49 return E_NOT_SUPPORTED;
50 }
51
SystemCoreClockUpdate(void)52 __weak void SystemCoreClockUpdate(void)
53 {
54 uint32_t base_freq, div, clk_src;
55
56 // Get the clock source and frequency
57 clk_src = (MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_SEL);
58 switch (clk_src) {
59 case MXC_S_GCR_CLKCTRL_SYSCLK_SEL_EXTCLK:
60 base_freq = HF_EXTCLK_FREQ;
61 break;
62 case MXC_S_GCR_CLKCTRL_SYSCLK_SEL_INRO:
63 base_freq = INRO_FREQ;
64 break;
65 case MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IPO:
66 base_freq = IPO_FREQ;
67 break;
68 case MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IBRO:
69 base_freq = IBRO_FREQ;
70 break;
71 case MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERTCO:
72 base_freq = ERTCO_FREQ;
73 break;
74 case MXC_S_GCR_CLKCTRL_SYSCLK_SEL_ERFO:
75 base_freq = ERFO_FREQ;
76 break;
77 default:
78 // Codes 001 and 111 are reserved.
79 // This code should never execute, however, initialize to safe value.
80 base_freq = HIRC_FREQ;
81 break;
82 }
83
84 if (clk_src == MXC_S_GCR_CLKCTRL_SYSCLK_SEL_IPO) {
85 uint32_t ovr = (MXC_PWRSEQ->lpctrl & MXC_F_PWRSEQ_LPCTRL_OVR);
86 switch (ovr) {
87 case MXC_S_PWRSEQ_LPCTRL_OVR_0_9V:
88 base_freq = base_freq >> 3;
89 break;
90 case MXC_S_PWRSEQ_LPCTRL_OVR_1_0V:
91 base_freq = base_freq >> 1;
92 break;
93 case MXC_S_PWRSEQ_LPCTRL_OVR_1_1V:
94 default:
95 /* Nothing to do here.
96 OVR = 1.1V means the clock runs full speed. */
97 break;
98 }
99 // Get the clock divider
100 base_freq = base_freq >> ((MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_IPO_DIV) >>
101 MXC_F_GCR_CLKCTRL_IPO_DIV_POS);
102 }
103
104 div = (MXC_GCR->clkctrl & MXC_F_GCR_CLKCTRL_SYSCLK_DIV) >> MXC_F_GCR_CLKCTRL_SYSCLK_DIV_POS;
105
106 SystemCoreClock = base_freq >> div;
107 }
108
109 /* This function is called before C runtime initialization and can be
110 * implemented by the application for early initializations. If a value other
111 * than '0' is returned, the C runtime initialization will be skipped.
112 *
113 * You may over-ride this function in your program by defining a custom
114 * PreInit(), but care should be taken to reproduce the initialization steps
115 * or a non-functional system may result.
116 */
PreInit(void)117 __weak int PreInit(void)
118 {
119 /* Do nothing */
120 return 0;
121 }
122
123 /* This function can be implemented by the application to initialize the board */
Board_Init(void)124 __weak int Board_Init(void)
125 {
126 /* Do nothing */
127 return 0;
128 }
129
PalSysInit(void)130 __weak void PalSysInit(void) {}
131
132 /* This function is called just before control is transferred to main().
133 *
134 * You may over-ride this function in your program by defining a custom
135 * SystemInit(), but care should be taken to reproduce the initialization
136 * steps or a non-functional system may result.
137 */
SystemInit(void)138 __weak void SystemInit(void)
139 {
140 #ifdef DEBUG
141 /* Delay to prevent bricks */
142 volatile int i;
143 for (i = 0; i < 0x3FFFF; i++) {}
144 #endif
145
146 /* Configure the interrupt controller to use the application vector table in */
147 /* the application space */
148 #if defined(__CC_ARM) || defined(__GNUC__)
149 /* IAR sets the VTOR pointer incorrectly and causes stack corruption */
150 SCB->VTOR = (uint32_t)__isr_vector;
151 #endif /* __CC_ARM || __GNUC__ */
152
153 /* Enable FPU on Cortex-M4, which occupies coprocessor slots 10 & 11 */
154 /* Grant full access, per "Table B3-24 CPACR bit assignments". */
155 /* DDI0403D "ARMv7-M Architecture Reference Manual" */
156 SCB->CPACR |= SCB_CPACR_CP10_Msk | SCB_CPACR_CP11_Msk;
157 __DSB();
158 __ISB();
159
160 MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO);
161 SystemCoreClockUpdate();
162
163 Board_Init();
164
165 __enable_irq();
166 }
167