Просмотр исходного кода

Merge branch 'feature/esp32c6_pcr_clock_selection_gptimer' into 'master'

GPTimer: bringup driver on ESP32C6 FPGA

See merge request espressif/esp-idf!20016
morris 3 лет назад
Родитель
Сommit
6134bcd2f2

+ 1 - 1
components/driver/deprecated/timer_legacy.c

@@ -359,9 +359,9 @@ esp_err_t timer_deinit(timer_group_t group_num, timer_idx_t timer_num)
     timer_hal_context_t *hal = &p_timer_obj[group_num][timer_num]->hal;
 
     TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
-    timer_ll_enable_counter(hal->dev, timer_num, false);
     timer_ll_enable_intr(hal->dev, TIMER_LL_EVENT_ALARM(timer_num), false);
     timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_num));
+    timer_hal_deinit(hal);
     TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
 
     free(p_timer_obj[group_num][timer_num]);

+ 17 - 5
components/driver/gptimer.c

@@ -78,9 +78,10 @@ struct gptimer_t {
     timer_hal_context_t hal;
     gptimer_fsm_t fsm;
     intr_handle_t intr;
-    portMUX_TYPE spinlock; // to protect per-timer resources concurent accessed by task and ISR handler
+    portMUX_TYPE spinlock; // to protect per-timer resources concurrent accessed by task and ISR handler
     gptimer_alarm_cb_t on_alarm;
     void *user_ctx;
+    gptimer_clock_source_t clk_src;
     esp_pm_lock_handle_t pm_lock; // power management lock
 #if CONFIG_PM_ENABLE
     char pm_lock_name[GPTIMER_PM_LOCK_NAME_LEN_MAX]; // pm lock name
@@ -176,10 +177,6 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
 
     // initialize HAL layer
     timer_hal_init(&timer->hal, group_id, timer_id);
-    // stop counter, alarm, auto-reload
-    timer_ll_enable_counter(timer->hal.dev, timer_id, false);
-    timer_ll_enable_auto_reload(timer->hal.dev, timer_id, false);
-    timer_ll_enable_alarm(timer->hal.dev, timer_id, false);
     // select clock source, set clock resolution
     ESP_GOTO_ON_ERROR(gptimer_select_periph_clock(timer, config->clk_src, config->resolution_hz), err, TAG, "set periph clock failed");
     // initialize counter value to zero
@@ -216,6 +213,13 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer)
     int group_id = group->group_id;
     int timer_id = timer->timer_id;
     ESP_LOGD(TAG, "del timer (%d,%d)", group_id, timer_id);
+    timer_hal_deinit(&timer->hal);
+    // [refactor-todo]: replace the following code with clk_tree_acquire/release, and call them in gptimer_enable/disable
+#if SOC_TIMER_GROUP_SUPPORT_RC_FAST
+    if (timer->clk_src == GPTIMER_CLK_SRC_RC_FAST) {
+        periph_rtc_dig_clk8m_disable();
+    }
+#endif
     // recycle memory resource
     ESP_RETURN_ON_ERROR(gptimer_destory(timer), TAG, "destory gptimer failed");
     return ESP_OK;
@@ -471,11 +475,19 @@ static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_sou
         counter_src_hz = esp_clk_xtal_freq();
         break;
 #endif // SOC_TIMER_GROUP_SUPPORT_XTAL
+#if SOC_TIMER_GROUP_SUPPORT_RC_FAST
+    case GPTIMER_CLK_SRC_RC_FAST:
+        // periph_rtc_dig_clk8m_enable must be called before periph_rtc_dig_clk8m_get_freq, to ensure a calibration is done
+        periph_rtc_dig_clk8m_enable();
+        periph_src_clk_hz = periph_rtc_dig_clk8m_get_freq();
+        break;
+#endif // SOC_TIMER_GROUP_SUPPORT_RC_FAST
     default:
         ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "clock source %d is not support", src_clk);
         break;
     }
     timer_ll_set_clock_source(timer->hal.dev, timer_id, src_clk);
+    timer->clk_src = src_clk;
     unsigned int prescale = counter_src_hz / resolution_hz; // potential resolution loss here
     timer_ll_set_clock_prescale(timer->hal.dev, timer_id, prescale);
     timer->resolution_hz = counter_src_hz / prescale; // this is the real resolution

+ 16 - 0
components/hal/esp32/include/hal/timer_ll.h

