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