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 if (IS_ENABLED(CFG_CORE_SEL2_SPMC))
13 write_cntp_ctl(0);
14 else
15 write_cntps_ctl(0);
16 }
17
timer_set_next(const struct callout_timer_desc * desc __unused,uint64_t ctrval)18 static void timer_set_next(const struct callout_timer_desc *desc __unused,
19 uint64_t ctrval)
20 {
21 if (IS_ENABLED(CFG_CORE_SEL2_SPMC)) {
22 write_cntp_cval(ctrval);
23 write_cntp_ctl(1);
24 } else {
25 write_cntps_cval(ctrval);
26 write_cntps_ctl(1);
27 }
28 }
29
30 static uint64_t
timer_ms_to_ticks(const struct callout_timer_desc * desc __unused,uint32_t timeout_ms)31 timer_ms_to_ticks(const struct callout_timer_desc *desc __unused,
32 uint32_t timeout_ms)
33 {
34 uint64_t freq = read_cntfrq();
35
36 return (freq * timeout_ms) / 1000;
37 }
38
timer_now(const struct callout_timer_desc * desc __unused)39 static uint64_t timer_now(const struct callout_timer_desc *desc __unused)
40 {
41 return barrier_read_counter_timer();
42 }
43
44 static struct itr_handler timer_itr __nex_bss;
45 static const struct callout_timer_desc timer_desc
46 __relrodata_unpaged("timer_desc") = {
47 .disable_timeout = timer_disable,
48 .set_next_timeout = timer_set_next,
49 .ms_to_ticks = timer_ms_to_ticks,
50 .get_now = timer_now,
51 .is_per_cpu = true,
52 };
53 DECLARE_KEEP_PAGER(timer_desc);
54
timer_itr_cb(struct itr_handler * h __unused)55 static enum itr_return timer_itr_cb(struct itr_handler *h __unused)
56 {
57 callout_service_cb();
58
59 return ITRR_HANDLED;
60 }
61 DECLARE_KEEP_PAGER(timer_itr_cb);
62
timer_init_callout_service(struct itr_chip * itr_chip,size_t itr_number)63 void timer_init_callout_service(struct itr_chip *itr_chip, size_t itr_number)
64 {
65 timer_itr = (struct itr_handler){
66 .it = itr_number,
67 .flags = ITRF_TRIGGER_LEVEL,
68 .handler = timer_itr_cb,
69 };
70
71 if (interrupt_add_handler_with_chip(itr_chip, &timer_itr))
72 panic();
73
74 interrupt_enable(timer_itr.chip, timer_itr.it);
75 callout_service_init(&timer_desc);
76 }
77