@@ -40,6 +40,22 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num,
     }
 }
 
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @note This function is not optional, created for backward compatible.
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)hw;
+    (void)timer_num;
+    (void)en;
+}
+
 /**
  * @brief Enable alarm event
  *

+ 13 - 0
components/hal/esp32c2/include/hal/timer_ll.h

@@ -44,6 +44,19 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num,
     }
 }
 
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)timer_num; // only one timer in the group
+    hw->regclk.timer_clk_is_active = en;
+}
+
 /**
  * @brief Enable alarm event
  *

+ 13 - 0
components/hal/esp32c3/include/hal/timer_ll.h

@@ -44,6 +44,19 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num,
     }
 }
 
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)timer_num; // only one timer in the group
+    hw->regclk.timer_clk_is_active = en;
+}
+
 /**
  * @brief Enable alarm event
  *

+ 32 - 4
components/hal/esp32c6/include/hal/timer_ll.h

@@ -13,6 +13,7 @@
 #include "hal/misc.h"
 #include "hal/timer_types.h"
 #include "soc/timer_group_struct.h"
+#include "soc/pcr_struct.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -31,17 +32,44 @@ extern "C" {
  */
 static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, gptimer_clock_source_t clk_src)
 {
+    (void)timer_num; // only one timer in each group
+    uint8_t clk_id = 0;
     switch (clk_src) {
+    case GPTIMER_CLK_SRC_XTAL:
+        clk_id = 0;
+        break;
     case GPTIMER_CLK_SRC_APB:
-        hw->hw_timer[timer_num].config.tx_use_xtal = 0;
+        clk_id = 1;
         break;
-    case GPTIMER_CLK_SRC_XTAL:
-        hw->hw_timer[timer_num].config.tx_use_xtal = 1;
+    case GPTIMER_CLK_SRC_RC_FAST:
+        clk_id = 2;
         break;
     default:
-        HAL_ASSERT(false && "unsupported clock source");
+        HAL_ASSERT(false);
         break;
     }
+    if (hw == &TIMERG0) {
+        PCR.timergroup0_timer_clk_conf.tg0_timer_clk_sel = clk_id;
+    } else {
+        PCR.timergroup1_timer_clk_conf.tg1_timer_clk_sel = clk_id;
+    }
+}
+
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)timer_num; // only one timer in each group
+    if (hw == &TIMERG0) {
+        PCR.timergroup0_timer_clk_conf.tg0_timer_clk_en = en;
+    } else {
+        PCR.timergroup1_timer_clk_conf.tg1_timer_clk_en = en;
+    }
 }
 
 /**

+ 13 - 0
components/hal/esp32h2/include/hal/timer_ll.h

@@ -44,6 +44,19 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num,
     }
 }
 
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)timer_num; // only one timer in the group
+    hw->regclk.timer_clk_is_active = en;
+}
+
 /**
  * @brief Enable alarm event
  *

+ 16 - 0
components/hal/esp32s2/include/hal/timer_ll.h

@@ -44,6 +44,22 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num,
     }
 }
 
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @note This function is not optional, created for backward compatible.
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)hw;
+    (void)timer_num;
+    (void)en;
+}
+
 /**
  * @brief Enable alarm event
  *

+ 16 - 0
components/hal/esp32s3/include/hal/timer_ll.h

@@ -44,6 +44,22 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num,
     }
 }
 
+/**
+ * @brief Enable Timer Group (GPTimer) module clock
+ *
+ * @note This function is not optional, created for backward compatible.
+ *
+ * @param hw Timer Group register base address
+ * @param timer_num Timer index in the group
+ * @param en true to enable, false to disable
+ */
+static inline void timer_ll_enable_clock(timg_dev_t *hw, uint32_t timer_num, bool en)
+{
+    (void)hw;
+    (void)timer_num;
+    (void)en;
+}
+
 /**
  * @brief Enable alarm event
  *

+ 7 - 0
components/hal/include/hal/timer_hal.h

@@ -37,6 +37,13 @@ typedef struct {
  */
 void timer_hal_init(timer_hal_context_t *hal, uint32_t group_num, uint32_t timer_num);
 
+/**
+ * @brief Deinit timer hal context.
+ *
+ * @param hal Context of HAL layer
+ */
+void timer_hal_deinit(timer_hal_context_t *hal);
+
 /**
  * @brief Load counter value into time-base counter
  *

+ 26 - 0
components/hal/timer_hal.c

@@ -4,11 +4,37 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#include <stdlib.h>
 #include "hal/timer_hal.h"
 #include "hal/timer_ll.h"
+#include "soc/soc_caps.h"
 
 void timer_hal_init(timer_hal_context_t *hal, uint32_t group_num, uint32_t timer_num)
 {
     hal->dev = TIMER_LL_GET_HW(group_num);
     hal->timer_id = timer_num;
+    // enable peripheral clock
+    timer_ll_enable_clock(hal->dev, timer_num, true);
+    // stop counter, alarm, auto-reload at first place
+    timer_ll_enable_counter(hal->dev, timer_num, false);
+    timer_ll_enable_auto_reload(hal->dev, timer_num, false);
+    timer_ll_enable_alarm(hal->dev, timer_num, false);
+    // enable RTM subsystem if available
+#if SOC_TIMER_SUPPORT_ETM
+    timer_ll_enable_etm(hal->dev, true);
+#endif
+}
+
+void timer_hal_deinit(timer_hal_context_t *hal)
+{
+    // disable peripheral clock
+    timer_ll_enable_clock(hal->dev, hal->timer_id, false);
+    // ensure counter, alarm, auto-reload are disabled
+    timer_ll_enable_counter(hal->dev, hal->timer_id, false);
+    timer_ll_enable_auto_reload(hal->dev, hal->timer_id, false);
+    timer_ll_enable_alarm(hal->dev, hal->timer_id, false);
+#if SOC_TIMER_SUPPORT_ETM
+    timer_ll_enable_etm(hal->dev, false);
+#endif
+    hal->dev = NULL;
 }

+ 8 - 0
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -603,10 +603,18 @@ config SOC_TIMER_GROUP_SUPPORT_APB
     bool
     default y
 
+config SOC_TIMER_GROUP_SUPPORT_RC_FAST
+    bool
+    default y
+
 config SOC_TIMER_GROUP_TOTAL_TIMERS
     int
     default 2
 
+config SOC_TIMER_SUPPORT_ETM
+    bool
+    default y
+
 config SOC_TWAI_BRP_MIN
     int
     default 2

+ 13 - 4
components/soc/esp32c6/include/soc/clk_tree_defs.h

@@ -128,15 +128,24 @@ typedef enum {
  * }
  * @endcode
  */
-#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_APB, SOC_MOD_CLK_XTAL}
+#if CONFIG_IDF_ENV_FPGA
+#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_XTAL}
+#else
+#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_APB, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
+#endif
 
 /**
  * @brief Type of GPTimer clock source
  */
 typedef enum {
-    GPTIMER_CLK_SRC_APB = SOC_MOD_CLK_APB,     /*!< Select APB as the source clock */
-    GPTIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,   /*!< Select XTAL as the source clock */
-    GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */
+    GPTIMER_CLK_SRC_APB = SOC_MOD_CLK_APB,         /*!< Select APB as the source clock */
+    GPTIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,       /*!< Select XTAL as the source clock */
+    GPTIMER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
+#if CONFIG_IDF_ENV_FPGA
+    GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL,    /*!< Select XTAL as the default choice */
+#else
+    GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB,     /*!< Select APB as the default choice */
+#endif
 } soc_periph_gptimer_clk_src_t;
 
 /**

+ 2 - 1
components/soc/esp32c6/include/soc/soc_caps.h

@@ -322,14 +322,15 @@
 #define SOC_SYSTIMER_INT_LEVEL              1  // Systimer peripheral uses level interrupt
 #define SOC_SYSTIMER_ALARM_MISS_COMPENSATE  1  // Systimer peripheral can generate interrupt immediately if t(target) > t(current)
 
-// TODO: IDF-5332 (Copy from esp32c3, need check)
 /*--------------------------- TIMER GROUP CAPS ---------------------------------------*/
 #define SOC_TIMER_GROUPS                  (2)
 #define SOC_TIMER_GROUP_TIMERS_PER_GROUP  (1U)
 #define SOC_TIMER_GROUP_COUNTER_BIT_WIDTH (54)
 #define SOC_TIMER_GROUP_SUPPORT_XTAL      (1)
 #define SOC_TIMER_GROUP_SUPPORT_APB       (1)
+#define SOC_TIMER_GROUP_SUPPORT_RC_FAST   (1)
 #define SOC_TIMER_GROUP_TOTAL_TIMERS      (2)
+#define SOC_TIMER_SUPPORT_ETM             (1)
 
 // TODO: IDF-5313 (Copy from esp32c3, need check)
 /*-------------------------- TWAI CAPS ---------------------------------------*/