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