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