From ae3fbe1adaa448b291ad9d922befc3bccf122bd7 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Thu, 11 Dec 2025 11:20:53 +0100 Subject: [PATCH] fix(esp_eth): fixes EMAC MDC out of the range issue Closes https://github.com/espressif/esp-idf/issues/17984 --- components/esp_eth/include/esp_eth_mac_esp.h | 3 +++ components/esp_eth/src/mac/esp_eth_mac_esp.c | 12 ++++++++- components/esp_hal_emac/emac_hal.c | 25 +++++++++++++++++++ .../esp_hal_emac/esp32/include/hal/emac_ll.h | 7 ++++++ .../esp32p4/include/hal/emac_ll.h | 6 +++++ .../esp_hal_emac/include/hal/emac_hal.h | 4 +++ .../port/esp32p4/esp_clk_tree.c | 7 ++++++ components/hal/esp32p4/clk_tree_hal.c | 2 +- components/hal/include/hal/clk_tree_hal.h | 11 ++++++-- .../soc/esp32p4/include/soc/clk_tree_defs.h | 1 + 10 files changed, 74 insertions(+), 4 deletions(-) diff --git a/components/esp_eth/include/esp_eth_mac_esp.h b/components/esp_eth/include/esp_eth_mac_esp.h index 2fa45815ed..c7d31805a5 100644 --- a/components/esp_eth/include/esp_eth_mac_esp.h +++ b/components/esp_eth/include/esp_eth_mac_esp.h @@ -126,6 +126,7 @@ typedef struct { #if !SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK eth_mac_clock_config_t clock_config_out_in; /*!< EMAC input clock configuration for internally generated output clock (when output clock is looped back externally) */ #endif //SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK + int32_t mdc_freq_hz; /*!< EMAC MDC frequency range limit, if set to 0 or a negative value, the driver will can set the CSR clock range up to 2.5 MHz */ } eth_esp32_emac_config_t; /** @@ -185,6 +186,7 @@ typedef bool (*ts_target_exceed_cb_from_isr_t)(esp_eth_mediator_t *eth, void *us }, \ .dma_burst_len = ETH_DMA_BURST_LEN_32, \ .intr_priority = 0, \ + .mdc_freq_hz = 0, \ } #elif CONFIG_IDF_TARGET_ESP32P4 #define ETH_ESP32_EMAC_DEFAULT_CONFIG() \ @@ -205,6 +207,7 @@ typedef bool (*ts_target_exceed_cb_from_isr_t)(esp_eth_mediator_t *eth, void *us }, \ .dma_burst_len = ETH_DMA_BURST_LEN_32, \ .intr_priority = 0, \ + .mdc_freq_hz = 0, \ .emac_dataif_gpio = \ { \ .rmii = \ diff --git a/components/esp_eth/src/mac/esp_eth_mac_esp.c b/components/esp_eth/src/mac/esp_eth_mac_esp.c index ae23482be4..9b30b2cf01 100644 --- a/components/esp_eth/src/mac/esp_eth_mac_esp.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp.c @@ -77,6 +77,7 @@ typedef struct { bool do_flow_ctrl; // indicates whether we need to do software flow control bool use_pll; // Only use (A/M)PLL in EMAC_DATA_INTERFACE_RMII && EMAC_CLK_OUT SemaphoreHandle_t multi_reg_mutex; // lock for multiple register access + int32_t mdc_freq_hz; #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif @@ -618,7 +619,14 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) } ESP_GOTO_ON_FALSE(to < emac->sw_reset_timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "reset timeout"); /* set smi clock */ - emac_hal_set_csr_clock_range(&emac->hal, esp_clk_apb_freq()); + uint32_t csr_freq_hz; + soc_module_clk_t csr_clk_src = emac_ll_get_csr_clk_src(); + ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(csr_clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &csr_freq_hz), err, TAG, "get CSR frequency failed"); + if (emac->mdc_freq_hz <= 0) { + emac_hal_set_csr_clock_range(&emac->hal, csr_freq_hz); + } else { + emac_hal_find_set_closest_csr_clock_range(&emac->hal, emac->mdc_freq_hz, csr_freq_hz); + } /* init mac registers by default */ emac_hal_init_mac_default(&emac->hal); /* init dma registers with selected EMAC-DMA configuration */ @@ -950,6 +958,8 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config emac->dma_burst_len = esp32_config->dma_burst_len; emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->mdc_freq_hz = esp32_config->mdc_freq_hz; + emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK; emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK; emac->parent.set_mediator = emac_esp32_set_mediator; diff --git a/components/esp_hal_emac/emac_hal.c b/components/esp_hal_emac/emac_hal.c index 954f0f01e3..5161e85d44 100644 --- a/components/esp_hal_emac/emac_hal.c +++ b/components/esp_hal_emac/emac_hal.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include "soc/soc_caps.h" #include "esp_attr.h" #include "hal/emac_hal.h" @@ -13,6 +14,15 @@ #define EMAC_PTP_INIT_TIMEOUT_US (10) #endif // SOC_EMAC_IEEE1588V2_SUPPORTED +static uint8_t emac_crs_div_table[] = { + 42, + 62, + 16, + 26, + 102, + 124, +}; + static esp_err_t emac_hal_flush_trans_fifo(emac_hal_context_t *hal) { emac_ll_flush_trans_fifo_enable(hal->dma_regs, true); @@ -39,6 +49,21 @@ void emac_hal_init(emac_hal_context_t *hal) #endif } +void emac_hal_find_set_closest_csr_clock_range(emac_hal_context_t *hal, int mdc_freq_hz, int freq_hz) +{ + int min_diff = abs(freq_hz / emac_crs_div_table[0] - mdc_freq_hz); + uint32_t best_div = 0; + + for (int i = 1; i < sizeof(emac_crs_div_table) / sizeof(emac_crs_div_table[0]); i++) { + int cur_diff = abs(freq_hz / emac_crs_div_table[i] - mdc_freq_hz); + if (cur_diff < min_diff) { + min_diff = cur_diff; + best_div = i; + } + } + emac_ll_set_csr_clock_division(hal->mac_regs, best_div); +} + void emac_hal_set_csr_clock_range(emac_hal_context_t *hal, int freq) { /* Tell MAC system clock Frequency in MHz, which will determine the frequency range of MDC(1MHz~2.5MHz) */ diff --git a/components/esp_hal_emac/esp32/include/hal/emac_ll.h b/components/esp_hal_emac/esp32/include/hal/emac_ll.h index c20fb1ca7a..4c5849b5df 100644 --- a/components/esp_hal_emac/esp32/include/hal/emac_ll.h +++ b/components/esp_hal_emac/esp32/include/hal/emac_ll.h @@ -22,6 +22,7 @@ #include "soc/emac_mac_struct.h" #include "soc/emac_ext_struct.h" #include "soc/dport_reg.h" +#include "soc/clk_tree_defs.h" #ifdef __cplusplus extern "C" { @@ -745,6 +746,12 @@ static inline void emac_ll_pause_frame_enable(emac_ext_dev_t *ext_regs, bool ena } /*************** End of ext regs operation *********************/ +static inline soc_module_clk_t emac_ll_get_csr_clk_src(void) +{ + // Source of the ESP32 EMAC CRS clock is APB clock. + return SOC_MOD_CLK_APB; +} + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_emac/esp32p4/include/hal/emac_ll.h b/components/esp_hal_emac/esp32p4/include/hal/emac_ll.h index 63b4bb0343..45d4c9310f 100644 --- a/components/esp_hal_emac/esp32p4/include/hal/emac_ll.h +++ b/components/esp_hal_emac/esp32p4/include/hal/emac_ll.h @@ -840,6 +840,12 @@ static inline void emac_ll_ts_target_int_trig_enable(emac_ptp_dev_t *ptp_regs) /************** End of ptp regs operation ********************/ +static inline soc_module_clk_t emac_ll_get_csr_clk_src(void) +{ + // Source of the ESP32P4 EMAC CRS clock is SYS clock. + return SOC_MOD_CLK_SYS; +} + /** * @brief Enable the bus clock for the EMAC module * diff --git a/components/esp_hal_emac/include/hal/emac_hal.h b/components/esp_hal_emac/include/hal/emac_hal.h index a262c26fc7..16ee8b89ad 100644 --- a/components/esp_hal_emac/include/hal/emac_hal.h +++ b/components/esp_hal_emac/include/hal/emac_hal.h @@ -245,6 +245,10 @@ void emac_hal_init(emac_hal_context_t *hal); #define emac_hal_is_reset_done(hal) emac_ll_is_reset_done((hal)->dma_regs) +#define emac_hal_get_csr_freq_hz(void) emac_ll_get_csr_freq_hz() + +void emac_hal_find_set_closest_csr_clock_range(emac_hal_context_t *hal, int mdc_freq_hz, int freq_hz); + void emac_hal_set_csr_clock_range(emac_hal_context_t *hal, int freq); void emac_hal_init_mac_default(emac_hal_context_t *hal); diff --git a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c index 40de0a781c..795132654e 100644 --- a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c @@ -8,6 +8,7 @@ #include "esp_clk_tree.h" #include "esp_err.h" #include "esp_check.h" +#include "soc/clk_tree_defs.h" #include "soc/rtc.h" #include "hal/clk_gate_ll.h" #include "hal/clk_tree_hal.h" @@ -32,6 +33,12 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr case SOC_MOD_CLK_XTAL: clk_src_freq = clk_hal_xtal_get_freq_mhz() * MHZ; break; + case SOC_MOD_CLK_SYS: + clk_src_freq = clk_hal_sys_get_freq_hz(); + break; + case SOC_MOD_CLK_APB: + clk_src_freq = clk_hal_apb_get_freq_hz(); + break; case SOC_MOD_CLK_PLL_F20M: clk_src_freq = CLK_LL_PLL_480M_FREQ_MHZ / clk_ll_pll_f20m_get_divider() * MHZ; break; diff --git a/components/hal/esp32p4/clk_tree_hal.c b/components/hal/esp32p4/clk_tree_hal.c index 16fc5d5b68..32d374a2fd 100644 --- a/components/hal/esp32p4/clk_tree_hal.c +++ b/components/hal/esp32p4/clk_tree_hal.c @@ -45,7 +45,7 @@ static uint32_t clk_hal_mem_get_freq_hz(void) return clk_hal_cpu_get_freq_hz() / clk_ll_mem_get_divider(); } -static uint32_t clk_hal_sys_get_freq_hz(void) +uint32_t clk_hal_sys_get_freq_hz(void) { return clk_hal_mem_get_freq_hz() / clk_ll_sys_get_divider(); } diff --git a/components/hal/include/hal/clk_tree_hal.h b/components/hal/include/hal/clk_tree_hal.h index 60d083f490..629d9a4ce1 100644 --- a/components/hal/include/hal/clk_tree_hal.h +++ b/components/hal/include/hal/clk_tree_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,7 +35,14 @@ uint32_t clk_hal_soc_root_get_freq_mhz(soc_cpu_clk_src_t cpu_clk_src); uint32_t clk_hal_cpu_get_freq_hz(void); /** - * @brief Get APB_CLK frequency + * @brief Get SYS_CLK frequency, derived from MEM_CLK + * + * @return SYS clock frequency, in Hz. Returns 0 if internal clock configuration is invalid. + */ +uint32_t clk_hal_sys_get_freq_hz(void); + +/** + * @brief Get APB_CLK frequency, derived from SYS_CLK * * @return APB clock frequency, in Hz. Returns 0 if internal clock configuration is invalid. */ diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 537fde5b66..47a1679513 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -160,6 +160,7 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL, RC_FAST, or LP_PLL by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, or RC32K by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals + SOC_MOD_CLK_SYS, /*!< SYS_CLK is the system clock, derived from HP_ROOT clock source */ SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_F20M, /*!< PLL_F20M_CLK is derived from SPLL (clock gating + default divider 24), its default frequency is 20MHz */ SOC_MOD_CLK_PLL_F25M, /*!< PLL_F25M_CLK is derived from MPLL (clock gating + configurable divider), it will have a frequency of 25MHz */