1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
4 */
5
6 #include "hal_base.h"
7
8 /** @addtogroup RK_HAL_Driver
9 * @{
10 */
11
12 /** @addtogroup HAL_BASE
13 * @{
14 */
15
16 /** @defgroup HAL_BASE_How_To_Use How To Use
17 * @{
18
19 HAL system support is including delay system, HAL tick system and global system clock,
20
21 HAL system tick setting:
22
23 - Attach HAL_IncTick() to system tick interrupt handler;
24 - Notify the HAL system the system's tick frequency by calling HAL_SetTickFreq() unless
25 it is the same as default value HAL_TICK_FREQ_1KHZ;
26 - If you need a more accurate delay system, specify SYS_TIMER in hal_conf.h.
27
28 Init HAL system:
29
30 - Initialize the HAL system by calling HAL_Init():
31
32 Reset when SOC system is changed:
33
34 - Update system with new core clock and new SysTick clock source by calling HAL_SystemCoreClockUpdate();
35
36 APIs:
37
38 - Get system time by calling HAL_GetTick();
39 - Delay for a certain length of time, HAL_DelayMs(), HAL_DelayUs(), and HAL_CPUDelayUs().
40 - Blocking for a certain period of time to continuously query HW status, use HAL_GetTick()
41 to do timeout, this will be more accurate.
42
43 @} */
44
45 /** @defgroup HAL_BASE_Private_Definition Private Definition
46 * @{
47 */
48 /********************* Private MACRO Definition ******************************/
49
50 #define HAL_TICK_FREQ_DEFAULT HAL_TICK_FREQ_1KHZ
51
52 /********************* Private Structure Definition **************************/
53
54 /********************* Private Variable Definition ***************************/
55
56 static __IO uint32_t uwTick;
57 static eHAL_tickFreq uwTickFreq = HAL_TICK_FREQ_DEFAULT;
58
59 /********************* Private Function Definition ***************************/
60 #if defined(__CORTEX_A) || defined(__CORTEX_M)
61 #if __CORTEX_M == 0U || !defined(__GNUC__)
CPUCycleLoop(uint32_t cycles)62 static void CPUCycleLoop(uint32_t cycles)
63 {
64 uint32_t count;
65
66 if (cycles < 100U) {
67 return;
68 }
69
70 count = cycles / 3;
71 while (count-- > 0) {
72 __asm volatile ("nop");
73 }
74 }
75 #else
CPUCycleLoop(uint32_t cycles)76 static void CPUCycleLoop(uint32_t cycles)
77 {
78 __ASM volatile (
79 "mov r0, %0\n\t"
80 "adds r0, r0, #2\n\t" // 1 2 Round to the nearest multiple of 4.
81 "lsrs r0, r0, #2\n\t" // 1 2 Divide by 4 and set flags.
82 "beq 2f\n\t" // 2 2 Skip if 0.
83 ".align 4\n\t"
84 "1:\n\t"
85 "adds r0, r0, #1\n\t" // 1 2 Increment the counter.
86 "subs r0, r0, #2\n\t" // 1 2 Decrement the counter by 2.
87 "bne 1b\n\t" // (1)2 2 2 CPU cycles (if branch is taken).
88 "nop\n\t" // 1 2 Loop alignment padding.
89 "2:"
90 : : "r" (cycles)
91 );
92 }
93 #endif
94 #elif defined(__RISC_V)
CPUCycleLoop(uint32_t cycles)95 static void CPUCycleLoop(uint32_t cycles)
96 {
97 asm volatile (
98 "mv a0, %0\n\t"
99 "addi a0, a0, 2\n\t" // 1 2 Round to the nearest multiple of 4.
100 "li a1, 4\n\t"
101 "div a0, a0, a1\n\t" // 1 2 Divide by 4 and set flags.
102 "li a1, 2\n\t"
103 "bnez a0, 1f\n\t" // 2 2 Skip if 0.
104 "j 2f\n\t"
105 ".align 6\n\t"
106 "1:\n\t"
107 "addi a0, a0, 1\n\t" // 1 2 Increment the counter.
108 "sub a0, a0, a1\n\t" // 1 2 Decrement the counter by 2.
109 "bnez a0, 1b\n\t" // (1)2 2 2 CPU cycles (if branch is taken).
110 "nop\n\t" // 1 2 Loop alignment padding.
111 "2:"
112 : : "r" (cycles)
113 );
114 }
115 #endif
116
117 #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
TimerDelayUs(uint32_t us)118 __STATIC_FORCEINLINE HAL_Status TimerDelayUs(uint32_t us)
119 {
120 uint64_t count, from, now, pass;
121
122 from = HAL_TIMER_GetCount(SYS_TIMER);
123 count = PLL_INPUT_OSC_RATE / 1000000 * us;
124
125 do {
126 now = HAL_TIMER_GetCount(SYS_TIMER);
127 pass = now > from ? now - from : from - now;
128 } while (pass < count);
129
130 return HAL_OK;
131 }
132 #endif
133
134 /** @} */
135 /********************* Public Function Definition ***************************/
136 /** @defgroup HAL_BASE_Exported_Functions_Group4 Init and DeInit Functions
137
138 This section provides functions allowing to init and deinit the module:
139
140 * @{
141 */
142
143 /**
144 * @brief Init HAL driver basic code.
145 * @return HAL_OK.
146 */
HAL_Init(void)147 HAL_Status HAL_Init(void)
148 {
149 #ifdef __CORTEX_M
150 #ifdef HAL_NVIC_MODULE_ENABLED
151 /* Set Interrupt Group Priority */
152 HAL_NVIC_Init();
153
154 /* Set Interrupt Group Priority */
155 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_DEFAULT);
156 #endif
157 #endif
158
159 #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
160 HAL_TIMER_SysTimerInit(SYS_TIMER);
161 #endif
162
163 #ifdef RK_BSP_TEMP
164 #ifdef HAL_PINCTRL_MODULE_ENABLED
165 HAL_PINCTRL_Init();
166 #endif
167 #endif
168
169 return HAL_OK;
170 }
171
172 /**
173 * @brief HAL system update with new core clock and systick clock source.
174 * @param hz: new core clock.
175 * @param clkSource: new systick clock source.
176 * @return HAL_OK.
177 */
HAL_SystemCoreClockUpdate(uint32_t hz,eHAL_systickClkSource clkSource)178 HAL_Status HAL_SystemCoreClockUpdate(uint32_t hz, eHAL_systickClkSource clkSource)
179 {
180 uint32_t rate = hz;
181 HAL_Status ret = HAL_OK;
182
183 #if defined(__CORTEX_M) && defined(HAL_SYSTICK_MODULE_ENABLED)
184 ret = HAL_SYSTICK_CLKSourceConfig(clkSource);
185 if (ret == HAL_OK && clkSource == HAL_SYSTICK_CLKSRC_EXT) {
186 rate = PLL_INPUT_OSC_RATE;
187 }
188 HAL_SYSTICK_Config(rate / (1000 / HAL_GetTickFreq()));
189 ret = HAL_OK;
190 #endif
191
192 if (ret == HAL_OK) {
193 SystemCoreClock = rate; /* Update global SystemCoreClock */
194 }
195
196 return ret;
197 }
198
199 /**
200 * @brief HAL deinit.
201 * @return HAL_Status: HAL_OK.
202 */
HAL_DeInit(void)203 HAL_Status HAL_DeInit(void)
204 {
205 /* TO-DO */
206
207 return HAL_OK;
208 }
209
210 /** @} */
211
212 /** @defgroup HAL_BASE_Exported_Functions_Group5 Other Functions
213 * @{
214 */
215
216 /**
217 * @brief Count plus tickFreq when interrupt occurs.
218 * @return HAL_Status: HAL_OK.
219 */
HAL_IncTick(void)220 HAL_Status HAL_IncTick(void)
221 {
222 uwTick += uwTickFreq;
223
224 return HAL_OK;
225 }
226
227 /**
228 * @brief Provides tick value in millisecond.
229 * @return uint32_t: tick value in millisecond.
230 * @attention this API allow direct use in the HAL layer.
231 */
HAL_GetTick(void)232 uint32_t HAL_GetTick(void)
233 {
234 #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
235 uint64_t tick = HAL_TIMER_GetCount(SYS_TIMER);
236 uint32_t base = PLL_INPUT_OSC_RATE / 1000;
237
238 if (tick >> 62) {
239 tick = ~tick;
240 }
241
242 return (uint32_t)HAL_DivU64(tick, base);
243 #else
244
245 return uwTick;
246 #endif
247 }
248
249 /**
250 * @brief Provides system timer count.
251 * @return uint64_t: timer count.
252 * @attention this API allow direct use in the HAL layer.
253 */
HAL_GetSysTimerCount(void)254 uint64_t HAL_GetSysTimerCount(void)
255 {
256 #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
257 uint64_t count = HAL_TIMER_GetCount(SYS_TIMER);
258 if (count >> 62) {
259 count = ~count;
260 }
261
262 return count;
263 #else
264
265 return 0LLU;
266 #endif
267 }
268
269 /**
270 * @brief Set new tick frequency.
271 * @return HAL_Status.
272 */
HAL_SetTickFreq(eHAL_tickFreq freq)273 HAL_Status HAL_SetTickFreq(eHAL_tickFreq freq)
274 {
275 HAL_ASSERT(IS_TICKFREQ(freq));
276
277 uwTickFreq = freq;
278
279 return HAL_OK;
280 }
281
282 /**
283 * @brief Return tick frequency.
284 * @return uint32_t: tick period in Hz.
285 * @attention this API allow direct use in the HAL layer.
286 */
HAL_GetTickFreq(void)287 eHAL_tickFreq HAL_GetTickFreq(void)
288 {
289 return uwTickFreq;
290 }
291
292 /**
293 * @brief SysTick mdelay.
294 * @param ms: mdelay count.
295 * @return HAL_Status: HAL_OK.
296 * @attention this API allow direct use in the HAL layer. Blocking for a
297 * certain period of time to continuously query HW status, use HAL_GetTick
298 * to do timeout, that will be more accurate.
299 */
HAL_DelayMs(uint32_t ms)300 __WEAK HAL_Status HAL_DelayMs(uint32_t ms)
301 {
302 for (uint32_t i = 0; i < ms; i++) {
303 HAL_DelayUs(1000);
304 }
305
306 return HAL_OK;
307 }
308
309 /**
310 * @brief SysTick udelay.
311 * @param us: udelay count.
312 * @return HAL_Status: HAL_OK.
313 * @attention this API allow direct use in the HAL layer. The longer the delay,
314 * the more accurate. Actual delay is greater than the parameter.
315 */
HAL_DelayUs(uint32_t us)316 HAL_Status HAL_DelayUs(uint32_t us)
317 {
318 #if defined(SYS_TIMER) && defined(HAL_TIMER_MODULE_ENABLED)
319
320 return TimerDelayUs(us);
321 #else
322
323 return HAL_CPUDelayUs(us);
324 #endif
325 }
326
327 /**
328 * @brief CPU loop udelay.
329 * @param us: udelay count.
330 * @return HAL_Status: HAL_OK.
331 * @attention this API allow direct use in the HAL layer. The longer the delay,
332 * the more accurate. Actual delay is greater than the parameter.
333 * During delay, CPU rate change result in delay imprecise, so call it in
334 * following case:
335 * 1.IRQ disable
336 * 2.CRU code
337 */
HAL_CPUDelayUs(uint32_t us)338 HAL_Status HAL_CPUDelayUs(uint32_t us)
339 {
340 volatile uint32_t cycles;
341
342 #if (__CORTEX_M == 0)
343 cycles = (uint32_t)HAL_DivU64((uint64_t)SystemCoreClock, 1000000) * us; /* Add few cycles penalty */
344 #else
345 cycles = SystemCoreClock / 1000000 * us; /* Add few cycles penalty */
346 #endif
347
348 CPUCycleLoop(cycles);
349
350 return HAL_OK;
351 }
352
353 /** @} */
354
355 /** @} */
356
357 /** @} */
358