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