diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index 421aac0613..2b9f98df18 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -126,6 +126,7 @@ We have two bits to control the interrupt: #include "driver/gpio.h" #include "hal/spi_hal.h" #include "hal/spi_ll.h" +#include "hal/hal_utils.h" #include "esp_heap_caps.h" #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_cache.h" @@ -163,7 +164,6 @@ typedef struct { struct spi_device_t { int id; - int real_clk_freq_hz; QueueHandle_t trans_queue; QueueHandle_t ret_queue; spi_device_interface_config_t cfg; @@ -368,11 +368,30 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa #endif spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT; uint32_t clock_source_hz = 0; + uint32_t clock_source_div = 1; if (dev_config->clock_source) { clk_src = dev_config->clock_source; } esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &clock_source_hz); +#if SPI_LL_SUPPORT_CLK_SRC_PRE_DIV + SPI_CHECK((dev_config->clock_speed_hz > 0) && (dev_config->clock_speed_hz <= MIN(clock_source_hz / 2, (80 * 1000000))), "invalid sclk speed", ESP_ERR_INVALID_ARG); + + if (clock_source_hz / 2 > (80 * 1000000)) { //clock_source_hz beyond peripheral HW limitation, calc pre-divider + hal_utils_clk_info_t clk_cfg = { + .src_freq_hz = clock_source_hz, + .exp_freq_hz = dev_config->clock_speed_hz * 2, //we have (hs_clk = 2*mst_clk), calc hs_clk first + .round_opt = HAL_DIV_ROUND, + }; + hal_utils_calc_clk_div_integer(&clk_cfg, &clock_source_div); + } + clock_source_div *= 2; //convert to mst_clk function divider + if (clock_source_div > SPI_LL_CLK_SRC_PRE_DIV_MAX) { + clock_source_div = SPI_LL_CLK_SRC_PRE_DIV_MAX; + } + clock_source_hz /= clock_source_div; //actual freq enter to SPI peripheral +#else SPI_CHECK((dev_config->clock_speed_hz > 0) && (dev_config->clock_speed_hz <= clock_source_hz), "invalid sclk speed", ESP_ERR_INVALID_ARG); +#endif #ifdef CONFIG_IDF_TARGET_ESP32 //The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full //duplex mode does absolutely nothing on the ESP32. @@ -416,10 +435,10 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa //output values of timing configuration spi_hal_timing_conf_t temp_timing_conf; - int freq; - esp_err_t ret = spi_hal_cal_clock_conf(&timing_param, &freq, &temp_timing_conf); - temp_timing_conf.clock_source = clk_src; + esp_err_t ret = spi_hal_cal_clock_conf(&timing_param, &temp_timing_conf); SPI_CHECK(ret == ESP_OK, "assigned clock speed not supported", ret); + temp_timing_conf.clock_source = clk_src; + temp_timing_conf.source_pre_div = clock_source_div; //Allocate memory for device dev = malloc(sizeof(spi_device_t)); @@ -447,7 +466,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa //We want to save a copy of the dev config in the dev struct. memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t)); dev->cfg.duty_cycle_pos = duty_cycle; - dev->real_clk_freq_hz = freq; // TODO: if we have to change the apb clock among transactions, re-calculate this each time the apb clock lock is locked. //Set CS pin, CS options @@ -483,7 +501,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa hal_dev->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0; *handle = dev; - ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host_id + 1, freecs, freq / 1000); + ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %d Hz", host_id + 1, freecs, temp_timing_conf.real_freq); return ESP_OK; @@ -545,7 +563,7 @@ esp_err_t spi_device_get_actual_freq(spi_device_handle_t handle, int* freq_khz) return ESP_ERR_INVALID_ARG; } - *freq_khz = handle->real_clk_freq_hz / 1000; + *freq_khz = handle->hal_dev.timing_conf.real_freq / 1000; return ESP_OK; } @@ -567,6 +585,11 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev) /* Configuration has not been applied yet. */ spi_hal_setup_device(hal, hal_dev); SPI_MASTER_PERI_CLOCK_ATOMIC() { +#if SPI_LL_SUPPORT_CLK_SRC_PRE_DIV + //we set mst_div as const 2, then (hs_clk = 2*mst_clk) to ensure timing turning work as past + //and sure (hs_div * mst_div = source_pre_div) + spi_ll_clk_source_pre_div(hal->hw, hal_dev->timing_conf.source_pre_div / 2, 2); +#endif spi_ll_set_clk_source(hal->hw, hal_dev->timing_conf.clock_source); } } diff --git a/components/hal/esp32p4/include/hal/spi_ll.h b/components/hal/esp32p4/include/hal/spi_ll.h index 9df298fd5f..45d7bc6851 100644 --- a/components/hal/esp32p4/include/hal/spi_ll.h +++ b/components/hal/esp32p4/include/hal/spi_ll.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 */ @@ -40,6 +40,8 @@ extern "C" { #define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits #define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words +#define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral +#define SPI_LL_CLK_SRC_PRE_DIV_MAX 512//div1(8bit) * div2(8bit but set const 2) /** * The data structure holding calculated clock configuration. Since the @@ -175,6 +177,12 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s { uint32_t clk_id = 0; switch (clk_source) { + case SPI_CLK_SRC_SPLL: + clk_id = 4; + break; + case SPI_CLK_SRC_RC_FAST: + clk_id = 1; + break; case SPI_CLK_SRC_XTAL: clk_id = 0; break; @@ -193,6 +201,32 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define spi_ll_set_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_set_clk_source(__VA_ARGS__) +/** + * Config clock source integrate pre_div before it enter GPSPI peripheral + * + * @note 1. For timing turning(e.g. input_delay) feature available, should be (mst_div >= 2) + * 2. From peripheral limitation: (sour_freq/hs_div <= 160M) and (sour_freq/hs_div/mst_div <= 80M) + * + * @param hw Beginning address of the peripheral registers. + * @param hs_div Timing turning clock divider: (hs_clk_o = sour_freq/hs_div) + * @param mst_div Functional output clock divider: (mst_clk_o = sour_freq/hs_div/mst_div) + */ +__attribute__((always_inline)) +static inline void spi_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div) +{ + if (hw == &GPSPI2) { + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_hs_clk_div_num = hs_div - 1; + HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_mst_clk_div_num = mst_div - 1; + } else if (hw == &GPSPI3) { + HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_hs_clk_div_num = hs_div - 1; + HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_mst_clk_div_num = mst_div - 1; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define spi_ll_clk_sour_pre_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_clk_sour_pre_div(__VA_ARGS__) + /** * Initialize SPI peripheral (master). * diff --git a/components/hal/include/hal/spi_hal.h b/components/hal/include/hal/spi_hal.h index 5937cd2952..147c4848f3 100644 --- a/components/hal/include/hal/spi_hal.h +++ b/components/hal/include/hal/spi_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -70,6 +70,8 @@ typedef struct { typedef struct { spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer spi_clock_source_t clock_source; ///< Clock source of each device used by LL layer + uint32_t source_pre_div; ///< Pre divider befor enter SPI peripheral + int real_freq; ///< Output of the actual frequency int timing_dummy; ///< Extra dummy needed to compensate the timing int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing } spi_hal_timing_conf_t; @@ -222,12 +224,11 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal); * It is highly suggested to do this at initialization, since it takes long time. * * @param timing_param Input parameters to calculate timing configuration - * @param out_freq Output of the actual frequency, left NULL if not required. * @param timing_conf Output of the timing configuration. * * @return ESP_OK if desired is available, otherwise fail. */ -esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf); +esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, spi_hal_timing_conf_t *timing_conf); /** * Get the frequency actual used. diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index aa090a71b8..723e1c0520 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,7 +52,7 @@ void spi_hal_deinit(spi_hal_context_t *hal) } } -esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf) +esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, spi_hal_timing_conf_t *timing_conf) { spi_hal_timing_conf_t temp_conf = {}; @@ -73,12 +73,10 @@ Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output dat ESP_ERR_NOT_SUPPORTED, freq_limit / 1000. / 1000 ); #endif + temp_conf.real_freq = eff_clk_n; if (timing_conf) { *timing_conf = temp_conf; } - if (out_freq) { - *out_freq = eff_clk_n; - } return ESP_OK; } diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 12a1c0adbb..b487498e0d 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -987,6 +987,14 @@ config SOC_SPI_SUPPORT_CLK_XTAL bool default y +config SOC_SPI_SUPPORT_CLK_RC_FAST + bool + default y + +config SOC_SPI_SUPPORT_CLK_SPLL + bool + default y + config SOC_MEMSPI_IS_INDEPENDENT bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index b192eac7a2..d0619b69ed 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -403,14 +403,10 @@ typedef enum { * @brief Type of SPI clock source. */ typedef enum { - SPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ -#if SOC_CLK_TREE_SUPPORTED - SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, - SPI_CLK_SRC_SPLL_480 = SOC_MOD_CLK_SPLL, - SPI_CLK_SRC_DEFAULT = SPI_CLK_SRC_SPLL_480, /*!< Select SPLL_480M as SPI source clock */ -#else - SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ -#endif + SPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */ + SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST_20M as SPI source clock */ + SPI_CLK_SRC_SPLL = SOC_MOD_CLK_SPLL, /*!< Select SPLL as SPI source clock */ + SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_SPLL, /*!< Select SPLL as SPI source clock */ } soc_periph_spi_clk_src_t; /////////////////////////////////////////////////PSRAM//////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 74e6215569..de2b308c7c 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -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 */ @@ -425,10 +425,8 @@ #define SOC_SPI_SUPPORT_CD_SIG 1 #define SOC_SPI_SUPPORT_OCT 1 #define SOC_SPI_SUPPORT_CLK_XTAL 1 -// #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 //bellow clks are waiting for clock tree -// #define SOC_SPI_SUPPORT_CLK_SPLL_F480M 1 //super pll -// #define SOC_SPI_SUPPORT_CLK_SDIO 1 //sdio pll -// #define SOC_SPI_SUPPORT_CLK_APLL 1 //audio pll +#define SOC_SPI_SUPPORT_CLK_RC_FAST 1 +#define SOC_SPI_SUPPORT_CLK_SPLL 1 // Peripheral supports DIO, DOUT, QIO, or QOUT // host_id = 0 -> SPI0/SPI1, host_id = 1 -> SPI2, diff --git a/components/spi_flash/test_apps/esp_flash_stress/README.md b/components/spi_flash/test_apps/esp_flash_stress/README.md index a8b7833fa3..bf47d80ec6 100644 --- a/components/spi_flash/test_apps/esp_flash_stress/README.md +++ b/components/spi_flash/test_apps/esp_flash_stress/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |