diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig index d92ab48e232..c529b522c56 100644 --- a/arch/xtensa/src/esp32s2/Kconfig +++ b/arch/xtensa/src/esp32s2/Kconfig @@ -173,6 +173,7 @@ endchoice # On-board Crystal Frequency config ESP32S2_RT_TIMER bool "Real-time Timer" + select ESP32S2_TIMER default n config ESP32S2_PARTITION diff --git a/arch/xtensa/src/esp32s2/Make.defs b/arch/xtensa/src/esp32s2/Make.defs index 7fbe1c1874a..79878aeaae1 100644 --- a/arch/xtensa/src/esp32s2/Make.defs +++ b/arch/xtensa/src/esp32s2/Make.defs @@ -85,3 +85,7 @@ endif ifeq ($(CONFIG_ESP32S2_FREERUN),y) CHIP_CSRCS += esp32s2_freerun.c endif + +ifeq ($(CONFIG_ESP32S2_RT_TIMER),y) +CHIP_CSRCS += esp32s2_rt_timer.c +endif diff --git a/arch/xtensa/src/esp32s2/esp32s2_rt_timer.c b/arch/xtensa/src/esp32s2/esp32s2_rt_timer.c new file mode 100644 index 00000000000..5c7664c38f8 --- /dev/null +++ b/arch/xtensa/src/esp32s2/esp32s2_rt_timer.c @@ -0,0 +1,838 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s2/esp32s2_rt_timer.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this args for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "xtensa.h" +#include "xtensa_attr.h" + +#include "hardware/esp32s2_soc.h" +#include "hardware/esp32s2_system.h" +#include "hardware/esp32s2_systimer.h" +#include "esp32s2_tim.h" +#include "esp32s2_rt_timer.h" +#include "esp32s2_clockconfig.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_SCHED_HPWORKPRIORITY +# if CONFIG_ESP32S2_RT_TIMER_TASK_PRIORITY >= CONFIG_SCHED_HPWORKPRIORITY +# error "RT timer priority should be smaller than high-prio workqueue" +# endif +#endif + +#define RT_TIMER_TASK_NAME CONFIG_ESP32S2_RT_TIMER_TASK_NAME +#define RT_TIMER_TASK_PRIORITY CONFIG_ESP32S2_RT_TIMER_TASK_PRIORITY +#define RT_TIMER_TASK_STACK_SIZE CONFIG_ESP32S2_RT_TIMER_TASK_STACK_SIZE + +/* Timer running at 80 MHz */ + +#define CYCLES_PER_USEC 80 +#define USEC_TO_CYCLES(u) ((u) * CYCLES_PER_USEC) +#define CYCLES_TO_USEC(c) ((c) / CYCLES_PER_USEC) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct esp32s2_rt_priv_s +{ + int pid; + sem_t toutsem; + struct list_node runlist; + struct list_node toutlist; + struct esp32s2_tim_dev_s *timer; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct esp32s2_rt_priv_s g_rt_priv = +{ + .pid = -EINVAL, +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: start_rt_timer + * + * Description: + * Start the timer by inserting it into the running list and reset the + * hardware timer alarm value if this timer is at the head of the list. + * Larger timeouts go to the end of the list (tail). + * + * Input Parameters: + * timer - RT timer pointer + * timeout - Timeout value + * repeat - repeat mode (true: enabled, false: disabled) + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void start_rt_timer(struct rt_timer_s *timer, + uint64_t timeout, + bool repeat) +{ + irqstate_t flags; + struct rt_timer_s *temp_p; + bool inserted = false; + uint64_t counter; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + flags = enter_critical_section(); + + /* Only idle timer can be started */ + + if (timer->state == RT_TIMER_IDLE) + { + /* Calculate the timer's alarm value */ + + ESP32S2_TIM_GETCTR(priv->timer, &counter); + counter = CYCLES_TO_USEC(counter); + timer->timeout = timeout; + timer->alarm = timer->timeout + counter; + + if (repeat) + { + timer->flags |= RT_TIMER_REPEAT; + } + else + { + timer->flags &= ~RT_TIMER_REPEAT; + } + + /* Scan the timer list and insert the new timer into previous + * node of timer whose alarm value is larger than new one + */ + + list_for_every_entry(&priv->runlist, temp_p, struct rt_timer_s, list) + { + if (temp_p->alarm > timer->alarm) + { + list_add_before(&temp_p->list, &timer->list); + inserted = true; + break; + } + } + + /* If we didn't find a larger one, insert the new timer at the tail + * of the list. + */ + + if (!inserted) + { + list_add_tail(&priv->runlist, &timer->list); + } + + timer->state = RT_TIMER_READY; + + /* If this timer is at the head of the list */ + + if (timer == container_of(priv->runlist.next, + struct rt_timer_s, list)) + { + /* Reset the hardware timer alarm */ + + ESP32S2_TIM_SETALRVL(priv->timer, USEC_TO_CYCLES(timer->alarm)); + ESP32S2_TIM_SETALRM(priv->timer, true); + } + } + else + { + tmrwarn("WARN: Timer not in idle mode.\n"\ + "Only idle timer can be started!\n"); + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: stop_rt_timer + * + * Description: + * Stop the timer by removing it from the running list and reset the + * hardware timer alarm value if this timer is at the head of list. + * + * Input Parameters: + * timer - RT timer pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void stop_rt_timer(struct rt_timer_s *timer) +{ + irqstate_t flags; + bool ishead; + struct rt_timer_s *next_timer; + uint64_t alarm; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + flags = enter_critical_section(); + + /* "start" function can set the timer's repeat flag, and "stop" function + * should remove this flag. + */ + + timer->flags &= ~RT_TIMER_REPEAT; + + /* Only timers in "ready" state can be stopped */ + + if (timer->state == RT_TIMER_READY) + { + /* Check if the timer is at the head of the list */ + + if (timer == container_of(priv->runlist.next, + struct rt_timer_s, list)) + { + ishead = true; + } + else + { + ishead = false; + } + + list_delete(&timer->list); + timer->state = RT_TIMER_IDLE; + + /* If the timer is at the head of the list */ + + if (ishead) + { + if (!list_is_empty(&priv->runlist)) + { + /* Set the value from the next timer as the new hardware timer + * alarm value. + */ + + next_timer = container_of(priv->runlist.next, + struct rt_timer_s, + list); + alarm = next_timer->alarm; + + ESP32S2_TIM_SETALRVL(priv->timer, USEC_TO_CYCLES(alarm)); + ESP32S2_TIM_SETALRM(priv->timer, true); + } + } + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: delete_rt_timer + * + * Description: + * Delete the timer by removing it from the list, then set the timer's + * state to "RT_TIMER_DELETE" and finally insert it into the work list + * to let the rt-timer's thread to delete it and free the resources. + * + * Input Parameters: + * timer - RT timer pointer + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void delete_rt_timer(struct rt_timer_s *timer) +{ + int ret; + irqstate_t flags; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + flags = enter_critical_section(); + + if (timer->state == RT_TIMER_READY) + { + stop_rt_timer(timer); + } + else if (timer->state == RT_TIMER_TIMEOUT) + { + list_delete(&timer->list); + } + else if (timer->state == RT_TIMER_DELETE) + { + goto exit; + } + + list_add_after(&priv->toutlist, &timer->list); + timer->state = RT_TIMER_DELETE; + + /* Wake up the thread to process deleted timers */ + + ret = nxsem_post(&priv->toutsem); + if (ret < 0) + { + tmrerr("ERROR: Failed to post sem ret=%d\n", ret); + } + +exit: + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: rt_timer_thread + * + * Description: + * RT timer working thread: Waits for a timeout semaphore, scans + * the timeout list and processes all the timers in the list. + * + * Input Parameters: + * argc - Not used + * argv - Not used + * + * Returned Value: + * 0. + * + ****************************************************************************/ + +static int rt_timer_thread(int argc, char *argv[]) +{ + int ret; + irqstate_t flags; + struct rt_timer_s *timer; + enum rt_timer_state_e raw_state; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + while (1) + { + /* Waiting for all timers to time out */ + + ret = nxsem_wait(&priv->toutsem); + if (ret) + { + tmrerr("ERROR: Wait priv->toutsem error=%d\n", ret); + assert(0); + } + + flags = enter_critical_section(); + + /* Process all the timers in list */ + + while (!list_is_empty(&priv->toutlist)) + { + /* Get the first timer in the list */ + + timer = container_of(priv->toutlist.next, + struct rt_timer_s, list); + + /* Cache the raw state to decide how to deal with this timer */ + + raw_state = timer->state; + + /* Delete the timer from the list */ + + list_delete(&timer->list); + + /* Set timer's state to idle so it can be restarted by the user. */ + + timer->state = RT_TIMER_IDLE; + + leave_critical_section(flags); + + if (raw_state == RT_TIMER_TIMEOUT) + { + timer->callback(timer->arg); + } + else if (raw_state == RT_TIMER_DELETE) + { + kmm_free(timer); + } + + /* Enter critical section for next scanning list */ + + flags = enter_critical_section(); + + if (raw_state == RT_TIMER_TIMEOUT) + { + /* Check if the timer is in "repeat" mode */ + + if (timer->flags & RT_TIMER_REPEAT) + { + start_rt_timer(timer, timer->timeout, true); + } + } + } + + leave_critical_section(flags); + } + + return 0; +} + +/**************************************************************************** + * Name: rt_timer_isr + * + * Description: + * Hardware timer interrupt service routine. + * + * Input Parameters: + * irq - Not used + * context - Not used + * arg - Not used + * + * Returned Value: + * 0. + * + ****************************************************************************/ + +static int rt_timer_isr(int irq, void *context, void *arg) +{ + int ret; + irqstate_t flags; + struct rt_timer_s *timer; + uint64_t alarm; + uint64_t counter; + bool wake = false; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + /* Clear interrupt register status */ + + ESP32S2_TIM_ACKINT(priv->timer); + + flags = enter_critical_section(); + + /* Check if there is a timer running */ + + if (!list_is_empty(&priv->runlist)) + { + /** + * When stop/delete timer, in the same time the hardware timer + * interrupt triggers, function "stop/delete" remove the timer + * from running list, so the 1st timer is not which triggers. + */ + + timer = container_of(priv->runlist.next, struct rt_timer_s, list); + ESP32S2_TIM_GETCTR(priv->timer, &counter); + counter = CYCLES_TO_USEC(counter); + if (timer->alarm <= counter) + { + /* Remove the first timer from the running list and add it to + * the timeout list. + * + * Set the timer's state to be RT_TIMER_TIMEOUT to avoid + * other operations. + */ + + list_delete(&timer->list); + timer->state = RT_TIMER_TIMEOUT; + list_add_after(&priv->toutlist, &timer->list); + wake = true; + + /* Check if there is a timer running */ + + if (!list_is_empty(&priv->runlist)) + { + /* Reset hardware timer alarm with next timer's alarm value */ + + timer = container_of(priv->runlist.next, + struct rt_timer_s, list); + alarm = timer->alarm; + ESP32S2_TIM_SETALRVL(priv->timer, USEC_TO_CYCLES(alarm)); + } + } + + /* If there is a timer in the list, the alarm should be enabled */ + + ESP32S2_TIM_SETALRM(priv->timer, true); + } + + if (wake) + { + /* Wake up the thread to process timed-out timers */ + + ret = nxsem_post(&priv->toutsem); + if (ret < 0) + { + tmrerr("ERROR: Failed to post sem ret=%d\n", ret); + } + } + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rt_timer_create + * + * Description: + * Create a RT timer from the provided arguments. + * + * Input Parameters: + * args - Input RT timer creation arguments + * timer_handle - Output RT timer handle pointer + * + * Returned Value: + * 0 is returned on success. Otherwise, a negated errno value is returned. + * + ****************************************************************************/ + +int rt_timer_create(const struct rt_timer_args_s *args, + struct rt_timer_s **timer_handle) +{ + struct rt_timer_s *timer; + + timer = (struct rt_timer_s *)kmm_malloc(sizeof(*timer)); + if (!timer) + { + tmrerr("ERROR: Failed to allocate %d bytes\n", sizeof(*timer)); + return -ENOMEM; + } + + timer->callback = args->callback; + timer->arg = args->arg; + timer->flags = RT_TIMER_NOFLAGS; + timer->state = RT_TIMER_IDLE; + list_initialize(&timer->list); + + *timer_handle = timer; + + return 0; +} + +/**************************************************************************** + * Name: rt_timer_start + * + * Description: + * Start the RT timer. + * + * Input Parameters: + * timer - RT timer pointer + * timeout - Timeout value + * repeat - repeat mode (true: enabled, false: disabled) + * + * Returned Value: + * None + * + ****************************************************************************/ + +void rt_timer_start(struct rt_timer_s *timer, + uint64_t timeout, + bool repeat) +{ + stop_rt_timer(timer); + + start_rt_timer(timer, timeout, repeat); +} + +/**************************************************************************** + * Name: rt_timer_stop + * + * Description: + * Stop the RT timer. + * + * Input Parameters: + * timer - RT timer pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +void rt_timer_stop(struct rt_timer_s *timer) +{ + stop_rt_timer(timer); +} + +/**************************************************************************** + * Name: rt_timer_delete + * + * Description: + * Stop and delete the RT timer. + * + * Input Parameters: + * timer - RT timer pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +void rt_timer_delete(struct rt_timer_s *timer) +{ + delete_rt_timer(timer); +} + +/**************************************************************************** + * Name: rt_timer_time_us + * + * Description: + * Get current counter value of the RT timer in microseconds. + * + * Input Parameters: + * None + * + * Returned Value: + * Time of the RT timer in microseconds. + * + ****************************************************************************/ + +uint64_t IRAM_ATTR rt_timer_time_us(void) +{ + uint64_t counter; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + ESP32S2_TIM_GETCTR(priv->timer, &counter); + counter = CYCLES_TO_USEC(counter); + + return counter; +} + +/**************************************************************************** + * Name: rt_timer_get_alarm + * + * Description: + * Get the remaining time to the next timeout. + * + * Input Parameters: + * None + * + * Returned Value: + * Timestamp of the nearest timer event in microseconds. + * + ****************************************************************************/ + +uint64_t IRAM_ATTR rt_timer_get_alarm(void) +{ + irqstate_t flags; + uint64_t counter; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + uint64_t alarm_value = 0; + + flags = enter_critical_section(); + + ESP32S2_TIM_GETCTR(priv->timer, &counter); + counter = CYCLES_TO_USEC(counter); + ESP32S2_TIM_GETALRVL(priv->timer, &alarm_value); + alarm_value = CYCLES_TO_USEC(alarm_value); + + if (alarm_value <= counter) + { + alarm_value = 0; + } + else + { + alarm_value -= counter; + } + + leave_critical_section(flags); + + return alarm_value; +} + +/**************************************************************************** + * Name: rt_timer_calibration + * + * Description: + * Adjust current RT timer by a certain value. + * + * Input Parameters: + * time_us - adjustment to apply to the RT timer in microseconds. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void IRAM_ATTR rt_timer_calibration(uint64_t time_us) +{ + uint64_t counter; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + irqstate_t flags; + + flags = enter_critical_section(); + ESP32S2_TIM_GETCTR(priv->timer, &counter); + counter = CYCLES_TO_USEC(counter); + counter += time_us; + ESP32S2_TIM_SETCTR(priv->timer, USEC_TO_CYCLES(counter)); + ESP32S2_TIM_RLD_NOW(priv->timer); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: esp32s2_rt_timer_init + * + * Description: + * Initialize ESP32-S2 RT timer. + * + * Input Parameters: + * None + * + * Returned Value: + * 0 is returned on success. Otherwise, a negated errno value is returned. + * + ****************************************************************************/ + +int esp32s2_rt_timer_init(void) +{ + int pid; + irqstate_t flags; + struct esp32s2_tim_dev_s *tim; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + uint32_t xtal_clk; + uint16_t pre; + uint16_t ticks; + + tim = esp32s2_tim_init(SYSTIMER_COMP0); + + if (tim == NULL) + { + tmrerr("ERROR: Failed to initialize ESP32-S2 Systimer 0\n"); + return -EINVAL; + } + + nxsem_init(&priv->toutsem, 0, 0); + + pid = kthread_create(RT_TIMER_TASK_NAME, + RT_TIMER_TASK_PRIORITY, + RT_TIMER_TASK_STACK_SIZE, + rt_timer_thread, + NULL); + if (pid < 0) + { + tmrerr("ERROR: Failed to create RT timer task error=%d\n", pid); + esp32s2_tim_deinit(tim); + return pid; + } + + list_initialize(&priv->runlist); + list_initialize(&priv->toutlist); + + priv->pid = pid; + priv->timer = tim; + + flags = enter_critical_section(); + + /* ESP32-S2 hardware timer configuration, acc. TRM V1.0 + * Systimer is clocked by APB_CLK. + * APB_CLK is determined by the source clock of CPU_CLK: + * CPU_CLK source | APB_CLK + * PLL_CLK | 80 MHz + * XTAL_CLK | CPU_CLK = XTAL_CLK / (SYSTEM_PRE_DIV_CNT + 1) + * The systimer period is determined by the step value. + * The step value is 1/(APB_CLK*ticks). + * On ESP32-S2, systimer has a mechanism that automatically + * detects which is the APB_CLK source and uses the step value + * configured for that specific source clock. + */ + + /* PLL step = 1/(80 MHz * t) s, t = 1 -> 80 cycles per us */ + + ESP32S2_TIM_SETSTEP(priv->timer, ESP32S2_TIM_PLL_CLK, 1); + + /* XTAL step = 1/((XTAL_CLK/(DIV +1)) * t) s + * To achieve the same 80 cycles per us, + * t = [(80 MHz * (DIV+1)) / XTAL_CLK] + * Example: XTAL_CLK = 40 MHz and DIV = 3, then t should be + * = ((80 MHz * 4) / 40 MHz) = 8. + */ + + xtal_clk = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_CLK_XTAL_FREQ); + pre = REG_GET_FIELD(SYSTEM_SYSCLK_CONF_REG, SYSTEM_PRE_DIV_CNT); + ticks = ((80 * (pre + 1)) / (xtal_clk)); + ESP32S2_TIM_SETSTEP(priv->timer, ESP32S2_TIM_XTAL_CLK, ticks); + + /* 1) Set Time-Delay work mode. + * 2) Clear the counter. + * 3) Set the ISR. + * 4) Enable timeout interrupt. + * 5) Start the counter. + * NOTE: No interrupt will be triggered until ESP32S2_TIM_SETALRM is set. + */ + + ESP32S2_TIM_SETWORKMODE(priv->timer, ESP32S2_TIM_DELAY_ALRM); + ESP32S2_TIM_CLEAR(priv->timer); + ESP32S2_TIM_SETISR(priv->timer, rt_timer_isr, NULL); + ESP32S2_TIM_ENABLEINT(priv->timer); + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: esp32s2_rt_timer_deinit + * + * Description: + * Deinitialize ESP32-S2 RT timer. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s2_rt_timer_deinit(void) +{ + irqstate_t flags; + struct esp32s2_rt_priv_s *priv = &g_rt_priv; + + flags = enter_critical_section(); + + ESP32S2_TIM_DISABLEINT(priv->timer); + ESP32S2_TIM_SETISR(priv->timer, NULL, NULL); + esp32s2_tim_deinit(priv->timer); + priv->timer = NULL; + + leave_critical_section(flags); + + if (priv->pid != -EINVAL) + { + kthread_delete(priv->pid); + priv->pid = -EINVAL; + } + + nxsem_destroy(&priv->toutsem); +} diff --git a/arch/xtensa/src/esp32s2/esp32s2_rt_timer.h b/arch/xtensa/src/esp32s2/esp32s2_rt_timer.h new file mode 100644 index 00000000000..74c6286bcc3 --- /dev/null +++ b/arch/xtensa/src/esp32s2/esp32s2_rt_timer.h @@ -0,0 +1,250 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s2/esp32s2_rt_timer.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_RT_TIMER_H +#define __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_RT_TIMER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define RT_TIMER_NOFLAGS (0) /* Timer supports no feature */ +#define RT_TIMER_REPEAT (1 << 0) /* Timer supports repeat mode */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/** + * RT timer state + */ + +enum rt_timer_state_e +{ + RT_TIMER_IDLE, /* Timer is not counting */ + RT_TIMER_READY, /* Timer is counting */ + RT_TIMER_TIMEOUT, /* Timer timed out */ + RT_TIMER_DELETE /* Timer is to be delete */ +}; + +/** + * RT timer data structure + */ + +struct rt_timer_s +{ + uint64_t timeout; /* Timeout value */ + uint64_t alarm; /* Timeout period */ + void (*callback)(void *arg); /* Callback function */ + void *arg; /* Private data */ + uint16_t flags; /* Supported features */ + enum rt_timer_state_e state; /* Timer state */ + struct list_node list; /* Working list */ +}; + +/** + * RT timer creation arguments data structure + */ + +struct rt_timer_args_s +{ + void (*callback)(void *arg); /* Callback function */ + void *arg; /* Private data */ +}; + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: rt_timer_create + * + * Description: + * Create a RT timer from the provided arguments. + * + * Input Parameters: + * args - Input RT timer creation arguments + * timer_handle - Output RT timer handle pointer + * + * Returned Value: + * 0 is returned on success. Otherwise, a negated errno value is returned. + * + ****************************************************************************/ + +int rt_timer_create(const struct rt_timer_args_s *args, + struct rt_timer_s **timer_handle); + +/**************************************************************************** + * Name: rt_timer_start + * + * Description: + * Start the RT timer. + * + * Input Parameters: + * timer - RT timer pointer + * timeout - Timeout value + * repeat - repeat mode (true: enabled, false: disabled) + * + * Returned Value: + * None + * + ****************************************************************************/ + +void rt_timer_start(struct rt_timer_s *timer, + uint64_t timeout, + bool repeat); + +/**************************************************************************** + * Name: rt_timer_stop + * + * Description: + * Stop the RT timer. + * + * Input Parameters: + * timer - RT timer pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +void rt_timer_stop(struct rt_timer_s *timer); + +/**************************************************************************** + * Name: rt_timer_delete + * + * Description: + * Stop and delete the RT timer. + * + * Input Parameters: + * timer - RT timer pointer + * + * Returned Value: + * None + * + ****************************************************************************/ + +void rt_timer_delete(struct rt_timer_s *timer); + +/**************************************************************************** + * Name: rt_timer_time_us + * + * Description: + * Get time of the RT timer in microseconds. + * + * Input Parameters: + * None + * + * Returned Value: + * Time of the RT timer in microseconds. + * + ****************************************************************************/ + +uint64_t rt_timer_time_us(void); + +/**************************************************************************** + * Name: rt_timer_get_alarm + * + * Description: + * Get the timestamp when the next timeout is expected to occur. + * + * Input Parameters: + * None + * + * Returned Value: + * Timestamp of the nearest timer event in microseconds. + * + ****************************************************************************/ + +uint64_t rt_timer_get_alarm(void); + +/**************************************************************************** + * Name: rt_timer_calibration + * + * Description: + * Adjust current RT timer by a certain value. + * + * Input Parameters: + * time_us - adjustment to apply to the RT timer in microseconds. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void rt_timer_calibration(uint64_t time_us); + +/**************************************************************************** + * Name: esp32s2_rt_timer_init + * + * Description: + * Initialize ESP32-S2 RT timer. + * + * Input Parameters: + * None + * + * Returned Value: + * 0 is returned on success. Otherwise, a negated errno value is returned. + * + ****************************************************************************/ + +int esp32s2_rt_timer_init(void); + +/**************************************************************************** + * Name: esp32s2_rt_timer_deinit + * + * Description: + * Deinitialize ESP32-S2 RT timer. + * + * Input Parameters: + * None + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void esp32s2_rt_timer_deinit(void); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_RT_TIMER_H */ diff --git a/arch/xtensa/src/esp32s2/esp32s2_tim.c b/arch/xtensa/src/esp32s2/esp32s2_tim.c index 27235effeed..2b09b55ee92 100644 --- a/arch/xtensa/src/esp32s2/esp32s2_tim.c +++ b/arch/xtensa/src/esp32s2/esp32s2_tim.c @@ -33,6 +33,8 @@ #include "xtensa.h" #include "hardware/esp32s2_tim.h" +#include "hardware/esp32s2_system.h" +#include "hardware/esp32s2_systimer.h" #include "esp32s2_tim.h" #include "esp32s2_cpuint.h" @@ -75,6 +77,9 @@ static void esp32s2_tim_setclksrc(struct esp32s2_tim_dev_s *dev, enum esp32s2_tim_clksrc_e src); static void esp32s2_tim_setpre(struct esp32s2_tim_dev_s *dev, uint16_t pre); +static void esp32s2_tim_setstep(struct esp32s2_tim_dev_s *dev, + enum esp32s2_tim_clksrc_e src, + uint16_t ticks); static void esp32s2_tim_getcounter(struct esp32s2_tim_dev_s *dev, uint64_t *value); static void esp32s2_tim_setcounter(struct esp32s2_tim_dev_s *dev, @@ -82,8 +87,14 @@ static void esp32s2_tim_setcounter(struct esp32s2_tim_dev_s *dev, static void esp32s2_tim_reload_now(struct esp32s2_tim_dev_s *dev); static void esp32s2_tim_getalarmvalue(struct esp32s2_tim_dev_s *dev, uint64_t *value); +static void esp32s2_tim_getperiod(struct esp32s2_tim_dev_s *dev, + uint32_t *value); static void esp32s2_tim_setalarmvalue(struct esp32s2_tim_dev_s *dev, uint64_t value); +static void esp32s2_tim_setperiod(struct esp32s2_tim_dev_s *dev, + uint32_t value); +static void esp32s2_tim_setworkmode(struct esp32s2_tim_dev_s *dev, + enum esp32s2_tim_work_mode_e mode); static void esp32s2_tim_setalarm(struct esp32s2_tim_dev_s *dev, bool enable); static void esp32s2_tim_setautoreload(struct esp32s2_tim_dev_s *dev, @@ -110,10 +121,14 @@ struct esp32s2_tim_ops_s esp32s2_tim_ops = .getcounter = esp32s2_tim_getcounter, .setclksrc = esp32s2_tim_setclksrc, .setpre = esp32s2_tim_setpre, + .setstep = NULL, .setcounter = esp32s2_tim_setcounter, .reloadnow = esp32s2_tim_reload_now, .getalarmvalue = esp32s2_tim_getalarmvalue, + .getperiod = NULL, .setalarmvalue = esp32s2_tim_setalarmvalue, + .setperiod = NULL, + .setworkmode = NULL, .setalarm = esp32s2_tim_setalarm, .setautoreload = esp32s2_tim_setautoreload, .setisr = esp32s2_tim_setisr, @@ -123,6 +138,34 @@ struct esp32s2_tim_ops_s esp32s2_tim_ops = .checkint = esp32s2_tim_checkint }; +/* ESP32S2 SYSTIMER ops */ + +struct esp32s2_tim_ops_s esp32s2_systim_ops = +{ + .start = NULL, /* Systimer doesn't support releasing counter */ + .stop = NULL, /* Systimer doesn't support halting counter */ + .clear = esp32s2_tim_clear, + .setmode = NULL, + .getcounter = esp32s2_tim_getcounter, + .setclksrc = NULL, + .setpre = NULL, + .setstep = esp32s2_tim_setstep, + .setcounter = esp32s2_tim_setcounter, + .reloadnow = esp32s2_tim_reload_now, + .getalarmvalue = esp32s2_tim_getalarmvalue, + .getperiod = esp32s2_tim_getperiod, + .setalarmvalue = esp32s2_tim_setalarmvalue, + .setperiod = esp32s2_tim_setperiod, + .setworkmode = esp32s2_tim_setworkmode, + .setalarm = esp32s2_tim_setalarm, + .setautoreload = NULL, + .setisr = esp32s2_tim_setisr, + .enableint = esp32s2_tim_enableint, + .disableint = esp32s2_tim_disableint, + .ackint = esp32s2_tim_ackint, + .checkint = esp32s2_tim_checkint +}; + #ifdef CONFIG_ESP32S2_TIMER0 /* TIMER0 */ @@ -188,6 +231,22 @@ struct esp32s2_tim_priv_s g_esp32s2_tim3_priv = }; #endif +#ifdef CONFIG_ESP32S2_RT_TIMER +/* SYSTIMER */ + +struct esp32s2_tim_priv_s g_esp32s2_tim4_priv = +{ + .ops = &esp32s2_systim_ops, + .gid = -ENODEV, /* There's no group in systimer */ + .tid = SYSTIMER_COMP0, /* Systimer contains 1 counter and 3 comps */ + .int_pri = ESP32S2_INT_PRIO_DEF, + .periph = ESP32S2_PERI_SYSTIMER_TARGET0, /* Peripheral ID */ + .irq = ESP32S2_IRQ_SYSTIMER_TARGET0, /* Interrupt ID */ + .cpuint = -ENOMEM, /* CPU interrupt assigned to this timer */ + .inuse = false, +}; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -374,6 +433,37 @@ static void esp32s2_tim_setpre(struct esp32s2_tim_dev_s *dev, } } +/**************************************************************************** + * Name: esp32s2_tim_setstep + * + * Description: + * Set the timer increment step, i.e, defines the time interval in ticks + * used by the counter. + * NOTE: dev pointer is not used because this feature is not available + * for Generic Timers and it doesn't rely in any systimer comparator. + * + * Parameters: + * src - Define the clock source for the ticks. + * ticks - Number of ticks to define 1 increment step. + * + ****************************************************************************/ + +static void esp32s2_tim_setstep(struct esp32s2_tim_dev_s *dev, + enum esp32s2_tim_clksrc_e src, + uint16_t ticks) +{ + if (src == ESP32S2_TIM_PLL_CLK) + { + REG_SET_FIELD(SYSTIMER_STEP_REG, SYSTIMER_TIMER_PLL_STEP, + ticks & SYSTIMER_TIMER_PLL_STEP_V); + } + else if(src == ESP32S2_TIM_XTAL_CLK) + { + REG_SET_FIELD(SYSTIMER_STEP_REG, SYSTIMER_TIMER_XTAL_STEP, + ticks & SYSTIMER_TIMER_XTAL_STEP_V); + } +} + /**************************************************************************** * Name: esp32s2_tim_getcounter * @@ -396,34 +486,55 @@ static void esp32s2_tim_getcounter(struct esp32s2_tim_dev_s *dev, DEBUGASSERT(dev); *value = 0; - - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - /* Dummy value (0 or 1) to latch the counter value to read it */ + /* Latch counter */ - putreg32(BIT(0), TIMG_T0UPDATE_REG(priv->gid)); + modifyreg32(SYSTIMER_UPDATE_REG, 0, SYSTIMER_TIMER_UPDATE); + + /* Wait until result is ready */ + + while (!REG_GET_FIELD(SYSTIMER_UPDATE_REG, + SYSTIMER_TIMER_VALUE_VALID)); /* Read value */ - value_32 = getreg32(TIMG_T0HI_REG(priv->gid)); /* High 32 bits */ + value_32 = getreg32(SYSTIMER_VALUE_HI_REG); /* High 32 bits */ *value |= (uint64_t)value_32; *value <<= SHIFT_32; - value_32 = getreg32(TIMG_T0LO_REG(priv->gid)); /* Low 32 bits */ + value_32 = getreg32(SYSTIMER_VALUE_LO_REG); /* Low 32 bits */ *value |= (uint64_t)value_32; } else { - /* Dummy value (0 or 1) to latch the counter value to read it */ + if (priv->tid == TIMER0) + { + /* Dummy value (0 or 1) to latch the counter value to read it */ - putreg32(BIT(0), TIMG_T1UPDATE_REG(priv->gid)); + putreg32(BIT(0), TIMG_T0UPDATE_REG(priv->gid)); - /* Read value */ + /* Read value */ - value_32 = getreg32(TIMG_T1HI_REG(priv->gid)); /* High 32 bits */ - *value |= (uint64_t)value_32; - *value <<= SHIFT_32; - value_32 = getreg32(TIMG_T1LO_REG(priv->gid)); /* Low 32 bits */ - *value |= (uint64_t)value_32; + value_32 = getreg32(TIMG_T0HI_REG(priv->gid)); /* High 32 bits */ + *value |= (uint64_t)value_32; + *value <<= SHIFT_32; + value_32 = getreg32(TIMG_T0LO_REG(priv->gid)); /* Low 32 bits */ + *value |= (uint64_t)value_32; + } + else + { + /* Dummy value (0 or 1) to latch the counter value to read it */ + + putreg32(BIT(0), TIMG_T1UPDATE_REG(priv->gid)); + + /* Read value */ + + value_32 = getreg32(TIMG_T1HI_REG(priv->gid)); /* High 32 bits */ + *value |= (uint64_t)value_32; + *value <<= SHIFT_32; + value_32 = getreg32(TIMG_T1LO_REG(priv->gid)); /* Low 32 bits */ + *value |= (uint64_t)value_32; + } } } @@ -436,6 +547,7 @@ static void esp32s2_tim_getcounter(struct esp32s2_tim_dev_s *dev, * the auto-reload before. * If you want the counter to be loaded instantly, call * esp32s2_tim_reload_now() after this function. + * NOTE: Systimer has 1 counter for 3 comparators. * * Parameters: * dev - Pointer to the timer driver struct. @@ -444,7 +556,7 @@ static void esp32s2_tim_getcounter(struct esp32s2_tim_dev_s *dev, ****************************************************************************/ static void esp32s2_tim_setcounter(struct esp32s2_tim_dev_s *dev, - uint64_t value) + uint64_t value) { struct esp32s2_tim_priv_s *priv = (struct esp32s2_tim_priv_s *)dev; uint64_t low_64 = value & UINT32_MAX; @@ -454,15 +566,23 @@ static void esp32s2_tim_setcounter(struct esp32s2_tim_dev_s *dev, /* Set the counter value */ - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - putreg32((uint32_t)low_64, TIMG_T0LOADLO_REG(priv->gid)); - putreg32((uint32_t)high_64, TIMG_T0LOADHI_REG(priv->gid)); + putreg32((uint32_t)low_64, SYSTIMER_LOAD_LO_REG); + putreg32((uint32_t)high_64, SYSTIMER_LOAD_HI_REG); } else { - putreg32((uint32_t)low_64, TIMG_T1LOADLO_REG(priv->gid)); - putreg32((uint32_t)high_64, TIMG_T1LOADHI_REG(priv->gid)); + if (priv->tid == TIMER0) + { + putreg32((uint32_t)low_64, TIMG_T0LOADLO_REG(priv->gid)); + putreg32((uint32_t)high_64, TIMG_T0LOADHI_REG(priv->gid)); + } + else + { + putreg32((uint32_t)low_64, TIMG_T1LOADLO_REG(priv->gid)); + putreg32((uint32_t)high_64, TIMG_T1LOADHI_REG(priv->gid)); + } } } @@ -486,13 +606,20 @@ static void esp32s2_tim_reload_now(struct esp32s2_tim_dev_s *dev) /* Dummy value to trigger reloading */ - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - putreg32(BIT(0), TIMG_T0LOAD_REG(priv->gid)); + putreg32(BIT(31), SYSTIMER_LOAD_REG); } else { - putreg32(BIT(0), TIMG_T1LOAD_REG(priv->gid)); + if (priv->tid == TIMER0) + { + putreg32(BIT(0), TIMG_T0LOAD_REG(priv->gid)); + } + else + { + putreg32(BIT(0), TIMG_T1LOAD_REG(priv->gid)); + } } } @@ -501,6 +628,8 @@ static void esp32s2_tim_reload_now(struct esp32s2_tim_dev_s *dev) * * Description: * Get the alarm value. + * NOTE: For systimer, the returned alarm value is the Time-Delay Alarm. + * See TRM for more details. * * Parameters: * dev - Pointer to the timer driver struct. @@ -520,21 +649,63 @@ static void esp32s2_tim_getalarmvalue(struct esp32s2_tim_dev_s *dev, /* Read value */ - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - value_32 = getreg32(TIMG_T0ALARMHI_REG(priv->gid)); /* High 32 bits */ + value_32 = getreg32(SYSTIMER_TARGET0_HI_REG); /* High 32 bits */ *value |= (uint64_t)value_32; *value <<= SHIFT_32; - value_32 = getreg32(TIMG_T0ALARMLO_REG(priv->gid)); /* Low 32 bits */ + value_32 = getreg32(SYSTIMER_TARGET0_LO_REG); /* Low 32 bits */ *value |= (uint64_t)value_32; } else { - value_32 = getreg32(TIMG_T1ALARMHI_REG(priv->gid)); /* High 32 bits */ - *value |= (uint64_t)value_32; - *value <<= SHIFT_32; - value_32 = getreg32(TIMG_T1ALARMLO_REG(priv->gid)); /* Low 32 bits */ - *value |= (uint64_t)value_32; + if (priv->tid == TIMER0) + { + value_32 = getreg32(TIMG_T0ALARMHI_REG(priv->gid)); /* High 32 bits */ + *value |= (uint64_t)value_32; + *value <<= SHIFT_32; + value_32 = getreg32(TIMG_T0ALARMLO_REG(priv->gid)); /* Low 32 bits */ + *value |= (uint64_t)value_32; + } + else + { + value_32 = getreg32(TIMG_T1ALARMHI_REG(priv->gid)); /* High 32 bits */ + *value |= (uint64_t)value_32; + *value <<= SHIFT_32; + value_32 = getreg32(TIMG_T1ALARMLO_REG(priv->gid)); /* Low 32 bits */ + *value |= (uint64_t)value_32; + } + } +} + +/**************************************************************************** + * Name: esp32s2_tim_getperiod + * + * Description: + * This function is only available for Systimer. And it's intended to get + * the alarm when it's working on periodic mode. + * + * Parameters: + * dev - Pointer to the timer driver struct. + * value - Pointer to retrieve the current configured alarm value. + * + ****************************************************************************/ + +static void esp32s2_tim_getperiod(struct esp32s2_tim_dev_s *dev, + uint32_t *value) +{ + struct esp32s2_tim_priv_s *priv = (struct esp32s2_tim_priv_s *)dev; + + DEBUGASSERT(dev); + + *value = 0; + + /* Read value */ + + if (priv->tid == SYSTIMER_COMP0) + { + *value = REG_GET_FIELD(SYSTIMER_TARGET0_CONF_REG, + SYSTIMER_TARGET0_PERIOD); } } @@ -562,15 +733,81 @@ static void esp32s2_tim_setalarmvalue(struct esp32s2_tim_dev_s *dev, /* Set an alarm value */ - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - putreg32((uint32_t)low_64, TIMG_T0ALARMLO_REG(priv->gid)); - putreg32((uint32_t)high_64, TIMG_T0ALARMHI_REG(priv->gid)); + putreg32((uint32_t)low_64, SYSTIMER_TARGET0_LO_REG); + putreg32((uint32_t)high_64, SYSTIMER_TARGET0_HI_REG); } else { - putreg32((uint32_t)low_64, TIMG_T1ALARMLO_REG(priv->gid)); - putreg32((uint32_t)high_64, TIMG_T1ALARMHI_REG(priv->gid)); + if (priv->tid == TIMER0) + { + putreg32((uint32_t)low_64, TIMG_T0ALARMLO_REG(priv->gid)); + putreg32((uint32_t)high_64, TIMG_T0ALARMHI_REG(priv->gid)); + } + else + { + putreg32((uint32_t)low_64, TIMG_T1ALARMLO_REG(priv->gid)); + putreg32((uint32_t)high_64, TIMG_T1ALARMHI_REG(priv->gid)); + } + } +} + +/**************************************************************************** + * Name: esp32s2_tim_setperiod + * + * Description: + * This function is only available for Systimer. And it's intended to set + * the alarm when it's working on periodic mode. + * + * Parameters: + * dev - Pointer to the timer driver struct. + * value - Period value. + * + ****************************************************************************/ + +static void esp32s2_tim_setperiod(struct esp32s2_tim_dev_s *dev, + uint32_t value) +{ + struct esp32s2_tim_priv_s *priv = (struct esp32s2_tim_priv_s *)dev; + + DEBUGASSERT(dev); + + /* Read value */ + + if (priv->tid == SYSTIMER_COMP0) + { + REG_SET_FIELD(SYSTIMER_TARGET0_CONF_REG, + SYSTIMER_TARGET0_PERIOD, value); + } +} + +/**************************************************************************** + * Name: esp32s2_tim_setworkmode + * + * Description: + * This function is only available for Systimer. And it's intended to set + * the work mode: Time-Delay alarm mode or periodic alarm mode. + * + * Parameters: + * dev - Pointer to the timer driver struct. + * value - Period value. + * + ****************************************************************************/ + +static void esp32s2_tim_setworkmode(struct esp32s2_tim_dev_s *dev, + enum esp32s2_tim_work_mode_e mode) +{ + struct esp32s2_tim_priv_s *priv = (struct esp32s2_tim_priv_s *)dev; + + DEBUGASSERT(dev); + + /* Read value */ + + if (priv->tid == SYSTIMER_COMP0) + { + REG_SET_FIELD(SYSTIMER_TARGET0_CONF_REG, + SYSTIMER_TARGET0_PERIOD_MODE, mode); } } @@ -594,26 +831,46 @@ static void esp32s2_tim_setalarm(struct esp32s2_tim_dev_s *dev, DEBUGASSERT(dev); - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { if (enable) { - modifyreg32(TIMG_T0CONFIG_REG(priv->gid), 0, TIMG_T0_ALARM_EN_M); + modifyreg32(SYSTIMER_TARGET0_CONF_REG, 0, + SYSTIMER_TARGET0_WORK_EN); } else { - modifyreg32(TIMG_T0CONFIG_REG(priv->gid), TIMG_T0_ALARM_EN_M, 0); + modifyreg32(SYSTIMER_TARGET0_CONF_REG, + SYSTIMER_TARGET0_WORK_EN, 0); } } else { - if (enable) + if (priv->tid == TIMER0) { - modifyreg32(TIMG_T1CONFIG_REG(priv->gid), 0, TIMG_T1_ALARM_EN_M); + if (enable) + { + modifyreg32(TIMG_T0CONFIG_REG(priv->gid), 0, + TIMG_T0_ALARM_EN_M); + } + else + { + modifyreg32(TIMG_T0CONFIG_REG(priv->gid), + TIMG_T0_ALARM_EN_M, 0); + } } else { - modifyreg32(TIMG_T1CONFIG_REG(priv->gid), TIMG_T1_ALARM_EN_M, 0); + if (enable) + { + modifyreg32(TIMG_T1CONFIG_REG(priv->gid), + 0, TIMG_T1_ALARM_EN_M); + } + else + { + modifyreg32(TIMG_T1CONFIG_REG(priv->gid), + TIMG_T1_ALARM_EN_M, 0); + } } } } @@ -729,7 +986,14 @@ static int esp32s2_tim_setisr(struct esp32s2_tim_dev_s *dev, esp32s2_free_cpuint(priv->periph); } - priv->cpuint = esp32s2_alloc_levelint(priv->int_pri); + if (priv->tid == SYSTIMER_COMP0) + { + priv->cpuint = esp32s2_alloc_edgeint(priv->int_pri); + } + else + { + priv->cpuint = esp32s2_alloc_levelint(priv->int_pri); + } if (priv->cpuint < 0) { @@ -765,7 +1029,7 @@ errout: * Name: esp32s2_tim_enableint * * Description: - * Enable a level Interrupt at the alarm if it is set. + * Enable Interrupt at the alarm if it is set. * * Parameters: * dev - Pointer to the timer driver struct. @@ -778,15 +1042,26 @@ static void esp32s2_tim_enableint(struct esp32s2_tim_dev_s *dev) DEBUGASSERT(dev); - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - modifyreg32(TIMG_T0CONFIG_REG(priv->gid), 0, TIMG_T0_LEVEL_INT_EN_M); - modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), 0, TIMG_T0_INT_ENA_M); + modifyreg32(SYSTIMER_INT_ENA_REG, 0, SYSTIMER_SYSTIMER_INT0_ENA_M); } else { - modifyreg32(TIMG_T1CONFIG_REG(priv->gid), 0, TIMG_T1_LEVEL_INT_EN_M); - modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), 0, TIMG_T1_INT_ENA_M); + if (priv->tid == TIMER0) + { + modifyreg32(TIMG_T0CONFIG_REG(priv->gid), 0, + TIMG_T0_LEVEL_INT_EN_M); + modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), 0, + TIMG_T0_INT_ENA_M); + } + else + { + modifyreg32(TIMG_T1CONFIG_REG(priv->gid), 0, + TIMG_T1_LEVEL_INT_EN_M); + modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), 0, + TIMG_T1_INT_ENA_M); + } } } @@ -794,7 +1069,7 @@ static void esp32s2_tim_enableint(struct esp32s2_tim_dev_s *dev) * Name: esp32s2_tim_disableint * * Description: - * Disable a level Interrupt at the alarm if it is set. + * Disable a Interrupt at the alarm if it is set. * * Parameters: * dev - Pointer to the timer driver struct. @@ -807,15 +1082,26 @@ static void esp32s2_tim_disableint(struct esp32s2_tim_dev_s *dev) DEBUGASSERT(dev); - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - modifyreg32(TIMG_T0CONFIG_REG(priv->gid), TIMG_T0_LEVEL_INT_EN_M, 0); - modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), TIMG_T0_INT_ENA_M, 0); + modifyreg32(SYSTIMER_INT_ENA_REG, SYSTIMER_SYSTIMER_INT0_ENA_M, 0); } else { - modifyreg32(TIMG_T1CONFIG_REG(priv->gid), TIMG_T1_LEVEL_INT_EN_M, 0); - modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), TIMG_T1_INT_ENA_M, 0); + if (priv->tid == TIMER0) + { + modifyreg32(TIMG_T0CONFIG_REG(priv->gid), + TIMG_T0_LEVEL_INT_EN_M, 0); + modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), + TIMG_T0_INT_ENA_M, 0); + } + else + { + modifyreg32(TIMG_T1CONFIG_REG(priv->gid), + TIMG_T1_LEVEL_INT_EN_M, 0); + modifyreg32(TIMG_INT_ENA_TIMERS_REG(priv->gid), + TIMG_T1_INT_ENA_M, 0); + } } } @@ -836,13 +1122,22 @@ static void esp32s2_tim_ackint(struct esp32s2_tim_dev_s *dev) DEBUGASSERT(dev); - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - modifyreg32(TIMG_INT_CLR_TIMERS_REG(priv->gid), 0, TIMG_T0_INT_CLR_M); + modifyreg32(SYSTIMER_INT_CLR_REG, 0, SYSTIMER_SYSTIMER_INT0_CLR_M); } else { - modifyreg32(TIMG_INT_CLR_TIMERS_REG(priv->gid), 0, TIMG_T1_INT_CLR_M); + if (priv->tid == TIMER0) + { + modifyreg32(TIMG_INT_CLR_TIMERS_REG(priv->gid), 0, + TIMG_T0_INT_CLR_M); + } + else + { + modifyreg32(TIMG_INT_CLR_TIMERS_REG(priv->gid), 0, + TIMG_T1_INT_CLR_M); + } } } @@ -868,15 +1163,23 @@ static int esp32s2_tim_checkint(struct esp32s2_tim_dev_s *dev) DEBUGASSERT(dev); - if (priv->tid == TIMER0) + if (priv->tid == SYSTIMER_COMP0) { - reg_value = getreg32(TIMG_INT_ST_TIMERS_REG(priv->gid)); - ret = REG_MASK(reg_value, TIMG_T0_INT_ST); + reg_value = getreg32(SYSTIMER_INT_RAW_REG); + ret = REG_MASK(reg_value, SYSTIMER_SYSTIMER_INT0_RAW); } else { - reg_value = getreg32(TIMG_INT_ST_TIMERS_REG(priv->gid)); - ret = REG_MASK(reg_value, TIMG_T1_INT_ST); + if (priv->tid == TIMER0) + { + reg_value = getreg32(TIMG_INT_ST_TIMERS_REG(priv->gid)); + ret = REG_MASK(reg_value, TIMG_T0_INT_ST); + } + else + { + reg_value = getreg32(TIMG_INT_ST_TIMERS_REG(priv->gid)); + ret = REG_MASK(reg_value, TIMG_T1_INT_ST); + } } return ret; @@ -912,7 +1215,7 @@ struct esp32s2_tim_dev_s *esp32s2_tim_init(int timer) switch (timer) { #ifdef CONFIG_ESP32S2_TIMER0 - case 0: + case TIMER0: { tim = &g_esp32s2_tim0_priv; break; @@ -920,7 +1223,7 @@ struct esp32s2_tim_dev_s *esp32s2_tim_init(int timer) #endif #ifdef CONFIG_ESP32S2_TIMER1 - case 1: + case TIMER1: { tim = &g_esp32s2_tim1_priv; break; @@ -928,7 +1231,7 @@ struct esp32s2_tim_dev_s *esp32s2_tim_init(int timer) #endif #ifdef CONFIG_ESP32S2_TIMER2 - case 2: + case TIMER2: { tim = &g_esp32s2_tim2_priv; break; @@ -936,18 +1239,28 @@ struct esp32s2_tim_dev_s *esp32s2_tim_init(int timer) #endif #ifdef CONFIG_ESP32S2_TIMER3 - case 3: + case TIMER3: { tim = &g_esp32s2_tim3_priv; break; } #endif - default: +#ifdef CONFIG_ESP32S2_RT_TIMER + case SYSTIMER_COMP0: { - tmrerr("ERROR: unsupported TIMER %d\n", timer); - goto errout; + tim = &g_esp32s2_tim4_priv; + + /* Enable Systimer peripheral clock and reset it */ + + modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, SYSTEM_SYSTIMER_CLK_EN); + modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, SYSTEM_SYSTIMER_RST); + modifyreg32(SYSTEM_PERIP_RST_EN0_REG, SYSTEM_SYSTIMER_RST, 0); + modifyreg32(SYSTIMER_CONF_REG, 0, SYSTIMER_CLK_EN + | SYSTIMER_CLK_FO); + break; } +#endif } /* Verify if it is in use */ @@ -962,7 +1275,6 @@ struct esp32s2_tim_dev_s *esp32s2_tim_init(int timer) tim = NULL; } -errout: return (struct esp32s2_tim_dev_s *)tim; } diff --git a/arch/xtensa/src/esp32s2/esp32s2_tim.h b/arch/xtensa/src/esp32s2/esp32s2_tim.h index 3ad4be67f29..30d373b19b2 100644 --- a/arch/xtensa/src/esp32s2/esp32s2_tim.h +++ b/arch/xtensa/src/esp32s2/esp32s2_tim.h @@ -42,12 +42,16 @@ #define ESP32S2_TIM_CLEAR(d) ((d)->ops->clear(d)) #define ESP32S2_TIM_SETMODE(d, m) ((d)->ops->setmode(d, m)) #define ESP32S2_TIM_SETPRE(d, p) ((d)->ops->setpre(d, p)) +#define ESP32S2_TIM_SETSTEP(d, s, t) ((d)->ops->setstep(d, s, t)) #define ESP32S2_TIM_GETCTR(d, v) ((d)->ops->getcounter(d, v)) #define ESP32S2_TIM_CLK_SRC(d, s) ((d)->ops->setclksrc(d, s)) #define ESP32S2_TIM_SETCTR(d, v) ((d)->ops->setcounter(d, v)) #define ESP32S2_TIM_RLD_NOW(d) ((d)->ops->reloadnow(d)) #define ESP32S2_TIM_GETALRVL(d, v) ((d)->ops->getalarmvalue(d, v)) +#define ESP32S2_TIM_GETPERIOD(d, v) ((d)->ops->getperiod(d, v)) #define ESP32S2_TIM_SETALRVL(d, v) ((d)->ops->setalarmvalue(d, v)) +#define ESP32S2_TIM_SETPERIOD(d, v) ((d)->ops->setperiod(d, v)) +#define ESP32S2_TIM_SETWORKMODE(d, v) ((d)->ops->setworkmode(d, v)) #define ESP32S2_TIM_SETALRM(d, e) ((d)->ops->setalarm(d, e)) #define ESP32S2_TIM_SETARLD(d, e) ((d)->ops->setautoreload(d, e)) #define ESP32S2_TIM_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg)) @@ -56,10 +60,13 @@ #define ESP32S2_TIM_ACKINT(d) ((d)->ops->ackint(d)) #define ESP32S2_TIM_CHECKINT(d) ((d)->ops->checkint(d)) -#define TIMER0 0 -#define TIMER1 1 -#define TIMER2 2 -#define TIMER3 3 +#define TIMER0 0 /* Timer group 0 timer 0 */ +#define TIMER1 1 /* Timer group 0 timer 1 */ +#define TIMER2 2 /* Timer group 1 timer 0 */ +#define TIMER3 3 /* Timer group 1 timer 1 */ +#define SYSTIMER_COMP0 4 /* Systimer comparator 0 */ +#define SYSTIMER_COMP1 5 /* Systimer comparator 1 */ +#define SYSTIMER_COMP2 6 /* Systimer comparator 2 */ /**************************************************************************** * Public Types @@ -73,12 +80,21 @@ enum esp32s2_tim_mode_e ESP32S2_TIM_MODE_UP, }; +/* Systimer Work modes */ + +enum esp32s2_tim_work_mode_e +{ + ESP32S2_TIM_DELAY_ALRM, + ESP32S2_TIM_PERIOD_ALRM, +}; + /* Timer mode */ enum esp32s2_tim_clksrc_e { - ESP32S2_TIM_APB_CLK, - ESP32S2_TIM_XTAL_CLK, + ESP32S2_TIM_APB_CLK, /* Available only for Generic Timers */ + ESP32S2_TIM_XTAL_CLK, /* Available for both Generic Timers and Systimer */ + ESP32S2_TIM_PLL_CLK /* Available only for Systimer */ }; /* ESP32-S2 TIM device */ @@ -105,6 +121,9 @@ struct esp32s2_tim_ops_s void (*setmode)(struct esp32s2_tim_dev_s *dev, enum esp32s2_tim_mode_e mode); void (*setpre)(struct esp32s2_tim_dev_s *dev, uint16_t pre); + void (*setstep)(struct esp32s2_tim_dev_s *dev, + enum esp32s2_tim_clksrc_e src, + uint16_t ticks); void (*getcounter)(struct esp32s2_tim_dev_s *dev, uint64_t *value); void (*setclksrc)(struct esp32s2_tim_dev_s *dev, @@ -113,8 +132,12 @@ struct esp32s2_tim_ops_s void (*reloadnow)(struct esp32s2_tim_dev_s *dev); void (*getalarmvalue)(struct esp32s2_tim_dev_s *dev, uint64_t *value); + void (*getperiod)(struct esp32s2_tim_dev_s *dev, uint32_t *value); void (*setalarmvalue)(struct esp32s2_tim_dev_s *dev, uint64_t value); + void (*setperiod)(struct esp32s2_tim_dev_s *dev, uint32_t value); + void (*setworkmode)(struct esp32s2_tim_dev_s *dev, + enum esp32s2_tim_work_mode_e); void (*setalarm)(struct esp32s2_tim_dev_s *dev, bool enable); void (*setautoreload)(struct esp32s2_tim_dev_s *dev, bool enable); diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_systimer.h b/arch/xtensa/src/esp32s2/hardware/esp32s2_systimer.h new file mode 100644 index 00000000000..112e2807154 --- /dev/null +++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_systimer.h @@ -0,0 +1,484 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s2/hardware/esp32s2_systimer.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_SYSTIMER_H +#define __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_SYSTIMER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "esp32s2_soc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* SYSTIMER_CONF_REG register + * Configure system timer clock + */ + +#define SYSTIMER_CONF_REG (DR_REG_SYSTIMER_BASE + 0x0) + +/* SYSTIMER_CLK_EN : R/W; bitpos: [31]; default: 0; + * register clock enable + */ + +#define SYSTIMER_CLK_EN (BIT(31)) +#define SYSTIMER_CLK_EN_M (SYSTIMER_CLK_EN_V << SYSTIMER_CLK_EN_S) +#define SYSTIMER_CLK_EN_V 0x00000001 +#define SYSTIMER_CLK_EN_S 31 + +/* SYSTIMER_CLK_FO : R/W; bitpos: [0]; default: 0; + * system timer force clock enable + */ + +#define SYSTIMER_CLK_FO (BIT(0)) +#define SYSTIMER_CLK_FO_M (SYSTIMER_CLK_FO_V << SYSTIMER_CLK_FO_S) +#define SYSTIMER_CLK_FO_V 0x00000001 +#define SYSTIMER_CLK_FO_S 0 + +/* SYSTIMER_LOAD_REG register + * load value to system timer + */ + +#define SYSTIMER_LOAD_REG (DR_REG_SYSTIMER_BASE + 0x4) + +/* SYSTIMER_TIMER_LOAD : WO; bitpos: [31]; default: 0; + * load value to system timer + */ + +#define SYSTIMER_TIMER_LOAD (BIT(31)) +#define SYSTIMER_TIMER_LOAD_M (SYSTIMER_TIMER_LOAD_V << SYSTIMER_TIMER_LOAD_S) +#define SYSTIMER_TIMER_LOAD_V 0x00000001 +#define SYSTIMER_TIMER_LOAD_S 31 + +/* SYSTIMER_LOAD_HI_REG register + * High 32-bit load to system timer + */ + +#define SYSTIMER_LOAD_HI_REG (DR_REG_SYSTIMER_BASE + 0x8) + +/* SYSTIMER_TIMER_LOAD_HI : R/W; bitpos: [31:0]; default: 0; + * High 32-bit load to system timer + */ + +#define SYSTIMER_TIMER_LOAD_HI 0xFFFFFFFF +#define SYSTIMER_TIMER_LOAD_HI_M (SYSTIMER_TIMER_LOAD_HI_V << SYSTIMER_TIMER_LOAD_HI_S) +#define SYSTIMER_TIMER_LOAD_HI_V 0xFFFFFFFF +#define SYSTIMER_TIMER_LOAD_HI_S 0 + +/* SYSTIMER_LOAD_LO_REG register + * Low 32-bit load to system timer + */ + +#define SYSTIMER_LOAD_LO_REG (DR_REG_SYSTIMER_BASE + 0xc) + +/* SYSTIMER_TIMER_LOAD_LO : R/W; bitpos: [31:0]; default: 0; + * Low 32-bit load to system timer + */ + +#define SYSTIMER_TIMER_LOAD_LO 0xFFFFFFFF +#define SYSTIMER_TIMER_LOAD_LO_M (SYSTIMER_TIMER_LOAD_LO_V << SYSTIMER_TIMER_LOAD_LO_S) +#define SYSTIMER_TIMER_LOAD_LO_V 0xFFFFFFFF +#define SYSTIMER_TIMER_LOAD_LO_S 0 + +/* SYSTIMER_STEP_REG register + * system timer accumulation step + */ + +#define SYSTIMER_STEP_REG (DR_REG_SYSTIMER_BASE + 0x10) + +/* SYSTIMER_TIMER_PLL_STEP : R/W; bitpos: [19:10]; default: 1; + * system timer accumulation step when using PLL + */ + +#define SYSTIMER_TIMER_PLL_STEP 0x000003FF +#define SYSTIMER_TIMER_PLL_STEP_M (SYSTIMER_TIMER_PLL_STEP_V << SYSTIMER_TIMER_PLL_STEP_S) +#define SYSTIMER_TIMER_PLL_STEP_V 0x000003FF +#define SYSTIMER_TIMER_PLL_STEP_S 10 + +/* SYSTIMER_TIMER_XTAL_STEP : R/W; bitpos: [9:0]; default: 80; + * system timer accumulation step when using XTAL + */ + +#define SYSTIMER_TIMER_XTAL_STEP 0x000003FF +#define SYSTIMER_TIMER_XTAL_STEP_M (SYSTIMER_TIMER_XTAL_STEP_V << SYSTIMER_TIMER_XTAL_STEP_S) +#define SYSTIMER_TIMER_XTAL_STEP_V 0x000003FF +#define SYSTIMER_TIMER_XTAL_STEP_S 0 + +/* SYSTIMER_TARGET0_HI_REG register + * System timer target0 high 32-bit + */ + +#define SYSTIMER_TARGET0_HI_REG (DR_REG_SYSTIMER_BASE + 0x14) + +/* SYSTIMER_TIMER_TARGET0_HI : R/W; bitpos: [31:0]; default: 0; + * System timer target0 high 32-bit + */ + +#define SYSTIMER_TIMER_TARGET0_HI 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET0_HI_M (SYSTIMER_TIMER_TARGET0_HI_V << SYSTIMER_TIMER_TARGET0_HI_S) +#define SYSTIMER_TIMER_TARGET0_HI_V 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET0_HI_S 0 + +/* SYSTIMER_TARGET0_LO_REG register + * System timer target0 low 32-bit + */ + +#define SYSTIMER_TARGET0_LO_REG (DR_REG_SYSTIMER_BASE + 0x18) + +/* SYSTIMER_TIMER_TARGET0_LO : R/W; bitpos: [31:0]; default: 0; + * System timer target0 low 32-bit + */ + +#define SYSTIMER_TIMER_TARGET0_LO 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET0_LO_M (SYSTIMER_TIMER_TARGET0_LO_V << SYSTIMER_TIMER_TARGET0_LO_S) +#define SYSTIMER_TIMER_TARGET0_LO_V 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET0_LO_S 0 + +/* SYSTIMER_TARGET1_HI_REG register + * System timer target1 high 32-bit + */ + +#define SYSTIMER_TARGET1_HI_REG (DR_REG_SYSTIMER_BASE + 0x1c) + +/* SYSTIMER_TIMER_TARGET1_HI : R/W; bitpos: [31:0]; default: 0; + * System timer target1 high 32-bit + */ + +#define SYSTIMER_TIMER_TARGET1_HI 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET1_HI_M (SYSTIMER_TIMER_TARGET1_HI_V << SYSTIMER_TIMER_TARGET1_HI_S) +#define SYSTIMER_TIMER_TARGET1_HI_V 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET1_HI_S 0 + +/* SYSTIMER_TARGET1_LO_REG register + * System timer target1 low 32-bit + */ + +#define SYSTIMER_TARGET1_LO_REG (DR_REG_SYSTIMER_BASE + 0x20) + +/* SYSTIMER_TIMER_TARGET1_LO : R/W; bitpos: [31:0]; default: 0; + * System timer target1 low 32-bit + */ + +#define SYSTIMER_TIMER_TARGET1_LO 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET1_LO_M (SYSTIMER_TIMER_TARGET1_LO_V << SYSTIMER_TIMER_TARGET1_LO_S) +#define SYSTIMER_TIMER_TARGET1_LO_V 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET1_LO_S 0 + +/* SYSTIMER_TARGET2_HI_REG register + * System timer target2 high 32-bit + */ + +#define SYSTIMER_TARGET2_HI_REG (DR_REG_SYSTIMER_BASE + 0x24) + +/* SYSTIMER_TIMER_TARGET2_HI : R/W; bitpos: [31:0]; default: 0; + * System timer target2 high 32-bit + */ + +#define SYSTIMER_TIMER_TARGET2_HI 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET2_HI_M (SYSTIMER_TIMER_TARGET2_HI_V << SYSTIMER_TIMER_TARGET2_HI_S) +#define SYSTIMER_TIMER_TARGET2_HI_V 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET2_HI_S 0 + +/* SYSTIMER_TARGET2_LO_REG register + * System timer target2 low 32-bit + */ + +#define SYSTIMER_TARGET2_LO_REG (DR_REG_SYSTIMER_BASE + 0x28) + +/* SYSTIMER_TIMER_TARGET2_LO : R/W; bitpos: [31:0]; default: 0; + * System timer target2 low 32-bit + */ + +#define SYSTIMER_TIMER_TARGET2_LO 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET2_LO_M (SYSTIMER_TIMER_TARGET2_LO_V << SYSTIMER_TIMER_TARGET2_LO_S) +#define SYSTIMER_TIMER_TARGET2_LO_V 0xFFFFFFFF +#define SYSTIMER_TIMER_TARGET2_LO_S 0 + +/* SYSTIMER_TARGET0_CONF_REG register + * Configure system timer target0 work mode + */ + +#define SYSTIMER_TARGET0_CONF_REG (DR_REG_SYSTIMER_BASE + 0x2c) + +/* SYSTIMER_TARGET0_WORK_EN : R/W; bitpos: [31]; default: 0; + * system timer target0 work enable + */ + +#define SYSTIMER_TARGET0_WORK_EN (BIT(31)) +#define SYSTIMER_TARGET0_WORK_EN_M (SYSTIMER_TARGET0_WORK_EN_V << SYSTIMER_TARGET0_WORK_EN_S) +#define SYSTIMER_TARGET0_WORK_EN_V 0x00000001 +#define SYSTIMER_TARGET0_WORK_EN_S 31 + +/* SYSTIMER_TARGET0_PERIOD_MODE : R/W; bitpos: [30]; default: 0; + * Whether system timer target0 work in period mode + */ + +#define SYSTIMER_TARGET0_PERIOD_MODE (BIT(30)) +#define SYSTIMER_TARGET0_PERIOD_MODE_M (SYSTIMER_TARGET0_PERIOD_MODE_V << SYSTIMER_TARGET0_PERIOD_MODE_S) +#define SYSTIMER_TARGET0_PERIOD_MODE_V 0x00000001 +#define SYSTIMER_TARGET0_PERIOD_MODE_S 30 + +/* SYSTIMER_TARGET0_PERIOD : R/W; bitpos: [29:0]; default: 0; + * System timer target0 alarm period + */ + +#define SYSTIMER_TARGET0_PERIOD 0x3FFFFFFF +#define SYSTIMER_TARGET0_PERIOD_M (SYSTIMER_TARGET0_PERIOD_V << SYSTIMER_TARGET0_PERIOD_S) +#define SYSTIMER_TARGET0_PERIOD_V 0x3FFFFFFF +#define SYSTIMER_TARGET0_PERIOD_S 0 + +/* SYSTIMER_TARGET1_CONF_REG register + * Configure system timer target1 work mode + */ + +#define SYSTIMER_TARGET1_CONF_REG (DR_REG_SYSTIMER_BASE + 0x30) + +/* SYSTIMER_TARGET1_WORK_EN : R/W; bitpos: [31]; default: 0; + * system timer target1 work enable + */ + +#define SYSTIMER_TARGET1_WORK_EN (BIT(31)) +#define SYSTIMER_TARGET1_WORK_EN_M (SYSTIMER_TARGET1_WORK_EN_V << SYSTIMER_TARGET1_WORK_EN_S) +#define SYSTIMER_TARGET1_WORK_EN_V 0x00000001 +#define SYSTIMER_TARGET1_WORK_EN_S 31 + +/* SYSTIMER_TARGET1_PERIOD_MODE : R/W; bitpos: [30]; default: 0; + * Whether system timer target1 work in period mode + */ + +#define SYSTIMER_TARGET1_PERIOD_MODE (BIT(30)) +#define SYSTIMER_TARGET1_PERIOD_MODE_M (SYSTIMER_TARGET1_PERIOD_MODE_V << SYSTIMER_TARGET1_PERIOD_MODE_S) +#define SYSTIMER_TARGET1_PERIOD_MODE_V 0x00000001 +#define SYSTIMER_TARGET1_PERIOD_MODE_S 30 + +/* SYSTIMER_TARGET1_PERIOD : R/W; bitpos: [29:0]; default: 0; + * System timer target1 alarm period + */ + +#define SYSTIMER_TARGET1_PERIOD 0x3FFFFFFF +#define SYSTIMER_TARGET1_PERIOD_M (SYSTIMER_TARGET1_PERIOD_V << SYSTIMER_TARGET1_PERIOD_S) +#define SYSTIMER_TARGET1_PERIOD_V 0x3FFFFFFF +#define SYSTIMER_TARGET1_PERIOD_S 0 + +/* SYSTIMER_TARGET2_CONF_REG register + * Configure system timer target2 work mode + */ + +#define SYSTIMER_TARGET2_CONF_REG (DR_REG_SYSTIMER_BASE + 0x34) + +/* SYSTIMER_TARGET2_WORK_EN : R/W; bitpos: [31]; default: 0; + * system timer target2 work enable + */ + +#define SYSTIMER_TARGET2_WORK_EN (BIT(31)) +#define SYSTIMER_TARGET2_WORK_EN_M (SYSTIMER_TARGET2_WORK_EN_V << SYSTIMER_TARGET2_WORK_EN_S) +#define SYSTIMER_TARGET2_WORK_EN_V 0x00000001 +#define SYSTIMER_TARGET2_WORK_EN_S 31 + +/* SYSTIMER_TARGET2_PERIOD_MODE : R/W; bitpos: [30]; default: 0; + * Whether system timer target2 work in period mode + */ + +#define SYSTIMER_TARGET2_PERIOD_MODE (BIT(30)) +#define SYSTIMER_TARGET2_PERIOD_MODE_M (SYSTIMER_TARGET2_PERIOD_MODE_V << SYSTIMER_TARGET2_PERIOD_MODE_S) +#define SYSTIMER_TARGET2_PERIOD_MODE_V 0x00000001 +#define SYSTIMER_TARGET2_PERIOD_MODE_S 30 + +/* SYSTIMER_TARGET2_PERIOD : R/W; bitpos: [29:0]; default: 0; + * System timer target2 alarm period + */ + +#define SYSTIMER_TARGET2_PERIOD 0x3FFFFFFF +#define SYSTIMER_TARGET2_PERIOD_M (SYSTIMER_TARGET2_PERIOD_V << SYSTIMER_TARGET2_PERIOD_S) +#define SYSTIMER_TARGET2_PERIOD_V 0x3FFFFFFF +#define SYSTIMER_TARGET2_PERIOD_S 0 + +/* SYSTIMER_UPDATE_REG register + * Read out system timer value + */ + +#define SYSTIMER_UPDATE_REG (DR_REG_SYSTIMER_BASE + 0x38) + +/* SYSTIMER_TIMER_UPDATE : WO; bitpos: [31]; default: 0; + * Update system timer value to register + */ + +#define SYSTIMER_TIMER_UPDATE (BIT(31)) +#define SYSTIMER_TIMER_UPDATE_M (SYSTIMER_TIMER_UPDATE_V << SYSTIMER_TIMER_UPDATE_S) +#define SYSTIMER_TIMER_UPDATE_V 0x00000001 +#define SYSTIMER_TIMER_UPDATE_S 31 + +/* SYSTIMER_TIMER_VALUE_VALID : RO; bitpos: [30]; default: 0; + * If it is valid to read out timer value from register + */ + +#define SYSTIMER_TIMER_VALUE_VALID (BIT(30)) +#define SYSTIMER_TIMER_VALUE_VALID_M (SYSTIMER_TIMER_VALUE_VALID_V << SYSTIMER_TIMER_VALUE_VALID_S) +#define SYSTIMER_TIMER_VALUE_VALID_V 0x00000001 +#define SYSTIMER_TIMER_VALUE_VALID_S 30 + +/* SYSTIMER_VALUE_HI_REG register + * system timer high 32-bit + */ + +#define SYSTIMER_VALUE_HI_REG (DR_REG_SYSTIMER_BASE + 0x3c) + +/* SYSTIMER_TIMER_VALUE_HI : RO; bitpos: [31:0]; default: 0; + * system timer high 32-bit + */ + +#define SYSTIMER_TIMER_VALUE_HI 0xFFFFFFFF +#define SYSTIMER_TIMER_VALUE_HI_M (SYSTIMER_TIMER_VALUE_HI_V << SYSTIMER_TIMER_VALUE_HI_S) +#define SYSTIMER_TIMER_VALUE_HI_V 0xFFFFFFFF +#define SYSTIMER_TIMER_VALUE_HI_S 0 + +/* SYSTIMER_VALUE_LO_REG register + * system timer low 32-bit + */ + +#define SYSTIMER_VALUE_LO_REG (DR_REG_SYSTIMER_BASE + 0x40) + +/* SYSTIMER_TIMER_VALUE_LO : RO; bitpos: [31:0]; default: 0; + * system timer low 32-bit + */ + +#define SYSTIMER_TIMER_VALUE_LO 0xFFFFFFFF +#define SYSTIMER_TIMER_VALUE_LO_M (SYSTIMER_TIMER_VALUE_LO_V << SYSTIMER_TIMER_VALUE_LO_S) +#define SYSTIMER_TIMER_VALUE_LO_V 0xFFFFFFFF +#define SYSTIMER_TIMER_VALUE_LO_S 0 + +/* SYSTIMER_INT_ENA_REG register + * system timer interrupt enable + */ + +#define SYSTIMER_INT_ENA_REG (DR_REG_SYSTIMER_BASE + 0x44) + +/* SYSTIMER_SYSTIMER_INT2_ENA : R/W; bitpos: [2]; default: 0; + * system timer target2 interrupt enable + */ + +#define SYSTIMER_SYSTIMER_INT2_ENA (BIT(2)) +#define SYSTIMER_SYSTIMER_INT2_ENA_M (SYSTIMER_SYSTIMER_INT2_ENA_V << SYSTIMER_SYSTIMER_INT2_ENA_S) +#define SYSTIMER_SYSTIMER_INT2_ENA_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT2_ENA_S 2 + +/* SYSTIMER_SYSTIMER_INT1_ENA : R/W; bitpos: [1]; default: 0; + * system timer target1 interrupt enable + */ + +#define SYSTIMER_SYSTIMER_INT1_ENA (BIT(1)) +#define SYSTIMER_SYSTIMER_INT1_ENA_M (SYSTIMER_SYSTIMER_INT1_ENA_V << SYSTIMER_SYSTIMER_INT1_ENA_S) +#define SYSTIMER_SYSTIMER_INT1_ENA_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT1_ENA_S 1 + +/* SYSTIMER_SYSTIMER_INT0_ENA : R/W; bitpos: [0]; default: 0; + * system timer target0 interrupt enable + */ + +#define SYSTIMER_SYSTIMER_INT0_ENA (BIT(0)) +#define SYSTIMER_SYSTIMER_INT0_ENA_M (SYSTIMER_SYSTIMER_INT0_ENA_V << SYSTIMER_SYSTIMER_INT0_ENA_S) +#define SYSTIMER_SYSTIMER_INT0_ENA_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT0_ENA_S 0 + +/* SYSTIMER_INT_RAW_REG register + * system timer interrupt raw + */ + +#define SYSTIMER_INT_RAW_REG (DR_REG_SYSTIMER_BASE + 0x48) + +/* SYSTIMER_SYSTIMER_INT2_RAW : RO; bitpos: [2]; default: 0; + * system timer target2 interrupt raw + */ + +#define SYSTIMER_SYSTIMER_INT2_RAW (BIT(2)) +#define SYSTIMER_SYSTIMER_INT2_RAW_M (SYSTIMER_SYSTIMER_INT2_RAW_V << SYSTIMER_SYSTIMER_INT2_RAW_S) +#define SYSTIMER_SYSTIMER_INT2_RAW_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT2_RAW_S 2 + +/* SYSTIMER_SYSTIMER_INT1_RAW : RO; bitpos: [1]; default: 0; + * system timer target1 interrupt raw + */ + +#define SYSTIMER_SYSTIMER_INT1_RAW (BIT(1)) +#define SYSTIMER_SYSTIMER_INT1_RAW_M (SYSTIMER_SYSTIMER_INT1_RAW_V << SYSTIMER_SYSTIMER_INT1_RAW_S) +#define SYSTIMER_SYSTIMER_INT1_RAW_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT1_RAW_S 1 + +/* SYSTIMER_SYSTIMER_INT0_RAW : RO; bitpos: [0]; default: 0; + * system timer target0 interrupt raw + */ + +#define SYSTIMER_SYSTIMER_INT0_RAW (BIT(0)) +#define SYSTIMER_SYSTIMER_INT0_RAW_M (SYSTIMER_SYSTIMER_INT0_RAW_V << SYSTIMER_SYSTIMER_INT0_RAW_S) +#define SYSTIMER_SYSTIMER_INT0_RAW_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT0_RAW_S 0 + +/* SYSTIMER_INT_CLR_REG register + * system timer interrupt clear + */ + +#define SYSTIMER_INT_CLR_REG (DR_REG_SYSTIMER_BASE + 0x4c) + +/* SYSTIMER_SYSTIMER_INT2_CLR : WO; bitpos: [2]; default: 0; + * system timer target2 interrupt clear + */ + +#define SYSTIMER_SYSTIMER_INT2_CLR (BIT(2)) +#define SYSTIMER_SYSTIMER_INT2_CLR_M (SYSTIMER_SYSTIMER_INT2_CLR_V << SYSTIMER_SYSTIMER_INT2_CLR_S) +#define SYSTIMER_SYSTIMER_INT2_CLR_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT2_CLR_S 2 + +/* SYSTIMER_SYSTIMER_INT1_CLR : WO; bitpos: [1]; default: 0; + * system timer target1 interrupt clear + */ + +#define SYSTIMER_SYSTIMER_INT1_CLR (BIT(1)) +#define SYSTIMER_SYSTIMER_INT1_CLR_M (SYSTIMER_SYSTIMER_INT1_CLR_V << SYSTIMER_SYSTIMER_INT1_CLR_S) +#define SYSTIMER_SYSTIMER_INT1_CLR_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT1_CLR_S 1 + +/* SYSTIMER_SYSTIMER_INT0_CLR : WO; bitpos: [0]; default: 0; + * system timer target0 interrupt clear + */ + +#define SYSTIMER_SYSTIMER_INT0_CLR (BIT(0)) +#define SYSTIMER_SYSTIMER_INT0_CLR_M (SYSTIMER_SYSTIMER_INT0_CLR_V << SYSTIMER_SYSTIMER_INT0_CLR_S) +#define SYSTIMER_SYSTIMER_INT0_CLR_V 0x00000001 +#define SYSTIMER_SYSTIMER_INT0_CLR_S 0 + +/* SYSTIMER_DATE_REG register + * system timer register version + */ + +#define SYSTIMER_DATE_REG (DR_REG_SYSTIMER_BASE + 0xfc) + +/* SYSTIMER_DATE : R/W; bitpos: [31:0]; default: 25194848; + * system timer register version + */ + +#define SYSTIMER_DATE 0xFFFFFFFF +#define SYSTIMER_DATE_M (SYSTIMER_DATE_V << SYSTIMER_DATE_S) +#define SYSTIMER_DATE_V 0xFFFFFFFF +#define SYSTIMER_DATE_S 0 + +#endif /* __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_SYSTIMER_H */ diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c index 42eab288f66..77297ac21d8 100644 --- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c +++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c @@ -50,6 +50,10 @@ # include "esp32s2_tim_lowerhalf.h" #endif +#ifdef CONFIG_ESP32S2_RT_TIMER +# include "esp32s2_rt_timer.h" +#endif + #include "esp32s2-saola-1.h" /**************************************************************************** @@ -154,6 +158,14 @@ int esp32s2_bringup(void) #endif /* CONFIG_TIMER */ +#ifdef CONFIG_ESP32S2_RT_TIMER + ret = esp32s2_rt_timer_init(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize RT timer: %d\n", ret); + } +#endif + /* If we got here then perhaps not all initialization was successful, but * at least enough succeeded to bring-up NSH with perhaps reduced * capabilities.