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 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "max32650.h"
25 #include "gcr_regs.h"
26 #include "mxc_sys.h"
27 #include "usbhs_regs.h"
28 #include "flc_regs.h"
29 #include "icc_regs.h"
30 #include "mxc_errors.h"
31 
32 extern void (*const __isr_vector[])(void);
33 uint32_t SystemCoreClock = 0;
34 uint8_t ChipRevision = 0;
35 
36 /*
37 The libc implementation from GCC 11+ depends on _getpid and _kill in some places.
38 There is no concept of processes/PIDs in the baremetal PeriphDrivers, therefore
39 we implement stub functions that return an error code to resolve linker warnings.
40 */
_getpid(void)41 __weak int _getpid(void)
42 {
43     return E_NOT_SUPPORTED;
44 }
45 
_kill(void)46 __weak int _kill(void)
47 {
48     return E_NOT_SUPPORTED;
49 }
50 
SystemCoreClockUpdate(void)51 __weak void SystemCoreClockUpdate(void)
52 {
53     uint32_t base_freq, div, clk_src;
54 
55     // Get the clock source and frequency
56     clk_src = (MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_SYSOSC_SEL);
57     if (clk_src == MXC_S_GCR_CLK_CTRL_SYSOSC_SEL_HFXIN) {
58         base_freq = HFX_FREQ;
59     } else if (clk_src == MXC_S_GCR_CLK_CTRL_SYSOSC_SEL_NANORING) {
60         base_freq = NANORING_FREQ;
61     } else if (clk_src == MXC_S_GCR_CLK_CTRL_SYSOSC_SEL_HIRC96) {
62         base_freq = HIRC96_FREQ;
63     } else if (clk_src == MXC_S_GCR_CLK_CTRL_SYSOSC_SEL_HIRC8) {
64         base_freq = HIRC8_FREQ;
65     } else {
66 #ifndef CRYPTO_FREQ
67         if (ChipRevision > 0xA1) {
68             base_freq = CRYPTO_FREQ_A3;
69         } else {
70             base_freq = CRYPTO_FREQ_A1;
71         }
72 #else
73         base_freq = CRYPTO_FREQ;
74 #endif
75     }
76 
77     // Get the clock divider
78     div = (MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_SYSCLK_PRESCALE) >>
79           MXC_F_GCR_CLK_CTRL_SYSCLK_PRESCALE_POS;
80 
81     SystemCoreClock = base_freq >> div;
82 }
83 
84 /* This function is called before C runtime initialization and can be
85  * implemented by the application for early initializations. If a value other
86  * than '0' is returned, the C runtime initialization will be skipped.
87  *
88  * You may over-ride this function in your program by defining a custom
89  *  PreInit(), but care should be taken to reproduce the initialization steps
90  *  or a non-functional system may result.
91  */
PreInit(void)92 __weak int PreInit(void)
93 {
94     /* Workaround: Write to SCON register on power up to fix trim issue for SRAM */
95     MXC_GCR->scon = (MXC_GCR->scon & ~(MXC_F_GCR_SCON_OVR)) | (MXC_S_GCR_SCON_OVR_1V1);
96     return 0;
97 }
98 
99 /* This function can be implemented by the application to initialize the board */
Board_Init(void)100 __weak int Board_Init(void)
101 {
102     /* Do nothing */
103     return 0;
104 }
105 
106 /* This function is called just before control is transferred to main().
107  *
108  * You may over-ride this function in your program by defining a custom
109  *  SystemInit(), but care should be taken to reproduce the initialization
110  *  steps or a non-functional system may result.
111  */
SystemInit(void)112 __weak void SystemInit(void)
113 {
114     ChipRevision = MXC_SYS_GetRev();
115     /* Configure the interrupt controller to use the application vector table in */
116     /* the application space */
117     SCB->VTOR = (uint32_t)__isr_vector;
118 
119     /* MAX3265x ROM turns off interrupts, which is not the same as the reset state. */
120     __enable_irq();
121 
122     /* Enable FPU on Cortex-M4, which occupies coprocessor slots 10 & 11 */
123     /* Grant full access, per "Table B3-24 CPACR bit assignments". */
124     /* DDI0403D "ARMv7-M Architecture Reference Manual" */
125     SCB->CPACR |= SCB_CPACR_CP10_Msk | SCB_CPACR_CP11_Msk;
126     __DSB();
127     __ISB();
128 
129     /* Change system clock source to the main high-speed clock */
130     MXC_SYS_Clock_Select(MXC_SYS_CLOCK_HIRC96);
131     SystemCoreClockUpdate();
132 
133     /* Erratum #?: Adjust register timing for VCORE == 1.1v, prevents USB failure. 2017-10-04 ZNM/HTN */
134     MXC_GCR->scon |= MXC_S_GCR_SCON_OVR_1V1;
135 
136     // Flush and enable instruction cache
137     MXC_ICC->invalidate = 1;
138     while (!(MXC_ICC->cache_ctrl & MXC_F_ICC_CACHE_CTRL_READY)) {}
139     MXC_ICC->cache_ctrl |= MXC_F_ICC_CACHE_CTRL_ENABLE;
140     while (!(MXC_ICC->cache_ctrl & MXC_F_ICC_CACHE_CTRL_READY)) {}
141 
142     /* Shutdown all peripheral clocks initially.  They will be re-enabled by each periph's init function. */
143     /* GPIO Clocks are left enabled */
144     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_USB);
145     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TFT);
146     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_DMA);
147     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPI0);
148     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPI1);
149     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPI2);
150     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_UART0);
151     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_UART1);
152     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_I2C0);
153     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TPU);
154     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TIMER0);
155     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TIMER1);
156     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TIMER2);
157     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TIMER3);
158     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TIMER4);
159     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TIMER5);
160     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_ADC);
161     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_I2C1);
162     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_PT);
163     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPIXIPF);
164     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPIXIPM);
165     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_UART2);
166     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_TRNG);
167     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_FLC);
168     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_HBC);
169     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SCACHE);
170     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SDMA);
171     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SEMA);
172     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SDHC);
173     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_ICACHE);
174     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_ICACHEXIP);
175     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_OWIRE);
176     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPI3);
177     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_I2S);
178     MXC_SYS_ClockDisable(MXC_SYS_PERIPH_CLOCK_SPIXIPR);
179 
180     Board_Init();
181 }
182 
183 #if defined(__CC_ARM)
184 /* Function called post memory initialization (post scatter load) in the Keil Toolchain, which
185  * we are using to call the system core clock update and board initialization
186  * to prevent data corruption if they are called from SystemInit. */
187 extern void $Super$$__main_after_scatterload(void);
$Sub$$__main_after_scatterload(void)188 void $Sub$$__main_after_scatterload(void)
189 {
190     SystemInit();
191     $Super$$__main_after_scatterload();
192 }
193 #endif /* __CC_ARM */
194