1 // Copyright (C) 2022 Beken Corporation
2 //
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 #include <common/bk_include.h>
16 #include <os/mem.h>
17 #include "string.h"
18
19 #include <driver/int.h>
20 #include "sys_driver.h"
21
22 #include <driver/aon_rtc.h>
23 #include "aon_rtc_hal.h"
24 #include "aon_rtc_driver.h"
25
26 #define AON_RTC_UNIT_NUM (AON_RTC_HAL_UNIT_NUM)
27 #define AON_RTC_NAME ((uint8_t *)"aon_rtc")
28
29 typedef struct {
30 //aon_rtc_id_t id; //no needs it until now:the id is matched from APP,DRIVER,HAL,HW/SOC layer.
31 bool inited;
32 //uint8_t using_cnt; //remove it as only one HW can't for many APPs
33
34 aon_rtc_hal_t hal;
35
36 //Record APP param's
37 //bool period;
38 //uint32_t tick;
39
40 //Alarm list
41 alarm_node_t *alarm_head_p;
42 uint32_t alarm_node_cnt;
43 } aon_rtc_driver_t;
44
45 typedef struct {
46 aon_rtc_isr_t callback;
47 void *isr_param;
48 } aon_rtc_callback_t;
49
50 typedef struct {
51 alarm_node_t nodes[AON_RTC_MAX_ALARM_CNT];
52 uint64_t busy_bits;
53 } aon_rtc_nodes_memory_t;
54
55 static aon_rtc_driver_t s_aon_rtc[AON_RTC_UNIT_NUM] = {0};
56 static aon_rtc_callback_t s_aon_rtc_tick_isr[AON_RTC_UNIT_NUM] = {NULL};
57 static aon_rtc_callback_t s_aon_rtc_upper_isr[AON_RTC_UNIT_NUM] = {NULL};
58 static aon_rtc_nodes_memory_t *s_aon_rtc_nodes_p[AON_RTC_UNIT_NUM];
59 static uint64_t s_high_tick[AON_RTC_UNIT_NUM];
60
alarm_dump_node(alarm_node_t * node_p)61 static void alarm_dump_node(alarm_node_t *node_p)
62 {
63 #if AON_RTC_DEBUG
64 AON_RTC_LOGD("%s[+]\r\n", __func__);
65
66 AON_RTC_LOGD("node_p=0x%x\r\n", node_p);
67 if(node_p)
68 {
69 AON_RTC_LOGD("next=0x%x\r\n", node_p->next);
70 AON_RTC_LOGD("name=%s\r\n", node_p->name);
71 AON_RTC_LOGD("period_tick=0x%x\r\n", node_p->period_tick);
72 AON_RTC_LOGD("period_cnt=%d\r\n", node_p->period_cnt);
73 AON_RTC_LOGD("start_tick=0x%x\r\n", node_p->start_tick);
74 AON_RTC_LOGD("expired_tick=0x%x\r\n", node_p->expired_tick);
75 }
76
77 AON_RTC_LOGD("%s[-]\r\n", __func__);
78 #endif
79 }
80
alarm_dump_list(alarm_node_t * head_p)81 static void alarm_dump_list(alarm_node_t *head_p)
82 {
83 #if AON_RTC_DEBUG
84 alarm_node_t *cur_p = head_p;
85 uint32_t count = 0;
86 uint32_t int_level = 0;
87
88 AON_RTC_LOGD("%s[+]\r\n", __func__);
89
90 int_level = rtos_disable_int();
91 while(cur_p)
92 {
93 alarm_dump_node(cur_p);
94 count++;
95
96 cur_p = cur_p->next;
97 }
98 rtos_enable_int(int_level);
99
100 AON_RTC_LOGD("node cnt=%d\r\n", count);
101
102 AON_RTC_LOGD("%s[-]\r\n", __func__);
103 #endif
104 }
105
aon_rtc_request_node(aon_rtc_id_t id)106 static alarm_node_t* aon_rtc_request_node(aon_rtc_id_t id)
107 {
108 uint32_t i = 0;
109
110 AON_RTC_LOGD("%s[+]\r\n", __func__);
111
112 for(i = 0; i < AON_RTC_MAX_ALARM_CNT; i++)
113 {
114 if((s_aon_rtc_nodes_p[id]->busy_bits & (0x1<<i)) == 0)
115 {
116 AON_RTC_LOGD("%s[-]:node[%d]=0x%x\r\n", __func__, i, &s_aon_rtc_nodes_p[id]->nodes[i]);
117 s_aon_rtc_nodes_p[id]->busy_bits |= (0x1<<i);
118 return &s_aon_rtc_nodes_p[id]->nodes[i];
119 }
120 }
121
122 return NULL;
123 }
124
aon_rtc_release_node(aon_rtc_id_t id,alarm_node_t * node_p)125 static void aon_rtc_release_node(aon_rtc_id_t id, alarm_node_t *node_p)
126 {
127 uint32_t i = 0;
128
129 AON_RTC_LOGD("%s[+]\r\n", __func__);
130
131 for(i = 0; i < AON_RTC_MAX_ALARM_CNT; i++)
132 {
133 if(&s_aon_rtc_nodes_p[id]->nodes[i] == node_p)
134 {
135 s_aon_rtc_nodes_p[id]->busy_bits &= ~(0x1<<i);
136 os_memset(&s_aon_rtc_nodes_p[id]->nodes[i], 0, sizeof(alarm_info_t));
137 AON_RTC_LOGD("%s[-]:node[%d]=0x%x\r\n", __func__, i, &s_aon_rtc_nodes_p[id]->nodes[i]);
138 break;
139 }
140 }
141
142 BK_ASSERT(i < AON_RTC_MAX_ALARM_CNT);
143 }
144
alarm_insert_node(aon_rtc_id_t id,alarm_node_t * node_p)145 static int32_t alarm_insert_node(aon_rtc_id_t id, alarm_node_t *node_p)
146 {
147 alarm_node_t *cur_p = NULL;
148 alarm_node_t *next_p = NULL;
149 uint32_t int_level = 0;
150
151 AON_RTC_LOGD("%s[+]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
152
153 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
154
155 int_level = rtos_disable_int();
156
157 //check whether the same name
158 cur_p = s_aon_rtc[id].alarm_head_p;
159 while(cur_p)
160 {
161 if(strncmp((const char *)cur_p->name, (const char *)node_p->name, ALARM_NAME_MAX_LEN) == 0)
162 {
163 AON_RTC_LOGE("name=%s has registered\r\n", node_p->name);
164 rtos_enable_int(int_level);
165 return -1;
166 }
167
168 cur_p = cur_p->next;
169 }
170
171 //search the node position
172 cur_p = s_aon_rtc[id].alarm_head_p;
173
174 //no node
175 if(cur_p == NULL)
176 {
177 s_aon_rtc[id].alarm_head_p = node_p;
178 s_aon_rtc[id].alarm_node_cnt++;
179 AON_RTC_LOGD("insert first node 0x%x,name=%s\r\n", node_p, node_p->name);
180
181 rtos_enable_int(int_level);
182 return 0;
183 }
184
185 //only one node
186 next_p = cur_p->next;
187 if(next_p == NULL)
188 {
189 if(cur_p->expired_tick <= node_p->expired_tick)
190 cur_p->next = node_p;
191 else
192 {
193 node_p->next = cur_p;
194 s_aon_rtc[id].alarm_head_p = node_p;
195 }
196 s_aon_rtc[id].alarm_node_cnt++;
197 rtos_enable_int(int_level);
198
199 //TODO:log debug
200 AON_RTC_LOGD("list total has two nodes\r\n");
201
202 return 0;
203 }
204
205 //more then 2 nodes
206 while(next_p)
207 {
208 if(cur_p->expired_tick <= node_p->expired_tick) //move after cur_p
209 {
210 if(next_p->expired_tick <= node_p->expired_tick) //search next
211 {
212 cur_p = next_p;
213 next_p = next_p->next;
214 continue;
215 }
216 else //insert
217 {
218 node_p->next = next_p;
219 cur_p->next = node_p;
220 s_aon_rtc[id].alarm_node_cnt++;
221 rtos_enable_int(int_level);
222 return 0;
223 }
224 }
225 else //insert before cur_p, means the first node, head
226 {
227 node_p->next = cur_p;
228 s_aon_rtc[id].alarm_head_p = node_p;
229 s_aon_rtc[id].alarm_node_cnt++;
230 rtos_enable_int(int_level);
231 return 0;
232 }
233 }
234
235 //the last one
236 cur_p->next = node_p;
237 s_aon_rtc[id].alarm_node_cnt++;
238 rtos_enable_int(int_level);
239
240 //dump list info
241 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
242
243 AON_RTC_LOGD("%s[-]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
244
245 return 0;
246 }
247
alarm_remove_node(aon_rtc_id_t id,uint8_t * name_p)248 static alarm_node_t *alarm_remove_node(aon_rtc_id_t id, uint8_t *name_p)
249 {
250 alarm_node_t *cur_p = NULL;
251 alarm_node_t *previous_p = NULL;
252 alarm_node_t *remove_node_p = NULL;
253 uint32_t int_level = 0;
254 uint32_t node_cnt = 0;
255
256 AON_RTC_LOGD("%s[+]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
257
258 int_level = rtos_disable_int();
259 //
260 previous_p = cur_p = s_aon_rtc[id].alarm_head_p;
261 while(cur_p)
262 {
263 //double check pointer is valid
264 node_cnt++;
265 BK_ASSERT(node_cnt <= AON_RTC_MAX_ALARM_CNT);
266
267 if(strncmp((const char *)cur_p->name, (const char *)name_p, ALARM_NAME_MAX_LEN) == 0)
268 {
269 //first one
270 if(previous_p == cur_p)
271 {
272 remove_node_p = s_aon_rtc[id].alarm_head_p;
273 s_aon_rtc[id].alarm_head_p = cur_p->next;
274 s_aon_rtc[id].alarm_node_cnt--;
275
276 AON_RTC_LOGD("free=0x%x,name=%s\r\n", cur_p, cur_p->name);
277 aon_rtc_release_node(id, cur_p);
278 break;
279 }
280 else
281 {
282 remove_node_p = cur_p;
283 previous_p->next = cur_p->next;
284 s_aon_rtc[id].alarm_node_cnt--;
285 AON_RTC_LOGD("free=0x%x,name=%s\r\n", cur_p, cur_p->name);
286 aon_rtc_release_node(id, cur_p);
287 break;
288 }
289 }
290
291 previous_p = cur_p;
292 cur_p = cur_p->next;
293 }
294
295 rtos_enable_int(int_level);
296
297 if(remove_node_p == NULL)
298 {
299 AON_RTC_LOGE("%s:can't find %s alarm\r\n", __func__, name_p);
300 }
301
302 //dump list info
303 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
304
305 AON_RTC_LOGD("%s[-]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
306
307 return remove_node_p;
308 }
309
alarm_update_expeired_nodes(aon_rtc_id_t id)310 static void alarm_update_expeired_nodes(aon_rtc_id_t id)
311 {
312 alarm_node_t *cur_p = NULL;
313 alarm_node_t *next_p = NULL;
314 uint32_t node_cnt = 0;
315 uint64_t cur_tick = 0;
316 uint32_t int_level = 0;
317
318 AON_RTC_LOGD("%s[+]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
319
320 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
321
322 int_level = rtos_disable_int();
323
324 //search the node position
325 cur_p = s_aon_rtc[id].alarm_head_p;
326 while(cur_p)
327 {
328 alarm_dump_node(cur_p);
329 alarm_dump_node(cur_p->next);
330
331 //double check pointer is valid
332 node_cnt++;
333 BK_ASSERT(node_cnt <= AON_RTC_MAX_ALARM_CNT);
334
335 next_p = cur_p->next;
336
337 cur_tick = bk_aon_rtc_get_current_tick(id);
338 //maybe callback runs too much time,so assume the time in AON_RTC_MS_TICK_CNT means has expired
339 if(cur_p->expired_tick <= cur_tick + AON_RTC_PRECISION_TICK)
340 {
341 if(cur_p->callback)
342 {
343 cur_p->callback(id, cur_p->name, cur_p->cb_param_p);
344 }
345
346 //last time alarm
347 if(cur_p->period_cnt == 1)
348 {
349 cur_p->period_cnt = 0;
350 s_aon_rtc[id].alarm_head_p = cur_p->next; //head move to next
351 s_aon_rtc[id].alarm_node_cnt--;
352 /*
353 * WARNING:As freertos doesn't support free memory in ISR context.
354 * The chip no needs to use a task for AON RTC which wastes some memory.
355 * so the APPLIACTION who calls bk_alarm_register should release the memory
356 * returns by bk_alarm_register.
357 */
358 #if 0
359 AON_RTC_LOGD("last alarm:free=0x%x,name=%s\r\n", cur_p, cur_p->name);
360 os_free(cur_p);
361 #endif
362 aon_rtc_release_node(id, cur_p);
363 }
364 //loop timer
365 else
366 {
367 if(cur_p->period_cnt != ALARM_LOOP_FOREVER)
368 {
369 cur_p->period_cnt--;
370 AON_RTC_LOGD("%s left %d times \r\n", cur_p->name, cur_p->period_cnt);
371 }
372
373 //has next
374 if(next_p) //move to switable position
375 {
376 s_aon_rtc[id].alarm_head_p = cur_p->next; //head move to next
377 cur_p->expired_tick += cur_p->period_tick;
378 cur_p->next = NULL; //cur_p is removed
379 s_aon_rtc[id].alarm_node_cnt--; //it will ++ in alarm_insert_node
380 if(alarm_insert_node(id, cur_p) != 0)
381 {
382 AON_RTC_LOGE("alarm name=%s insert fail\r\n", cur_p->name);
383 rtos_enable_int(int_level);
384 return;
385 }
386 }
387 else //only self
388 {
389 //just update self expired time
390 cur_p->expired_tick += cur_p->period_tick;
391 AON_RTC_LOGD("%s update next expired time %d \r\n", cur_p->name, cur_p->expired_tick);
392 }
393 }
394 }
395 else //no expired
396 {
397 break;
398 }
399
400 cur_p = next_p; //TODO:maybe cur_p offset is too small and calback excutes too much time, here can't switch to next NODE.
401
402 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
403 }
404
405 rtos_enable_int(int_level);
406
407 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
408
409 AON_RTC_LOGD("%s[-]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
410 }
411
bk_aon_rtc_register_tick_isr(aon_rtc_id_t id,aon_rtc_isr_t isr,void * param)412 bk_err_t bk_aon_rtc_register_tick_isr(aon_rtc_id_t id, aon_rtc_isr_t isr, void *param)
413 {
414 //AON_RTC_RETURN_ON_INVALID_ID(id);
415 uint32_t int_level = rtos_disable_int();
416 s_aon_rtc_tick_isr[id].callback = isr;
417 s_aon_rtc_tick_isr[id].isr_param = param;
418 rtos_enable_int(int_level);
419 return BK_OK;
420 }
421
422 /*
423 * aon rtc set tick uses 3 cycles of 32k in ASIC,
424 * cpu should check whether set tick success.
425 * If twice set tick in 3/32 ms, the second time set tick value will be failed.
426 */
aon_rtc_set_tick(aon_rtc_hal_t * hal,uint32_t val)427 static void aon_rtc_set_tick(aon_rtc_hal_t *hal, uint32_t val)
428 {
429 volatile int i = 0;
430
431 aon_rtc_hal_set_tick_val(hal, val);
432 while(aon_rtc_hal_get_tick_val_lpo(hal) != val)
433 {
434 i++;
435 if(i > 768) //32k, 3ticks == 3/32 ms:++is 30 cycles
436 {
437 AON_RTC_LOGE("%s:set tick timeout\r\n", __func__);
438 break;
439 }
440 }
441 }
442
bk_aon_rtc_register_upper_isr(aon_rtc_id_t id,aon_rtc_isr_t isr,void * param)443 bk_err_t bk_aon_rtc_register_upper_isr(aon_rtc_id_t id, aon_rtc_isr_t isr, void *param)
444 {
445 //AON_RTC_RETURN_ON_INVALID_ID(id);
446 uint32_t int_level = rtos_disable_int();
447 s_aon_rtc_upper_isr[id].callback = isr;
448 s_aon_rtc_upper_isr[id].isr_param = param;
449 rtos_enable_int(int_level);
450 return BK_OK;
451 }
452
453 #if 0
454 static bk_err_t aon_rtc_isr_handler(aon_rtc_id_t id)
455 {
456 //uses tick as one time timer
457 if(aon_rtc_hal_get_tick_int_status(&s_aon_rtc[id].hal))
458 {
459 if (s_aon_rtc_tick_isr[id].callback) {
460 s_aon_rtc_tick_isr[id].callback(id, AON_RTC_NAME, s_aon_rtc_tick_isr[id].isr_param);
461 }
462 aon_rtc_hal_clear_tick_int_status(&s_aon_rtc[id].hal);
463
464 bk_aon_rtc_destroy(id);
465 }
466
467 //uses upper timer as period timer
468 if(aon_rtc_hal_get_upper_int_status(&s_aon_rtc[id].hal))
469 {
470 if (s_aon_rtc_upper_isr[id].callback) {
471 s_aon_rtc_upper_isr[id].callback(id, AON_RTC_NAME, s_aon_rtc_upper_isr[id].isr_param);
472 }
473
474 aon_rtc_hal_clear_upper_int_status(&s_aon_rtc[id].hal);
475 }
476
477 //TODO: clear NVIC/INTC/PLIC int pending status
478
479 return BK_OK;
480 }
481 #else
482
483 #if AON_RTC_DEBUG
484 #define AON_RTC_ISR_DEBUG_MAX_CNT (256)
485 static uint32_t s_isr_cnt = 0;
486 static uint32_t s_isr_debug_in_tick[AON_RTC_ISR_DEBUG_MAX_CNT];
487 static uint32_t s_isr_debug_out_tick[AON_RTC_ISR_DEBUG_MAX_CNT];
488 static uint32_t s_isr_debug_set_tick[AON_RTC_ISR_DEBUG_MAX_CNT];
489 #endif
aon_rtc_isr_handler(aon_rtc_id_t id)490 static bk_err_t aon_rtc_isr_handler(aon_rtc_id_t id)
491 {
492 uint32_t int_level = rtos_disable_int();
493
494 #if AON_RTC_DEBUG
495 s_isr_debug_in_tick[(s_isr_cnt)%AON_RTC_ISR_DEBUG_MAX_CNT] = bk_aon_rtc_get_current_tick(id);
496 #endif
497
498 AON_RTC_LOGD("%s[+]\r\n", __func__);
499
500 //uses tick as one time timer
501 if(aon_rtc_hal_get_tick_int_status(&s_aon_rtc[id].hal))
502 {
503 //maybe the isr callback runs too much time and set next tick value too small, caused next isr can't response.
504 aon_rtc_hal_clear_tick_int_status(&s_aon_rtc[id].hal);
505
506 alarm_update_expeired_nodes(id);
507
508 //reset the timer tick
509 if(s_aon_rtc[id].alarm_head_p)
510 {
511 //+1:to assume set it valid,maybe aon rtc add 1 tick when set the value now.
512 BK_ASSERT(bk_aon_rtc_get_current_tick(id) + 1/*AON_RTC_PRECISION_TICK*/ < s_aon_rtc[id].alarm_head_p->expired_tick); //4:reserve enough time to set the tick
513 aon_rtc_set_tick(&s_aon_rtc[id].hal, (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick);
514 #if AON_RTC_DEBUG
515 s_isr_debug_set_tick[(s_isr_cnt)%AON_RTC_ISR_DEBUG_MAX_CNT] = (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick;
516 #endif
517 AON_RTC_LOGD("next tick=0x%x, cur_tick=0x%x\r\n", (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick, (uint32_t)bk_aon_rtc_get_current_tick(id));
518 }
519 else
520 {
521 aon_rtc_set_tick(&s_aon_rtc[id].hal, AON_RTC_ROUND_TICK);
522 AON_RTC_LOGI("no alarm:cur_tick=0x%x\r\n", (uint32_t)bk_aon_rtc_get_current_tick(id));
523 }
524 }
525
526 //uses upper timer as period timer
527 if(aon_rtc_hal_get_upper_int_status(&s_aon_rtc[id].hal))
528 {
529 s_high_tick[id]++;
530 AON_RTC_LOGI("32bits data overflow:high_tick=%d\r\n", s_high_tick[id]);
531 if (s_aon_rtc_upper_isr[id].callback) {
532 s_aon_rtc_upper_isr[id].callback(id, AON_RTC_NAME, s_aon_rtc_upper_isr[id].isr_param);
533 }
534
535 aon_rtc_hal_clear_upper_int_status(&s_aon_rtc[id].hal);
536 }
537
538 //TODO: clear NVIC/INTC/PLIC int pending status
539
540 AON_RTC_LOGD("%s[-]\r\n", __func__);
541 #if AON_RTC_DEBUG
542 s_isr_debug_out_tick[(s_isr_cnt)%AON_RTC_ISR_DEBUG_MAX_CNT] = bk_aon_rtc_get_current_tick(id);
543 s_isr_cnt++;
544 #endif
545 rtos_enable_int(int_level);
546
547 return BK_OK;
548 }
549
550 #endif
551
aon_rtc1_isr_handler(void)552 static void aon_rtc1_isr_handler(void)
553 {
554 aon_rtc_isr_handler(AON_RTC_ID_1);
555 }
556
557 #if (SOC_AON_RTC_UNIT_NUM > 1)
aon_rtc2_isr_handler(void)558 static void aon_rtc2_isr_handler(void)
559 {
560 aon_rtc_isr_handler(AON_RTC_ID_2);
561 }
562 #endif
563
564 #if (CONFIG_SYSTEM_CTRL)
aon_rtc_interrupt_enable(aon_rtc_id_t id)565 static void aon_rtc_interrupt_enable(aon_rtc_id_t id)
566 {
567 switch(id)
568 {
569 case AON_RTC_ID_1:
570 sys_drv_int_group2_enable(RTC_INTERRUPT_CTRL_BIT);
571 break;
572 #if (SOC_AON_RTC_UNIT_NUM > 1)
573 case AON_RTC_ID_2:
574 sys_drv_int_group2_enable(RTC1_INTERRUPT_CTRL_BIT);
575 break;
576 #endif
577 default:
578 break;
579 }
580 }
581
aon_rtc_interrupt_disable(aon_rtc_id_t id)582 static void aon_rtc_interrupt_disable(aon_rtc_id_t id)
583 {
584 switch(id)
585 {
586 case AON_RTC_ID_1:
587 sys_drv_int_group2_disable(RTC_INTERRUPT_CTRL_BIT);
588 break;
589 #if (SOC_AON_RTC_UNIT_NUM > 1)
590 case AON_RTC_ID_2:
591 sys_drv_int_group2_disable(RTC1_INTERRUPT_CTRL_BIT);
592 break;
593 #endif
594 default:
595 break;
596 }
597 }
598 #endif
599
600 //run from 0
601 #if 0
602 static void aon_rtc_start_run(aon_rtc_id_t id)
603 {
604 extern void delay_10us(UINT32 count);
605
606 AON_RTC_LOGD("%s[+]\r\n", __func__);
607
608 //start to run
609 aon_rtc_hal_start_counter(&s_aon_rtc[id].hal);
610 aon_rtc_hal_reset_counter(&s_aon_rtc[id].hal); //maybe the start value isn't 0
611 delay_10us(4); //one cycle of 32k
612 aon_rtc_hal_clear_reset_counter(&s_aon_rtc[id].hal);
613
614 AON_RTC_LOGD("%s[-]\r\n", __func__);
615 }
616 #endif
617
aon_rtc_sw_init(aon_rtc_id_t id)618 static bk_err_t aon_rtc_sw_init(aon_rtc_id_t id)
619 {
620 os_memset(&s_aon_rtc[id], 0, sizeof(s_aon_rtc[id]));
621 os_memset(&s_aon_rtc_tick_isr[id], 0, sizeof(s_aon_rtc_tick_isr[id]));
622 os_memset(&s_aon_rtc_upper_isr[id], 0, sizeof(s_aon_rtc_upper_isr[id]));
623
624 s_high_tick[id] = 0;
625
626 s_aon_rtc_nodes_p[id] = os_zalloc(sizeof(aon_rtc_nodes_memory_t));
627 if(s_aon_rtc_nodes_p[id] == NULL)
628 {
629 return BK_ERR_NO_MEM;
630 }
631
632 return BK_OK;
633 }
634
aon_rtc_hw_init(aon_rtc_id_t id)635 static void aon_rtc_hw_init(aon_rtc_id_t id)
636 {
637 aon_rtc_int_config_t int_config_table[] = AON_RTC_INT_CONFIG_TABLE;
638 aon_rtc_int_config_t *cur_int_cfg = &int_config_table[id];
639
640 aon_rtc_hal_init(&s_aon_rtc[id].hal);
641
642 //set upper to max value
643 aon_rtc_hal_set_upper_val(&s_aon_rtc[id].hal, AON_RTC_ROUND_TICK);
644 aon_rtc_hal_enable_upper_int(&s_aon_rtc[id].hal);
645
646 bk_int_isr_register(cur_int_cfg->int_src, cur_int_cfg->isr, NULL);
647 #if (CONFIG_SYSTEM_CTRL)
648 aon_rtc_interrupt_enable(id);
649 #endif
650 aon_rtc_hal_start_counter(&s_aon_rtc[id].hal);
651 }
652
bk_aon_rtc_driver_init(void)653 bk_err_t bk_aon_rtc_driver_init(void)
654 {
655
656 AON_RTC_LOGD("%s[+]\r\n", __func__);
657
658 //TOTO: Enter critical protect
659 for (int id = AON_RTC_ID_1; id < AON_RTC_ID_MAX; id++) {
660 if(!s_aon_rtc[id].inited)
661 {
662 aon_rtc_sw_init(id);
663 aon_rtc_hw_init(id);
664 s_aon_rtc[id].inited = true;
665 }
666 }
667
668 //TOTO: exit critical protect
669 AON_RTC_LOGD("%s[-]\r\n", __func__);
670
671 return BK_OK;
672 }
673
bk_aon_rtc_driver_deinit(void)674 bk_err_t bk_aon_rtc_driver_deinit(void)
675 {
676 aon_rtc_int_config_t int_cfg_table[] = AON_RTC_INT_CONFIG_TABLE;
677
678 AON_RTC_LOGD("%s[+]\r\n", __func__);
679
680 for (int id = AON_RTC_ID_1; id < AON_RTC_ID_MAX; id++) {
681 if(s_aon_rtc[id].inited)
682 {
683 bk_int_isr_unregister(int_cfg_table[id].int_src);
684 #if (CONFIG_SYSTEM_CTRL)
685 aon_rtc_interrupt_disable(id);
686 #endif
687 if(s_aon_rtc_nodes_p[id] != NULL)
688 {
689 os_free(s_aon_rtc_nodes_p[id]);
690 s_aon_rtc_nodes_p[id] = NULL;
691 }
692
693 s_aon_rtc[id].inited = false;
694 }
695 }
696
697 AON_RTC_LOGD("%s[-]\r\n", __func__);
698 return BK_OK;
699 }
700
701 #if 0 //remove it, only one HW can't be used for many APPs.
702 bk_err_t bk_aon_rtc_create(aon_rtc_id_t id, uint32_t tick, bool period)
703 {
704 //Avoid APP call this function before driver has done bk_aon_rtc_driver_init
705 if(s_aon_rtc[id].inited == false)
706 {
707 //TODO: logs: call aon_rtc_init first.
708 return BK_ERR_NOT_INIT;
709 }
710
711 if(s_aon_rtc[id].using_cnt)
712 {
713 //TODO: logs: call bk_aon_rtc_destroy first.
714 return BK_ERR_BUSY;
715 }
716
717 //TOTO: Enter critical protect
718
719 s_aon_rtc[id].using_cnt++;
720 s_aon_rtc[id].tick = tick;
721 s_aon_rtc[id].period = period;
722
723 //init HW
724 s_aon_rtc[id].hal.id = id;
725 aon_rtc_hal_init(&s_aon_rtc[id].hal);
726
727 if(period) //use upper value int
728 {
729 aon_rtc_hal_set_upper_val(&s_aon_rtc[id].hal, tick);
730 aon_rtc_hal_enable_upper_int(&s_aon_rtc[id].hal);
731 }
732 else
733 {
734 //confirm tick val <= upper value, or tick int never be entry.
735 aon_rtc_hal_set_upper_val(&s_aon_rtc[id].hal, AON_RTC_UPPER_VAL_MAX);
736
737 aon_rtc_set_tick(&s_aon_rtc[id].hal, tick);
738 aon_rtc_hal_enable_tick_int(&s_aon_rtc[id].hal);
739 }
740
741 //start to run
742 aon_rtc_start_run(id);
743
744 //TOTO: Exit critical protect
745
746 return BK_OK;
747 }
748
749 bk_err_t bk_aon_rtc_destroy(aon_rtc_id_t id)
750 {
751 //TOTO: Enter critical protect
752
753 if(s_aon_rtc[id].inited == false)
754 {
755 //TODO: logs: call aon_rtc_init first.
756 //TOTO: Exit critical protect
757 return BK_ERR_NOT_INIT;
758 }
759
760 if(s_aon_rtc[id].using_cnt == 0)
761 {
762 //TODO: logs: call bk_aon_rtc_create first.
763 //TOTO: Exit critical protect
764 return BK_ERR_NOT_INIT;
765 }
766
767 //stop HW before SW change value, avoid ISR status was update to INTC/NVIC/PLIC...
768 //but doesn't response ISR, after HW deinit, the ISR comes caused error.
769 aon_rtc_hal_deinit(&s_aon_rtc[id].hal);
770
771 s_aon_rtc[id].using_cnt = 0;
772 s_aon_rtc[id].tick = 0;
773 s_aon_rtc[id].period = false;
774
775 //TOTO: Exit critical protect
776
777 return BK_OK;
778 }
779 #endif
780
bk_alarm_register(aon_rtc_id_t id,alarm_info_t * alarm_info_p)781 bk_err_t bk_alarm_register(aon_rtc_id_t id, alarm_info_t *alarm_info_p)
782 {
783 alarm_node_t *node_p = NULL;
784 uint32_t int_level = 0;
785
786 AON_RTC_LOGD("%s[+]\r\n", __func__);
787
788 if(id >= AON_RTC_ID_MAX)
789 {
790 AON_RTC_LOGE("%s:id=%d\r\n", __func__, id);
791 return BK_ERR_PARAM;
792 }
793
794 if(alarm_info_p == NULL)
795 {
796 return BK_ERR_PARAM;
797 }
798
799 if(alarm_info_p->period_tick < AON_RTC_PRECISION_TICK) //in protect area to reduce consume time before set tick.
800 {
801 AON_RTC_LOGE("period_tick should not smaller then %d\r\n", AON_RTC_PRECISION_TICK);
802 return BK_FAIL;
803 }
804
805 int_level = rtos_disable_int();
806
807 if(s_aon_rtc[id].alarm_node_cnt >= AON_RTC_MAX_ALARM_CNT)
808 {
809 rtos_enable_int(int_level);
810 AON_RTC_LOGE("alarm registered too much:%d\r\n", AON_RTC_MAX_ALARM_CNT);
811 return BK_FAIL;
812 }
813
814 //request a node
815 node_p = aon_rtc_request_node(id);
816 if(node_p == NULL)
817 {
818 rtos_enable_int(int_level);
819 AON_RTC_LOGE("alarm registered:no memory\r\n");
820 return BK_ERR_NO_MEM;
821 }
822
823 memset(node_p, 0, sizeof(alarm_node_t));
824 node_p->callback = alarm_info_p->callback;
825 node_p->cb_param_p = alarm_info_p->param_p;
826 memcpy(&node_p->name[0], alarm_info_p->name, ALARM_NAME_MAX_LEN);
827 node_p->name[ALARM_NAME_MAX_LEN] = 0;
828 node_p->start_tick = bk_aon_rtc_get_current_tick(id); //tick
829 node_p->period_tick = alarm_info_p->period_tick;
830 BK_ASSERT(alarm_info_p->period_cnt);
831 node_p->period_cnt = alarm_info_p->period_cnt;
832 node_p->expired_tick = node_p->start_tick + (alarm_info_p->period_tick);
833
834 //push to alarm list
835 if(alarm_insert_node(id, node_p) != 0)
836 {
837 AON_RTC_LOGE("alarm name=%s has registered\r\n", alarm_info_p->name);
838 aon_rtc_release_node(id, node_p);
839 rtos_enable_int(int_level);
840 return BK_FAIL;
841 }
842
843 //reset the timer tick
844 if(node_p == s_aon_rtc[id].alarm_head_p) //insert node is the first one, should reset tick val
845 {
846 //+1:to assume set it valid,maybe aon rtc add 1 tick when set the value now.
847 BK_ASSERT(bk_aon_rtc_get_current_tick(id) + 1/*AON_RTC_PRECISION_TICK*/ < s_aon_rtc[id].alarm_head_p->expired_tick); //4:reserve enough time to set the tick
848 aon_rtc_set_tick(&s_aon_rtc[id].hal, (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick);
849 }
850
851 aon_rtc_hal_enable_tick_int(&s_aon_rtc[id].hal);
852 AON_RTC_LOGD("next tick=0x%x, cur_tick=0x%x\r\n", (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick, (uint32_t)bk_aon_rtc_get_current_tick(id));
853
854 rtos_enable_int(int_level);
855
856 AON_RTC_LOGD("%s[-]\r\n", __func__);
857
858 return BK_OK;
859 }
860
861
862 //the timer isn't expired, but app un-register it.
bk_alarm_unregister(aon_rtc_id_t id,uint8_t * name_p)863 bk_err_t bk_alarm_unregister(aon_rtc_id_t id, uint8_t *name_p)
864 {
865 alarm_node_t *remove_node_p = NULL;
866 alarm_node_t *previous_head_node_p = NULL;
867 uint32_t int_level = 0;
868
869 AON_RTC_LOGD("%s[+]\r\n", __func__);
870
871 if(id >= AON_RTC_ID_MAX)
872 {
873 AON_RTC_LOGE("%s:id=%d\r\n", __func__, id);
874 return BK_ERR_PARAM;
875 }
876
877 int_level = rtos_disable_int();
878 previous_head_node_p = s_aon_rtc[id].alarm_head_p;
879 remove_node_p = alarm_remove_node(id, name_p);
880
881 //reset the timer tick
882 if(previous_head_node_p == remove_node_p) //the previous head is removed
883 {
884 if(s_aon_rtc[id].alarm_head_p) //new head exist
885 {
886 //+1:to assume set it valid,maybe aon rtc add 1 tick when set the value now.
887 BK_ASSERT(bk_aon_rtc_get_current_tick(id) + 1/*AON_RTC_PRECISION_TICK*/ < s_aon_rtc[id].alarm_head_p->expired_tick); //reserve enough time to set the tick
888 aon_rtc_set_tick(&s_aon_rtc[id].hal, (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick);
889 AON_RTC_LOGD("next tick=0x%x, cur_tick=0x%x\r\n", s_aon_rtc[id].alarm_head_p->expired_tick, bk_aon_rtc_get_current_tick(id));
890 }
891 else //has no nodes now
892 {
893 aon_rtc_set_tick(&s_aon_rtc[id].hal, AON_RTC_ROUND_TICK);
894 AON_RTC_LOGI("no alarm:cur_tick=0x%x\r\n", bk_aon_rtc_get_current_tick(id));
895 }
896 }
897
898 rtos_enable_int(int_level);
899
900 AON_RTC_LOGD("%s[-]\r\n", __func__);
901 return BK_OK;
902 }
903
904 #if (CONFIG_AON_RTC && (!CONFIG_AON_RTC_MANY_USERS))
bk_aon_rtc_tick_init()905 bk_err_t bk_aon_rtc_tick_init()
906 {
907 aon_rtc_hal_tick_init();
908 return BK_OK;
909 }
bk_aon_rtc_open_rtc_wakeup(uint32_t period)910 bk_err_t bk_aon_rtc_open_rtc_wakeup(uint32_t period)
911 {
912 aon_rtc_hal_open_rtc_wakeup(period);
913 return BK_OK;
914 }
915 #endif
916
bk_aon_rtc_get_current_tick(aon_rtc_id_t id)917 uint64_t bk_aon_rtc_get_current_tick(aon_rtc_id_t id)
918 {
919 if(id >= AON_RTC_ID_MAX)
920 {
921 AON_RTC_LOGE("%s:id=%d\r\n", __func__, id);
922 return 0;
923 }
924
925 return ((s_high_tick[id] << 32) + aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal));
926 }
927
928 #if AON_RTC_DEBUG
bk_aon_rtc_timing_test(aon_rtc_id_t id,uint32_t round,uint32_t cycles,uint32_t set_tick)929 void bk_aon_rtc_timing_test(aon_rtc_id_t id, uint32_t round, uint32_t cycles, uint32_t set_tick)
930 {
931 uint32_t int_level = 0;
932 uint32_t i = 0, j = 0;
933 uint32_t start_tick = 0, end_tick = 0;
934 uint64_t u64_start_tick = 0, u64_end_tick = 0;
935 uint32_t max_offset_tick = 0, min_offset_tick = 0xffffffff;
936 uint32_t fail_cnt = 0;
937
938 AON_RTC_LOGD("%s[+]\r\n", __func__);
939
940 int_level = rtos_disable_int();
941
942 //get uint32_t tick counter check
943 for(i = 0; i < round; i++)
944 {
945 start_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
946 for(j = 0; j < cycles; j++)
947 {
948 aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
949 }
950 end_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
951
952 if(min_offset_tick > end_tick - start_tick)
953 min_offset_tick = end_tick - start_tick;
954 if(max_offset_tick < end_tick - start_tick)
955 max_offset_tick = end_tick - start_tick;
956 }
957 AON_RTC_LOGI("Gettick uint32:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
958
959 //get uint64_t tick counter check
960 max_offset_tick = 0;
961 min_offset_tick = 0xffffffff;
962 for(i = 0; i < round; i++)
963 {
964 u64_start_tick = bk_aon_rtc_get_current_tick(id);
965 for(j = 0; j < cycles; j++)
966 {
967 bk_aon_rtc_get_current_tick(id);
968 }
969 u64_end_tick = bk_aon_rtc_get_current_tick(id);
970
971 if(min_offset_tick > (uint32_t)(u64_end_tick - u64_start_tick))
972 min_offset_tick = (uint32_t)(u64_end_tick - u64_start_tick);
973 if(max_offset_tick < u64_end_tick - u64_start_tick)
974 max_offset_tick = u64_end_tick - u64_start_tick;
975 }
976 AON_RTC_LOGI("Gettick uint64:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
977
978 //set tick val check
979 max_offset_tick = 0;
980 min_offset_tick = 0xffffffff;
981 for(i = 0; i < round; i++)
982 {
983 start_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
984 for(j = 0; j < cycles; j++)
985 {
986 aon_rtc_set_tick(&s_aon_rtc[id].hal, set_tick);
987 }
988 end_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
989
990 if(min_offset_tick > end_tick - start_tick)
991 min_offset_tick = end_tick - start_tick;
992 if(max_offset_tick < end_tick - start_tick)
993 max_offset_tick = end_tick - start_tick;
994 }
995 AON_RTC_LOGI("Settick:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
996
997 fail_cnt = 0;
998 max_offset_tick = 0;
999 min_offset_tick = 0xffffffff;
1000 for(i = 0; i < round; i++)
1001 {
1002 start_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
1003 for(j = 0; j < cycles; j++)
1004 {
1005 aon_rtc_set_tick(&s_aon_rtc[id].hal, set_tick);
1006 if(set_tick != aon_rtc_hal_get_tick_val(&s_aon_rtc[id].hal))
1007 {
1008 fail_cnt++;
1009 }
1010 }
1011 end_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
1012
1013 if(min_offset_tick > end_tick - start_tick)
1014 min_offset_tick = end_tick - start_tick;
1015 if(max_offset_tick < end_tick - start_tick)
1016 max_offset_tick = end_tick - start_tick;
1017 }
1018 AON_RTC_LOGI("Settick:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
1019 AON_RTC_LOGI("Settick:%d rounds*%d times:check fail_cnt=%d\r\n", i, j, fail_cnt);
1020
1021 rtos_enable_int(int_level);
1022 AON_RTC_LOGD("%s[-]\r\n", __func__);
1023 }
1024 #endif
1025
bk_aon_rtc_dump(aon_rtc_id_t id)1026 void bk_aon_rtc_dump(aon_rtc_id_t id)
1027 {
1028 #if AON_RTC_DEBUG
1029 uint32_t i = 0, index = 0;
1030
1031 for(i = s_isr_cnt - AON_RTC_ISR_DEBUG_MAX_CNT; i < s_isr_cnt; i++)
1032 {
1033 index = i % AON_RTC_ISR_DEBUG_MAX_CNT;
1034
1035 for(volatile uint32_t j = 0; j < 1800; j++); //confirm log output normarlly
1036
1037 AON_RTC_LOGI("isr_in[%d]=0x%x,out=0x%x,set=0x%x\r\n", index, s_isr_debug_in_tick[index], s_isr_debug_out_tick[index], s_isr_debug_set_tick[index]);
1038 }
1039 #endif
1040 aon_rtc_struct_dump();
1041
1042 alarm_dump_list(s_aon_rtc[id].alarm_head_p);
1043 }
1044
1045 #if AON_RTC_DEBUG
bk_64bits_test(void)1046 void bk_64bits_test(void)
1047 {
1048 uint64_t val_64bits = 0xffffffffffff;
1049 uint64_t x1 = 0x111111111, x2 = 0x222222222, x3 = 0x333333333, t = 0;
1050 uint32_t xh1 = 0x1, xl1 = 0x11111111;
1051 //uint32_t xh2 = 0x2, xl2 = 0x22222222;
1052 //uint32_t xh3 = 0x3, xl3 = 0x33333333;
1053 //uint32_t th1 = 0, tl1 = 0;
1054
1055 t = xh1;
1056 t = t<<32;
1057 t += xl1;
1058 if (t == 0x111111111)
1059 {
1060 AON_RTC_LOGD("left move 0x1<<32 is right\r\n");
1061 }
1062
1063 if (t == x1)
1064 {
1065 AON_RTC_LOGD("uint64 compare is right\r\n");
1066 }
1067
1068 if ((t & 0xffffffff) == xl1)
1069 {
1070 AON_RTC_LOGD("uint64 low 32bits is right\r\n");
1071 }
1072
1073 if ((t >> 32) == xh1)
1074 {
1075 AON_RTC_LOGD("right move uint64 high 32bits is right\r\n");
1076 }
1077
1078 if(x1 + x2 == x3)
1079 {
1080 AON_RTC_LOGD("uint64 add is right\r\n");
1081 }
1082
1083 if(x3 - x2 == x1)
1084 {
1085 AON_RTC_LOGD("uint64 minus is right\r\n");
1086 }
1087
1088 if((x1 * 2) == x2)
1089 {
1090 AON_RTC_LOGD("uint64 multi is right\r\n");
1091 }
1092
1093 if((x2 / 2) == x1)
1094 {
1095 AON_RTC_LOGD("uint64 divide2 is right\r\n");
1096 }
1097
1098 if((x2 / 32) == 0x11111111)
1099 {
1100 AON_RTC_LOGD("uint64 divide32 is right\r\n");
1101 }
1102
1103 //pass:only output low 32 bits valid data
1104 for(uint32_t i = 0; i < 64; i++)
1105 AON_RTC_LOGD("0xffffffffffff>>%d == 0x%llx\r\n", i, val_64bits>>i); //64 bits printf is error
1106
1107 //print:BIT64(i) low 32 bits
1108 for(uint32_t i = 0; i < 64; i++)
1109 AON_RTC_LOGD("Bit[%d] = 0x%llx, &=0x%llx\r\n", i, BIT64(i), (val_64bits & BIT64(i)));
1110
1111 AON_RTC_LOGD("64bits move\r\n");
1112 for(uint64_t i = 0; i < 64; i++)
1113 AON_RTC_LOGD("Bit[%d] = 0x%llx, &=0x%llx\r\n", i, BIT64(i), (val_64bits & BIT64(i)));
1114
1115 AON_RTC_LOGD("32bits move\r\n");
1116 val_64bits = 0xa0a0a0a0a0a0a0a0;
1117 for(uint32_t i = 0; i < 64; i++)
1118 {
1119 uint64_t ret = val_64bits & BIT64(i);
1120 AON_RTC_LOGD("ret[%d] = 0x%llx = 0x%llx \r\n", i, ret, ret); //print ret twice as 64 bits
1121 }
1122
1123 AON_RTC_LOGD("64bits move\r\n");
1124 val_64bits = 0xa0a0a0a0a0a0a0a0;
1125 for(uint64_t i = 0; i < 64; i++)
1126 {
1127 uint64_t ret = val_64bits & BIT64(i);
1128 AON_RTC_LOGD("ret[%d] = 0x%llx = 0x%llx \r\n", i, i, ret); //print i twice as 64 bits
1129 }
1130 }
1131 #endif
1132
1133