1 /*
2  * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/kernel.h>
7 #include <zephyr/logging/log.h>
8 
9 #include <stdlib.h>
10 
11 #include "sys/param.h"
12 #include "esp_timer_impl.h"
13 #include "esp_timer.h"
14 #include "esp_err.h"
15 #include "esp_system.h"
16 #include "esp_task.h"
17 #include "esp_attr.h"
18 #include "esp_intr_alloc.h"
19 #include "esp_log.h"
20 #include "esp_private/esp_clk.h"
21 #include "esp_private/periph_ctrl.h"
22 #include "soc/soc.h"
23 #include "soc/timer_group_reg.h"
24 #include "soc/rtc.h"
25 
26 #ifdef CONFIG_SOC_SERIES_ESP32C3
27 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
28 #else
29 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
30 #endif
31 
32 /**
33  * @file esp_timer_lac.c
34  * @brief Implementation of chip-specific part of esp_timer
35  *
36  * This implementation uses TG0 LAC timer of the ESP32. This timer is
37  * a 64-bit up-counting timer, with a programmable compare value (called 'alarm'
38  * hereafter). When the timer reaches compare value, interrupt is raised.
39  * The timer can be configured to produce an edge or a level interrupt.
40  */
41 
42 /* Selects which Timer Group peripheral to use */
43 #define LACT_MODULE     0
44 
45 #if LACT_MODULE == 0
46 #define INTR_SOURCE_LACT ETS_TG0_LACT_LEVEL_INTR_SOURCE
47 #define PERIPH_LACT PERIPH_TIMG0_MODULE
48 #elif LACT_MODULE == 1
49 #define INTR_SOURCE_LACT ETS_TG1_LACT_LEVEL_INTR_SOURCE
50 #define PERIPH_LACT PERIPH_TIMG1_MODULE
51 #else
52 #error "Incorrect the number of LACT module (only 0 or 1)"
53 #endif
54 
55 /* Desired number of timer ticks per microsecond.
56  * This value should be small enough so that all possible APB frequencies
57  * could be divided by it without remainder.
58  * On the other hand, the smaller this value is, the longer we need to wait
59  * after setting UPDATE_REG before the timer value can be read.
60  * If TICKS_PER_US == 1, then we need to wait up to 1 microsecond, which
61  * makes esp_timer_impl_get_time function take too much time.
62  * The value TICKS_PER_US == 2 allows for most of the APB frequencies, and
63  * allows reading the counter quickly enough.
64  */
65 #define TICKS_PER_US    2
66 
67 /* Shorter register names, used in this file */
68 #define CONFIG_REG      (TIMG_LACTCONFIG_REG(LACT_MODULE))
69 #define RTC_STEP_REG    (TIMG_LACTRTC_REG(LACT_MODULE))
70 #define ALARM_LO_REG    (TIMG_LACTALARMLO_REG(LACT_MODULE))
71 #define ALARM_HI_REG    (TIMG_LACTALARMHI_REG(LACT_MODULE))
72 #define COUNT_LO_REG    (TIMG_LACTLO_REG(LACT_MODULE))
73 #define COUNT_HI_REG    (TIMG_LACTHI_REG(LACT_MODULE))
74 #define UPDATE_REG      (TIMG_LACTUPDATE_REG(LACT_MODULE))
75 #define LOAD_REG        (TIMG_LACTLOAD_REG(LACT_MODULE))
76 #define LOAD_LO_REG     (TIMG_LACTLOADLO_REG(LACT_MODULE))
77 #define LOAD_HI_REG     (TIMG_LACTLOADHI_REG(LACT_MODULE))
78 #define INT_ENA_REG     (TIMG_INT_ENA_TIMERS_REG(LACT_MODULE))
79 #define INT_ST_REG      (TIMG_INT_ST_TIMERS_REG(LACT_MODULE))
80 #define INT_CLR_REG     (TIMG_INT_CLR_TIMERS_REG(LACT_MODULE))
81 
82 /* Function prototype for alarm interrupt handler function */
83 typedef void (*alarm_intr_handler_t)(const void *arg);
84 
85 /* Helper type to convert between a 64-bit value and a pair of 32-bit values without shifts and masks */
86 typedef struct {
87     union {
88         struct {
89             uint32_t lo;
90             uint32_t hi;
91         };
92         uint64_t val;
93     };
94 } timer_64b_reg_t;
95 
96 static const char* TAG = "esp_timer_impl";
97 
98 #define NOT_USED 0xBAD00FAD
99 
100 /* Function from the upper layer to be called when the interrupt happens.
101  * Registered in esp_timer_impl_init.
102  */
103 static alarm_intr_handler_t s_alarm_handler;
104 
105 /* Spinlock used to protect access to the hardware registers. */
106 extern unsigned int s_time_update_lock;
107 
108 /* Alarm values to generate interrupt on match */
109 extern uint64_t timestamp_id[2];
110 
esp_timer_impl_get_counter_reg(void)111 uint64_t IRAM_ATTR esp_timer_impl_get_counter_reg(void)
112 {
113     uint32_t lo, hi;
114     uint32_t lo_start = REG_READ(COUNT_LO_REG);
115     uint32_t div = REG_GET_FIELD(CONFIG_REG, TIMG_LACT_DIVIDER);
116     /* The peripheral doesn't have a bit to indicate that the update is done, so we poll the
117      * lower 32 bit part of the counter until it changes, or a timeout expires.
118      */
119     REG_WRITE(UPDATE_REG, 1);
120     do {
121         lo = REG_READ(COUNT_LO_REG);
122     } while (lo == lo_start && div-- > 0);
123 
124     /* Since this function is called without a critical section, verify that LO and HI
125      * registers are consistent. That is, if an interrupt happens between reading LO and
126      * HI registers, and esp_timer_impl_get_time is called from an ISR, then try to
127      * detect this by the change in LO register value, and re-read both registers.
128      */
129     do {
130         lo_start = lo;
131         hi = REG_READ(COUNT_HI_REG);
132         lo = REG_READ(COUNT_LO_REG);
133     } while (lo != lo_start);
134 
135     timer_64b_reg_t result = {
136         .lo = lo,
137         .hi = hi
138     };
139     return result.val;
140 }
141 
esp_timer_impl_get_time(void)142 int64_t IRAM_ATTR esp_timer_impl_get_time(void)
143 {
144     return esp_timer_impl_get_counter_reg() / TICKS_PER_US;
145 }
146 
147 int64_t esp_timer_get_time(void) __attribute__((alias("esp_timer_impl_get_time")));
148 
esp_timer_impl_set_alarm_id(uint64_t timestamp,unsigned alarm_id)149 void IRAM_ATTR esp_timer_impl_set_alarm_id(uint64_t timestamp, unsigned alarm_id)
150 {
151     s_time_update_lock = irq_lock();
152     timestamp_id[alarm_id] = timestamp;
153     timestamp = MIN(timestamp_id[0], timestamp_id[1]);
154     if (timestamp != UINT64_MAX) {
155         int64_t offset = TICKS_PER_US * 2;
156         uint64_t now_time = esp_timer_impl_get_counter_reg();
157         timer_64b_reg_t alarm = { .val = MAX(timestamp * TICKS_PER_US, now_time + offset) };
158         do {
159             REG_CLR_BIT(CONFIG_REG, TIMG_LACT_ALARM_EN);
160             REG_WRITE(ALARM_LO_REG, alarm.lo);
161             REG_WRITE(ALARM_HI_REG, alarm.hi);
162             REG_SET_BIT(CONFIG_REG, TIMG_LACT_ALARM_EN);
163             now_time = esp_timer_impl_get_counter_reg();
164             int64_t delta = (int64_t)alarm.val - (int64_t)now_time;
165             if (delta <= 0 && REG_GET_FIELD(INT_ST_REG, TIMG_LACT_INT_ST) == 0) {
166                 // new alarm is less than the counter and the interrupt flag is not set
167                 offset += llabs(delta) + TICKS_PER_US * 2;
168                 alarm.val = now_time + offset;
169             } else {
170                 // finish if either (alarm > counter) or the interrupt flag is already set.
171                 break;
172             }
173         } while(1);
174     }
175     irq_unlock(s_time_update_lock);
176 }
177 
timer_alarm_isr(void * arg)178 static void IRAM_ATTR timer_alarm_isr(void *arg)
179 {
180     /* Clear interrupt status */
181     REG_WRITE(INT_CLR_REG, TIMG_LACT_INT_CLR);
182     /* Call the upper layer handler */
183     (*s_alarm_handler)(arg);
184 }
185 
esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)186 void IRAM_ATTR esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us)
187 {
188     s_time_update_lock = irq_lock();
189     assert(apb_ticks_per_us >= 3 && "divider value too low");
190     assert(apb_ticks_per_us % TICKS_PER_US == 0 && "APB frequency (in MHz) should be divisible by TICK_PER_US");
191     REG_SET_FIELD(CONFIG_REG, TIMG_LACT_DIVIDER, apb_ticks_per_us / TICKS_PER_US);
192     irq_unlock(s_time_update_lock);
193 }
194 
esp_timer_impl_set(uint64_t new_us)195 void esp_timer_impl_set(uint64_t new_us)
196 {
197     s_time_update_lock = irq_lock();
198     timer_64b_reg_t dst = { .val = new_us * TICKS_PER_US };
199     REG_WRITE(LOAD_LO_REG, dst.lo);
200     REG_WRITE(LOAD_HI_REG, dst.hi);
201     REG_WRITE(LOAD_REG, 1);
202     irq_unlock(s_time_update_lock);
203 }
204 
esp_timer_impl_advance(int64_t time_diff_us)205 void esp_timer_impl_advance(int64_t time_diff_us)
206 {
207     uint64_t now = esp_timer_impl_get_time();
208     esp_timer_impl_set(now + time_diff_us);
209 }
210 
esp_timer_impl_early_init(void)211 esp_err_t esp_timer_impl_early_init(void)
212 {
213     periph_module_enable(PERIPH_LACT);
214 
215     REG_WRITE(CONFIG_REG, 0);
216     REG_WRITE(LOAD_LO_REG, 0);
217     REG_WRITE(LOAD_HI_REG, 0);
218     REG_WRITE(ALARM_LO_REG, UINT32_MAX);
219     REG_WRITE(ALARM_HI_REG, UINT32_MAX);
220     REG_WRITE(LOAD_REG, 1);
221     REG_SET_BIT(INT_CLR_REG, TIMG_LACT_INT_CLR);
222     REG_SET_FIELD(CONFIG_REG, TIMG_LACT_DIVIDER, APB_CLK_FREQ / 1000000 / TICKS_PER_US);
223     REG_SET_BIT(CONFIG_REG, TIMG_LACT_INCREASE |
224         TIMG_LACT_LEVEL_INT_EN |
225         TIMG_LACT_EN);
226 
227     return ESP_OK;
228 }
229 
esp_timer_impl_init(intr_handler_t alarm_handler)230 esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
231 {
232     int isr_flags = ((1 << 1) & ESP_INTR_FLAG_LEVELMASK) | ESP_INTR_FLAG_IRAM;
233 
234 	esp_err_t err = esp_intr_alloc(INTR_SOURCE_LACT, isr_flags,
235 								   (intr_handler_t)timer_alarm_isr, NULL, NULL);
236 
237 	if (err != ESP_OK) {
238         ESP_EARLY_LOGE(TAG, "Can not allocate ISR handler (0x%0x)", err);
239         return err;
240     }
241 
242     if (s_alarm_handler == NULL) {
243         s_alarm_handler = (alarm_intr_handler_t) alarm_handler;
244         /* In theory, this needs a shared spinlock with the timer group driver.
245         * However since esp_timer_impl_init is called early at startup, this
246         * will not cause issues in practice.
247         */
248         REG_SET_BIT(INT_ENA_REG, TIMG_LACT_INT_ENA);
249 
250         esp_timer_impl_update_apb_freq(esp_clk_apb_freq() / 1000000);
251 
252         // Set the step for the sleep mode when the timer will work
253         // from a slow_clk frequency instead of the APB frequency.
254         uint32_t slowclk_ticks_per_us = esp_clk_slowclk_cal_get() * TICKS_PER_US;
255         REG_SET_FIELD(RTC_STEP_REG, TIMG_LACT_RTC_STEP_LEN, slowclk_ticks_per_us);
256     }
257 
258     return err;
259 }
260 
esp_timer_impl_deinit(void)261 void esp_timer_impl_deinit(void)
262 {
263     REG_WRITE(CONFIG_REG, 0);
264     REG_SET_BIT(INT_CLR_REG, TIMG_LACT_INT_CLR);
265     /* TODO: also clear TIMG_LACT_INT_ENA; however see the note in esp_timer_impl_init. */
266     s_alarm_handler = NULL;
267 }
268 
esp_timer_impl_get_alarm_reg(void)269 uint64_t esp_timer_impl_get_alarm_reg(void)
270 {
271     s_time_update_lock = irq_lock();
272     timer_64b_reg_t alarm = {
273         .lo = REG_READ(ALARM_LO_REG),
274         .hi = REG_READ(ALARM_HI_REG)
275     };
276     irq_unlock(s_time_update_lock);
277     return alarm.val;
278 }
279 
280 void esp_timer_private_update_apb_freq(uint32_t apb_ticks_per_us) __attribute__((alias("esp_timer_impl_update_apb_freq")));
281 void esp_timer_private_set(uint64_t new_us) __attribute__((alias("esp_timer_impl_set")));
282 void esp_timer_private_advance(int64_t time_diff_us) __attribute__((alias("esp_timer_impl_advance")));
283