From ffd5d1fd66c2cf17ce131583a41a37ba6159e90b Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 12 Apr 2024 16:50:26 +0800 Subject: [PATCH] feat(esp_hw_support): support set clock divider for esp32p4 clock output --- components/esp_hw_support/esp_clock_output.c | 15 +++++++++++-- .../esp_hw_support/include/esp_clock_output.h | 22 +++++++++++++++---- .../main/test_esp_clock_output.c | 3 +++ components/hal/esp32p4/clk_tree_hal.c | 6 +++++ .../hal/esp32p4/include/hal/clk_tree_ll.h | 22 +++++++++++++++++-- components/hal/include/hal/clk_tree_hal.h | 11 +++++++++- .../esp32c61/include/soc/Kconfig.soc_caps.in | 4 ---- .../soc/esp32c61/include/soc/soc_caps.h | 2 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32p4/include/soc/soc_caps.h | 1 + 10 files changed, 76 insertions(+), 14 deletions(-) diff --git a/components/esp_hw_support/esp_clock_output.c b/components/esp_hw_support/esp_clock_output.c index 4f628cb6bf..e8e3179fa9 100644 --- a/components/esp_hw_support/esp_clock_output.c +++ b/components/esp_hw_support/esp_clock_output.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -88,7 +88,6 @@ static clkout_channel_handle_t* clkout_channel_alloc(soc_clkout_sig_id_t clk_sig allocated_channel->mapped_io_bmap |= BIT(gpio_num); allocated_channel->mapped_clock = clk_sig; allocated_channel->ref_cnt++; - if (allocated_channel->ref_cnt == 1) { portENTER_CRITICAL(&s_clkout_lock); #if SOC_CLOCKOUT_HAS_SOURCE_GATE @@ -219,6 +218,18 @@ esp_err_t esp_clock_output_stop(esp_clock_output_mapping_handle_t clkout_mapping return ESP_OK; } +#if SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER +esp_err_t esp_clock_output_set_divider(esp_clock_output_mapping_handle_t clkout_mapping_hdl, uint32_t div_num) +{ + ESP_RETURN_ON_FALSE(((div_num > 0) && (div_num <= 256)), ESP_ERR_INVALID_ARG, TAG, "Divider number must be in the range of [1, 256]"); + ESP_RETURN_ON_FALSE((clkout_mapping_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Clock out mapping handle passed in is invalid"); + portENTER_CRITICAL(&clkout_mapping_hdl->clkout_mapping_lock); + clk_hal_clock_output_set_divider(clkout_mapping_hdl->clkout_channel_hdl->channel_id, div_num); + portEXIT_CRITICAL(&clkout_mapping_hdl->clkout_mapping_lock); + return ESP_OK; +} +#endif + #if CONFIG_IDF_TARGET_ESP32 // Due to a hardware bug, PIN_CTRL cannot select 0xf output, whereas 0xf is the default value. __attribute__((constructor)) diff --git a/components/esp_hw_support/include/esp_clock_output.h b/components/esp_hw_support/include/esp_clock_output.h index 2acbb1377d..f4f21ea633 100644 --- a/components/esp_hw_support/include/esp_clock_output.h +++ b/components/esp_hw_support/include/esp_clock_output.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,7 +25,7 @@ typedef struct esp_clock_output_mapping *esp_clock_output_mapping_handle_t; * * @param[in] clk_src The clock signal source to be mapped to GPIOs * @param[in] gpio_num GPIO number to be mapped soc_root_clk signal source - * @param[out] clkout_mapping_ret_hdl Clock output controll handler + * @param[out] clkout_mapping_ret_hdl Clock output control handler * @return * - ESP_OK: Output specified clock signal to specified GPIO successfully * - ESP_ERR_INVALID_ARG: Specified GPIO not supported to output internal clock @@ -36,12 +36,26 @@ esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_nu /** * @brief Stop clock signal to GPIO outputting - * @param[in] clkout_mapping_hdl Clock output mapping controll handle + * @param[in] clkout_mapping_hdl Clock output mapping control handle * @return * - ESP_OK: Disable the clock output on GPIO successfully - * - ESP_ERR_INVALID_STATE The clock in handle is already in the disabled state + * - ESP_ERR_INVALID_ARG The clock mapping handle is not initialized yet + * - ESP_ERR_INVALID_STATE The clock mapping handle is already in the disabled state */ esp_err_t esp_clock_output_stop(esp_clock_output_mapping_handle_t clkout_mapping_hdl); + +#if SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER +/** + * @brief Output the mapped clock after frequency division + * @param clkout_mapping_hdl clkout_mapping_hdl Clock output mapping control handle + * @param div_num clock frequency division value, should be in the range of 1 ~ 256 + * @return + * - ESP_OK: Disable the clock output on GPIO successfully + * - ESP_ERR_INVALID_ARG The clock mapping handle is not initialized yet or the div_num is in bad range + */ +esp_err_t esp_clock_output_set_divider(esp_clock_output_mapping_handle_t clkout_mapping_hdl, uint32_t div_num); +#endif + #endif // SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX || SOC_GPIO_CLOCKOUT_BY_IO_MUX #ifdef __cplusplus diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_esp_clock_output.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_esp_clock_output.c index 06fa1cdde6..d4d5245450 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_esp_clock_output.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_esp_clock_output.c @@ -35,6 +35,9 @@ void output_clock_1(void *pvParameter) esp_clock_output_mapping_handle_t clkout_mapping_hdl; for (int i = 0; i < TEST_LOOPS; ++i) { TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[0], test_clk_out_io[0], &clkout_mapping_hdl)); +#if SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER + TEST_ESP_OK(esp_clock_output_set_divider(clkout_mapping_hdl, 8)); +#endif vTaskDelay(3); TEST_ESP_OK(esp_clock_output_stop(clkout_mapping_hdl)); vTaskDelay(7); diff --git a/components/hal/esp32p4/clk_tree_hal.c b/components/hal/esp32p4/clk_tree_hal.c index ba1e57f351..b633752484 100644 --- a/components/hal/esp32p4/clk_tree_hal.c +++ b/components/hal/esp32p4/clk_tree_hal.c @@ -83,9 +83,15 @@ uint32_t clk_hal_xtal_get_freq_mhz(void) void clk_hal_clock_output_setup(soc_clkout_sig_id_t clk_sig, clock_out_channel_t channel_id) { clk_ll_set_dbg_clk_ctrl(clk_sig, channel_id); + clk_ll_set_dbg_clk_channel_divider(channel_id, 1); clk_ll_enable_dbg_clk_channel(channel_id, true); } +void clk_hal_clock_output_set_divider(clock_out_channel_t channel_id, uint32_t div_num) +{ + clk_ll_set_dbg_clk_channel_divider(channel_id, div_num); +} + void clk_hal_clock_output_teardown(clock_out_channel_t channel_id) { clk_ll_enable_dbg_clk_channel(channel_id, false); diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index b155e607a9..f504917fe7 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -833,15 +833,17 @@ static inline __attribute__((always_inline)) void clk_ll_set_dbg_clk_ctrl(soc_cl { if (channel_id == CLKOUT_CHANNEL_1) { HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.dbg_clk_ctrl0, reg_dbg_ch0_sel, clk_sig); - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.dbg_clk_ctrl0, reg_dbg_ch0_div_num, 0); } else if (channel_id == CLKOUT_CHANNEL_2) { HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.dbg_clk_ctrl0, reg_dbg_ch1_sel, clk_sig); - HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.dbg_clk_ctrl1, reg_dbg_ch1_div_num, 0); } else { abort(); } } +/** + * @brief Enable the clock output channel + * @param enable Enable or disable the clock output channel + */ static inline __attribute__((always_inline)) void clk_ll_enable_dbg_clk_channel(clock_out_channel_t channel_id, bool enable) { if (channel_id == CLKOUT_CHANNEL_1) { @@ -853,6 +855,22 @@ static inline __attribute__((always_inline)) void clk_ll_enable_dbg_clk_channel( } } +/** + * @brief Output the mapped clock after frequency division + * @param channel_id channel id that need to be configured with frequency division + * @param div_num clock frequency division value + */ +static inline __attribute__((always_inline)) void clk_ll_set_dbg_clk_channel_divider(clock_out_channel_t channel_id, uint32_t div_num) +{ + if (channel_id == CLKOUT_CHANNEL_1) { + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.dbg_clk_ctrl0, reg_dbg_ch0_div_num, div_num - 1); + } else if (channel_id == CLKOUT_CHANNEL_2) { + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.dbg_clk_ctrl1, reg_dbg_ch1_div_num, div_num - 1); + } else { + abort(); + } +} + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/clk_tree_hal.h b/components/hal/include/hal/clk_tree_hal.h index 2d61fa138b..9e3cf888b6 100644 --- a/components/hal/include/hal/clk_tree_hal.h +++ b/components/hal/include/hal/clk_tree_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -68,6 +68,15 @@ uint32_t clk_hal_apll_get_freq_hz(void); */ void clk_hal_clock_output_setup(soc_clkout_sig_id_t clk_sig, clock_out_channel_t channel_id); +#if SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER +/** + * @brief Output the mapped clock after frequency division + * @param channel_id channel id that need to be configured with frequency division + * @param div_num clock frequency division value + */ +void clk_hal_clock_output_set_divider(clock_out_channel_t channel_id, uint32_t div_num); +#endif + /** * @brief Teardown clock output channel configuration * @param channel_id The clock output channel to teardown diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 2fd7ccca92..214bf3ec8d 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -199,10 +199,6 @@ config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool default y -config SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX - bool - default y - config SOC_GPIO_CLOCKOUT_CHANNEL_NUM int default 3 diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index b50060d940..12b054b07d 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -213,7 +213,7 @@ #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) // The Clock Out signal is route to the pin by GPIO matrix -#define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) +// #define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) #define SOC_GPIO_CLOCKOUT_CHANNEL_NUM (3) /*-------------------------- RTCIO CAPS --------------------------------------*/ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 580ca7af45..1d24950af7 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -563,6 +563,10 @@ config SOC_GPIO_CLOCKOUT_CHANNEL_NUM int default 2 +config SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER + bool + default y + config SOC_GPIO_SUPPORT_FORCE_HOLD bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 594c83481b..c0606c49d8 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -234,6 +234,7 @@ // The Clock Out signal is route to the pin by GPIO matrix #define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) #define SOC_GPIO_CLOCKOUT_CHANNEL_NUM (2) +#define SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER (1) // Support to force hold all IOs #define SOC_GPIO_SUPPORT_FORCE_HOLD (1)