1 /*
2 * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <sys/param.h>
9 #include "sdkconfig.h"
10 #include "esp_timer_impl.h"
11 #include "esp_err.h"
12 #include "esp_timer.h"
13 #include "esp_attr.h"
14 #include "esp_log.h"
15 #include "esp_compiler.h"
16 #include "soc/periph_defs.h"
17 #include "soc/soc_caps.h"
18 #include "esp_private/esp_clk.h"
19 #include "esp_private/systimer.h"
20 #include "esp_private/periph_ctrl.h"
21 #include "hal/systimer_ll.h"
22 #include "hal/systimer_types.h"
23 #include "hal/systimer_hal.h"
24
25 #if defined(CONFIG_SOC_SERIES_ESP32C2) || \
26 defined(CONFIG_SOC_SERIES_ESP32C3) || \
27 defined(CONFIG_SOC_SERIES_ESP32C6)
28 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
29 #define ISR_HANDLER isr_handler_t
30 #else
31 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
32 #define ISR_HANDLER intr_handler_t
33 #endif
34
35 /**
36 * @file esp_timer_systimer.c
37 * @brief Implementation of esp_timer using systimer.
38 *
39 * This timer is a 64-bit up-counting timer, with a programmable compare value (called 'alarm' hereafter).
40 * When the timer reaches compare value, interrupt is raised.
41 * The timer can be configured to produce an edge interrupt.
42 *
43 * @note systimer counter0 and alarm2 are adopted to implemented esp_timer
44 */
45
46 static const char *TAG = "esp_timer_systimer";
47
48 #define NOT_USED 0xBAD00FAD
49
50 /* Function from the upper layer to be called when the interrupt happens.
51 * Registered in esp_timer_impl_init.
52 */
53 static ISR_HANDLER s_alarm_handler = NULL;
54
55 /* Systimer HAL layer object */
56 static systimer_hal_context_t systimer_hal;
57
58 /* Spinlock used to protect access to the hardware registers. */
59 extern unsigned int s_time_update_lock;
60
61 /* Alarm values to generate interrupt on match */
62 extern uint64_t timestamp_id[2];
63
esp_timer_impl_get_counter_reg(void)64 uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void)
65 {
66 return systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER);
67 }
68
esp_timer_impl_get_time(void)69 int64_t IRAM_ATTR esp_timer_impl_get_time(void)
70 {
71 // we hope the execution time of this function won't > 1us
72 // thus, to save one function call, we didn't use the existing `systimer_hal_get_time`
73 return systimer_hal.ticks_to_us(systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER));
74 }
75
76 int64_t esp_timer_get_time(void) __attribute__((alias("esp_timer_impl_get_time")));
77
esp_timer_impl_set_alarm_id(uint64_t timestamp,unsigned alarm_id)78 void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id)
79 {
80 s_time_update_lock = irq_lock();
81 timestamp_id[alarm_id] = timestamp;
82 timestamp = MIN(timestamp_id[0], timestamp_id[1]);
83 systimer_hal_set_alarm_target(&systimer_hal, SYSTIMER_ALARM_ESPTIMER, timestamp);
84 irq_unlock(s_time_update_lock);
85 }
86
timer_alarm_isr(void * arg)87 static void IRAM_ATTR timer_alarm_isr(void *arg)
88 {
89 // clear the interrupt
90 systimer_ll_clear_alarm_int(systimer_hal.dev, SYSTIMER_ALARM_ESPTIMER);
91 /* Call the upper layer handler */
92 (*s_alarm_handler)(arg);
93 }
94
esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)95 void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)
96 {
97 #if !SOC_SYSTIMER_FIXED_DIVIDER
98 systimer_hal_on_apb_freq_update(&systimer_hal, apb_ticks_per_us);
99 #endif
100 }
101
esp_timer_impl_set(uint64_t new_us)102 void esp_timer_impl_set(uint64_t new_us)
103 {
104 s_time_update_lock = irq_lock();
105 systimer_counter_value_t new_count = {
106 .val = systimer_hal.us_to_ticks(new_us),
107 };
108 systimer_ll_set_counter_value(systimer_hal.dev, SYSTIMER_COUNTER_ESPTIMER, new_count.val);
109 systimer_ll_apply_counter_value(systimer_hal.dev, SYSTIMER_COUNTER_ESPTIMER);
110 irq_unlock(s_time_update_lock);
111 }
112
esp_timer_impl_advance(int64_t time_diff_us)113 void esp_timer_impl_advance(int64_t time_diff_us)
114 {
115 s_time_update_lock = irq_lock();
116 systimer_hal_counter_value_advance(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER, time_diff_us);
117 irq_unlock(s_time_update_lock);
118 }
119
esp_timer_impl_early_init(void)120 esp_err_t esp_timer_impl_early_init(void)
121 {
122 periph_module_enable(PERIPH_SYSTIMER_MODULE);
123 systimer_hal_tick_rate_ops_t ops = {
124 .ticks_to_us = systimer_ticks_to_us,
125 .us_to_ticks = systimer_us_to_ticks,
126 };
127 systimer_hal_init(&systimer_hal);
128 systimer_hal_set_tick_rate_ops(&systimer_hal, &ops);
129
130 #if !SOC_SYSTIMER_FIXED_DIVIDER
131 assert(esp_clk_xtal_freq() == (40 * 1000000) &&
132 "update the step for xtal to support other XTAL:APB frequency ratios");
133 systimer_hal_set_steps_per_tick(&systimer_hal, 0, 2); // for xtal
134 systimer_hal_set_steps_per_tick(&systimer_hal, 1, 1); // for pll
135 #endif
136
137 systimer_hal_enable_counter(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER);
138 systimer_hal_select_alarm_mode(&systimer_hal, SYSTIMER_ALARM_ESPTIMER, SYSTIMER_ALARM_MODE_ONESHOT);
139 systimer_hal_connect_alarm_counter(&systimer_hal, SYSTIMER_ALARM_ESPTIMER, SYSTIMER_COUNTER_ESPTIMER);
140
141 for (unsigned cpuid = 0; cpuid < SOC_CPU_CORES_NUM; ++cpuid) {
142 systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER, cpuid, (cpuid < CONFIG_MP_MAX_NUM_CPUS) ? true : false);
143 }
144
145 return ESP_OK;
146 }
147
esp_timer_impl_init(ISR_HANDLER alarm_handler)148 esp_err_t esp_timer_impl_init(ISR_HANDLER alarm_handler)
149 {
150 int isr_flags = 0 /* ZEP-795 (GH #74368): esp_timer ISR priority relaxed to avoid
151 * IRQ not being allocated when several peripherals are enabled
152 */
153 #if !SOC_SYSTIMER_INT_LEVEL
154 | ESP_INTR_FLAG_EDGE
155 #endif
156 | ESP_INTR_FLAG_IRAM;
157
158 esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, isr_flags,
159 (ISR_HANDLER)timer_alarm_isr, NULL, NULL);
160 if (err != ESP_OK) {
161 ESP_EARLY_LOGE(TAG, "esp_intr_alloc failed (0x%x)", err);
162 return err;
163 }
164
165 if (s_alarm_handler == NULL) {
166 s_alarm_handler = alarm_handler;
167 /* TODO: if SYSTIMER is used for anything else, access to SYSTIMER_INT_ENA_REG has to be
168 * protected by a shared spinlock. Since this code runs as part of early startup, this
169 * is practically not an issue.
170 */
171 systimer_hal_enable_alarm_int(&systimer_hal, SYSTIMER_ALARM_ESPTIMER);
172 }
173
174 return err;
175 }
176
esp_timer_impl_deinit(void)177 void esp_timer_impl_deinit(void)
178 {
179 systimer_ll_enable_alarm(systimer_hal.dev, SYSTIMER_ALARM_ESPTIMER, false);
180 /* TODO: may need a spinlock, see the note related to SYSTIMER_INT_ENA_REG in systimer_hal_init */
181 systimer_ll_enable_alarm_int(systimer_hal.dev, SYSTIMER_ALARM_ESPTIMER, false);
182 s_alarm_handler = NULL;
183 }
184
esp_timer_impl_get_alarm_reg(void)185 uint64_t esp_timer_impl_get_alarm_reg(void)
186 {
187 s_time_update_lock = irq_lock();
188 uint64_t val = systimer_hal_get_alarm_value(&systimer_hal, SYSTIMER_ALARM_ESPTIMER);
189 irq_unlock(s_time_update_lock);
190 return val;
191 }
192
193 void esp_timer_private_update_apb_freq(uint32_t apb_ticks_per_us) __attribute__((alias("esp_timer_impl_update_apb_freq")));
194 void esp_timer_private_set(uint64_t new_us) __attribute__((alias("esp_timer_impl_set")));
195 void esp_timer_private_advance(int64_t time_diff_us) __attribute__((alias("esp_timer_impl_advance")));
196