Merge branch 'feature/support_esp32p4_clock_output' into 'master'

feat: support esp32p4 clock output

Closes IDF-8226

See merge request espressif/esp-idf!28619
This commit is contained in:
Wu Zheng Hui
2024-04-17 17:40:40 +08:00
51 changed files with 788 additions and 100 deletions
@@ -1,63 +0,0 @@
/*
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "soc/soc_caps.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 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 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
}
#endif
+22 -6
View File
@@ -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
*/
@@ -11,8 +11,9 @@
#include "esp_clock_output.h"
#include "esp_check.h"
#include "esp_rom_gpio.h"
#include "clkout_channel.h"
#include "soc/clkout_channel.h"
#include "hal/gpio_hal.h"
#include "hal/clk_tree_hal.h"
#include "hal/clk_tree_ll.h"
#include "soc/soc_caps.h"
#include "soc/io_mux_reg.h"
@@ -20,7 +21,7 @@
typedef struct clkout_channel_handle {
bool is_mapped;
soc_clkout_sig_id_t mapped_clock;
uint8_t channel_id;
clock_out_channel_t channel_id;
uint8_t ref_cnt;
uint64_t mapped_io_bmap;
portMUX_TYPE clkout_channel_lock;
@@ -87,13 +88,12 @@ 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
clk_ll_enable_clkout_source(clk_sig, true);
#endif
gpio_ll_set_pin_ctrl(clk_sig, CLKOUT_CHANNEL_MASK(allocated_channel->channel_id), CLKOUT_CHANNEL_SHIFT(allocated_channel->channel_id));
clk_hal_clock_output_setup(clk_sig, allocated_channel->channel_id);
portEXIT_CRITICAL(&s_clkout_lock);
}
portEXIT_CRITICAL(&allocated_channel->clkout_channel_lock);
@@ -150,7 +150,7 @@ static void clkout_channel_free(clkout_channel_handle_t *channel_hdl)
#if SOC_CLOCKOUT_HAS_SOURCE_GATE
clk_ll_enable_clkout_source(channel_hdl->mapped_clock, false);
#endif
gpio_ll_set_pin_ctrl(0, CLKOUT_CHANNEL_MASK(channel_hdl->channel_id), CLKOUT_CHANNEL_SHIFT(channel_hdl->channel_id));
clk_hal_clock_output_teardown(channel_hdl->channel_id);
portEXIT_CRITICAL(&s_clkout_lock);
channel_hdl->mapped_clock = CLKOUT_SIG_INVALID;
channel_hdl->is_mapped = false;
@@ -187,7 +187,11 @@ static void clkout_mapping_free(esp_clock_output_mapping_t *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");
#if SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "%s", "Output GPIO number error");
#else
ESP_RETURN_ON_FALSE(IS_VALID_CLKOUT_IO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "%s", "Output GPIO number error");
#endif
esp_clock_output_mapping_t *hdl;
SLIST_FOREACH(hdl, &s_mapping_list, next) {
@@ -214,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))
@@ -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
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -20,6 +20,8 @@
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};
#elif CONFIG_IDF_TARGET_ESP32P4
static const int test_clk_out_io[] = {7, 8};
#else
static const int test_clk_out_io[] = {3, 4, 5, 6};
#endif
@@ -33,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);
@@ -54,6 +59,7 @@ void output_clock_2(void *pvParameter)
vTaskDelete(NULL);
}
#if SOC_GPIO_CLOCKOUT_CHANNEL_NUM >= 3
void output_clock_3(void *pvParameter)
{
rtc_dig_clk8m_enable();
@@ -67,7 +73,7 @@ void output_clock_3(void *pvParameter)
xSemaphoreGive(test_done_semphr);
vTaskDelete(NULL);
}
#endif
// This case is now tested only manually
TEST_CASE("GPIO output internal clock", "[gpio_output_clock][ignore]")
@@ -75,10 +81,12 @@ 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);
#if SOC_GPIO_CLOCKOUT_CHANNEL_NUM >= 3
xTaskCreate(&output_clock_3, "output_clock_3", 4096, NULL, 4, NULL);
#endif
int cnt = 0;
while (cnt < 3) {
while (cnt < SOC_GPIO_CLOCKOUT_CHANNEL_NUM) {
if (xSemaphoreTake(test_done_semphr, portMAX_DELAY) == pdTRUE) {
cnt++;
}
@@ -86,8 +94,13 @@ TEST_CASE("GPIO output internal clock", "[gpio_output_clock][ignore]")
vTaskDelay(1);
vSemaphoreDelete(test_done_semphr);
#if CONFIG_IDF_TARGET_ESP32
/* ESP32 clock out channel pin reuses UART TX/RX pin, restore its default
configuration at the end of the test */
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);
#endif
}
#if SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX