1 /*
2 * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <soc/soc_caps.h>
7 #include <soc/soc.h>
8 #include <soc/interrupt_core0_reg.h>
9 #include <soc/periph_defs.h>
10 #include <soc/system_reg.h>
11 #include <hal/systimer_hal.h>
12 #include <hal/systimer_ll.h>
13 #include <rom/ets_sys.h>
14 #include <esp_attr.h>
15
16 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
17 #include <zephyr/drivers/timer/system_timer.h>
18 #include <zephyr/sys_clock.h>
19 #include <soc.h>
20 #include <zephyr/init.h>
21 #include <zephyr/spinlock.h>
22
23 #define CYC_PER_TICK ((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() \
24 / (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC))
25 #define MAX_CYC 0xffffffffu
26 #define MAX_TICKS ((MAX_CYC - CYC_PER_TICK) / CYC_PER_TICK)
27 #define MIN_DELAY 1
28
29 #if defined(CONFIG_TEST)
30 const int32_t z_sys_timer_irq_for_test = DT_IRQN(DT_NODELABEL(systimer0));
31 #endif
32
33 #define TICKLESS IS_ENABLED(CONFIG_TICKLESS_KERNEL)
34
35 static struct k_spinlock lock;
36 static uint64_t last_count;
37
38 /* Systimer HAL layer object */
39 static systimer_hal_context_t systimer_hal;
40
set_systimer_alarm(uint64_t time)41 static void set_systimer_alarm(uint64_t time)
42 {
43 systimer_hal_select_alarm_mode(&systimer_hal,
44 SYSTIMER_LL_ALARM_OS_TICK_CORE0, SYSTIMER_ALARM_MODE_ONESHOT);
45
46 systimer_counter_value_t alarm = {.val = time};
47
48 systimer_ll_enable_alarm(systimer_hal.dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0, false);
49 systimer_ll_set_alarm_target(systimer_hal.dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0, alarm.val);
50 systimer_ll_apply_alarm_value(systimer_hal.dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0);
51 systimer_ll_enable_alarm(systimer_hal.dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0, true);
52 systimer_ll_enable_alarm_int(systimer_hal.dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0, true);
53 }
54
get_systimer_alarm(void)55 static uint64_t get_systimer_alarm(void)
56 {
57 return systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK);
58 }
59
sys_timer_isr(const void * arg)60 static void sys_timer_isr(const void *arg)
61 {
62 ARG_UNUSED(arg);
63 systimer_ll_clear_alarm_int(systimer_hal.dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0);
64
65 k_spinlock_key_t key = k_spin_lock(&lock);
66 uint64_t now = get_systimer_alarm();
67
68 uint64_t dticks = (uint64_t)((now - last_count) / CYC_PER_TICK);
69
70 last_count += dticks * CYC_PER_TICK;
71
72 if (!TICKLESS) {
73 uint64_t next = last_count + CYC_PER_TICK;
74
75 if ((int64_t)(next - now) < MIN_DELAY) {
76 next += CYC_PER_TICK;
77 }
78 set_systimer_alarm(next);
79 }
80
81 k_spin_unlock(&lock, key);
82 sys_clock_announce(dticks);
83 }
84
sys_clock_set_timeout(int32_t ticks,bool idle)85 void sys_clock_set_timeout(int32_t ticks, bool idle)
86 {
87 ARG_UNUSED(idle);
88
89 #if defined(CONFIG_TICKLESS_KERNEL)
90 ticks = ticks == K_TICKS_FOREVER ? MAX_TICKS : ticks;
91 ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS);
92
93 k_spinlock_key_t key = k_spin_lock(&lock);
94 uint64_t now = get_systimer_alarm();
95 uint32_t adj, cyc = ticks * CYC_PER_TICK;
96
97 /* Round up to next tick boundary. */
98 adj = (uint32_t)(now - last_count) + (CYC_PER_TICK - 1);
99 if (cyc <= MAX_CYC - adj) {
100 cyc += adj;
101 } else {
102 cyc = MAX_CYC;
103 }
104 cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK;
105
106 if ((int32_t)(cyc + last_count - now) < MIN_DELAY) {
107 cyc += CYC_PER_TICK;
108 }
109
110 set_systimer_alarm(cyc + last_count);
111 k_spin_unlock(&lock, key);
112 #endif
113 }
114
sys_clock_elapsed(void)115 uint32_t sys_clock_elapsed(void)
116 {
117 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
118 return 0;
119 }
120
121 k_spinlock_key_t key = k_spin_lock(&lock);
122 uint32_t ret = ((uint32_t)get_systimer_alarm() - (uint32_t)last_count) / CYC_PER_TICK;
123
124 k_spin_unlock(&lock, key);
125 return ret;
126 }
127
sys_clock_cycle_get_32(void)128 uint32_t sys_clock_cycle_get_32(void)
129 {
130 return (uint32_t)get_systimer_alarm();
131 }
132
sys_clock_cycle_get_64(void)133 uint64_t sys_clock_cycle_get_64(void)
134 {
135 return get_systimer_alarm();
136 }
137
sys_clock_driver_init(void)138 static int sys_clock_driver_init(void)
139 {
140
141 esp_intr_alloc(DT_IRQN(DT_NODELABEL(systimer0)),
142 0,
143 sys_timer_isr,
144 NULL,
145 NULL);
146
147 systimer_hal_init(&systimer_hal);
148 systimer_hal_connect_alarm_counter(&systimer_hal,
149 SYSTIMER_LL_ALARM_OS_TICK_CORE0, SYSTIMER_LL_COUNTER_OS_TICK);
150
151 systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK);
152 systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, 0, true);
153 last_count = get_systimer_alarm();
154 set_systimer_alarm(last_count + CYC_PER_TICK);
155 return 0;
156 }
157
158 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
159 CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
160