fix(esp_eth): fixes EMAC MDC out of the range issue

Closes https://github.com/espressif/esp-idf/issues/17984
This commit is contained in:
Ondrej Kosta
2025-12-11 11:20:53 +01:00
parent 81c961a656
commit ae3fbe1ada
10 changed files with 74 additions and 4 deletions
@@ -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 = \
+11 -1
View File
@@ -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;
+25
View File
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#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) */
@@ -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
@@ -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
*
@@ -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);
@@ -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;
+1 -1
View File
@@ -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();
}
+9 -2
View File
@@ -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.
*/
@@ -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 */