1 /**
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * Description: Provides timer driver source \n
16 *
17 * History: \n
18 * 2022-11-07, Create file. \n
19 */
20 #include <stdbool.h>
21 #include <limits.h>
22 #include "securec.h"
23 #include "common_def.h"
24 #include "interrupt/osal_interrupt.h"
25 #include "tcxo.h"
26 #include "timer_porting.h"
27 #include "timer.h"
28
29 #ifndef UINT64_MAX
30 #define UINT64_MAX (0xFFFFFFFFFFFFFFFFUL)
31 #endif
32
33 #if defined(CONFIG_TIMER_USING_OLD_VERSION)
34 #define TIMER_OLD_VERSION_LOAD_COUNT_MASK 0x0F
35 #endif
36
37 #ifdef CONFIG_TIMER_MAX_TIMERS_NUM
38 #ifndef CONFIG_TIMER_MAX_TIMERS_NUM_0
39 #define CONFIG_TIMER_MAX_TIMERS_NUM_0 CONFIG_TIMER_MAX_TIMERS_NUM
40 #endif
41 #ifndef CONFIG_TIMER_MAX_TIMERS_NUM_1
42 #define CONFIG_TIMER_MAX_TIMERS_NUM_1 CONFIG_TIMER_MAX_TIMERS_NUM
43 #endif
44 #ifndef CONFIG_TIMER_MAX_TIMERS_NUM_2
45 #define CONFIG_TIMER_MAX_TIMERS_NUM_2 CONFIG_TIMER_MAX_TIMERS_NUM
46 #endif
47 #ifndef CONFIG_TIMER_MAX_TIMERS_NUM_3
48 #define CONFIG_TIMER_MAX_TIMERS_NUM_3 CONFIG_TIMER_MAX_TIMERS_NUM
49 #endif
50 #ifndef CONFIG_TIMER_MAX_TIMERS_NUM_EXTRA
51 #define CONFIG_TIMER_MAX_TIMERS_NUM_EXTRA CONFIG_TIMER_MAX_TIMERS_NUM
52 #endif
53 #endif
54
55 typedef enum timer_flag {
56 TIMER_FLAG_NORMAL,
57 TIMER_FLAG_PERMANENT
58 } timer_flag_t;
59
60 typedef struct timer_info {
61 timer_handle_t key;
62 timer_index_t index;
63 bool enable;
64 bool is_run;
65 timer_flag_t flag;
66 uint64_t cycle;
67 timer_callback_t callback;
68 uintptr_t data;
69 } timer_info_t;
70
71 typedef struct soft_timer_cfg {
72 uintptr_t timer_addr;
73 uint8_t timer_num;
74 } soft_timer_cfg_t;
75
76 #define CUR_MAX_HARDWARE_TIMER_NUM 4
77 #define TIMER_SIZE_0 0
78 #define TIMER_SIZE_1 1
79 #define TIMER_SIZE_2 2
80 #define TIMER_SIZE_3 3
81 #define TIMER_SIZE_4 4
82
83 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_0)
84 static timer_info_t g_timerlist_0[CONFIG_TIMER_MAX_TIMERS_NUM_0];
85 #endif
86 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_1)
87 static timer_info_t g_timerlist_1[CONFIG_TIMER_MAX_TIMERS_NUM_1];
88 #endif
89 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_2)
90 static timer_info_t g_timerlist_2[CONFIG_TIMER_MAX_TIMERS_NUM_2];
91 #endif
92 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_3)
93 static timer_info_t g_timerlist_3[CONFIG_TIMER_MAX_TIMERS_NUM_3];
94 #endif
95 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_4)
96 static timer_info_t \
97 g_timerlist_extra[CONFIG_TIMER_MAX_NUM - CUR_MAX_HARDWARE_TIMER_NUM][CONFIG_TIMER_MAX_TIMERS_NUM_EXTRA];
98 #endif
99 typedef struct timers_manager {
100 uint64_t last_time_load_cycle;
101 timer_info_t *timers;
102 uint32_t hw_timer_irq_id;
103 uint16_t hw_timer_int_priority;
104 bool in_timer_irq;
105 uint8_t soft_time_num;
106 } timers_manager_t;
107
108 static bool g_timer_inited = false;
109 static bool g_timer_adapted[CONFIG_TIMER_MAX_NUM];
110 timers_manager_t g_timers_manager[CONFIG_TIMER_MAX_NUM];
111
112 /*
113 * Reduces the time left for all the timers by timer us amount
114 */
timer_update_timers_time(timer_index_t index,uint64_t update_amount_cycle)115 STATIC bool timer_update_timers_time(timer_index_t index, uint64_t update_amount_cycle)
116 {
117 bool has_new_timer = false;
118 uint32_t irq_sts = osal_irq_lock();
119 uint8_t soft_time_num = g_timers_manager[index].soft_time_num;
120 for (uint8_t i = 0; i < soft_time_num; i++) {
121 if (g_timers_manager[index].timers[i].cycle <= update_amount_cycle) {
122 g_timers_manager[index].timers[i].cycle = 0;
123 if (g_timers_manager[index].timers[i].is_run) {
124 has_new_timer = true;
125 }
126 } else {
127 g_timers_manager[index].timers[i].cycle -= (uint32_t)update_amount_cycle;
128 }
129 }
130 osal_irq_restore(irq_sts);
131 return has_new_timer;
132 }
133
134 /*
135 * Loops through the timers to see if any need to be processed
136 */
timer_process_timers(timer_index_t index)137 STATIC bool timer_process_timers(timer_index_t index)
138 {
139 bool re_run = false;
140 uint64_t start_time = uapi_tcxo_get_count();
141 uint8_t soft_time_num = g_timers_manager[index].soft_time_num;
142 for (uint8_t i = 0; i < soft_time_num; i++) {
143 if (g_timers_manager[index].timers[i].enable &&
144 g_timers_manager[index].timers[i].cycle == 0 &&
145 g_timers_manager[index].timers[i].is_run) {
146 g_timers_manager[index].timers[i].is_run = false;
147 if (g_timers_manager[index].timers[i].callback) {
148 g_timers_manager[index].timers[i].callback(g_timers_manager[index].timers[i].data);
149 }
150 re_run = true;
151 }
152 }
153
154 if (re_run) {
155 uint64_t end_time = uapi_tcxo_get_count();
156 uint64_t diff = end_time - start_time;
157 uint64_t cycle = 0;
158 cycle = timer_porting_compensat_by_tcxo(diff);
159 re_run = timer_update_timers_time(index, cycle);
160 }
161
162 return re_run;
163 }
164
165 /*
166 * Gets the index of the next timer to expire
167 */
timer_get_next_timer(timer_index_t index)168 STATIC uint32_t timer_get_next_timer(timer_index_t index)
169 {
170 uint64_t shortest_time_found = UINT64_MAX;
171 uint8_t soft_time_num = g_timers_manager[index].soft_time_num;
172 uint32_t timer_found = soft_time_num;
173 for (uint8_t i = 0; i < soft_time_num; i++) {
174 if (g_timers_manager[index].timers[i].enable &&
175 g_timers_manager[index].timers[i].cycle <= shortest_time_found &&
176 g_timers_manager[index].timers[i].is_run) {
177 shortest_time_found = (uint32_t)g_timers_manager[index].timers[i].cycle;
178 timer_found = i;
179 }
180 }
181 return timer_found;
182 }
183
184 /*
185 * Gets the time in us till the next interrupt, UINT64_MAX indicates that no timer is set
186 */
timer_get_time_till_interrupt(timer_index_t index)187 STATIC uint64_t timer_get_time_till_interrupt(timer_index_t index)
188 {
189 uint64_t current_value = hal_timer_get_current_value(index);
190 if (current_value != 0) {
191 return (uint32_t)current_value;
192 }
193
194 uint32_t next_timer = timer_get_next_timer(index);
195 if (next_timer >= g_timers_manager[index].soft_time_num) {
196 return UINT64_MAX;
197 }
198
199 uint64_t cycle = (uint32_t)g_timers_manager[index].timers[next_timer].cycle;
200 if (g_timers_manager[index].in_timer_irq) {
201 return cycle;
202 }
203
204 hal_timer_stop(index);
205 hal_timer_config_load(index, cycle);
206 hal_timer_start(index);
207 return cycle;
208 }
209
210 /*
211 * Searches through the timers to find the one with the lowest callback time
212 */
timer_set_next_timer_interrupt(timer_index_t index)213 STATIC void timer_set_next_timer_interrupt(timer_index_t index)
214 {
215 uint32_t irq_sts = osal_irq_lock();
216 hal_timer_stop(index);
217 uint32_t timer_found = timer_get_next_timer(index);
218 if (timer_found < g_timers_manager[index].soft_time_num) {
219 uint64_t cycle_with_mask;
220 #if defined(CONFIG_TIMER_USING_OLD_VERSION)
221 cycle_with_mask = g_timers_manager[index].timers[timer_found].cycle | TIMER_OLD_VERSION_LOAD_COUNT_MASK;
222 #else
223 cycle_with_mask = g_timers_manager[index].timers[timer_found].cycle;
224 #endif
225 hal_timer_config_load(index, cycle_with_mask);
226 hal_timer_start(index);
227 g_timers_manager[index].last_time_load_cycle = cycle_with_mask;
228 }
229 osal_irq_restore(irq_sts);
230 }
231
timer_int_callback(timer_index_t index)232 STATIC void timer_int_callback(timer_index_t index)
233 {
234 uint32_t irq_sts = osal_irq_lock();
235 g_timers_manager[index].in_timer_irq = true;
236 timer_update_timers_time(index, g_timers_manager[index].last_time_load_cycle);
237 g_timers_manager[index].last_time_load_cycle = 0;
238 osal_irq_restore(irq_sts);
239
240 while (timer_process_timers(index)) {
241 }
242
243 timer_set_next_timer_interrupt(index);
244 g_timers_manager[index].in_timer_irq = false;
245 }
246
soft_timer_list_cfg_get(uint32_t index,soft_timer_cfg_t * timer_info)247 STATIC errcode_t soft_timer_list_cfg_get(uint32_t index, soft_timer_cfg_t *timer_info)
248 {
249 switch (index) {
250 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_0)
251 case TIMER_SIZE_0:
252 timer_info->timer_num = CONFIG_TIMER_MAX_TIMERS_NUM_0;
253 timer_info->timer_addr = (uintptr_t)g_timerlist_0;
254 break;
255 #endif
256 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_1)
257 case TIMER_SIZE_1:
258 timer_info->timer_num = CONFIG_TIMER_MAX_TIMERS_NUM_1;
259 timer_info->timer_addr = (uintptr_t)g_timerlist_1;
260 break;
261 #endif
262 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_2)
263 case TIMER_SIZE_2:
264 timer_info->timer_num = CONFIG_TIMER_MAX_TIMERS_NUM_2;
265 timer_info->timer_addr = (uintptr_t)g_timerlist_2;
266 break;
267 #endif
268 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_3)
269 case TIMER_SIZE_3:
270 timer_info->timer_num = CONFIG_TIMER_MAX_TIMERS_NUM_3;
271 timer_info->timer_addr = (uintptr_t)g_timerlist_3;
272 break;
273 #endif
274
275 default:
276 #if defined(CONFIG_TIMER_MAX_NUM) && (CONFIG_TIMER_MAX_NUM > TIMER_SIZE_4)
277 timer_info->timer_num = CONFIG_TIMER_MAX_TIMERS_NUM_EXTRA;
278 timer_info->timer_addr = (uintptr_t)&g_timerlist_extra[index - CUR_MAX_HARDWARE_TIMER_NUM];
279 #endif
280 break;
281 }
282 if (memset_s((uint8_t *)timer_info->timer_addr, sizeof(timer_info_t) * timer_info->timer_num, 0,
283 sizeof(timer_info_t) * timer_info->timer_num) != EOK) {
284 return ERRCODE_MEMSET;
285 }
286 return ERRCODE_SUCC;
287 }
288
uapi_timer_init(void)289 errcode_t uapi_timer_init(void)
290 {
291 uint32_t irq_sts = osal_irq_lock();
292 if (g_timer_inited) {
293 osal_irq_restore(irq_sts);
294 return ERRCODE_SUCC;
295 }
296 if (memset_s(&g_timers_manager, sizeof(g_timers_manager), 0, sizeof(g_timers_manager)) != EOK) {
297 osal_irq_restore(irq_sts);
298 return ERRCODE_MEMSET;
299 }
300
301 #if defined(CONFIG_TIMER_SUPPORT_LPC)
302 timer_port_clock_enable(true);
303 #endif
304
305 for (uint32_t i = 0; i < CONFIG_TIMER_MAX_NUM; i++) {
306 soft_timer_cfg_t time_info;
307 uint32_t ret;
308 g_timer_adapted[i] = false;
309 ret = soft_timer_list_cfg_get(i, &time_info);
310 if (ret != ERRCODE_SUCC) {
311 osal_irq_restore(irq_sts);
312 return ret;
313 }
314 g_timers_manager[i].soft_time_num = time_info.timer_num;
315 g_timers_manager[i].timers = (timer_info_t *)time_info.timer_addr;
316 }
317
318 g_timer_inited = true;
319 osal_irq_restore(irq_sts);
320 return ERRCODE_SUCC;
321 }
322
uapi_timer_adapter(timer_index_t index,uint32_t int_id,uint16_t int_priority)323 errcode_t uapi_timer_adapter(timer_index_t index, uint32_t int_id, uint16_t int_priority)
324 {
325 uint32_t irq_sts = osal_irq_lock();
326 if (!g_timer_inited) {
327 osal_irq_restore(irq_sts);
328 return ERRCODE_TIMER_NOT_INIT;
329 }
330
331 if (g_timer_adapted[index]) {
332 osal_irq_restore(irq_sts);
333 return ERRCODE_SUCC;
334 }
335
336 errcode_t ret = hal_timer_init(index, timer_int_callback);
337 if (ret != ERRCODE_SUCC) {
338 osal_irq_restore(irq_sts);
339 return ret;
340 }
341
342 timer_port_register_irq(index, int_id, int_priority);
343
344 g_timers_manager[index].hw_timer_irq_id = int_id;
345 g_timers_manager[index].hw_timer_int_priority = int_priority;
346
347 g_timer_adapted[index] = true;
348 osal_irq_restore(irq_sts);
349 return ERRCODE_SUCC;
350 }
351
uapi_timer_deinit(void)352 errcode_t uapi_timer_deinit(void)
353 {
354 uint32_t irq_sts = osal_irq_lock();
355 if (!g_timer_inited) {
356 osal_irq_restore(irq_sts);
357 return ERRCODE_SUCC;
358 }
359
360 for (uint32_t i = 0; i < CONFIG_TIMER_MAX_NUM; i++) {
361 if (g_timer_adapted[i]) {
362 hal_timer_stop(i);
363 timer_port_unregister_irq(i, g_timers_manager[i].hw_timer_irq_id);
364 }
365 }
366
367 if (memset_s(&g_timers_manager, sizeof(g_timers_manager), 0, sizeof(g_timers_manager)) != EOK) {
368 osal_irq_restore(irq_sts);
369 return ERRCODE_MEMSET;
370 }
371
372 for (uint32_t i = 0; i < CONFIG_TIMER_MAX_NUM; i++) {
373 if (g_timer_adapted[i]) {
374 hal_timer_deinit(i);
375 }
376 }
377
378 #if defined(CONFIG_TIMER_SUPPORT_LPC)
379 timer_port_clock_enable(false);
380 #endif
381
382 g_timer_inited = false;
383 for (uint32_t i = 0; i < CONFIG_TIMER_MAX_NUM; i++) {
384 g_timer_adapted[i] = false;
385 }
386 osal_irq_restore(irq_sts);
387 return ERRCODE_SUCC;
388 }
389
uapi_timer_create(timer_index_t index,timer_handle_t * timer)390 errcode_t uapi_timer_create(timer_index_t index, timer_handle_t *timer)
391 {
392 if (timer == NULL) {
393 return ERRCODE_INVALID_PARAM;
394 }
395
396 uint32_t irq_sts = osal_irq_lock();
397 for (uint32_t i = 0; i < g_timers_manager[index].soft_time_num; i++) {
398 if (g_timers_manager[index].timers[i].enable == false) {
399 g_timers_manager[index].timers[i].enable = true;
400 g_timers_manager[index].timers[i].is_run = false;
401 g_timers_manager[index].timers[i].index = index;
402 g_timers_manager[index].timers[i].key = (timer_handle_t)&g_timers_manager[index].timers[i];
403
404 *timer = g_timers_manager[index].timers[i].key;
405 osal_irq_restore(irq_sts);
406 return ERRCODE_SUCC;
407 }
408 }
409
410 *timer = NULL;
411 osal_irq_restore(irq_sts);
412 return ERRCODE_TIMER_NO_ENOUGH;
413 }
414
uapi_timer_delete(timer_handle_t timer)415 errcode_t uapi_timer_delete(timer_handle_t timer)
416 {
417 if (timer == NULL) {
418 return ERRCODE_INVALID_PARAM;
419 }
420 timer_info_t *timer_info = (timer_info_t *)timer;
421 uint32_t irq_sts = osal_irq_lock();
422 timer_info->enable = false;
423 osal_irq_restore(irq_sts);
424 return ERRCODE_SUCC;
425 }
426
uapi_timer_get_max_us(void)427 uint32_t uapi_timer_get_max_us(void)
428 {
429 return timer_porting_cycle_2_us(UINT32_MAX);
430 }
431
uapi_timer_start(timer_handle_t timer,uint32_t time_us,timer_callback_t callback,uintptr_t data)432 errcode_t uapi_timer_start(timer_handle_t timer, uint32_t time_us, timer_callback_t callback, uintptr_t data)
433 {
434 timer_index_t index;
435
436 if (timer == NULL || callback == NULL || time_us == 0 || time_us > uapi_timer_get_max_us()) {
437 return ERRCODE_INVALID_PARAM;
438 }
439
440 timer_info_t *timer_info = (timer_info_t *)timer;
441 uint32_t irq_sts = osal_irq_lock();
442 if (timer_info->enable == false) {
443 osal_irq_restore(irq_sts);
444 return ERRCODE_TIEMR_NOT_CREATED;
445 }
446
447 uint64_t cycle;
448 #if defined(CONFIG_TIMER_USING_OLD_VERSION)
449 cycle = timer_porting_us_2_cycle(time_us) | TIMER_OLD_VERSION_LOAD_COUNT_MASK;
450 #else
451 cycle = timer_porting_us_2_cycle(time_us);
452 #endif
453 index = timer_info->index;
454 timer_info->cycle = cycle;
455 timer_info->callback = callback;
456 timer_info->data = data;
457
458 uint64_t remain_time_cycle = timer_get_time_till_interrupt(index);
459 if (cycle <= remain_time_cycle) {
460 if (remain_time_cycle != UINT64_MAX && g_timers_manager[index].last_time_load_cycle != 0) {
461 timer_update_timers_time(index, g_timers_manager[index].last_time_load_cycle - remain_time_cycle);
462 }
463 g_timers_manager[index].last_time_load_cycle = cycle;
464 hal_timer_stop(index);
465 hal_timer_config_load(index, cycle);
466 hal_timer_start(index);
467 } else {
468 timer_info->cycle += (g_timers_manager[index].last_time_load_cycle - remain_time_cycle);
469 }
470 timer_info->is_run = true;
471 osal_irq_restore(irq_sts);
472 return ERRCODE_SUCC;
473 }
474
uapi_timer_stop(timer_handle_t timer)475 errcode_t uapi_timer_stop(timer_handle_t timer)
476 {
477 if (timer == NULL) {
478 return ERRCODE_INVALID_PARAM;
479 }
480
481 timer_info_t *timer_info = (timer_info_t *)timer;
482
483 uint32_t irq_sts = osal_irq_lock();
484 if (unlikely(timer_info->enable == false)) {
485 osal_irq_restore(irq_sts);
486 return ERRCODE_TIEMR_NOT_CREATED;
487 }
488
489 if (unlikely(timer_info->is_run == false)) {
490 osal_irq_restore(irq_sts);
491 return ERRCODE_SUCC;
492 }
493
494 timer_info->is_run = false;
495 timer_info->cycle = 0;
496 timer_info->callback = NULL;
497 timer_info->data = 0;
498
499 /* 检查当前是否还有在运行的定时器, 若没有定时器则停止硬件计时 */
500 timer_index_t index = timer_info->index;
501 uint32_t next_timer = timer_get_next_timer(index);
502 if (next_timer >= g_timers_manager[index].soft_time_num) {
503 hal_timer_stop(index);
504 }
505 osal_irq_restore(irq_sts);
506 return ERRCODE_SUCC;
507 }
508
uapi_timer_get_current_time_us(timer_index_t index,uint32_t * current_time_us)509 errcode_t uapi_timer_get_current_time_us(timer_index_t index, uint32_t *current_time_us)
510 {
511 if (unlikely(index >= TIMER_MAX_NUM || current_time_us == NULL)) {
512 return ERRCODE_INVALID_PARAM;
513 }
514
515 uint32_t irq_sts = osal_irq_lock();
516 uint64_t current_value = hal_timer_get_current_value(index);
517 osal_irq_restore(irq_sts);
518 *current_time_us = timer_porting_cycle_2_us(current_value);
519 return ERRCODE_SUCC;
520 }
521
522 #if defined(CONFIG_TIMER_SUPPORT_LPM)
uapi_timer_suspend(uintptr_t val)523 errcode_t uapi_timer_suspend(uintptr_t val)
524 {
525 unused(val);
526 uint32_t int_sts = osal_irq_lock();
527 for (uint32_t index = 0; index < TIMER_MAX_NUM; index++) {
528 if (g_timer_adapted[index] == false) {
529 continue;
530 }
531 timer_update_timers_time(index,
532 g_timers_manager[index].last_time_load_cycle - hal_timer_get_current_value(index));
533 g_timers_manager[index].last_time_load_cycle = 0;
534 timer_set_next_timer_interrupt(index);
535 }
536 osal_irq_restore(int_sts);
537 return ERRCODE_SUCC;
538 }
539
uapi_timer_resume(uintptr_t val)540 errcode_t uapi_timer_resume(uintptr_t val)
541 {
542 uint32_t int_sts = osal_irq_lock();
543 uint64_t compansation_count = *(uint64_t *)val;
544 for (uint32_t index = 0; index < TIMER_MAX_NUM; index++) {
545 if (g_timer_adapted[index] == false) {
546 continue;
547 }
548 g_timers_manager[index].last_time_load_cycle = compansation_count;
549 hal_timer_stop(index);
550 hal_timer_config_load(index, timer_porting_us_2_cycle(1));
551 hal_timer_start(index);
552 }
553 osal_irq_restore(int_sts);
554 return ERRCODE_SUCC;
555 }
556 #endif /* CONFIG_TIMER_SUPPORT_LPM */