1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "sys/param.h"
8 #include "esp_timer_impl.h"
9 #include "esp_err.h"
10 #include "esp_timer.h"
11 #include "esp_attr.h"
12 #include "esp_log.h"
13 #include "esp_compiler.h"
14 #include "soc/periph_defs.h"
15 #include "soc/soc_caps.h"
16 #include "soc/rtc.h"
17 #ifndef __ZEPHYR__
18 #include "freertos/FreeRTOS.h"
19 #endif
20 #include "hal/systimer_ll.h"
21 #include "hal/systimer_types.h"
22 #include "hal/systimer_hal.h"
23 #include <zephyr/kernel.h>
24
25 #ifdef CONFIG_SOC_SERIES_ESP32C3
26 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
27 #define ISR_HANDLER isr_handler_t
28 #else
29 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
30 #define ISR_HANDLER intr_handler_t
31 #endif
32
33 /**
34 * @file esp_timer_systimer.c
35 * @brief Implementation of esp_timer using systimer.
36 *
37 * This timer is a 64-bit up-counting timer, with a programmable compare value (called 'alarm' hereafter).
38 * When the timer reaches compare value, interrupt is raised.
39 * The timer can be configured to produce an edge interrupt.
40 *
41 * @note systimer counter0 and alarm2 are adopted to implemented esp_timer
42 */
43
44 /* Function from the upper layer to be called when the interrupt happens.
45 * Registered in esp_timer_impl_init.
46 */
47 static intr_handler_t s_alarm_handler = NULL;
48
49 /* Systimer HAL layer object */
50 static systimer_hal_context_t systimer_hal;
51
52 /* Spinlock used to protect access to the hardware registers. */
53 static unsigned int s_time_update_lock;
54
55 #define SYS_TIMER_ESP_IRQ 17
56
esp_timer_impl_lock(void)57 void esp_timer_impl_lock(void)
58 {
59 s_time_update_lock = irq_lock();
60 }
61
esp_timer_impl_unlock(void)62 void esp_timer_impl_unlock(void)
63 {
64 irq_unlock(s_time_update_lock);
65 }
66
esp_timer_impl_get_counter_reg(void)67 uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void)
68 {
69 return systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK);
70 }
71
esp_timer_impl_get_time(void)72 int64_t IRAM_ATTR esp_timer_impl_get_time(void)
73 {
74 return systimer_hal_get_counter_value(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK) / SYSTIMER_LL_TICKS_PER_US;
75 }
76
77 int64_t esp_timer_get_time(void) __attribute__((alias("esp_timer_impl_get_time")));
78
esp_timer_impl_set_alarm_id(uint64_t timestamp,unsigned alarm_id)79 void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id)
80 {
81 static uint64_t timestamp_id[2] = { UINT64_MAX, UINT64_MAX };
82 esp_timer_impl_lock();
83 timestamp_id[alarm_id] = timestamp;
84 timestamp = MIN(timestamp_id[0], timestamp_id[1]);
85 if (timestamp != UINT64_MAX) {
86 systimer_hal_set_alarm_target(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, timestamp);
87 }
88 esp_timer_impl_unlock();
89 }
90
esp_timer_impl_set_alarm(uint64_t timestamp)91 void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
92 {
93 esp_timer_impl_set_alarm_id(timestamp, 0);
94 }
95
timer_alarm_isr(void * arg)96 static void IRAM_ATTR timer_alarm_isr(void *arg)
97 {
98 // clear the interrupt
99 systimer_ll_clear_alarm_int(systimer_hal.dev, SYSTIMER_LL_ALARM_CLOCK);
100 /* Call the upper layer handler */
101 (*s_alarm_handler)(arg);
102 }
103
esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)104 void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)
105 {
106 #if !SOC_SYSTIMER_FIXED_TICKS_US
107 systimer_hal_on_apb_freq_update(&systimer_hal, apb_ticks_per_us);
108 #endif
109 }
110
esp_timer_impl_advance(int64_t time_us)111 void esp_timer_impl_advance(int64_t time_us)
112 {
113 esp_timer_impl_lock();
114 systimer_hal_counter_value_advance(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK, time_us);
115 esp_timer_impl_unlock();
116 }
117
esp_timer_impl_early_init(void)118 esp_err_t esp_timer_impl_early_init(void)
119 {
120 systimer_hal_init(&systimer_hal);
121
122 #if !SOC_SYSTIMER_FIXED_TICKS_US
123 assert(rtc_clk_xtal_freq_get() == 40 && "update the step for xtal to support other XTAL:APB frequency ratios");
124 systimer_hal_set_steps_per_tick(&systimer_hal, 0, 2); // for xtal
125 systimer_hal_set_steps_per_tick(&systimer_hal, 1, 1); // for pll
126 #endif
127
128 systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_CLOCK);
129 systimer_hal_select_alarm_mode(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, SYSTIMER_ALARM_MODE_ONESHOT);
130 systimer_hal_connect_alarm_counter(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK, SYSTIMER_LL_COUNTER_CLOCK);
131
132 return ESP_OK;
133 }
134
esp_timer_impl_init(intr_handler_t alarm_handler)135 esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
136 {
137 s_alarm_handler = alarm_handler;
138 const int interrupt_lvl = (1 << 1) & ESP_INTR_FLAG_LEVELMASK;
139 #if SOC_SYSTIMER_INT_LEVEL
140 int int_type = 0;
141 #else
142 int int_type = ESP_INTR_FLAG_EDGE;
143 #endif // SOC_SYSTIMER_INT_LEVEL
144
145 esp_intr_alloc(ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE,
146 ESP_INTR_FLAG_IRAM | int_type | interrupt_lvl,
147 (ISR_HANDLER)timer_alarm_isr,
148 NULL,
149 NULL);
150
151 /* TODO: if SYSTIMER is used for anything else, access to SYSTIMER_INT_ENA_REG has to be
152 * protected by a shared spinlock. Since this code runs as part of early startup, this
153 * is practically not an issue.
154 */
155 systimer_hal_enable_alarm_int(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK);
156 irq_enable(SYS_TIMER_ESP_IRQ);
157
158 return ESP_OK;
159 }
160
esp_timer_impl_deinit(void)161 void esp_timer_impl_deinit(void)
162 {
163 systimer_ll_enable_alarm(systimer_hal.dev, SYSTIMER_LL_ALARM_CLOCK, false);
164 /* TODO: may need a spinlock, see the note related to SYSTIMER_INT_ENA_REG in systimer_hal_init */
165 systimer_ll_enable_alarm_int(systimer_hal.dev, SYSTIMER_LL_ALARM_CLOCK, false);
166 s_alarm_handler = NULL;
167 }
168
esp_timer_impl_get_min_period_us(void)169 uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us(void)
170 {
171 return 50;
172 }
173
esp_timer_impl_get_alarm_reg(void)174 uint64_t esp_timer_impl_get_alarm_reg(void)
175 {
176 esp_timer_impl_lock();
177 uint64_t val = systimer_hal_get_alarm_value(&systimer_hal, SYSTIMER_LL_ALARM_CLOCK);
178 esp_timer_impl_unlock();
179 return val;
180 }
181
182 void esp_timer_private_update_apb_freq(uint32_t apb_ticks_per_us) __attribute__((alias("esp_timer_impl_update_apb_freq")));
183 void esp_timer_private_advance(int64_t time_us) __attribute__((alias("esp_timer_impl_advance")));
184 void esp_timer_private_lock(void) __attribute__((alias("esp_timer_impl_lock")));
185 void esp_timer_private_unlock(void) __attribute__((alias("esp_timer_impl_unlock")));
186