1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2024, Linaro Limited
4  */
5 
6 #include <arm.h>
7 #include <kernel/callout.h>
8 #include <kernel/timer.h>
9 
timer_disable(const struct callout_timer_desc * desc __unused)10 static void timer_disable(const struct callout_timer_desc *desc __unused)
11 {
12 	write_cntps_ctl(0);
13 }
14 
timer_set_next(const struct callout_timer_desc * desc __unused,uint64_t ctrval)15 static void timer_set_next(const struct callout_timer_desc *desc __unused,
16 			   uint64_t ctrval)
17 {
18 	write_cntps_cval(ctrval);
19 	write_cntps_ctl(1);
20 }
21 
22 static uint64_t
timer_ms_to_ticks(const struct callout_timer_desc * desc __unused,uint32_t timeout_ms)23 timer_ms_to_ticks(const struct callout_timer_desc *desc __unused,
24 		  uint32_t timeout_ms)
25 {
26 	uint64_t freq = read_cntfrq();
27 
28 	return (freq * timeout_ms) / 1000;
29 }
30 
timer_now(const struct callout_timer_desc * desc __unused)31 static uint64_t timer_now(const struct callout_timer_desc *desc __unused)
32 {
33 	return barrier_read_counter_timer();
34 }
35 
36 static struct itr_handler timer_itr __nex_bss;
37 static const struct callout_timer_desc timer_desc
38 __relrodata_unpaged("timer_desc") = {
39 	.disable_timeout = timer_disable,
40 	.set_next_timeout = timer_set_next,
41 	.ms_to_ticks = timer_ms_to_ticks,
42 	.get_now = timer_now,
43 	.is_per_cpu = true,
44 };
45 DECLARE_KEEP_PAGER(timer_desc);
46 
timer_itr_cb(struct itr_handler * h __unused)47 static enum itr_return timer_itr_cb(struct itr_handler *h __unused)
48 {
49 	callout_service_cb();
50 
51 	return ITRR_HANDLED;
52 }
53 DECLARE_KEEP_PAGER(timer_itr_cb);
54 
timer_init_callout_service(struct itr_chip * itr_chip,size_t itr_number)55 void timer_init_callout_service(struct itr_chip *itr_chip, size_t itr_number)
56 {
57 	timer_itr = (struct itr_handler){
58 		.it = itr_number,
59 		.flags = ITRF_TRIGGER_LEVEL,
60 		.handler = timer_itr_cb,
61 	};
62 
63 	if (interrupt_add_handler_with_chip(itr_chip, &timer_itr))
64 		panic();
65 
66 	interrupt_enable(timer_itr.chip, timer_itr.it);
67 	callout_service_init(&timer_desc);
68 }
69