1 | /* |
2 | * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. |
3 | * Copyright 2016-2021 NXP |
4 | * All rights reserved. |
5 | * |
6 | * SPDX-License-Identifier: BSD-3-Clause |
7 | */ |
8 | |
9 | #include "fsl_common.h" |
10 | |
11 | /* Component ID definition, used by tools. */ |
12 | #ifndef FSL_COMPONENT_ID |
13 | #define FSL_COMPONENT_ID "platform.drivers.common_arm" |
14 | #endif |
15 | |
16 | #ifndef __GIC_PRIO_BITS |
17 | #if defined(ENABLE_RAM_VECTOR_TABLE) |
18 | uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler) |
19 | { |
20 | #ifdef __VECTOR_TABLE |
21 | #undef __VECTOR_TABLE |
22 | #endif |
23 | |
24 | /* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */ |
25 | #if defined(__CC_ARM) || defined(__ARMCC_VERSION) |
26 | extern uint32_t Image$$VECTOR_ROM$$Base[]; |
27 | extern uint32_t Image$$VECTOR_RAM$$Base[]; |
28 | extern uint32_t Image$$RW_m_data$$Base[]; |
29 | |
30 | #define __VECTOR_TABLE Image$$VECTOR_ROM$$Base |
31 | #define __VECTOR_RAM Image$$VECTOR_RAM$$Base |
32 | #define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base)) |
33 | #elif defined(__ICCARM__) |
34 | extern uint32_t __RAM_VECTOR_TABLE_SIZE[]; |
35 | extern uint32_t __VECTOR_TABLE[]; |
36 | extern uint32_t __VECTOR_RAM[]; |
37 | #elif defined(__GNUC__) |
38 | extern uint32_t __VECTOR_TABLE[]; |
39 | extern uint32_t __VECTOR_RAM[]; |
40 | extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[]; |
41 | uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES); |
42 | #endif /* defined(__CC_ARM) || defined(__ARMCC_VERSION) */ |
43 | uint32_t n; |
44 | uint32_t ret; |
45 | uint32_t irqMaskValue; |
46 | |
47 | irqMaskValue = DisableGlobalIRQ(); |
48 | if (SCB->VTOR != (uint32_t)__VECTOR_RAM) |
49 | { |
50 | /* Copy the vector table from ROM to RAM */ |
51 | for (n = 0; n < ((uint32_t)__RAM_VECTOR_TABLE_SIZE) / sizeof(uint32_t); n++) |
52 | { |
53 | __VECTOR_RAM[n] = __VECTOR_TABLE[n]; |
54 | } |
55 | /* Point the VTOR to the position of vector table */ |
56 | SCB->VTOR = (uint32_t)__VECTOR_RAM; |
57 | } |
58 | |
59 | ret = __VECTOR_RAM[(int32_t)irq + 16]; |
60 | /* make sure the __VECTOR_RAM is noncachable */ |
61 | __VECTOR_RAM[(int32_t)irq + 16] = irqHandler; |
62 | |
63 | EnableGlobalIRQ(irqMaskValue); |
64 | |
65 | return ret; |
66 | } |
67 | #endif /* ENABLE_RAM_VECTOR_TABLE. */ |
68 | #endif /* __GIC_PRIO_BITS. */ |
69 | |
70 | #if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) |
71 | |
72 | /* |
73 | * When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value, |
74 | * powerlib should be used instead of these functions. |
75 | */ |
76 | #if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0)) |
77 | |
78 | /* |
79 | * When the SYSCON STARTER registers are discontinuous, these functions are |
80 | * implemented in fsl_power.c. |
81 | */ |
82 | #if !(defined(FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS) && FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS) |
83 | |
84 | void EnableDeepSleepIRQ(IRQn_Type interrupt) |
85 | { |
86 | uint32_t intNumber = (uint32_t)interrupt; |
87 | |
88 | uint32_t index = 0; |
89 | |
90 | while (intNumber >= 32u) |
91 | { |
92 | index++; |
93 | intNumber -= 32u; |
94 | } |
95 | |
96 | SYSCON->STARTERSET[index] = 1UL << intNumber; |
97 | (void)EnableIRQ(interrupt); /* also enable interrupt at NVIC */ |
98 | } |
99 | |
100 | void DisableDeepSleepIRQ(IRQn_Type interrupt) |
101 | { |
102 | uint32_t intNumber = (uint32_t)interrupt; |
103 | |
104 | (void)DisableIRQ(interrupt); /* also disable interrupt at NVIC */ |
105 | uint32_t index = 0; |
106 | |
107 | while (intNumber >= 32u) |
108 | { |
109 | index++; |
110 | intNumber -= 32u; |
111 | } |
112 | |
113 | SYSCON->STARTERCLR[index] = 1UL << intNumber; |
114 | } |
115 | #endif /* FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS */ |
116 | #endif /* FSL_FEATURE_POWERLIB_EXTEND */ |
117 | #endif /* FSL_FEATURE_SOC_SYSCON_COUNT */ |
118 | |
119 | #if defined(SDK_DELAY_USE_DWT) && defined(DWT) |
120 | /* Use WDT. */ |
121 | static void enableCpuCycleCounter(void) |
122 | { |
123 | /* Make sure the DWT trace fucntion is enabled. */ |
124 | if (CoreDebug_DEMCR_TRCENA_Msk != (CoreDebug_DEMCR_TRCENA_Msk & CoreDebug->DEMCR)) |
125 | { |
126 | CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; |
127 | } |
128 | |
129 | /* CYCCNT not supported on this device. */ |
130 | assert(DWT_CTRL_NOCYCCNT_Msk != (DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk)); |
131 | |
132 | /* Read CYCCNT directly if CYCCENT has already been enabled, otherwise enable CYCCENT first. */ |
133 | if (DWT_CTRL_CYCCNTENA_Msk != (DWT_CTRL_CYCCNTENA_Msk & DWT->CTRL)) |
134 | { |
135 | DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; |
136 | } |
137 | } |
138 | |
139 | static uint32_t getCpuCycleCount(void) |
140 | { |
141 | return DWT->CYCCNT; |
142 | } |
143 | #else /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */ |
144 | /* Use software loop. */ |
145 | #if defined(__CC_ARM) /* This macro is arm v5 specific */ |
146 | /* clang-format off */ |
147 | __ASM static void DelayLoop(uint32_t count) |
148 | { |
149 | loop |
150 | SUBS R0, R0, #1 |
151 | CMP R0, #0 |
152 | BNE loop |
153 | BX LR |
154 | } |
155 | /* clang-format on */ |
156 | #elif defined(__ARMCC_VERSION) || defined(__ICCARM__) || defined(__GNUC__) |
157 | /* Cortex-M0 has a smaller instruction set, SUBS isn't supported in thumb-16 mode reported from __GNUC__ compiler, |
158 | * use SUB and CMP here for compatibility */ |
159 | static void DelayLoop(uint32_t count) |
160 | { |
161 | __ASM volatile(" MOV R0, %0" : : "r"(count)); |
162 | __ASM volatile( |
163 | "loop: \n" |
164 | #if defined(__GNUC__) && !defined(__ARMCC_VERSION) |
165 | " SUB R0, R0, #1 \n" |
166 | #else |
167 | " SUBS R0, R0, #1 \n" |
168 | #endif |
169 | " CMP R0, #0 \n" |
170 | |
171 | " BNE loop \n" |
172 | : |
173 | : |
174 | : "r0"); |
175 | } |
176 | #endif /* defined(__CC_ARM) */ |
177 | #endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */ |
178 | |
179 | /*! |
180 | * @brief Delay at least for some time. |
181 | * Please note that, if not uses DWT, this API will use while loop for delay, different run-time environments have |
182 | * effect on the delay time. If precise delay is needed, please enable DWT delay. The two parmeters delayTime_us and |
183 | * coreClock_Hz have limitation. For example, in the platform with 1GHz coreClock_Hz, the delayTime_us only supports |
184 | * up to 4294967 in current code. If long time delay is needed, please implement a new delay function. |
185 | * |
186 | * @param delayTime_us Delay time in unit of microsecond. |
187 | * @param coreClock_Hz Core clock frequency with Hz. |
188 | */ |
189 | void SDK_DelayAtLeastUs(uint32_t delayTime_us, uint32_t coreClock_Hz) |
190 | { |
191 | uint64_t count; |
192 | |
193 | if (delayTime_us > 0U) |
194 | { |
195 | count = USEC_TO_COUNT(delayTime_us, coreClock_Hz); |
196 | |
197 | assert(count <= UINT32_MAX); |
198 | |
199 | #if defined(SDK_DELAY_USE_DWT) && defined(DWT) /* Use DWT for better accuracy */ |
200 | |
201 | enableCpuCycleCounter(); |
202 | /* Calculate the count ticks. */ |
203 | count += getCpuCycleCount(); |
204 | |
205 | if (count > UINT32_MAX) |
206 | { |
207 | count -= UINT32_MAX; |
208 | /* Wait for cyccnt overflow. */ |
209 | while (count < getCpuCycleCount()) |
210 | { |
211 | } |
212 | } |
213 | |
214 | /* Wait for cyccnt reach count value. */ |
215 | while (count > getCpuCycleCount()) |
216 | { |
217 | } |
218 | #else |
219 | /* Divide value may be different in various environment to ensure delay is precise. |
220 | * Every loop count includes three instructions, due to Cortex-M7 sometimes executes |
221 | * two instructions in one period, through test here set divide 1.5. Other M cores use |
222 | * divide 4. By the way, divide 1.5 or 4 could let the count lose precision, but it does |
223 | * not matter because other instructions outside while loop is enough to fill the time. |
224 | */ |
225 | #if (__CORTEX_M == 7) |
226 | count = count / 3U * 2U; |
227 | #else |
228 | count = count / 4U; |
229 | #endif |
230 | DelayLoop((uint32_t)count); |
231 | #endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */ |
232 | } |
233 | } |
234 | |