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