From 1f10c84a4fc0f297ba0ad8c69fc6a686fce2b3fd Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 1 Sep 2023 10:44:24 +0800 Subject: [PATCH 1/5] change(hal): rewrite gpio_ll_set_iomux_pin_ctrl api --- components/driver/i2s/i2s_common.c | 6 +++--- components/hal/esp32/include/hal/gpio_ll.h | 8 +++++--- components/hal/esp32c2/include/hal/gpio_ll.h | 12 ++++++++++++ components/hal/esp32c3/include/hal/gpio_ll.h | 12 ++++++++++++ components/hal/esp32c6/include/hal/gpio_ll.h | 12 ++++++++++++ components/hal/esp32h2/include/hal/gpio_ll.h | 12 ++++++++++++ components/hal/esp32p4/include/hal/gpio_ll.h | 11 +++++++++++ components/hal/esp32s2/include/hal/gpio_ll.h | 11 +++++++++++ components/hal/esp32s3/include/hal/gpio_ll.h | 12 ++++++++++++ 9 files changed, 90 insertions(+), 6 deletions(-) diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index 3a80b15805..530f2c449d 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -746,13 +746,13 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_sr bool is_apll = clk_src == I2S_CLK_SRC_APLL; if (gpio_num == GPIO_NUM_0) { gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); - gpio_ll_iomux_pin_ctrl(is_apll ? 0xFFF6 : (is_i2s0 ? 0xFFF0 : 0xFFFF)); + gpio_ll_set_iomux_pin_ctrl(is_apll ? 0xFFF6 : (is_i2s0 ? 0xFFF0 : 0xFFFF), 0xFFFFFFFF, 0); } else if (gpio_num == GPIO_NUM_1) { gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); - gpio_ll_iomux_pin_ctrl(is_apll ? 0xF6F6 : (is_i2s0 ? 0xF0F0 : 0xF0FF)); + gpio_ll_set_iomux_pin_ctrl(is_apll ? 0xF6F6 : (is_i2s0 ? 0xF0F0 : 0xF0FF), 0xFFFFFFFF, 0); } else { gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); - gpio_ll_iomux_pin_ctrl(is_apll ? 0xFF66 : (is_i2s0 ? 0xFF00 : 0xFF0F)); + gpio_ll_set_iomux_pin_ctrl(is_apll ? 0xFF66 : (is_i2s0 ? 0xFF00 : 0xFF0F), 0xFFFFFFFF, 0); } #else ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid"); diff --git a/components/hal/esp32/include/hal/gpio_ll.h b/components/hal/esp32/include/hal/gpio_ll.h index 19aea31609..3a5963f26c 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -679,11 +679,13 @@ static inline __attribute__((always_inline)) void gpio_ll_iomux_func_sel(uint32_ /** * @brief Control the pin in the IOMUX * - * @param val Control value + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value */ -static inline __attribute__((always_inline)) void gpio_ll_iomux_pin_ctrl(uint32_t val) +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) { - WRITE_PERI_REG(PIN_CTRL, val); + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); } /** diff --git a/components/hal/esp32c2/include/hal/gpio_ll.h b/components/hal/esp32c2/include/hal/gpio_ll.h index 8b3b420d0a..ad70573110 100644 --- a/components/hal/esp32c2/include/hal/gpio_ll.h +++ b/components/hal/esp32c2/include/hal/gpio_ll.h @@ -492,6 +492,18 @@ static inline __attribute__((always_inline)) void gpio_ll_iomux_func_sel(uint32_ PIN_FUNC_SELECT(pin_name, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); +} + /** * @brief Set peripheral output to an GPIO pad through the IOMUX. * diff --git a/components/hal/esp32c3/include/hal/gpio_ll.h b/components/hal/esp32c3/include/hal/gpio_ll.h index 1c9a285e52..75e9e82c60 100644 --- a/components/hal/esp32c3/include/hal/gpio_ll.h +++ b/components/hal/esp32c3/include/hal/gpio_ll.h @@ -508,6 +508,18 @@ static inline __attribute__((always_inline)) void gpio_ll_iomux_func_sel(uint32_ PIN_FUNC_SELECT(pin_name, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); +} + /** * @brief Set peripheral output to an GPIO pad through the IOMUX. * diff --git a/components/hal/esp32c6/include/hal/gpio_ll.h b/components/hal/esp32c6/include/hal/gpio_ll.h index 52939fbee7..5bd7ea1178 100644 --- a/components/hal/esp32c6/include/hal/gpio_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_ll.h @@ -458,6 +458,18 @@ static inline void gpio_ll_iomux_func_sel(uint32_t pin_name, uint32_t func) PIN_FUNC_SELECT(pin_name, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); +} + /** * @brief Select a function for the pin in the IOMUX * diff --git a/components/hal/esp32h2/include/hal/gpio_ll.h b/components/hal/esp32h2/include/hal/gpio_ll.h index cc4c933a4d..df08c857be 100644 --- a/components/hal/esp32h2/include/hal/gpio_ll.h +++ b/components/hal/esp32h2/include/hal/gpio_ll.h @@ -534,6 +534,18 @@ static inline void gpio_ll_iomux_out(gpio_dev_t *hw, uint8_t gpio_num, int func, gpio_ll_func_sel(hw, gpio_num, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); +} + /** * @brief Set clock source of IO MUX module * diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index 39d9eb770c..b3c41a5faa 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -579,6 +579,17 @@ static inline void gpio_ll_iomux_func_sel(uint32_t pin_name, uint32_t func) PIN_FUNC_SELECT(pin_name, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + // TODO: IDF-8226 +} /** * @brief Select a function for the pin in the IOMUX * diff --git a/components/hal/esp32s2/include/hal/gpio_ll.h b/components/hal/esp32s2/include/hal/gpio_ll.h index 9b1544733a..80de859887 100644 --- a/components/hal/esp32s2/include/hal/gpio_ll.h +++ b/components/hal/esp32s2/include/hal/gpio_ll.h @@ -507,6 +507,17 @@ static inline __attribute__((always_inline)) void gpio_ll_iomux_func_sel(uint32_ PIN_FUNC_SELECT(pin_name, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); +} /** * @brief Set peripheral output to an GPIO pad through the IOMUX. * diff --git a/components/hal/esp32s3/include/hal/gpio_ll.h b/components/hal/esp32s3/include/hal/gpio_ll.h index d86188c984..394d7681d1 100644 --- a/components/hal/esp32s3/include/hal/gpio_ll.h +++ b/components/hal/esp32s3/include/hal/gpio_ll.h @@ -526,6 +526,18 @@ static inline __attribute__((always_inline)) void gpio_ll_iomux_func_sel(uint32_ PIN_FUNC_SELECT(pin_name, func); } +/** + * @brief Control the pin in the IOMUX + * + * @param bmap write mask of control value + * @param val Control value + * @param shift write mask shift of control value + */ +static inline __attribute__((always_inline)) void gpio_ll_set_pin_ctrl(uint32_t val, uint32_t bmap, uint32_t shift) +{ + SET_PERI_REG_BITS(PIN_CTRL, bmap, val, shift); +} + /** * @brief Set peripheral output to an GPIO pad through the IOMUX. * From 6a436286dce54a88a7a0bd55526df52b5d786e3d Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 4 Sep 2023 17:20:36 +0800 Subject: [PATCH 2/5] feat(esp_hw_support): add api to gpio driver to support output internal clock on GPIO --- components/esp_hw_support/CMakeLists.txt | 4 + components/esp_hw_support/esp_clock_output.c | 164 ++++++++++++++++++ .../esp_hw_support/include/esp_clock_output.h | 53 ++++++ .../include/esp_private/clkout_channel.h | 48 +++++ .../soc/esp32/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32/include/soc/clk_tree_defs.h | 15 ++ .../soc/esp32/include/soc/clkout_channel.h | 20 --- components/soc/esp32/include/soc/soc_caps.h | 3 + .../esp32c2/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32c2/include/soc/clk_tree_defs.h | 10 ++ .../soc/esp32c2/include/soc/clkout_channel.h | 12 -- components/soc/esp32c2/include/soc/soc_caps.h | 3 + .../esp32c3/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32c3/include/soc/clk_tree_defs.h | 10 ++ .../soc/esp32c3/include/soc/clkout_channel.h | 12 -- components/soc/esp32c3/include/soc/soc_caps.h | 3 + .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32c6/include/soc/clk_tree_defs.h | 16 ++ .../soc/esp32c6/include/soc/clkout_channel.h | 8 - components/soc/esp32c6/include/soc/soc_caps.h | 3 + .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32h2/include/soc/clk_tree_defs.h | 14 ++ .../soc/esp32h2/include/soc/clkout_channel.h | 8 - components/soc/esp32h2/include/soc/soc_caps.h | 3 + .../soc/esp32p4/include/soc/clkout_channel.h | 8 - .../esp32s2/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32s2/include/soc/clk_tree_defs.h | 12 ++ .../soc/esp32s2/include/soc/clkout_channel.h | 20 --- components/soc/esp32s2/include/soc/soc_caps.h | 3 + .../esp32s3/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32s3/include/soc/clk_tree_defs.h | 9 + .../soc/esp32s3/include/soc/clkout_channel.h | 20 --- components/soc/esp32s3/include/soc/soc_caps.h | 3 + 33 files changed, 404 insertions(+), 108 deletions(-) create mode 100644 components/esp_hw_support/esp_clock_output.c create mode 100644 components/esp_hw_support/include/esp_clock_output.h create mode 100644 components/esp_hw_support/include/esp_private/clkout_channel.h delete mode 100644 components/soc/esp32/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32c2/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32c3/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32c6/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32h2/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32p4/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32s2/include/soc/clkout_channel.h delete mode 100644 components/soc/esp32s3/include/soc/clkout_channel.h diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 61863f28a1..ad5e37ad64 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -125,6 +125,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "sleep_wake_stub.c") endif() + if(CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX OR CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX) + list(APPEND srcs "esp_clock_output.c") + endif() + if(CONFIG_IDF_TARGET_ESP32P4) list(REMOVE_ITEM srcs "sleep_cpu.c" # TODO: IDF-7528, IDF-7529 diff --git a/components/esp_hw_support/esp_clock_output.c b/components/esp_hw_support/esp_clock_output.c new file mode 100644 index 0000000000..89397f59fb --- /dev/null +++ b/components/esp_hw_support/esp_clock_output.c @@ -0,0 +1,164 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" + +#include "driver/gpio.h" +#include "esp_clock_output.h" +#include "esp_check.h" +#include "esp_rom_gpio.h" +#include "esp_private/clkout_channel.h" +#include "esp_private/startup_internal.h" +#include "hal/gpio_hal.h" +#include "soc/soc_caps.h" +#include "soc/io_mux_reg.h" + +typedef struct gpio_clock_out_ctx { + bool is_mapped; + uint8_t ref_cnt; + clock_out_channel_t clk_out; + gpio_num_t mapped_io; + soc_clkout_sig_id_t mapped_clock; +} gpio_clock_out_ctx_t; + +static const char *TAG = "gpio_output_clk"; + +static portMUX_TYPE s_clkout_channel_lock = portMUX_INITIALIZER_UNLOCKED; + +static gpio_clock_out_ctx_t s_pin_ctrl_clk_out[CLKOUT_CHANNEL_MAX] = { + [0 ... CLKOUT_CHANNEL_MAX - 1] = { + .is_mapped = false, + .ref_cnt = 0, + } +}; + +static gpio_clock_out_ctx_t* io_mux_pin_ctrl_clk_out_alloc(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num) +{ + gpio_clock_out_ctx_t *allocated_clk_out = NULL; + +#if SOC_GPIO_CLOCKOUT_BY_IO_MUX + portENTER_CRITICAL(&s_clkout_channel_lock); + if (!s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].is_mapped) { + s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].is_mapped = true; + s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].clk_out = IONUM_TO_CLKOUT(gpio_num); + allocated_clk_out = &s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)]; + } else if ((s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].mapped_io == gpio_num) && + (s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].mapped_clock == clk_sig)) { + allocated_clk_out = &s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)]; + } + portEXIT_CRITICAL(&s_clkout_channel_lock); +#elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + for(uint32_t i = 0; i < CLKOUT_CHANNEL_MAX; i++) { + portENTER_CRITICAL(&s_clkout_channel_lock); + if (!s_pin_ctrl_clk_out[i].is_mapped) { + s_pin_ctrl_clk_out[i].is_mapped = true; + s_pin_ctrl_clk_out[i].clk_out = (clock_out_channel_t)i; + allocated_clk_out = &s_pin_ctrl_clk_out[i]; + portEXIT_CRITICAL(&s_clkout_channel_lock); + break; + } else if ((s_pin_ctrl_clk_out[i].mapped_io == gpio_num) && + (s_pin_ctrl_clk_out[i].mapped_clock == clk_sig)) { + allocated_clk_out = &s_pin_ctrl_clk_out[i]; + portEXIT_CRITICAL(&s_clkout_channel_lock); + break; + } + portEXIT_CRITICAL(&s_clkout_channel_lock); + } +#endif + + if (allocated_clk_out != NULL) { + portENTER_CRITICAL(&s_clkout_channel_lock); + allocated_clk_out->mapped_io = gpio_num; + allocated_clk_out->mapped_clock = clk_sig; + allocated_clk_out->ref_cnt++; + portEXIT_CRITICAL(&s_clkout_channel_lock); + } + + return allocated_clk_out; +} + +static bool io_mux_pin_ctrl_clk_out_sig_try_free(gpio_clock_out_handle_t clk_out_hdl) +{ + bool do_free = false; + portENTER_CRITICAL(&s_clkout_channel_lock); + if (--clk_out_hdl->ref_cnt == 0) { + do_free = true; + clk_out_hdl->is_mapped = false; + } + portEXIT_CRITICAL(&s_clkout_channel_lock); + return do_free; +} + +esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num, gpio_clock_out_handle_t *clk_out_hdl) +{ + ESP_RETURN_ON_FALSE((clk_out_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Clock out handle passed in is invalid"); + + ESP_RETURN_ON_FALSE(IS_VALID_CLKOUT_IO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "%s", "Output GPIO number error"); + + gpio_clock_out_ctx_t* new_hdl= io_mux_pin_ctrl_clk_out_alloc(clk_sig, gpio_num); + +#if SOC_GPIO_CLOCKOUT_BY_IO_MUX + ESP_RETURN_ON_FALSE((new_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Selected clock out IO is already mapped to other internal clock source"); +#elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + ESP_RETURN_ON_FALSE((new_hdl != NULL), ESP_FAIL, TAG, "Maximum support for %d output clock signals, no available clock_out channel for assignment", CLKOUT_CHANNEL_MAX); +#endif + + if (new_hdl->ref_cnt == 1) { + uint32_t clk_out_mask = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? CLK_OUT1 : + (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? CLK_OUT2 : + (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? CLK_OUT3 : 0; + uint32_t clk_out_shift = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? CLK_OUT1_S : + (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? CLK_OUT2_S : + (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? CLK_OUT3_S : 0; + + portENTER_CRITICAL(&s_clkout_channel_lock); + gpio_ll_set_pin_ctrl(clk_sig, clk_out_mask, clk_out_shift); + portEXIT_CRITICAL(&s_clkout_channel_lock); + +#if SOC_GPIO_CLOCKOUT_BY_IO_MUX + uint32_t clk_out_func = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? FUNC_CLK_OUT1 : + (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? FUNC_CLK_OUT2 : + (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? FUNC_CLK_OUT3 : 0; + + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], clk_out_func); +#elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + uint32_t gpio_clk_out_sig_idx = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? CLK_OUT_OUT1_IDX : + (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? CLK_OUT_OUT2_IDX : + (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? CLK_OUT_OUT3_IDX : SIG_GPIO_OUT_IDX; + + gpio_set_pull_mode(gpio_num, GPIO_FLOATING); + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO); + gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT); + esp_rom_gpio_connect_out_signal(gpio_num, gpio_clk_out_sig_idx, false, false); +#endif + } + + *clk_out_hdl = new_hdl; + return ESP_OK; +} + +esp_err_t esp_clock_output_stop(gpio_clock_out_handle_t clk_out_hdl) +{ + assert(clk_out_hdl != NULL); + ESP_RETURN_ON_FALSE(clk_out_hdl->is_mapped, ESP_ERR_INVALID_STATE, TAG, "%s", "Clock outputting is already disabled"); + if (io_mux_pin_ctrl_clk_out_sig_try_free(clk_out_hdl)) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[clk_out_hdl->mapped_io], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(clk_out_hdl->mapped_io, SIG_GPIO_OUT_IDX, false, false); + gpio_set_direction(clk_out_hdl->mapped_io, GPIO_MODE_DISABLE); + } + return ESP_OK; +} + +#if CONFIG_IDF_TARGET_ESP32 +// Due to a hardware bug, PIN_CTRL cannot select 0xf output, whereas 0xf is the default value. +__attribute__((constructor)) +static void esp_clock_output_pin_ctrl_init(void) +{ + gpio_ll_set_pin_ctrl(0, CLK_OUT1, CLK_OUT1_S); + gpio_ll_set_pin_ctrl(0, CLK_OUT2, CLK_OUT2_S); + gpio_ll_set_pin_ctrl(0, CLK_OUT3, CLK_OUT3_S); +} +#endif diff --git a/components/esp_hw_support/include/esp_clock_output.h b/components/esp_hw_support/include/esp_clock_output.h new file mode 100644 index 0000000000..1ccf58a6a6 --- /dev/null +++ b/components/esp_hw_support/include/esp_clock_output.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "soc/soc_caps.h" +#include "soc/clk_tree_defs.h" + +#include "esp_err.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX || SOC_GPIO_CLOCKOUT_BY_IO_MUX +typedef struct gpio_clock_out_ctx* gpio_clock_out_handle_t; + +/** + * @brief Start output specified clock signal to specified GPIO, will also + * initialize the clk_out_hdl. + * + * @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] clk_out_hdl Clock output controll handler + * @return + * - ESP_OK: Output specified clock signal to specified GPIO successfully + * - ESP_ERR_INVALID_ARG: Specified GPIO not supported to output internal clock + * or specified GPIO is already mapped to other internal clock source. + * - ESP_FAIL: There are no clock out signals that can be allocated. + */ +esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num, gpio_clock_out_handle_t *clk_out_hdl); + +/** + * @brief Stop clock signal to GPIO outputting + * @param[in] clk_out_hdl Clock output controll 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_t esp_clock_output_stop(gpio_clock_out_handle_t clk_out_hdl); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/include/esp_private/clkout_channel.h b/components/esp_hw_support/include/esp_private/clkout_channel.h new file mode 100644 index 0000000000..ff6e580273 --- /dev/null +++ b/components/esp_hw_support/include/esp_private/clkout_channel.h @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum clock_out_channel { + CLKOUT_CHANNEL_1, + CLKOUT_CHANNEL_2, + CLKOUT_CHANNEL_3, + CLKOUT_CHANNEL_MAX, +} clock_out_channel_t; + +#if SOC_GPIO_CLOCKOUT_BY_IO_MUX +#if CONFIG_IDF_TARGET_ESP32 +#define CLKOUT_CHANNEL1_GPIO GPIO_NUM_0 +#define CLKOUT_CHANNEL2_GPIO GPIO_NUM_3 +#define CLKOUT_CHANNEL3_GPIO GPIO_NUM_1 +#define FUNC_CLK_OUT1 FUNC_GPIO0_CLK_OUT1 +#define FUNC_CLK_OUT2 FUNC_U0RXD_CLK_OUT2 +#define FUNC_CLK_OUT3 FUNC_U0TXD_CLK_OUT3 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#define CLKOUT_CHANNEL1_GPIO GPIO_NUM_20 +#define CLKOUT_CHANNEL2_GPIO GPIO_NUM_19 +#define CLKOUT_CHANNEL3_GPIO GPIO_NUM_18 +#define FUNC_CLK_OUT1 FUNC_GPIO20_CLK_OUT1 +#define FUNC_CLK_OUT2 FUNC_GPIO19_CLK_OUT2 +#define FUNC_CLK_OUT3 FUNC_DAC_2_CLK_OUT3 +#endif +#define IS_VALID_CLKOUT_IO(gpio_num) ((gpio_num == CLKOUT_CHANNEL1_GPIO) || (gpio_num == CLKOUT_CHANNEL2_GPIO) || (gpio_num == CLKOUT_CHANNEL3_GPIO)) +#elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX +#define IS_VALID_CLKOUT_IO(gpio_num) GPIO_IS_VALID_GPIO(gpio_num) +#endif + +#define IONUM_TO_CLKOUT(gpio_num) ((gpio_num == CLKOUT_CHANNEL1_GPIO) ? CLKOUT_CHANNEL_1 : \ + (gpio_num == CLKOUT_CHANNEL2_GPIO) ? CLKOUT_CHANNEL_2 : \ + (gpio_num == CLKOUT_CHANNEL3_GPIO) ? CLKOUT_CHANNEL_3 : 0) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 9e71a8a2c0..e51f180e76 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -315,6 +315,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0xEF0FEA +config SOC_GPIO_CLOCKOUT_BY_IO_MUX + bool + default y + config SOC_I2C_NUM int default 2 diff --git a/components/soc/esp32/include/soc/clk_tree_defs.h b/components/soc/esp32/include/soc/clk_tree_defs.h index 4f636913d2..e536d0c951 100644 --- a/components/soc/esp32/include/soc/clk_tree_defs.h +++ b/components/soc/esp32/include/soc/clk_tree_defs.h @@ -441,6 +441,21 @@ typedef enum { SDMMC_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the source clock */ } soc_periph_sdmmc_clk_src_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_I2S0 = 0, /*!< I2S0 clock, depends on the i2s driver configuration */ + CLKOUT_SIG_PLL = 1, /*!< PLL_CLK is the output of crystal oscillator frequency multiplier */ + CLKOUT_SIG_RC_SLOW = 4, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_APLL = 6, /*!< Divided by PLL, frequency is configurable */ + CLKOUT_SIG_REF_TICK = 12, /*!< Divided by APB clock, usually be 1MHz */ + CLKOUT_SIG_PLL_F80M = 13, /*!< From PLL, usually be 80MHz */ + CLKOUT_SIG_RC_FAST = 14, /*!< RC fast clock, about 8MHz */ + CLKOUT_SIG_I2S1 = 15, /*!< I2S1 clock, depends on the i2s driver configuration */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; + + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32/include/soc/clkout_channel.h b/components/soc/esp32/include/soc/clkout_channel.h deleted file mode 100644 index a2b05fcb2c..0000000000 --- a/components/soc/esp32/include/soc/clkout_channel.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SOC_CLKOUT_CHANNEL_H -#define _SOC_CLKOUT_CHANNEL_H - -//CLKOUT channels -#define CLKOUT_IOMUX_FUNC_NUM 1 - -#define CLKOUT_GPIO0_DIRECT_CHANNEL CLKOUT_CHANNEL_1 -#define CLKOUT_CHANNEL_1_DIRECT_GPIO_NUM 0 -#define CLKOUT_GPIO3_DIRECT_CHANNEL CLKOUT_CHANNEL_2 -#define CLKOUT_CHANNEL_2_DIRECT_GPIO_NUM 3 -#define CLKOUT_GPIO1_DIRECT_CHANNEL CLKOUT_CHANNEL_3 -#define CLKOUT_CHANNEL_3_DIRECT_GPIO_NUM 1 - -#endif diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 5d1d1d68fd..7c83fa9949 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -181,6 +181,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM: 1, 3, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 21, 22, 23) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0xEF0FEAULL +// The Clock Out singnal is binding to the pin's IO_MUX function +#define SOC_GPIO_CLOCKOUT_BY_IO_MUX (1) + /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32 has 2 I2C #define SOC_I2C_NUM (2) diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index 1c876e0bdc..080f24a2a2 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -279,6 +279,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x00000000001FFFC0 +config SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + bool + default y + config SOC_DEDIC_GPIO_OUT_CHANNELS_NUM int default 8 diff --git a/components/soc/esp32c2/include/soc/clk_tree_defs.h b/components/soc/esp32c2/include/soc/clk_tree_defs.h index 4aaf76d103..ae3668c770 100644 --- a/components/soc/esp32c2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c2/include/soc/clk_tree_defs.h @@ -285,6 +285,16 @@ typedef enum { LEDC_USE_RTC8M_CLK __attribute__((deprecated("please use 'LEDC_USE_RC_FAST_CLK' instead"))) = LEDC_USE_RC_FAST_CLK, /*!< Alias of 'LEDC_USE_RC_FAST_CLK' */ } soc_periph_ledc_clk_src_legacy_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_PLL = 1, /*!< PLL_CLK is the output of crystal oscillator frequency multiplier */ + CLKOUT_SIG_RC_SLOW = 4, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_PLL_F80M = 13, /*!< From PLL, usually be 80MHz */ + CLKOUT_SIG_RC_FAST = 14, /*!< RC fast clock, about 8MHz */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c2/include/soc/clkout_channel.h b/components/soc/esp32c2/include/soc/clkout_channel.h deleted file mode 100644 index ceb3369171..0000000000 --- a/components/soc/esp32c2/include/soc/clkout_channel.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SOC_CLKOUT_CHANNEL_H -#define _SOC_CLKOUT_CHANNEL_H - -// ESP32C2 CLKOUT signals has no corresponding iomux pins - -#endif diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 21940700b5..805dbbf8a5 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -136,6 +136,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_6~GPIO_NUM_20) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00000000001FFFC0ULL +// The Clock Out singnal is route to the pin by GPIO matrix +#define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) + /*-------------------------- Dedicated GPIO CAPS -----------------------------*/ #define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 25c23a3320..0e433b9c2b 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -371,6 +371,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x00000000003FFFC0 +config SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + bool + default y + config SOC_DEDIC_GPIO_OUT_CHANNELS_NUM int default 8 diff --git a/components/soc/esp32c3/include/soc/clk_tree_defs.h b/components/soc/esp32c3/include/soc/clk_tree_defs.h index 3eb948f397..7dc874c333 100644 --- a/components/soc/esp32c3/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c3/include/soc/clk_tree_defs.h @@ -357,6 +357,16 @@ typedef enum { LEDC_USE_RTC8M_CLK __attribute__((deprecated("please use 'LEDC_USE_RC_FAST_CLK' instead"))) = LEDC_USE_RC_FAST_CLK, /*!< Alias of 'LEDC_USE_RC_FAST_CLK' */ } soc_periph_ledc_clk_src_legacy_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_PLL = 1, /*!< PLL_CLK is the output of crystal oscillator frequency multiplier */ + CLKOUT_SIG_RC_SLOW = 4, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_PLL_F80M = 13, /*!< From PLL, usually be 80MHz */ + CLKOUT_SIG_RC_FAST = 14, /*!< RC fast clock, about 17.5MHz */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c3/include/soc/clkout_channel.h b/components/soc/esp32c3/include/soc/clkout_channel.h deleted file mode 100644 index 0d36368328..0000000000 --- a/components/soc/esp32c3/include/soc/clkout_channel.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SOC_CLKOUT_CHANNEL_H -#define _SOC_CLKOUT_CHANNEL_H - -// ESP32C3 CLKOUT signals has no corresponding iomux pins - -#endif diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index e2bf720dde..27ac1025f5 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -174,6 +174,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_6~GPIO_NUM_21) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00000000003FFFC0ULL +// The Clock Out singnal is route to the pin by GPIO matrix +#define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) + /*-------------------------- Dedicated GPIO CAPS -----------------------------*/ #define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index c4287d6d54..fd64e06298 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -475,6 +475,10 @@ config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool default y +config SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + bool + default y + config SOC_RTCIO_PIN_COUNT int default 8 diff --git a/components/soc/esp32c6/include/soc/clk_tree_defs.h b/components/soc/esp32c6/include/soc/clk_tree_defs.h index 97539e6355..0d47064956 100644 --- a/components/soc/esp32c6/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c6/include/soc/clk_tree_defs.h @@ -463,6 +463,22 @@ typedef enum { PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F240M, /*!< Select PLL_F240M as the default clock choice */ } soc_periph_parlio_clk_src_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_PLL = 1, /*!< PLL_CLK is the output of crystal oscillator frequency multiplier */ + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_PLL_F80M = 13, /*!< From PLL, usually be 80MHz */ + CLKOUT_SIG_CPU = 16, /*!< CPU clock */ + CLKOUT_SIG_AHB = 17, /*!< AHB clock */ + CLKOUT_SIG_APB = 18, /*!< APB clock */ + CLKOUT_SIG_XTAL32K = 21, /*!< External 32kHz crystal clock */ + CLKOUT_SIG_EXT32K = 22, /*!< External slow clock input through XTAL_32K_P */ + CLKOUT_SIG_RC_FAST = 23, /*!< RC fast clock, about 17.5MHz */ + CLKOUT_SIG_RC_32K = 24, /*!< Internal slow RC oscillator */ + CLKOUT_SIG_RC_SLOW = 25, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c6/include/soc/clkout_channel.h b/components/soc/esp32c6/include/soc/clkout_channel.h deleted file mode 100644 index 035248b78d..0000000000 --- a/components/soc/esp32c6/include/soc/clkout_channel.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -// ESP32C6 CLKOUT signals has no corresponding iomux pins diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 737ee15612..ed69e78246 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -208,6 +208,9 @@ // Support to hold a single digital I/O when the digital domain is powered off #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) +// The Clock Out singnal is route to the pin by GPIO matrix +#define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) + /*-------------------------- RTCIO CAPS --------------------------------------*/ #define SOC_RTCIO_PIN_COUNT 8 #define SOC_RTCIO_INPUT_OUTPUT_SUPPORTED 1 /* This macro indicates that the target has separate RTC IOMUX hardware feature, diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index d576e5821f..adc34fbbc8 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -467,6 +467,10 @@ config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool default y +config SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + bool + default y + config SOC_RTCIO_PIN_COUNT int default 8 diff --git a/components/soc/esp32h2/include/soc/clk_tree_defs.h b/components/soc/esp32h2/include/soc/clk_tree_defs.h index b8a91f4dfe..d56380c04a 100644 --- a/components/soc/esp32h2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h2/include/soc/clk_tree_defs.h @@ -479,6 +479,20 @@ typedef enum { MSPI_CLK_SRC_ROM_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as ROM default clock source */ } soc_periph_mspi_clk_src_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_CPU = 16, /*!< CPU clock */ + CLKOUT_SIG_AHB = 17, /*!< AHB clock */ + CLKOUT_SIG_APB = 18, /*!< APB clock */ + CLKOUT_SIG_XTAL32K = 21, /*!< External 32kHz crystal clock */ + CLKOUT_SIG_EXT32K = 22, /*!< External slow clock input through XTAL_32K_P */ + CLKOUT_SIG_RC_FAST = 23, /*!< RC fast clock, about 17.5MHz */ + CLKOUT_SIG_RC_32K = 24, /*!< Internal slow RC oscillator */ + CLKOUT_SIG_RC_SLOW = 25, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h2/include/soc/clkout_channel.h b/components/soc/esp32h2/include/soc/clkout_channel.h deleted file mode 100644 index d580d83c49..0000000000 --- a/components/soc/esp32h2/include/soc/clkout_channel.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -// ESP32H2 CLKOUT signals has no corresponding iomux pins diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index bffa8ee12d..9a3231707e 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -210,6 +210,9 @@ // Support to hold a single digital I/O when the digital domain is powered off #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1) +// The Clock Out singnal is route to the pin by GPIO matrix +#define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1) + /*-------------------------- RTCIO CAPS --------------------------------------*/ /* No dedicated LP_IOMUX subsystem on ESP32-H2. LP functions are still supported * for hold, wake & 32kHz crystal functions - via LP_AON registers */ diff --git a/components/soc/esp32p4/include/soc/clkout_channel.h b/components/soc/esp32p4/include/soc/clkout_channel.h deleted file mode 100644 index 4064eaf8d2..0000000000 --- a/components/soc/esp32p4/include/soc/clkout_channel.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -// ESP32P4 CLKOUT signals has no corresponding iomux pins diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 3bb460933a..f5813cc213 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -367,6 +367,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x00007FFFFC000000 +config SOC_GPIO_CLOCKOUT_BY_IO_MUX + bool + default y + config SOC_DEDIC_GPIO_OUT_CHANNELS_NUM int default 8 diff --git a/components/soc/esp32s2/include/soc/clk_tree_defs.h b/components/soc/esp32s2/include/soc/clk_tree_defs.h index 5eb67a1921..bbc4981660 100644 --- a/components/soc/esp32s2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s2/include/soc/clk_tree_defs.h @@ -415,6 +415,18 @@ typedef enum { LEDC_USE_RTC8M_CLK __attribute__((deprecated("please use 'LEDC_USE_RC_FAST_CLK' instead"))) = LEDC_USE_RC_FAST_CLK, /*!< Alias of 'LEDC_USE_RC_FAST_CLK' */ } soc_periph_ledc_clk_src_legacy_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_PLL = 1, /*!< PLL_CLK is the output of crystal oscillator frequency multiplier */ + CLKOUT_SIG_RC_SLOW = 4, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_APLL = 6, /*!< Divided by PLL, frequency is configurable */ + CLKOUT_SIG_REF_TICK = 12, /*!< Divided by APB clock, usually be 1MHz */ + CLKOUT_SIG_PLL_F80M = 13, /*!< From PLL, usually be 80MHz */ + CLKOUT_SIG_RC_FAST = 14, /*!< RC fast clock, about 17.5MHz */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32s2/include/soc/clkout_channel.h b/components/soc/esp32s2/include/soc/clkout_channel.h deleted file mode 100644 index abecc7bd64..0000000000 --- a/components/soc/esp32s2/include/soc/clkout_channel.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SOC_CLKOUT_CHANNEL_H -#define _SOC_CLKOUT_CHANNEL_H - -//CLKOUT channels -#define CLKOUT_IOMUX_FUNC_NUM 3 - -#define CLKOUT_GPIO20_DIRECT_CHANNEL CLKOUT_CHANNEL_1 -#define CLKOUT_CHANNEL_1_DIRECT_GPIO_NUM 20 -#define CLKOUT_GPIO19_DIRECT_CHANNEL CLKOUT_CHANNEL_2 -#define CLKOUT_CHANNEL_2_DIRECT_GPIO_NUM 19 -#define CLKOUT_GPIO18_DIRECT_CHANNEL CLKOUT_CHANNEL_3 -#define CLKOUT_CHANNEL_3_DIRECT_GPIO_NUM 18 - -#endif diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 449847b000..575df03bf6 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -171,6 +171,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_26~GPIO_NUM_46) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00007FFFFC000000ULL +// The Clock Out singnal is binding to the pin's IO_MUX function +#define SOC_GPIO_CLOCKOUT_BY_IO_MUX (1) + /*-------------------------- Dedicated GPIO CAPS ---------------------------------------*/ #define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 9fa6d132c9..3da46a8c1d 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -435,6 +435,10 @@ config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x0001FFFFFC000000 +config SOC_GPIO_CLOCKOUT_BY_IO_MUX + bool + default y + config SOC_DEDIC_GPIO_OUT_CHANNELS_NUM int default 8 diff --git a/components/soc/esp32s3/include/soc/clk_tree_defs.h b/components/soc/esp32s3/include/soc/clk_tree_defs.h index d3fadb96b1..881c2b3a1f 100644 --- a/components/soc/esp32s3/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s3/include/soc/clk_tree_defs.h @@ -444,6 +444,15 @@ typedef enum { SDMMC_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ } soc_periph_sdmmc_clk_src_t; +//////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// +typedef enum { + CLKOUT_SIG_PLL = 1, /*!< PLL_CLK is the output of crystal oscillator frequency multiplier */ + CLKOUT_SIG_RC_SLOW = 4, /*!< RC slow clock, depends on the RTC_CLK_SRC configuration */ + CLKOUT_SIG_XTAL = 5, /*!< Main crystal oscillator clock */ + CLKOUT_SIG_PLL_F80M = 13, /*!< From PLL, usually be 80MHz */ + CLKOUT_SIG_RC_FAST = 14, /*!< RC fast clock, about 17.5MHz */ + CLKOUT_SIG_INVALID = 0xFF, +} soc_clkout_sig_id_t; #ifdef __cplusplus } diff --git a/components/soc/esp32s3/include/soc/clkout_channel.h b/components/soc/esp32s3/include/soc/clkout_channel.h deleted file mode 100644 index 2dd19304ba..0000000000 --- a/components/soc/esp32s3/include/soc/clkout_channel.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -//CLKOUT channels -#define CLKOUT_IOMUX_FUNC_NUM 3 - -#define CLKOUT_GPIO20_DIRECT_CHANNEL CLKOUT_CHANNEL_1 -#define CLKOUT_CHANNEL_1_DIRECT_GPIO_NUM 20 -#define CLKOUT_GPIO19_DIRECT_CHANNEL CLKOUT_CHANNEL_2 -#define CLKOUT_CHANNEL_2_DIRECT_GPIO_NUM 19 -#define CLKOUT_GPIO18_DIRECT_CHANNEL CLKOUT_CHANNEL_3 -#define CLKOUT_CHANNEL_3_DIRECT_GPIO_NUM 18 - -// ESP32S3 has two other sets of GPIO pins which could route to CLKOUT_CHANNEL_1/2/3 through IO_MUX -// Please check TRM IO MUX Function List table if needed diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index c74a883913..42aeff02e3 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -177,6 +177,9 @@ // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_26~GPIO_NUM_48) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x0001FFFFFC000000ULL +// The Clock Out singnal is binding to the pin's IO_MUX function +#define SOC_GPIO_CLOCKOUT_BY_IO_MUX (1) + /*-------------------------- Dedicated GPIO CAPS -----------------------------*/ #define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ From 7195bf19df2354654b844d7b5dea22332b9da142 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 19 Oct 2023 22:21:53 +0800 Subject: [PATCH 3/5] feat(esp_hw_support): support one-to-many signal-gpio mapping output --- components/esp_hw_support/esp_clock_output.c | 238 +++++++++++------- .../esp_hw_support/include/esp_clock_output.h | 12 +- .../include/esp_private/clkout_channel.h | 19 +- 3 files changed, 169 insertions(+), 100 deletions(-) diff --git a/components/esp_hw_support/esp_clock_output.c b/components/esp_hw_support/esp_clock_output.c index 89397f59fb..0ccf012323 100644 --- a/components/esp_hw_support/esp_clock_output.c +++ b/components/esp_hw_support/esp_clock_output.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include "sdkconfig.h" #include "driver/gpio.h" @@ -16,139 +17,194 @@ #include "soc/soc_caps.h" #include "soc/io_mux_reg.h" -typedef struct gpio_clock_out_ctx { +typedef struct clkout_channel_handle { bool is_mapped; - uint8_t ref_cnt; - clock_out_channel_t clk_out; - gpio_num_t mapped_io; soc_clkout_sig_id_t mapped_clock; -} gpio_clock_out_ctx_t; + uint8_t channel_id; + uint8_t ref_cnt; + uint64_t mapped_io_bmap; + portMUX_TYPE clkout_channel_lock; +} clkout_channel_handle_t; -static const char *TAG = "gpio_output_clk"; +typedef struct esp_clock_output_mapping { + gpio_num_t mapped_io; + clkout_channel_handle_t* clkout_channel_hdl; + uint8_t ref_cnt; + portMUX_TYPE clkout_mapping_lock; + SLIST_ENTRY(esp_clock_output_mapping) next; +} esp_clock_output_mapping_t; -static portMUX_TYPE s_clkout_channel_lock = portMUX_INITIALIZER_UNLOCKED; +static const char *TAG = "esp_clock_output"; -static gpio_clock_out_ctx_t s_pin_ctrl_clk_out[CLKOUT_CHANNEL_MAX] = { +static SLIST_HEAD(esp_clock_output_mapping_head, esp_clock_output_mapping) s_mapping_list = SLIST_HEAD_INITIALIZER(s_mapping_list_head); +static portMUX_TYPE s_mapping_list_lock = portMUX_INITIALIZER_UNLOCKED; +static portMUX_TYPE s_clkout_lock = portMUX_INITIALIZER_UNLOCKED; + +static clkout_channel_handle_t s_clkout_handle[CLKOUT_CHANNEL_MAX] = { [0 ... CLKOUT_CHANNEL_MAX - 1] = { .is_mapped = false, .ref_cnt = 0, + .mapped_io_bmap = 0, + .clkout_channel_lock = portMUX_INITIALIZER_UNLOCKED, } }; -static gpio_clock_out_ctx_t* io_mux_pin_ctrl_clk_out_alloc(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num) +static clkout_channel_handle_t* clkout_channel_alloc(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num) { - gpio_clock_out_ctx_t *allocated_clk_out = NULL; + clkout_channel_handle_t *allocated_channel = NULL; #if SOC_GPIO_CLOCKOUT_BY_IO_MUX - portENTER_CRITICAL(&s_clkout_channel_lock); - if (!s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].is_mapped) { - s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].is_mapped = true; - s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].clk_out = IONUM_TO_CLKOUT(gpio_num); - allocated_clk_out = &s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)]; - } else if ((s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].mapped_io == gpio_num) && - (s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)].mapped_clock == clk_sig)) { - allocated_clk_out = &s_pin_ctrl_clk_out[IONUM_TO_CLKOUT(gpio_num)]; + portENTER_CRITICAL(&s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)].clkout_channel_lock); + if (!s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)].is_mapped) { + s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)].is_mapped = true; + allocated_channel = &s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)]; + } else if ((s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)].mapped_io_bmap & BIT(gpio_num)) && + (s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)].mapped_clock == clk_sig)) { + allocated_channel = &s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)]; } - portEXIT_CRITICAL(&s_clkout_channel_lock); + allocated_channel->channel_id = (clock_out_channel_t)IONUM_TO_CLKOUT_CHANNEL(gpio_num); + portEXIT_CRITICAL(&s_clkout_handle[IONUM_TO_CLKOUT_CHANNEL(gpio_num)].clkout_channel_lock); #elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX - for(uint32_t i = 0; i < CLKOUT_CHANNEL_MAX; i++) { - portENTER_CRITICAL(&s_clkout_channel_lock); - if (!s_pin_ctrl_clk_out[i].is_mapped) { - s_pin_ctrl_clk_out[i].is_mapped = true; - s_pin_ctrl_clk_out[i].clk_out = (clock_out_channel_t)i; - allocated_clk_out = &s_pin_ctrl_clk_out[i]; - portEXIT_CRITICAL(&s_clkout_channel_lock); + for(uint32_t channel = 0; channel < CLKOUT_CHANNEL_MAX; channel++) { + portENTER_CRITICAL(&s_clkout_handle[channel].clkout_channel_lock); + if (!s_clkout_handle[channel].is_mapped) { + s_clkout_handle[channel].is_mapped = true; + allocated_channel = &s_clkout_handle[channel]; + allocated_channel->channel_id = (clock_out_channel_t)channel; + portEXIT_CRITICAL(&s_clkout_handle[channel].clkout_channel_lock); break; - } else if ((s_pin_ctrl_clk_out[i].mapped_io == gpio_num) && - (s_pin_ctrl_clk_out[i].mapped_clock == clk_sig)) { - allocated_clk_out = &s_pin_ctrl_clk_out[i]; - portEXIT_CRITICAL(&s_clkout_channel_lock); + } else if (s_clkout_handle[channel].mapped_clock == clk_sig) { + allocated_channel = &s_clkout_handle[channel]; + portEXIT_CRITICAL(&s_clkout_handle[channel].clkout_channel_lock); break; } - portEXIT_CRITICAL(&s_clkout_channel_lock); + portEXIT_CRITICAL(&s_clkout_handle[channel].clkout_channel_lock); } #endif - if (allocated_clk_out != NULL) { - portENTER_CRITICAL(&s_clkout_channel_lock); - allocated_clk_out->mapped_io = gpio_num; - allocated_clk_out->mapped_clock = clk_sig; - allocated_clk_out->ref_cnt++; - portEXIT_CRITICAL(&s_clkout_channel_lock); + if (allocated_channel != NULL) { + portENTER_CRITICAL(&allocated_channel->clkout_channel_lock); + 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); + gpio_ll_set_pin_ctrl(clk_sig, CLKOUT_CHANNEL_MASK(allocated_channel->channel_id), CLKOUT_CHANNEL_SHIFT(allocated_channel->channel_id)); + portEXIT_CRITICAL(&s_clkout_lock); + } + portEXIT_CRITICAL(&allocated_channel->clkout_channel_lock); } - return allocated_clk_out; + return allocated_channel; } -static bool io_mux_pin_ctrl_clk_out_sig_try_free(gpio_clock_out_handle_t clk_out_hdl) +static esp_clock_output_mapping_t* clkout_mapping_alloc(clkout_channel_handle_t* channel_hdl, gpio_num_t gpio_num) { - bool do_free = false; - portENTER_CRITICAL(&s_clkout_channel_lock); - if (--clk_out_hdl->ref_cnt == 0) { - do_free = true; - clk_out_hdl->is_mapped = false; + esp_clock_output_mapping_t *allocated_mapping = NULL; + + portENTER_CRITICAL(&s_mapping_list_lock); + esp_clock_output_mapping_t *hdl; + SLIST_FOREACH(hdl, &s_mapping_list, next) { + if ((hdl->clkout_channel_hdl == channel_hdl) && (hdl->mapped_io == gpio_num)) { + allocated_mapping = hdl; + } } - portEXIT_CRITICAL(&s_clkout_channel_lock); - return do_free; -} + portEXIT_CRITICAL(&s_mapping_list_lock); -esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num, gpio_clock_out_handle_t *clk_out_hdl) -{ - ESP_RETURN_ON_FALSE((clk_out_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Clock out handle passed in is invalid"); - - ESP_RETURN_ON_FALSE(IS_VALID_CLKOUT_IO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "%s", "Output GPIO number error"); - - gpio_clock_out_ctx_t* new_hdl= io_mux_pin_ctrl_clk_out_alloc(clk_sig, gpio_num); + if (allocated_mapping == NULL) { + allocated_mapping = (esp_clock_output_mapping_t *)malloc(sizeof(esp_clock_output_mapping_t)); + allocated_mapping->mapped_io = gpio_num; + allocated_mapping->clkout_channel_hdl = channel_hdl; + allocated_mapping->ref_cnt = 0; + portMUX_INITIALIZE(&allocated_mapping->clkout_mapping_lock); + portENTER_CRITICAL(&s_mapping_list_lock); + SLIST_INSERT_HEAD(&s_mapping_list, allocated_mapping, next); + portEXIT_CRITICAL(&s_mapping_list_lock); + } + portENTER_CRITICAL(&allocated_mapping->clkout_mapping_lock); + allocated_mapping->ref_cnt++; + if (allocated_mapping->ref_cnt == 1) { #if SOC_GPIO_CLOCKOUT_BY_IO_MUX - ESP_RETURN_ON_FALSE((new_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Selected clock out IO is already mapped to other internal clock source"); + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], CLKOUT_CHANNEL_TO_IOMUX_FUNC(allocated_mapping->clkout_channel_hdl->channel_id)); #elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX - ESP_RETURN_ON_FALSE((new_hdl != NULL), ESP_FAIL, TAG, "Maximum support for %d output clock signals, no available clock_out channel for assignment", CLKOUT_CHANNEL_MAX); -#endif - - if (new_hdl->ref_cnt == 1) { - uint32_t clk_out_mask = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? CLK_OUT1 : - (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? CLK_OUT2 : - (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? CLK_OUT3 : 0; - uint32_t clk_out_shift = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? CLK_OUT1_S : - (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? CLK_OUT2_S : - (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? CLK_OUT3_S : 0; - - portENTER_CRITICAL(&s_clkout_channel_lock); - gpio_ll_set_pin_ctrl(clk_sig, clk_out_mask, clk_out_shift); - portEXIT_CRITICAL(&s_clkout_channel_lock); - -#if SOC_GPIO_CLOCKOUT_BY_IO_MUX - uint32_t clk_out_func = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? FUNC_CLK_OUT1 : - (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? FUNC_CLK_OUT2 : - (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? FUNC_CLK_OUT3 : 0; - - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], clk_out_func); -#elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX - uint32_t gpio_clk_out_sig_idx = (new_hdl->clk_out == CLKOUT_CHANNEL_1) ? CLK_OUT_OUT1_IDX : - (new_hdl->clk_out == CLKOUT_CHANNEL_2) ? CLK_OUT_OUT2_IDX : - (new_hdl->clk_out == CLKOUT_CHANNEL_3) ? CLK_OUT_OUT3_IDX : SIG_GPIO_OUT_IDX; - gpio_set_pull_mode(gpio_num, GPIO_FLOATING); gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO); gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT); - esp_rom_gpio_connect_out_signal(gpio_num, gpio_clk_out_sig_idx, false, false); + esp_rom_gpio_connect_out_signal(gpio_num, CLKOUT_CHANNEL_TO_GPIO_SIG_ID(allocated_mapping->clkout_channel_hdl->channel_id), false, false); #endif } + portEXIT_CRITICAL(&allocated_mapping->clkout_mapping_lock); + return allocated_mapping; +} + +static void clkout_channel_free(clkout_channel_handle_t *channel_hdl) +{ + portENTER_CRITICAL(&channel_hdl->clkout_channel_lock); + if (--channel_hdl->ref_cnt == 0) { + channel_hdl->mapped_clock = CLKOUT_SIG_INVALID; + portENTER_CRITICAL(&s_clkout_lock); + gpio_ll_set_pin_ctrl(0, CLKOUT_CHANNEL_MASK(channel_hdl->channel_id), CLKOUT_CHANNEL_SHIFT(channel_hdl->channel_id)); + portEXIT_CRITICAL(&s_clkout_lock); + channel_hdl->is_mapped = false; + } + portEXIT_CRITICAL(&channel_hdl->clkout_channel_lock); +} + +static void clkout_mapping_free(esp_clock_output_mapping_t *mapping_hdl) +{ + portENTER_CRITICAL(&mapping_hdl->clkout_mapping_lock); + clkout_channel_free(mapping_hdl->clkout_channel_hdl); + bool do_free_mapping_hdl = false; + if (--mapping_hdl->ref_cnt == 0) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[mapping_hdl->mapped_io], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(mapping_hdl->mapped_io, SIG_GPIO_OUT_IDX, false, false); + gpio_set_direction(mapping_hdl->mapped_io, GPIO_MODE_DISABLE); + + portENTER_CRITICAL(&mapping_hdl->clkout_channel_hdl->clkout_channel_lock); + mapping_hdl->clkout_channel_hdl->mapped_io_bmap &= ~BIT(mapping_hdl->mapped_io); + portEXIT_CRITICAL(&mapping_hdl->clkout_channel_hdl->clkout_channel_lock); + + portENTER_CRITICAL(&s_mapping_list_lock); + SLIST_REMOVE(&s_mapping_list, mapping_hdl, esp_clock_output_mapping, next); + portEXIT_CRITICAL(&s_mapping_list_lock); + do_free_mapping_hdl = true; + } + portEXIT_CRITICAL(&mapping_hdl->clkout_mapping_lock); + + if (do_free_mapping_hdl) { + free(mapping_hdl); + } +} + +esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num, esp_clock_output_mapping_handle_t *clkout_mapping_ret_hdl) +{ + ESP_RETURN_ON_FALSE((clkout_mapping_ret_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Clock out mapping handle passed in is invalid"); + ESP_RETURN_ON_FALSE(IS_VALID_CLKOUT_IO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "%s", "Output GPIO number error"); + + esp_clock_output_mapping_t *hdl; + SLIST_FOREACH(hdl, &s_mapping_list, next) { + ESP_RETURN_ON_FALSE(!((hdl->mapped_io == gpio_num) && (hdl->clkout_channel_hdl->mapped_clock != clk_sig)), ESP_ERR_INVALID_ARG, TAG, "Selected io is already mapped by another signal"); + } + + clkout_channel_handle_t *channel_hdl = clkout_channel_alloc(clk_sig, gpio_num); +#if SOC_GPIO_CLOCKOUT_BY_IO_MUX + ESP_RETURN_ON_FALSE((channel_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Selected clock out IO is already mapped to other internal clock source"); +#elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX + ESP_RETURN_ON_FALSE((channel_hdl != NULL), ESP_FAIL, TAG, "Maximum support for %d output clock signals, no available clock_out channel for assignment", CLKOUT_CHANNEL_MAX); +#endif + + *clkout_mapping_ret_hdl = clkout_mapping_alloc(channel_hdl, gpio_num); - *clk_out_hdl = new_hdl; return ESP_OK; } -esp_err_t esp_clock_output_stop(gpio_clock_out_handle_t clk_out_hdl) +esp_err_t esp_clock_output_stop(esp_clock_output_mapping_handle_t clkout_mapping_hdl) { - assert(clk_out_hdl != NULL); - ESP_RETURN_ON_FALSE(clk_out_hdl->is_mapped, ESP_ERR_INVALID_STATE, TAG, "%s", "Clock outputting is already disabled"); - if (io_mux_pin_ctrl_clk_out_sig_try_free(clk_out_hdl)) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[clk_out_hdl->mapped_io], PIN_FUNC_GPIO); - esp_rom_gpio_connect_out_signal(clk_out_hdl->mapped_io, SIG_GPIO_OUT_IDX, false, false); - gpio_set_direction(clk_out_hdl->mapped_io, GPIO_MODE_DISABLE); - } + ESP_RETURN_ON_FALSE((clkout_mapping_hdl != NULL), ESP_ERR_INVALID_ARG, TAG, "Clock out mapping handle passed in is invalid"); + ESP_RETURN_ON_FALSE(clkout_mapping_hdl->ref_cnt > 0, ESP_ERR_INVALID_STATE, TAG, "%s", "Clock outputting is already disabled"); + clkout_mapping_free(clkout_mapping_hdl); return ESP_OK; } diff --git a/components/esp_hw_support/include/esp_clock_output.h b/components/esp_hw_support/include/esp_clock_output.h index 1ccf58a6a6..33c87f9cec 100644 --- a/components/esp_hw_support/include/esp_clock_output.h +++ b/components/esp_hw_support/include/esp_clock_output.h @@ -21,31 +21,31 @@ extern "C" { #endif #if SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX || SOC_GPIO_CLOCKOUT_BY_IO_MUX -typedef struct gpio_clock_out_ctx* gpio_clock_out_handle_t; +typedef struct esp_clock_output_mapping *esp_clock_output_mapping_handle_t; /** * @brief Start output specified clock signal to specified GPIO, will also - * initialize the clk_out_hdl. + * initialize the clkout_mapping_ret_hdl. * * @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] clk_out_hdl Clock output controll handler + * @param[out] clkout_mapping_ret_hdl Clock output controll handler * @return * - ESP_OK: Output specified clock signal to specified GPIO successfully * - ESP_ERR_INVALID_ARG: Specified GPIO not supported to output internal clock * or specified GPIO is already mapped to other internal clock source. * - ESP_FAIL: There are no clock out signals that can be allocated. */ -esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num, gpio_clock_out_handle_t *clk_out_hdl); +esp_err_t esp_clock_output_start(soc_clkout_sig_id_t clk_sig, gpio_num_t gpio_num, esp_clock_output_mapping_handle_t *clkout_mapping_ret_hdl); /** * @brief Stop clock signal to GPIO outputting - * @param[in] clk_out_hdl Clock output controll handle + * @param[in] clkout_mapping_hdl Clock output mapping controll 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_t esp_clock_output_stop(gpio_clock_out_handle_t clk_out_hdl); +esp_err_t esp_clock_output_stop(esp_clock_output_mapping_handle_t clkout_mapping_hdl); #endif #ifdef __cplusplus diff --git a/components/esp_hw_support/include/esp_private/clkout_channel.h b/components/esp_hw_support/include/esp_private/clkout_channel.h index ff6e580273..2daa0d447f 100644 --- a/components/esp_hw_support/include/esp_private/clkout_channel.h +++ b/components/esp_hw_support/include/esp_private/clkout_channel.h @@ -34,14 +34,27 @@ typedef enum clock_out_channel { #define FUNC_CLK_OUT2 FUNC_GPIO19_CLK_OUT2 #define FUNC_CLK_OUT3 FUNC_DAC_2_CLK_OUT3 #endif +#define IONUM_TO_CLKOUT_CHANNEL(gpio_num) ((gpio_num == CLKOUT_CHANNEL1_GPIO) ? CLKOUT_CHANNEL_1 : \ + (gpio_num == CLKOUT_CHANNEL2_GPIO) ? CLKOUT_CHANNEL_2 : \ + (gpio_num == CLKOUT_CHANNEL3_GPIO) ? CLKOUT_CHANNEL_3 : 0) +#define CLKOUT_CHANNEL_TO_IOMUX_FUNC(channel) ((channel == CLKOUT_CHANNEL_1) ? FUNC_CLK_OUT1 : \ + (channel == CLKOUT_CHANNEL_2) ? FUNC_CLK_OUT2 : \ + (channel == CLKOUT_CHANNEL_3) ? FUNC_CLK_OUT3 : 0) #define IS_VALID_CLKOUT_IO(gpio_num) ((gpio_num == CLKOUT_CHANNEL1_GPIO) || (gpio_num == CLKOUT_CHANNEL2_GPIO) || (gpio_num == CLKOUT_CHANNEL3_GPIO)) #elif SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX +#define CLKOUT_CHANNEL_TO_GPIO_SIG_ID(channel) ((channel == CLKOUT_CHANNEL_1) ? CLK_OUT_OUT1_IDX : \ + (channel == CLKOUT_CHANNEL_2) ? CLK_OUT_OUT2_IDX : \ + (channel == CLKOUT_CHANNEL_3) ? CLK_OUT_OUT3_IDX : SIG_GPIO_OUT_IDX) #define IS_VALID_CLKOUT_IO(gpio_num) GPIO_IS_VALID_GPIO(gpio_num) #endif -#define IONUM_TO_CLKOUT(gpio_num) ((gpio_num == CLKOUT_CHANNEL1_GPIO) ? CLKOUT_CHANNEL_1 : \ - (gpio_num == CLKOUT_CHANNEL2_GPIO) ? CLKOUT_CHANNEL_2 : \ - (gpio_num == CLKOUT_CHANNEL3_GPIO) ? CLKOUT_CHANNEL_3 : 0) +#define CLKOUT_CHANNEL_MASK(channel) ((channel == CLKOUT_CHANNEL_1) ? CLK_OUT1 : \ + (channel == CLKOUT_CHANNEL_2) ? CLK_OUT2 : \ + (channel == CLKOUT_CHANNEL_3) ? CLK_OUT3 : 0) + +#define CLKOUT_CHANNEL_SHIFT(channel) ((channel == CLKOUT_CHANNEL_1) ? CLK_OUT1_S : \ + (channel == CLKOUT_CHANNEL_2) ? CLK_OUT2_S : \ + (channel == CLKOUT_CHANNEL_3) ? CLK_OUT3_S : 0) #ifdef __cplusplus } From d6cda1b6e11e8e8d3461e6d35b64c2db096fb84d Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 11 Sep 2023 15:37:22 +0800 Subject: [PATCH 4/5] ci(esp_hw_support): add test case for gpio output internal clock feature ci --- .../main/CMakeLists.txt | 4 + .../main/test_esp_clock_output.c | 148 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_esp_clock_output.c diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt index 982a32fa20..0f499f0d84 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt @@ -8,6 +8,10 @@ set(srcs "test_app_main.c" "test_random.c" ) +if(CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX OR CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX) + list(APPEND srcs "test_esp_clock_output.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} 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 new file mode 100644 index 0000000000..e3e189283e --- /dev/null +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_esp_clock_output.c @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "driver/gpio.h" +#include "esp_err.h" +#include "esp_clock_output.h" +#include "hal/gpio_hal.h" + +#include "soc/rtc.h" + +#define TEST_LOOPS 100 + +#if CONFIG_IDF_TARGET_ESP32 +static const int test_clk_out_io[] = {0, 1, 3}; +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +static const int test_clk_out_io[] = {18, 19, 20}; +#else +static const int test_clk_out_io[] = {3, 4, 5, 6}; +#endif + +static soc_clkout_sig_id_t test_clk_out_sig[] = {CLKOUT_SIG_XTAL, CLKOUT_SIG_RC_SLOW, CLKOUT_SIG_RC_FAST, CLKOUT_SIG_INVALID}; + +static SemaphoreHandle_t test_done_semphr; + +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)); + vTaskDelay(3); + TEST_ESP_OK(esp_clock_output_stop(clkout_mapping_hdl)); + vTaskDelay(7); + } + xSemaphoreGive(test_done_semphr); + vTaskDelete(NULL); +} + +void output_clock_2(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[1], test_clk_out_io[1], &clkout_mapping_hdl)); + vTaskDelay(4); + TEST_ESP_OK(esp_clock_output_stop(clkout_mapping_hdl)); + vTaskDelay(6); + } + xSemaphoreGive(test_done_semphr); + vTaskDelete(NULL); +} + +void output_clock_3(void *pvParameter) +{ + rtc_dig_clk8m_enable(); + 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[2], test_clk_out_io[2], &clkout_mapping_hdl)); + vTaskDelay(5); + TEST_ESP_OK(esp_clock_output_stop(clkout_mapping_hdl)); + vTaskDelay(5); + } + xSemaphoreGive(test_done_semphr); + vTaskDelete(NULL); +} + + +// This case is now tested only manually +TEST_CASE("GPIO output internal clock", "[gpio_output_clock][ignore]") +{ + test_done_semphr = xSemaphoreCreateCounting(3, 0); + xTaskCreate(&output_clock_1, "output_clock_1", 4096, NULL, 4, NULL); + xTaskCreate(&output_clock_2, "output_clock_2", 4096, NULL, 4, NULL); + xTaskCreate(&output_clock_3, "output_clock_3", 4096, NULL, 4, NULL); + + int cnt = 0; + while (cnt < 3) { + if (xSemaphoreTake(test_done_semphr, portMAX_DELAY) == pdTRUE) { + cnt++; + } + } + vTaskDelay(1); + + vSemaphoreDelete(test_done_semphr); + gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); + gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD); +} + +#if SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX +TEST_CASE("GPIO output internal clock one-to-many", "[gpio_output_clock][ignore]") +{ + // Test NULL handle assertion + TEST_ESP_ERR(esp_clock_output_start(test_clk_out_sig[0], test_clk_out_io[0], NULL), ESP_ERR_INVALID_ARG); + + // Test first mapping + esp_clock_output_mapping_handle_t clkout_mapping_hdl_0; + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[0], test_clk_out_io[0], &clkout_mapping_hdl_0)); // [0]:0(1) [1]:x [2]:x + + // Test the same mapping allocate the same handle + esp_clock_output_mapping_handle_t clkout_mapping_hdl_1; + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[0], test_clk_out_io[0], &clkout_mapping_hdl_1)); // [0]:0(2) [1]:x [2]:x + TEST_ASSERT(clkout_mapping_hdl_0 == clkout_mapping_hdl_1); + + // Test map multi signal to one IO assertion + esp_clock_output_mapping_handle_t clkout_mapping_hdl_2; + TEST_ESP_ERR(esp_clock_output_start(test_clk_out_sig[1], test_clk_out_io[0], &clkout_mapping_hdl_2), ESP_ERR_INVALID_ARG); + + // Test the same signal mapping to multi GPIO + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[0], test_clk_out_io[1], &clkout_mapping_hdl_2)); // [0]:0(2) 1 [1]:x [2]:x + esp_clock_output_mapping_handle_t clkout_mapping_hdl_3; + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[0], test_clk_out_io[2], &clkout_mapping_hdl_3)); // [0]:0(2) 1 2 [1]:x [2]:x + + // Test the clkout mapping ref_cnt validity + esp_clock_output_stop(clkout_mapping_hdl_0); // [0]:0(1) 1 2 [1]:x [2]:x + esp_clock_output_mapping_handle_t clkout_mapping_hdl_4; + TEST_ESP_ERR(esp_clock_output_start(test_clk_out_sig[1], test_clk_out_io[0], &clkout_mapping_hdl_4), ESP_ERR_INVALID_ARG); + esp_clock_output_stop(clkout_mapping_hdl_1); // [0]:1 2 [1]:x [2]:x + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[1], test_clk_out_io[0], &clkout_mapping_hdl_4)); // [0]:1 2 [1]:0 [2]:x + +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 + test_clk_out_sig[3] = CLKOUT_SIG_PLL_F80M; +#else + test_clk_out_sig[3] = CLKOUT_SIG_RC_32K; +#endif + + // Test the excess clock channel request assertion + esp_clock_output_stop(clkout_mapping_hdl_3); // [0]:1 [1]:0 [2]:x + esp_clock_output_mapping_handle_t clkout_mapping_hdl_5; + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[2], test_clk_out_io[2], &clkout_mapping_hdl_5)); // [0]:1 [1]:0 [2]:2 + esp_clock_output_mapping_handle_t clkout_mapping_hdl_6; + TEST_ASSERT(ESP_FAIL == esp_clock_output_start(test_clk_out_sig[3], test_clk_out_io[3], &clkout_mapping_hdl_6)); + + // Test the clock out channel recycle + esp_clock_output_stop(clkout_mapping_hdl_4); // [0]:1 [1]:x [2]:2 + esp_clock_output_mapping_handle_t clkout_mapping_hdl_7; + TEST_ESP_OK(esp_clock_output_start(test_clk_out_sig[3], test_clk_out_io[0], &clkout_mapping_hdl_7)); // [0]:1 [1]:0 [2]:2 + + // Stop all + esp_clock_output_stop(clkout_mapping_hdl_2); + esp_clock_output_stop(clkout_mapping_hdl_5); + esp_clock_output_stop(clkout_mapping_hdl_6); + esp_clock_output_stop(clkout_mapping_hdl_7); +} +#endif From e2c182ab4bd00e1ada6b40cab480d57ddc4241d7 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 11 Sep 2023 15:09:31 +0800 Subject: [PATCH 5/5] refactor(i2s): stop to output mclk after uninstalled on esp32 --- components/driver/deprecated/i2s_legacy.c | 30 +++++++++++------------ components/driver/i2s/i2s_common.c | 24 +++++++++--------- components/driver/i2s/i2s_private.h | 10 ++++++-- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 076cb60ce7..bfbb850b56 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -39,6 +39,10 @@ #include "driver/adc_types_legacy.h" #endif // SOC_I2S_SUPPORTS_ADC +#if CONFIG_IDF_TARGET_ESP32 +#include "esp_clock_output.h" +#endif + #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" #endif @@ -135,7 +139,9 @@ typedef struct { bool use_apll; /*!< I2S use APLL clock */ int fixed_mclk; /*!< I2S fixed MLCK clock */ i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of I2S master clock(MCLK) to sample rate */ - +#if CONFIG_IDF_TARGET_ESP32 + esp_clock_output_mapping_handle_t mclk_out_hdl; +#endif #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif @@ -1500,6 +1506,12 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) i2s_obj_t *obj = p_i2s[i2s_num]; i2s_stop(i2s_num); +#if CONFIG_IDF_TARGET_ESP32 + if (obj->mclk_out_hdl) { + esp_clock_output_stop(obj->mclk_out_hdl); + } +#endif + #if SOC_I2S_SUPPORTS_ADC_DAC if ((int)(obj->mode) == I2S_COMM_MODE_ADC_DAC) { if (obj->dir & I2S_DIR_TX) { @@ -1800,20 +1812,8 @@ static esp_err_t i2s_check_set_mclk(i2s_port_t i2s_num, gpio_num_t gpio_num) return ESP_OK; } #if CONFIG_IDF_TARGET_ESP32 - ESP_RETURN_ON_FALSE((gpio_num == GPIO_NUM_0 || gpio_num == GPIO_NUM_1 || gpio_num == GPIO_NUM_3), - ESP_ERR_INVALID_ARG, TAG, - "ESP32 only support to set GPIO0/GPIO1/GPIO3 as mclk signal, error GPIO number:%d", gpio_num); - bool is_i2s0 = i2s_num == I2S_NUM_0; - if (gpio_num == GPIO_NUM_0) { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); - WRITE_PERI_REG(PIN_CTRL, is_i2s0 ? 0xFFF0 : 0xFFFF); - } else if (gpio_num == GPIO_NUM_1) { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); - WRITE_PERI_REG(PIN_CTRL, is_i2s0 ? 0xF0F0 : 0xF0FF); - } else { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); - WRITE_PERI_REG(PIN_CTRL, is_i2s0 ? 0xFF00 : 0xFF0F); - } + soc_clkout_sig_id_t clkout_sig = (i2s_num == I2S_NUM_0) ? CLKOUT_SIG_I2S0 : CLKOUT_SIG_I2S1; + ESP_RETURN_ON_ERROR(esp_clock_output_start(clkout_sig, gpio_num, &p_i2s[i2s_num]->mclk_out_hdl), TAG, "mclk configure failed"); #else ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid"); gpio_matrix_out_check_and_set(gpio_num, i2s_periph_signal[i2s_num].mck_out_sig, 0, 0); diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index 530f2c449d..41b58a035a 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -46,6 +46,10 @@ #include "driver/i2s_common.h" #include "i2s_private.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp_clock_output.h" +#endif + #include "clk_ctrl_os.h" #include "esp_clk_tree.h" #include "esp_intr_alloc.h" @@ -152,6 +156,11 @@ static esp_err_t i2s_destroy_controller_obj(i2s_controller_t **i2s_obj) ESP_ERR_INVALID_STATE, TAG, "there still have channels under this i2s controller"); int id = (*i2s_obj)->id; +#if CONFIG_IDF_TARGET_ESP32 + if ((*i2s_obj)->mclk_out_hdl) { + esp_clock_output_stop((*i2s_obj)->mclk_out_hdl); + } +#endif #if SOC_I2S_HW_VERSION_1 i2s_ll_enable_dma((*i2s_obj)->hal.dev, false); #endif @@ -739,20 +748,11 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_sr return ESP_OK; } #if CONFIG_IDF_TARGET_ESP32 - ESP_RETURN_ON_FALSE((gpio_num == GPIO_NUM_0 || gpio_num == GPIO_NUM_1 || gpio_num == GPIO_NUM_3), - ESP_ERR_INVALID_ARG, TAG, - "ESP32 only support to set GPIO0/GPIO1/GPIO3 as mclk signal, error GPIO number:%d", gpio_num); bool is_i2s0 = id == I2S_NUM_0; bool is_apll = clk_src == I2S_CLK_SRC_APLL; - if (gpio_num == GPIO_NUM_0) { - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); - gpio_ll_set_iomux_pin_ctrl(is_apll ? 0xFFF6 : (is_i2s0 ? 0xFFF0 : 0xFFFF), 0xFFFFFFFF, 0); - } else if (gpio_num == GPIO_NUM_1) { - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); - gpio_ll_set_iomux_pin_ctrl(is_apll ? 0xF6F6 : (is_i2s0 ? 0xF0F0 : 0xF0FF), 0xFFFFFFFF, 0); - } else { - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); - gpio_ll_set_iomux_pin_ctrl(is_apll ? 0xFF66 : (is_i2s0 ? 0xFF00 : 0xFF0F), 0xFFFFFFFF, 0); + if (g_i2s.controller[id]->mclk_out_hdl == NULL) { + soc_clkout_sig_id_t clkout_sig = is_apll ? CLKOUT_SIG_APLL : (is_i2s0 ? CLKOUT_SIG_I2S0 : CLKOUT_SIG_I2S1); + ESP_RETURN_ON_ERROR(esp_clock_output_start(clkout_sig, gpio_num, &(g_i2s.controller[id]->mclk_out_hdl)), TAG, "mclk configure failed"); } #else ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid"); diff --git a/components/driver/i2s/i2s_private.h b/components/driver/i2s/i2s_private.h index 9405062ca5..0777091c85 100644 --- a/components/driver/i2s/i2s_private.h +++ b/components/driver/i2s/i2s_private.h @@ -7,12 +7,15 @@ #pragma once #include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" #include "soc/lldesc.h" #include "soc/soc_caps.h" #include "hal/i2s_hal.h" #include "driver/i2s_types.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp_clock_output.h" +#endif #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" #endif @@ -114,6 +117,9 @@ typedef struct { i2s_chan_handle_t tx_chan; /*!< tx channel handler */ i2s_chan_handle_t rx_chan; /*!< rx channel handler */ int mclk; /*!< MCK out pin, shared by tx/rx*/ +#if CONFIG_IDF_TARGET_ESP32 + esp_clock_output_mapping_handle_t mclk_out_hdl; /*!< The handle of MCLK output signal */ +#endif } i2s_controller_t; struct i2s_channel_obj_t {