feat(esp_eth): a new folder structure of the driver and other improvements

Fixed memory leak in emac_esp_new_dma function.

Polished ESP EMAC cache management.

Added emac_periph definitions based on SoC features and improved(generalized) ESP EMAC GPIO
initialization.

Added ESP EMAC GPIO reservation.

Added check for frame error condition indicated by EMAC DMA and created a target test.
This commit is contained in:
Ondrej Kosta 2024-04-26 12:27:54 +02:00
parent ee8a9e8410
commit d15a9c2c48
63 changed files with 2068 additions and 1442 deletions

View File

@ -12,11 +12,11 @@ set(ld_fragments linker.lf)
# As CONFIG_ETH_ENABLED comes from Kconfig, it is not evaluated yet
# when components are being registered.
# Thus, always add the (private) requirements, regardless of Kconfig
set(priv_requires driver log esp_timer)
set(priv_requires log esp_timer esp_driver_spi esp_driver_gpio)
# If Ethernet disabled in Kconfig, this is a config-only component
if(CONFIG_ETH_ENABLED)
set(srcs "src/esp_eth.c" "src/esp_eth_phy_802_3.c")
set(srcs "src/esp_eth.c" "src/phy/esp_eth_phy_802_3.c")
set(include "include")
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
@ -27,34 +27,34 @@ if(CONFIG_ETH_ENABLED)
endif()
if(CONFIG_ETH_USE_ESP32_EMAC)
list(APPEND srcs "src/esp_eth_mac_esp.c"
"src/esp_eth_mac_esp_dma.c"
"src/esp_eth_mac_esp_gpio.c"
"src/esp_eth_phy_dp83848.c"
"src/esp_eth_phy_ip101.c"
"src/esp_eth_phy_ksz80xx.c"
"src/esp_eth_phy_lan87xx.c"
"src/esp_eth_phy_rtl8201.c")
list(APPEND srcs "src/mac/esp_eth_mac_esp.c"
"src/mac/esp_eth_mac_esp_dma.c"
"src/mac/esp_eth_mac_esp_gpio.c"
"src/phy/esp_eth_phy_dp83848.c"
"src/phy/esp_eth_phy_ip101.c"
"src/phy/esp_eth_phy_ksz80xx.c"
"src/phy/esp_eth_phy_lan87xx.c"
"src/phy/esp_eth_phy_rtl8201.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_DM9051)
list(APPEND srcs "src/esp_eth_mac_dm9051.c"
"src/esp_eth_phy_dm9051.c")
list(APPEND srcs "src/spi/dm9051/esp_eth_mac_dm9051.c"
"src/spi/dm9051/esp_eth_phy_dm9051.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_W5500)
list(APPEND srcs "src/esp_eth_mac_w5500.c"
"src/esp_eth_phy_w5500.c")
list(APPEND srcs "src/spi/w5500/esp_eth_mac_w5500.c"
"src/spi/w5500/esp_eth_phy_w5500.c")
endif()
if(CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL)
list(APPEND srcs "src/esp_eth_mac_ksz8851snl.c"
"src/esp_eth_phy_ksz8851snl.c")
list(APPEND srcs "src/spi/ksz8851snl/esp_eth_mac_ksz8851snl.c"
"src/spi/ksz8851snl/esp_eth_phy_ksz8851snl.c")
endif()
if(CONFIG_ETH_USE_OPENETH)
list(APPEND srcs "src/esp_eth_mac_openeth.c"
"src/esp_eth_phy_dp83848.c")
list(APPEND srcs "src/openeth/esp_eth_mac_openeth.c"
"src/phy/esp_eth_phy_dp83848.c")
endif()
endif()
@ -66,7 +66,7 @@ idf_component_register(SRCS "${srcs}"
if(CONFIG_ETH_ENABLED)
if(CONFIG_ETH_USE_SPI_ETHERNET)
idf_component_optional_requires(PUBLIC driver esp_driver_gpio)
idf_component_optional_requires(PUBLIC esp_driver_spi)
endif()
idf_component_optional_requires(PRIVATE esp_netif esp_pm)
if(CONFIG_SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE)

View File

@ -24,7 +24,7 @@ menu "Ethernet"
endchoice
if ETH_PHY_INTERFACE_RMII
choice ETH_RMII_CLK_MODE
choice ETH_RMII_CLK_MODE # IDF-9724
depends on IDF_TARGET_ESP32
prompt "RMII clock mode"
default ETH_RMII_CLK_INPUT

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -14,6 +14,17 @@
extern "C" {
#endif
/**
* @brief Offset for start of MAC custom ioctl commands
*
*/
#define ETH_CMD_CUSTOM_MAC_CMDS_OFFSET 0x0FFF
/**
* @brief Offset for start of PHY custom ioctl commands
*
*/
#define ETH_CMD_CUSTOM_PHY_CMDS_OFFSET 0x1FFF
/**
* @brief Ethernet driver state
*

View File

@ -1,12 +1,20 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_eth_com.h"
#include "esp_eth_mac.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "esp_eth_mac_spi.h"
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#if CONFIG_ETH_USE_ESP32_EMAC
#include "esp_eth_mac_esp.h"
#endif // CONFIG_ETH_USE_ESP32_EMAC
#if CONFIG_ETH_USE_OPENETH
#include "esp_eth_mac_openeth.h"
#endif // CONFIG_ETH_USE_OPENETH
#include "esp_eth_phy.h"
#ifdef __cplusplus
@ -151,8 +159,8 @@ typedef enum {
ETH_CMD_READ_PHY_REG, /*!< Read PHY register */
ETH_CMD_WRITE_PHY_REG, /*!< Write PHY register */
ETH_CMD_CUSTOM_MAC_CMDS = 0x0FFF, // Offset for start of MAC custom commands
ETH_CMD_CUSTOM_PHY_CMDS = 0x1FFF, // Offset for start of PHY custom commands
ETH_CMD_CUSTOM_MAC_CMDS = ETH_CMD_CUSTOM_MAC_CMDS_OFFSET, // Offset for start of MAC custom commands
ETH_CMD_CUSTOM_PHY_CMDS = ETH_CMD_CUSTOM_PHY_CMDS_OFFSET, // Offset for start of PHY custom commands
} esp_eth_io_cmd_t;
/**
@ -272,7 +280,7 @@ esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length);
* @param[in] argc number variable arguments
* @param ... variable arguments
* @return
* - ESP_OK: transmit successfull
* - ESP_OK: transmit successful
* - ESP_ERR_INVALID_STATE: invalid driver state (e.i. driver is not started)
* - ESP_ERR_TIMEOUT: transmit frame buffer failed because HW was not get available in predefined period
* - ESP_FAIL: transmit frame buffer failed because some other error occurred
@ -280,7 +288,7 @@ esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length);
esp_err_t esp_eth_transmit_vargs(esp_eth_handle_t hdl, uint32_t argc, ...);
/**
* @brief Misc IO function of Etherent driver
* @brief Misc IO function of Ethernet driver
*
* @param[in] hdl: handle of Ethernet driver
* @param[in] cmd: IO control command
@ -314,6 +322,28 @@ esp_err_t esp_eth_transmit_vargs(esp_eth_handle_t hdl, uint32_t argc, ...);
*/
esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data);
/**
* @brief Get PHY instance memory address
*
* @param[in] hdl handle of Ethernet driver
* @param[out] phy pointer to memory to store the instance
* @return esp_err_t
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: failed because of some invalid argument
*/
esp_err_t esp_eth_get_phy_instance(esp_eth_handle_t hdl, esp_eth_phy_t **phy);
/**
* @brief Get MAC instance memory address
*
* @param[in] hdl handle of Ethernet driver
* @param[out] mac pointer to memory to store the instance
* @return esp_err_t
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: failed because of some invalid argument
*/
esp_err_t esp_eth_get_mac_instance(esp_eth_handle_t hdl, esp_eth_mac_t **mac);
/**
* @brief Increase Ethernet driver reference
* @note Ethernet driver handle can be obtained by os timer, netif, etc.

View File

@ -9,9 +9,6 @@
#include "soc/soc_caps.h"
#include "esp_eth_com.h"
#include "sdkconfig.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif
#ifdef __cplusplus
extern "C" {
@ -306,7 +303,7 @@ struct esp_eth_mac_s {
* - ESP_FAIL: process io command failed because some other error occurred
* - ESP_ERR_NOT_SUPPORTED: requested feature is not supported
*/
esp_err_t (*custom_ioctl)(esp_eth_mac_t *mac, uint32_t cmd, void *data);
esp_err_t (*custom_ioctl)(esp_eth_mac_t *mac, int cmd, void *data);
/**
* @brief Free memory of Ethernet MAC
@ -321,115 +318,6 @@ struct esp_eth_mac_s {
esp_err_t (*del)(esp_eth_mac_t *mac);
};
/**
* @brief RMII Clock Mode Options
*
*/
typedef enum {
/**
* @brief Default values configured using Kconfig are going to be used when "Default" selected.
*
* @note May not be supported on all targets.
*
*/
EMAC_CLK_DEFAULT,
/**
* @brief Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected.
*
* @note MAC will get RMII clock from outside. Note that ESP32 only supports GPIO0 to input the RMII clock.
*
*/
EMAC_CLK_EXT_IN,
/**
* @brief Output RMII Clock from internal (A/M)PLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected.
*
*/
EMAC_CLK_OUT
} emac_rmii_clock_mode_t;
#if CONFIG_IDF_TARGET_ESP32
/**
* @brief RMII Clock GPIO number Options for ESP32
*
*/
typedef enum {
/**
* @brief MAC will get RMII clock from outside at this GPIO.
*
* @note ESP32 only supports GPIO0 to input the RMII clock.
*
*/
EMAC_CLK_IN_GPIO = 0,
/**
* @brief Output RMII Clock from internal APLL Clock available at GPIO0
*
* @note GPIO0 can be set to output a pre-divided PLL clock (test only!). Enabling this option will configure GPIO0 to output a 50MHz clock.
* In fact this clock doesnt have directly relationship with EMAC peripheral. Sometimes this clock wont work well with your PHY chip.
* You might need to add some extra devices after GPIO0 (e.g. inverter). Note that outputting RMII clock on GPIO0 is an experimental practice.
* If you want the Ethernet to work with WiFi, dont select GPIO0 output mode for stability.
*
*/
EMAC_APPL_CLK_OUT_GPIO = 0,
/**
* @brief Output RMII Clock from internal APLL Clock available at GPIO16
*
*/
EMAC_CLK_OUT_GPIO = 16,
/**
* @brief Inverted Output RMII Clock from internal APLL Clock available at GPIO17
*
*/
EMAC_CLK_OUT_180_GPIO = 17
} emac_rmii_clock_gpio_t;
#else
/**
* @brief RMII Clock GPIO number
*
*/
typedef int emac_rmii_clock_gpio_t;
#endif // CONFIG_IDF_TARGET_ESP32
/**
* @brief Ethernet MAC Clock Configuration
*
*/
typedef union {
struct {
// MII interface is not fully implemented...
// Reserved for GPIO number, clock source, etc. in MII mode
} mii; /*!< EMAC MII Clock Configuration */
struct {
emac_rmii_clock_mode_t clock_mode; /*!< RMII Clock Mode Configuration */
emac_rmii_clock_gpio_t clock_gpio; /*!< RMII Clock GPIO Configuration */
} rmii; /*!< EMAC RMII Clock Configuration */
} eth_mac_clock_config_t;
#if SOC_EMAC_USE_IO_MUX
/**
* @brief Ethernet MAC MII/RMII data plane GPIO configuration
*
*/
typedef union {
struct {
// MII interface is not fully implemented...
// Reserved for data interface GPIO numbers in MII mode
} mii; /*!< EMAC MII Data GPIO Configuration */
struct {
int32_t tx_en_num; /*!< TX_EN GPIO number */
int32_t txd0_num; /*!< TXD0 GPIO number */
int32_t txd1_num; /*!< TXD1 GPIO number */
int32_t crs_dv_num; /*!< CRS_DV GPIO number */
int32_t rxd0_num; /*!< RXD0 GPIO number */
int32_t rxd1_num; /*!< RXD1 GPIO number */
} rmii; /*!< EMAC RMII Data GPIO Configuration */
} eth_mac_dataif_gpio_config_t;
#endif // SOC_EMAC_USE_IO_MUX
/**
* @brief Configuration of Ethernet MAC object
*
@ -456,327 +344,6 @@ typedef struct {
.flags = 0, \
}
#if CONFIG_ETH_USE_ESP32_EMAC
/**
* @brief EMAC specific configuration
*
*/
typedef struct {
int smi_mdc_gpio_num; /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */
int smi_mdio_gpio_num; /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */
eth_data_interface_t interface; /*!< EMAC Data interface to PHY (MII/RMII) */
eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */
eth_mac_dma_burst_len_t dma_burst_len; /*!< EMAC DMA burst length for both Tx and Rx */
int intr_priority; /*!< EMAC interrupt priority, if set to 0 or a negative value, the driver will try to allocate an interrupt with a default priority */
#if SOC_EMAC_USE_IO_MUX
eth_mac_dataif_gpio_config_t emac_dataif_gpio; /*!< EMAC MII/RMII data plane GPIO configuration */
#endif // SOC_EMAC_USE_IO_MUX
#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
} eth_esp32_emac_config_t;
/**
* @brief Default ESP32's EMAC specific configuration
*
*/
#if CONFIG_IDF_TARGET_ESP32
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_mdc_gpio_num = 23, \
.smi_mdio_gpio_num = 18, \
.interface = EMAC_DATA_INTERFACE_RMII, \
.clock_config = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_DEFAULT, \
.clock_gpio = EMAC_CLK_IN_GPIO \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
.intr_priority = 0, \
}
#elif CONFIG_IDF_TARGET_ESP32P4
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_mdc_gpio_num = 31, \
.smi_mdio_gpio_num = 27, \
.interface = EMAC_DATA_INTERFACE_RMII, \
.clock_config = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_EXT_IN, \
.clock_gpio = 50 \
} \
}, \
.clock_config_out_in = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_DEFAULT, \
.clock_gpio = -1 \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
.intr_priority = 0, \
.emac_dataif_gpio = \
{ \
.rmii = \
{ \
.tx_en_num = 49, \
.txd0_num = 34, \
.txd1_num = 35, \
.crs_dv_num = 28, \
.rxd0_num = 29, \
.rxd1_num = 30 \
} \
}, \
}
#endif // CONFIG_IDF_TARGET_ESP32P4
/**
* @brief Create ESP32 Ethernet MAC instance
*
* @param esp32_config: EMAC specific configuration
* @param config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config);
#endif // CONFIG_ETH_USE_ESP32_EMAC
#if CONFIG_ETH_USE_SPI_ETHERNET
/**
* @brief Custom SPI Driver Configuration.
* This structure declares configuration and callback functions to access Ethernet SPI module via
* user's custom SPI driver.
*
*/
typedef struct
{
/**
* @brief Custom driver specific configuration data used by `init()` function.
*
* @note Type and its content is fully under user's control
*
*/
void *config;
/**
* @brief Custom driver SPI Initialization
*
* @param[in] spi_config: Custom driver specific configuration
*
* @return
* - spi_ctx: when initialization is successful, a pointer to context structure holding all variables
* needed for subsequent SPI access operations (e.g. SPI bus identification, mutexes, etc.)
* - NULL: driver initialization failed
*
* @note return type and its content is fully under user's control
*/
void *(*init)(const void *spi_config);
/**
* @brief Custom driver De-initialization
*
* @param[in] spi_ctx: a pointer to driver specific context structure
*
* @return
* - ESP_OK: driver de-initialization was successful
* - ESP_FAIL: driver de-initialization failed
* - any other failure codes are allowed to be used to provide failure isolation
*/
esp_err_t (*deinit)(void *spi_ctx);
/**
* @brief Custom driver SPI read
*
* @note The read function is responsible to construct command, address and data fields
* of the SPI frame in format expected by particular SPI Ethernet module
*
* @param[in] spi_ctx: a pointer to driver specific context structure
* @param[in] cmd: command
* @param[in] addr: register address
* @param[out] data: read data
* @param[in] data_len: read data length in bytes
*
* @return
* - ESP_OK: read was successful
* - ESP_FAIL: read failed
* - any other failure codes are allowed to be used to provide failure isolation
*/
esp_err_t (*read)(void *spi_ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len);
/**
* @brief Custom driver SPI write
*
* @note The write function is responsible to construct command, address and data fields
* of the SPI frame in format expected by particular SPI Ethernet module
*
* @param[in] spi_ctx: a pointer to driver specific context structure
* @param[in] cmd: command
* @param[in] addr: register address
* @param[in] data: data to write
* @param[in] data_len: length of data to write in bytes
*
* @return
* - ESP_OK: write was successful
* - ESP_FAIL: write failed
* - any other failure codes are allowed to be used to provide failure isolation
*/
esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len);
} eth_spi_custom_driver_config_t;
/**
* @brief Default configuration of the custom SPI driver.
* Internal ESP-IDF SPI Master driver is used by default.
*
*/
#define ETH_DEFAULT_SPI \
{ \
.config = NULL, \
.init = NULL, \
.deinit = NULL, \
.read = NULL, \
.write = NULL \
}
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#if CONFIG_ETH_SPI_ETHERNET_DM9051
/**
* @brief DM9051 specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_dm9051_config_t;
/**
* @brief Default DM9051 specific configuration
*
*/
#define ETH_DM9051_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create DM9051 Ethernet MAC instance
*
* @param dm9051_config: DM9051 specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_DM9051
#if CONFIG_ETH_SPI_ETHERNET_W5500
/**
* @brief W5500 specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined)*/
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined)*/
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_w5500_config_t;
/**
* @brief Default W5500 specific configuration
*
*/
#define ETH_W5500_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create W5500 Ethernet MAC instance
*
* @param w5500_config: W5500 specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_W5500
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
/**
* @brief KSZ8851SNL specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_ksz8851snl_config_t;
/**
* @brief Default KSZ8851SNL specific configuration
*
*/
#define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create KSZ8851SNL Ethernet MAC instance
*
* @param ksz8851snl_config: KSZ8851SNL specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851snl_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_KSZ8851
#if CONFIG_ETH_USE_OPENETH
/**
* @brief Create OpenCores Ethernet MAC instance
*
* @param config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config);
#endif // CONFIG_ETH_USE_OPENETH
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,296 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "esp_eth_com.h"
#include "esp_eth_mac.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ETH_USE_ESP32_EMAC
/**
* @brief RMII Clock Mode Options
*
*/
typedef enum {
/**
* @brief Default values configured using Kconfig are going to be used when "Default" selected.
*
* @warning Deprecated option. Clock configuration using Kconfig is limitedly supported only for ESP32 SoC via @c ETH_ESP32_EMAC_DEFAULT_CONFIG
* and is going to be reevaluated in the next major release.
* Clock mode and clock GPIO number is supposed to be defined in `EMAC specific configuration` structure from user's code.
*
*/
EMAC_CLK_DEFAULT __attribute__((deprecated)), // IDF-9724
/**
* @brief Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected.
*
* @note MAC will get RMII clock from outside. Note that ESP32 only supports GPIO0 to input the RMII clock.
*
*/
EMAC_CLK_EXT_IN,
/**
* @brief Output RMII Clock from internal (A/M)PLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected.
*
*/
EMAC_CLK_OUT
} emac_rmii_clock_mode_t;
#if CONFIG_IDF_TARGET_ESP32
/**
* @brief RMII Clock GPIO number Options for ESP32
*
*/
typedef enum {
/**
* @brief MAC will get RMII clock from outside at this GPIO.
*
* @note ESP32 only supports GPIO0 to input the RMII clock.
*
*/
EMAC_CLK_IN_GPIO = 0,
/**
* @brief Output RMII Clock from internal APLL Clock available at GPIO0
*
* @note GPIO0 can be set to output a pre-divided PLL clock (test only!). Enabling this option will configure GPIO0 to output a 50MHz clock.
* In fact this clock doesnt have directly relationship with EMAC peripheral. Sometimes this clock wont work well with your PHY chip.
* You might need to add some extra devices after GPIO0 (e.g. inverter). Note that outputting RMII clock on GPIO0 is an experimental practice.
* If you want the Ethernet to work with WiFi, dont select GPIO0 output mode for stability.
*
*/
EMAC_APPL_CLK_OUT_GPIO = 0,
/**
* @brief Output RMII Clock from internal APLL Clock available at GPIO16
*
*/
EMAC_CLK_OUT_GPIO = 16,
/**
* @brief Inverted Output RMII Clock from internal APLL Clock available at GPIO17
*
*/
EMAC_CLK_OUT_180_GPIO = 17
} emac_rmii_clock_gpio_t;
#else
/**
* @brief RMII Clock GPIO number
*
*/
typedef int emac_rmii_clock_gpio_t;
#endif // CONFIG_IDF_TARGET_ESP32
/**
* @brief Ethernet MAC Clock Configuration
*
*/
typedef union {
struct {
// MII interface is not fully implemented...
// Reserved for GPIO number, clock source, etc. in MII mode
} mii; /*!< EMAC MII Clock Configuration */
struct {
emac_rmii_clock_mode_t clock_mode; /*!< RMII Clock Mode Configuration */
emac_rmii_clock_gpio_t clock_gpio; /*!< RMII Clock GPIO Configuration */
} rmii; /*!< EMAC RMII Clock Configuration */
} eth_mac_clock_config_t;
/**
* @brief EMAC SMI GPIO configuration
*/
typedef struct {
int mdc_num; /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */
int mdio_num; /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */
} emac_esp_smi_gpio_config_t;
/**
* @brief EMAC MII data interface GPIO configuration
*/
typedef struct {
int tx_clk_num; /*!< TX_CLK GPIO number */
int tx_en_num; /*!< TX_EN GPIO number */
int txd0_num; /*!< TXD0 GPIO number */
int txd1_num; /*!< TXD1 GPIO number */
int txd2_num; /*!< TXD2 GPIO number */
int txd3_num; /*!< TXD3 GPIO number */
int rx_clk_num; /*!< RX_CLK GPIO number */
int rx_dv_num; /*!< RX_DV GPIO number */
int rxd0_num; /*!< RXD0 GPIO number */
int rxd1_num; /*!< RXD1 GPIO number */
int rxd2_num; /*!< RXD2 GPIO number */
int rxd3_num; /*!< RXD3 GPIO number */
int col_in_num; /*!< COL_IN GPIO number */
int crs_in_num; /*!< CRS_IN GPIO number */
int tx_er_num; /*!< TX_ER GPIO number */
int rx_er_num; /*!< RX_ER GPIO number */
} eth_mac_mii_gpio_config_t;
/**
* @brief EMAC RMII data interface GPIO configuration
*/
typedef struct {
int tx_en_num; /*!< TX_EN GPIO number */
int txd0_num; /*!< TXD0 GPIO number */
int txd1_num; /*!< TXD1 GPIO number */
int crs_dv_num; /*!< CRS_DV GPIO number */
int rxd0_num; /*!< RXD0 GPIO number */
int rxd1_num; /*!< RXD1 GPIO number */
} eth_mac_rmii_gpio_config_t;
#if SOC_EMAC_USE_MULTI_IO_MUX || SOC_EMAC_MII_USE_GPIO_MATRIX
/**
* @brief Ethernet MAC MII/RMII data plane GPIO configuration
*
*/
typedef union {
eth_mac_mii_gpio_config_t mii; /*!< EMAC MII Data GPIO Configuration */
eth_mac_rmii_gpio_config_t rmii; /*!< EMAC RMII Data GPIO Configuration */
} eth_mac_dataif_gpio_config_t;
#endif // SOC_EMAC_USE_MULTI_IO_MUX
/**
* @brief EMAC specific configuration
*
*/
typedef struct {
union {
emac_esp_smi_gpio_config_t smi_gpio; /*!< SMI GPIO numbers */
struct {
int smi_mdc_gpio_num __attribute__((deprecated("Please use smi_gpio instead"))); /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */
int smi_mdio_gpio_num __attribute__((deprecated("Please use smi_gpio instead"))); /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */
};
};
eth_data_interface_t interface; /*!< EMAC Data interface to PHY (MII/RMII) */
eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */
eth_mac_dma_burst_len_t dma_burst_len; /*!< EMAC DMA burst length for both Tx and Rx */
int intr_priority; /*!< EMAC interrupt priority, if set to 0 or a negative value, the driver will try to allocate an interrupt with a default priority */
#if SOC_EMAC_USE_MULTI_IO_MUX || SOC_EMAC_MII_USE_GPIO_MATRIX
eth_mac_dataif_gpio_config_t emac_dataif_gpio; /*!< EMAC MII/RMII data plane GPIO configuration */
#endif // SOC_EMAC_USE_MULTI_IO_MUX
#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
} eth_esp32_emac_config_t;
/**
* @brief List of ESP EMAC specific commands for ioctl API
*
*/
typedef enum {
ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS = ETH_CMD_CUSTOM_MAC_CMDS_OFFSET, /*!< Set Transmit Descriptor Word 0 control bit mask (debug option)*/
ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS, /*!< Clear Transmit Descriptor Word 0 control bit mask (debug option)*/
ETH_MAC_ESP_CMD_PTP_ENABLE, /*!< Enable IEEE1588 Time stamping */
} eth_mac_esp_io_cmd_t;
/**
* @brief Default ESP32's EMAC specific configuration
*
*/
#if CONFIG_IDF_TARGET_ESP32
#if CONFIG_ETH_RMII_CLK_INPUT // IDF-9724
#define DEFAULT_RMII_CLK_MODE EMAC_CLK_EXT_IN
#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
#define DEFAULT_RMII_CLK_GPIO CONFIG_ETH_RMII_CLK_IN_GPIO
#else
#error "ESP32 EMAC only support input RMII clock to GPIO0"
#endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0
#elif CONFIG_ETH_RMII_CLK_OUTPUT
#define DEFAULT_RMII_CLK_MODE EMAC_CLK_OUT
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
#define DEFAULT_RMII_CLK_GPIO EMAC_APPL_CLK_OUT_GPIO
#else
#define DEFAULT_RMII_CLK_GPIO CONFIG_ETH_RMII_CLK_OUT_GPIO
#endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
#else
#error "Unsupported RMII clock mode"
#endif // CONFIG_ETH_RMII_CLK_INPUT
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_gpio = \
{ \
.mdc_num = 23, \
.mdio_num = 18 \
}, \
.interface = EMAC_DATA_INTERFACE_RMII, \
.clock_config = \
{ \
.rmii = \
{ \
.clock_mode = DEFAULT_RMII_CLK_MODE, \
.clock_gpio = DEFAULT_RMII_CLK_GPIO \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
.intr_priority = 0, \
}
#elif CONFIG_IDF_TARGET_ESP32P4
#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \
{ \
.smi_gpio = \
{ \
.mdc_num = 31, \
.mdio_num = 27 \
}, \
.interface = EMAC_DATA_INTERFACE_RMII, \
.clock_config = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_EXT_IN, \
.clock_gpio = 50 \
} \
}, \
.clock_config_out_in = \
{ \
.rmii = \
{ \
.clock_mode = EMAC_CLK_EXT_IN, \
.clock_gpio = -1 \
} \
}, \
.dma_burst_len = ETH_DMA_BURST_LEN_32, \
.intr_priority = 0, \
.emac_dataif_gpio = \
{ \
.rmii = \
{ \
.tx_en_num = 49, \
.txd0_num = 34, \
.txd1_num = 35, \
.crs_dv_num = 28, \
.rxd0_num = 29, \
.rxd1_num = 30 \
} \
}, \
}
#endif // CONFIG_IDF_TARGET_ESP32P4
/**
* @brief Create ESP32 Ethernet MAC instance
*
* @param esp32_config: EMAC specific configuration
* @param config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config);
#endif // CONFIG_ETH_USE_ESP32_EMAC
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_eth_com.h"
#include "esp_eth_mac.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ETH_USE_OPENETH
/**
* @brief Create OpenCores Ethernet MAC instance
*
* @param config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config);
#endif // CONFIG_ETH_USE_OPENETH
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,236 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "esp_eth_com.h"
#include "esp_eth_mac.h"
#include "sdkconfig.h"
#include "driver/spi_master.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_ETH_USE_SPI_ETHERNET
/**
* @brief Custom SPI Driver Configuration.
* This structure declares configuration and callback functions to access Ethernet SPI module via
* user's custom SPI driver.
*
*/
typedef struct
{
/**
* @brief Custom driver specific configuration data used by `init()` function.
*
* @note Type and its content is fully under user's control
*
*/
void *config;
/**
* @brief Custom driver SPI Initialization
*
* @param[in] spi_config: Custom driver specific configuration
*
* @return
* - spi_ctx: when initialization is successful, a pointer to context structure holding all variables
* needed for subsequent SPI access operations (e.g. SPI bus identification, mutexes, etc.)
* - NULL: driver initialization failed
*
* @note return type and its content is fully under user's control
*/
void *(*init)(const void *spi_config);
/**
* @brief Custom driver De-initialization
*
* @param[in] spi_ctx: a pointer to driver specific context structure
*
* @return
* - ESP_OK: driver de-initialization was successful
* - ESP_FAIL: driver de-initialization failed
* - any other failure codes are allowed to be used to provide failure isolation
*/
esp_err_t (*deinit)(void *spi_ctx);
/**
* @brief Custom driver SPI read
*
* @note The read function is responsible to construct command, address and data fields
* of the SPI frame in format expected by particular SPI Ethernet module
*
* @param[in] spi_ctx: a pointer to driver specific context structure
* @param[in] cmd: command
* @param[in] addr: register address
* @param[out] data: read data
* @param[in] data_len: read data length in bytes
*
* @return
* - ESP_OK: read was successful
* - ESP_FAIL: read failed
* - any other failure codes are allowed to be used to provide failure isolation
*/
esp_err_t (*read)(void *spi_ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len);
/**
* @brief Custom driver SPI write
*
* @note The write function is responsible to construct command, address and data fields
* of the SPI frame in format expected by particular SPI Ethernet module
*
* @param[in] spi_ctx: a pointer to driver specific context structure
* @param[in] cmd: command
* @param[in] addr: register address
* @param[in] data: data to write
* @param[in] data_len: length of data to write in bytes
*
* @return
* - ESP_OK: write was successful
* - ESP_FAIL: write failed
* - any other failure codes are allowed to be used to provide failure isolation
*/
esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len);
} eth_spi_custom_driver_config_t;
/**
* @brief Default configuration of the custom SPI driver.
* Internal ESP-IDF SPI Master driver is used by default.
*
*/
#define ETH_DEFAULT_SPI \
{ \
.config = NULL, \
.init = NULL, \
.deinit = NULL, \
.read = NULL, \
.write = NULL \
}
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#if CONFIG_ETH_SPI_ETHERNET_DM9051
/**
* @brief DM9051 specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_dm9051_config_t;
/**
* @brief Default DM9051 specific configuration
*
*/
#define ETH_DM9051_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create DM9051 Ethernet MAC instance
*
* @param dm9051_config: DM9051 specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_DM9051
#if CONFIG_ETH_SPI_ETHERNET_W5500
/**
* @brief W5500 specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined)*/
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined)*/
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_w5500_config_t;
/**
* @brief Default W5500 specific configuration
*
*/
#define ETH_W5500_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create W5500 Ethernet MAC instance
*
* @param w5500_config: W5500 specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_W5500
#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
/**
* @brief KSZ8851SNL specific configuration
*
*/
typedef struct {
int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */
uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */
spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */
spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */
eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */
} eth_ksz8851snl_config_t;
/**
* @brief Default KSZ8851SNL specific configuration
*
*/
#define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \
{ \
.int_gpio_num = 4, \
.poll_period_ms = 0, \
.spi_host_id = spi_host, \
.spi_devcfg = spi_devcfg_p, \
.custom_spi_driver = ETH_DEFAULT_SPI, \
}
/**
* @brief Create KSZ8851SNL Ethernet MAC instance
*
* @param ksz8851snl_config: KSZ8851SNL specific configuration
* @param mac_config: Ethernet MAC configuration
*
* @return
* - instance: create MAC instance successfully
* - NULL: create MAC instance failed because some error occurred
*/
esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851snl_config, const eth_mac_config_t *mac_config);
#endif // CONFIG_ETH_SPI_ETHERNET_KSZ8851
#ifdef __cplusplus
}
#endif

View File

@ -16,7 +16,7 @@ extern "C" {
#define ESP_ETH_PHY_ADDR_AUTO (-1)
/**
* @brief Auto-negotiation controll commands
* @brief Auto-negotiation control commands
*
*/
typedef enum {
@ -253,7 +253,7 @@ struct esp_eth_phy_s {
* - ESP_FAIL: process io command failed because some other error occurred
* - ESP_ERR_NOT_SUPPORTED: requested feature is not supported
*/
esp_err_t (*custom_ioctl)(esp_eth_phy_t *phy, uint32_t cmd, void *data);
esp_err_t (*custom_ioctl)(esp_eth_phy_t *phy, int cmd, void *data);
/**
* @brief Free memory of Ethernet PHY instance

View File

@ -6,7 +6,7 @@
#pragma once
#include <stdbool.h>
#include "esp_eth.h"
#include "esp_eth_phy.h"
#include "sdkconfig.h"
#include "eth_phy_802_3_regs.h"
@ -45,7 +45,7 @@ typedef enum {
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param eth Ethernet mediator pointer
* @return
* - ESP_OK: Ethermet mediator set successfuly
* - ESP_OK: Ethermet mediator set successfully
* - ESP_ERR_INVALID_ARG: if @c eth is @c NULL
*/
esp_err_t esp_eth_phy_802_3_set_mediator(phy_802_3_t *phy_802_3, esp_eth_mediator_t *eth);
@ -55,8 +55,8 @@ esp_err_t esp_eth_phy_802_3_set_mediator(phy_802_3_t *phy_802_3, esp_eth_mediato
*
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @return
* - ESP_OK: Ethernet PHY reset successfuly
* - ESP_FAIL: reset Ethernet PHY failed because some error occured
* - ESP_OK: Ethernet PHY reset successfully
* - ESP_FAIL: reset Ethernet PHY failed because some error occurred
*/
esp_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3);
@ -67,8 +67,8 @@ esp_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3);
* @param cmd autonegotiation command enumeration
* @param[out] autonego_en_stat autonegotiation enabled flag
* @return
* - ESP_OK: Ethernet PHY autonegotiation configured successfuly
* - ESP_FAIL: Ethernet PHY autonegotiation configuration fail because some error occured
* - ESP_OK: Ethernet PHY autonegotiation configured successfully
* - ESP_FAIL: Ethernet PHY autonegotiation configuration fail because some error occurred
* - ESP_ERR_INVALID_ARG: invalid value of @c cmd
*/
esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat);
@ -79,8 +79,8 @@ esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autone
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param enable set true to power ON Ethernet PHY; set false to power OFF Ethernet PHY
* @return
* - ESP_OK: Ethernet PHY power down mode set successfuly
* - ESP_FAIL: Ethernet PHY power up or power down failed because some error occured
* - ESP_OK: Ethernet PHY power down mode set successfully
* - ESP_FAIL: Ethernet PHY power up or power down failed because some error occurred
*/
esp_err_t esp_eth_phy_802_3_pwrctl(phy_802_3_t *phy_802_3, bool enable);
@ -100,7 +100,7 @@ esp_err_t esp_eth_phy_802_3_set_addr(phy_802_3_t *phy_802_3, uint32_t addr);
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param[out] addr Ethernet PHY address
* @return
* - ESP_OK: Ethernet PHY address read successfuly
* - ESP_OK: Ethernet PHY address read successfully
* - ESP_ERR_INVALID_ARG: @c addr pointer is @c NULL
*/
esp_err_t esp_eth_phy_802_3_get_addr(phy_802_3_t *phy_802_3, uint32_t *addr);
@ -111,8 +111,8 @@ esp_err_t esp_eth_phy_802_3_get_addr(phy_802_3_t *phy_802_3, uint32_t *addr);
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param ability enable or disable pause ability
* @return
* - ESP_OK: pause ability set successfuly
* - ESP_FAIL: Advertise pause function ability failed because some error occured
* - ESP_OK: pause ability set successfully
* - ESP_FAIL: Advertise pause function ability failed because some error occurred
*/
esp_err_t esp_eth_phy_802_3_advertise_pause_ability(phy_802_3_t *phy_802_3, uint32_t ability);
@ -122,8 +122,8 @@ esp_err_t esp_eth_phy_802_3_advertise_pause_ability(phy_802_3_t *phy_802_3, uint
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param enable set true to enable loopback; set false to disable loopback
* @return
* - ESP_OK: Ethernet PHY loopback mode set successfuly
* - ESP_FAIL: Ethernet PHY loopback configuration failed because some error occured
* - ESP_OK: Ethernet PHY loopback mode set successfully
* - ESP_FAIL: Ethernet PHY loopback configuration failed because some error occurred
*/
esp_err_t esp_eth_phy_802_3_loopback(phy_802_3_t *phy_802_3, bool enable);
@ -133,8 +133,8 @@ esp_err_t esp_eth_phy_802_3_loopback(phy_802_3_t *phy_802_3, bool enable);
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param speed new speed of Ethernet PHY link
* @return
* - ESP_OK: Ethernet PHY speed set successfuly
* - ESP_FAIL: Set Ethernet PHY speed failed because some error occured
* - ESP_OK: Ethernet PHY speed set successfully
* - ESP_FAIL: Set Ethernet PHY speed failed because some error occurred
*/
esp_err_t esp_eth_phy_802_3_set_speed(phy_802_3_t *phy_802_3, eth_speed_t speed);
@ -144,9 +144,9 @@ esp_err_t esp_eth_phy_802_3_set_speed(phy_802_3_t *phy_802_3, eth_speed_t speed)
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param duplex new duplex mode for Ethernet PHY link
* @return
* - ESP_OK: Ethernet PHY duplex mode set successfuly
* - ESP_OK: Ethernet PHY duplex mode set successfully
* - ESP_ERR_INVALID_STATE: unable to set duplex mode to Half if loopback is enabled
* - ESP_FAIL: Set Ethernet PHY duplex mode failed because some error occured
* - ESP_FAIL: Set Ethernet PHY duplex mode failed because some error occurred
*/
esp_err_t esp_eth_phy_802_3_set_duplex(phy_802_3_t *phy_802_3, eth_duplex_t duplex);
@ -156,7 +156,7 @@ esp_err_t esp_eth_phy_802_3_set_duplex(phy_802_3_t *phy_802_3, eth_duplex_t dupl
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @param link new link status
* @return
* - ESP_OK: Ethernet PHY link set successfuly
* - ESP_OK: Ethernet PHY link set successfully
*/
esp_err_t esp_eth_phy_802_3_set_link(phy_802_3_t *phy_802_3, eth_link_t link);
@ -165,7 +165,7 @@ esp_err_t esp_eth_phy_802_3_set_link(phy_802_3_t *phy_802_3, eth_link_t link);
*
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @return
* - ESP_OK: Ethernet PHY initialized successfuly
* - ESP_OK: Ethernet PHY initialized successfully
*/
esp_err_t esp_eth_phy_802_3_init(phy_802_3_t *phy_802_3);
@ -174,7 +174,7 @@ esp_err_t esp_eth_phy_802_3_init(phy_802_3_t *phy_802_3);
*
* @param phy_802_3 IEEE 802.3 PHY object infostructure
* @return
* - ESP_OK: Ethernet PHY powered off successfuly
* - ESP_OK: Ethernet PHY powered off successfully
*/
esp_err_t esp_eth_phy_802_3_deinit(phy_802_3_t *phy_802_3);
@ -275,8 +275,8 @@ esp_err_t esp_eth_phy_802_3_read_manufac_info(phy_802_3_t *phy_802_3, uint8_t *m
* @param devaddr Address of MDIO device
* @param[out] mmd_addr Current address stored in device's register
* @return
* - ESP_OK: Address register read successfuly
* - ESP_FAIL: Address register read failed because of some error occured
* - ESP_OK: Address register read successfully
* - ESP_FAIL: Address register read failed because of some error occurred
* - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits)
*/
esp_err_t esp_eth_phy_802_3_get_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t *mmd_addr);
@ -288,8 +288,8 @@ esp_err_t esp_eth_phy_802_3_get_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr
* @param devaddr Address of MDIO device
* @param[out] mmd_addr New value of MDIO device's address register value
* @return
* - ESP_OK: Address register written to successfuly
* - ESP_FAIL: Address register write failed because of some error occured
* - ESP_OK: Address register written to successfully
* - ESP_FAIL: Address register write failed because of some error occurred
* - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits)
*/
esp_err_t esp_eth_phy_802_3_set_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr);
@ -302,8 +302,8 @@ esp_err_t esp_eth_phy_802_3_set_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr
* @param function MMD function
* @param[out] data Data read from the device's memory
* @return
* - ESP_OK: Memory read successfuly
* - ESP_FAIL: Memory read failed because of some error occured
* - ESP_OK: Memory read successfully
* - ESP_FAIL: Memory read failed because of some error occurred
* - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) or MMD access function is invalid
*/
esp_err_t esp_eth_phy_802_3_read_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t *data);
@ -316,8 +316,8 @@ esp_err_t esp_eth_phy_802_3_read_mmd_data(phy_802_3_t *phy_802_3, uint8_t devadd
* @param function MMD function
* @param[out] data Data to write to the device's memory
* @return
* - ESP_OK: Memory written successfuly
* - ESP_FAIL: Memory write failed because of some error occured
* - ESP_OK: Memory written successfully
* - ESP_FAIL: Memory write failed because of some error occurred
* - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) or MMD access function is invalid
*/
esp_err_t esp_eth_phy_802_3_write_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t data);
@ -330,8 +330,8 @@ esp_err_t esp_eth_phy_802_3_write_mmd_data(phy_802_3_t *phy_802_3, uint8_t devad
* @param mmd_addr Address of MDIO device register
* @param[out] data Data read from the device's memory
* @return
* - ESP_OK: Memory read successfuly
* - ESP_FAIL: Memory read failed because of some error occured
* - ESP_OK: Memory read successfully
* - ESP_FAIL: Memory read failed because of some error occurred
* - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits)
*/
esp_err_t esp_eth_phy_802_3_read_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t *data);
@ -344,8 +344,8 @@ esp_err_t esp_eth_phy_802_3_read_mmd_register(phy_802_3_t *phy_802_3, uint8_t de
* @param mmd_addr Address of MDIO device register
* @param[out] data Data to write to the device's memory
* @return
* - ESP_OK: Memory written to successfuly
* - ESP_FAIL: Memory write failed because of some error occured
* - ESP_OK: Memory written to successfully
* - ESP_FAIL: Memory write failed because of some error occurred
* - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits)
*/
esp_err_t esp_eth_phy_802_3_write_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t data);

View File

@ -15,20 +15,144 @@ extern "C" {
* @brief Indicate to ::emac_esp_dma_receive_frame that receive frame buffer was allocated by ::emac_esp_dma_alloc_recv_buf
*
*/
#define EMAC_HAL_BUF_SIZE_AUTO 0
#define EMAC_DMA_BUF_SIZE_AUTO 0
/**
* @brief EMAC DMA handle
*
*/
typedef struct emac_esp_dma_t *emac_esp_dma_handle_t;
typedef void *emac_esp_dma_config_t;
void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma);
/**
* @brief EMAC DMA configuration
* @note Currently just a placeholder
*
*/
typedef struct emac_esp_dma_config_t emac_esp_dma_config_t;
/**
* @brief Reset DMA
* @note This function should be called prior each EMAC start
*
* @param[in] emac_esp_dma EMAC DMA handle
*/
void emac_esp_dma_reset(emac_esp_dma_handle_t emac_esp_dma);
/**
* @brief Transmit data from buffer over EMAC
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[in] buf buffer to be transmitted
* @param[in] length length of the buffer
* @return number of transmitted bytes on success
* zero on fail
*/
uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t length);
uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t **buffs, uint32_t *lengths, uint32_t buffs_cnt);
uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_t *size);
uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc);
void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma, uint32_t *frames_remain, uint32_t *free_desc);
/**
* @brief Transmit data from multiple buffers over EMAC in single Ethernet frame. Data will be joint into
* single frame in order in which the buffers are stored in input array.
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[in] buffs array of pointers to buffers to be transmitted
* @param[in] lengths array of lengths of the buffers
* @param[in] inbuffs_cnt number of buffers (i.e. input arrays size)
* @return number of transmitted bytes on success
* zero on fail
*
* @pre @p lengths array must have the same size as @p buffs array and their elements need to be stored in the same
* order, i.e. lengths[1] is a length associated with data buffer referenced at buffs[1] position.
*/
uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t **buffs, uint32_t *lengths, uint32_t buffs_cnt);
/**
* @brief Allocate buffer with size equal to actually received Ethernet frame size.
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[in, out] size as an input defines maximum size of buffer to be allocated. As an output, indicates actual size of received
* Ethernet frame which is waiting to be processed. Returned size may be 0 when there is no waiting valid frame.
*
* @note If maximum allowed size of buffer to be allocated is less than actual size of received Ethernet frame, the buffer
* is allocated with that limit and the frame will be truncated by emac_hal_receive_frame.
*
* @return Pointer to allocated buffer
* NULL when allocation fails (returned @p size is non-zero)
* NULL when there is no waiting Ethernet frame (returned @p size is zero)
*/
uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_t *size);
/**
* @brief Copy received Ethernet frame from EMAC DMA memory space to application.
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[in] buf buffer into which the Ethernet frame is to be copied
* @param[in] size buffer size. When buffer was allocated by ::emac_esp_dma_alloc_recv_buf, this parameter needs to be set
* to @c EMAC_DMA_BUF_SIZE_AUTO
*
* @return - number of copied bytes when success
* - number of bytes of received Ethernet frame when maximum allowed buffer @p size is less than actual size of
* received Ethernet frame and @p size is NOT set to @c EMAC_DMA_BUF_SIZE_AUTO
* - 0 when there is no waiting Ethernet frame or on frame error when @p size is NOT set to @c EMAC_DMA_BUF_SIZE_AUTO
*
* @note When this function is called with @c EMAC_DMA_BUF_SIZE_AUTO size option (preferred), buffer needs to be
* successfully allocated by ::emac_esp_dma_alloc_recv_buf function at first.
* @note When this function is NOT called with @c EMAC_DMA_BUF_SIZE_AUTO size option and maximum allowed buffer @p size
* is less than actual size of received Ethernet frame, the frame will be truncated.
* @note FCS field is never copied
*/
uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size);
/**
* @brief Flush frame stored in Rx DMA
*
* @param[in] emac_esp_dma EMAC DMA handle
*/
void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma);
/**
* @brief Get number of frames remaining in Rx DMA
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[out] frames_remain number of frames remaining to be processed
* @param[out] free_desc number of free DMA Rx descriptors
*/
void emac_esp_dma_get_remain_frames(emac_esp_dma_handle_t emac_esp_dma, uint32_t *remain_frames, uint32_t *used_descs);
/**
* @brief Set the Transmit Descriptor Word 0 (TDES0) control bits
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[in] bit_mask mask of control bits to be set
*/
void emac_esp_dma_set_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t bit_mask);
/**
* @brief Clear the Transmit Descriptor Word 0 (TDES0) control bits
*
* @param[in] emac_esp_dma EMAC DMA handle
* @param[in] bit_mask mask of control bits to be cleared
*/
void emac_esp_dma_clear_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t bit_mask);
/**
* @brief Creates a new instance of the ESP EMAC DMA
*
* @param config ESP EMAC DMA configuration
* @param[out] ret_handle EMAC DMA handle
* @return esp_err_t
* ESP_OK on success
* ESP_ERR_NO_MEM when there is not enough memory to allocate instance
*/
esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_handle_t *ret_handle);
/**
* @brief Deletes the ESP EMAC DMA instance
*
* @param[in] emac_esp_dma EMAC DMA handle
* @return esp_err_t
* ESP_OK on success
*/
esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma);
#ifdef __cplusplus

View File

@ -10,53 +10,23 @@ extern "C" {
#endif
#include "esp_err.h"
#include "esp_eth_mac.h"
#include "esp_eth_mac_esp.h"
/**
* @brief EMAC SMI GPIO configuration
*/
typedef struct {
int mdc_num;
int mdio_num;
} emac_esp_smi_gpio_config_t;
#if CONFIG_ETH_USE_ESP32_EMAC
/**
* @brief EMAC MII data interface GPIO configuration
*/
typedef struct {
uint8_t tx_clk_num;
uint8_t tx_en_num;
uint8_t txd0_num;
uint8_t txd1_num;
uint8_t txd2_num;
uint8_t txd3_num;
uint8_t rx_clk_num;
uint8_t rx_dv_num;
uint8_t rxd0_num;
uint8_t rxd1_num;
uint8_t rxd2_num;
uint8_t rxd3_num;
} emac_esp_mii_gpio_config_t;
/**
* @brief EMAC RMII data interface GPIO configuration
*/
typedef struct {
uint8_t tx_en_num;
uint8_t txd0_num;
uint8_t txd1_num;
uint8_t crs_dv_num;
uint8_t rxd0_num;
uint8_t rxd1_num;
} emac_esp_rmii_gpio_config_t;
esp_err_t emac_esp_iomux_init_mii(emac_esp_mii_gpio_config_t *mii_gpio);
esp_err_t emac_esp_iomux_init_rmii(emac_esp_rmii_gpio_config_t *rmii_gpio);
esp_err_t emac_esp_gpio_matrix_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio);
esp_err_t emac_esp_iomux_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio);
esp_err_t emac_esp_iomux_init_rmii(const eth_mac_rmii_gpio_config_t *rmii_gpio);
esp_err_t emac_esp_iomux_rmii_clk_input(int num);
esp_err_t emac_esp_iomux_rmii_clk_ouput(int num);
esp_err_t emac_esp_iomux_init_tx_er(int num);
esp_err_t emac_esp_iomux_init_rx_er(int num);
void emac_esp32_gpio_init_smi(emac_esp_smi_gpio_config_t *smi_gpio);
esp_err_t emac_esp_iomux_rmii_init_tx_er(int num);
esp_err_t emac_esp_iomux_rmii_init_rx_er(int num);
esp_err_t emac_esp_iomux_mii_init_tx_er(int num);
esp_err_t emac_esp_iomux_mii_init_rx_er(int num);
esp_err_t emac_esp_gpio_init_smi(const emac_esp_smi_gpio_config_t *smi_gpio);
esp_err_t emac_esp_gpio_deinit_all(void);
#endif // CONFIG_ETH_USE_ESP32_EMAC
#ifdef __cplusplus
}

View File

@ -499,6 +499,24 @@ err:
return ret;
}
esp_err_t esp_eth_get_phy_instance(esp_eth_handle_t hdl, esp_eth_phy_t **phy)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_RETURN_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, TAG, "ethernet driver handle can't be null");
ESP_RETURN_ON_FALSE(phy != NULL, ESP_ERR_INVALID_ARG, TAG, "can't store PHY instance to null");
*phy = eth_driver->phy;
return ESP_OK;
}
esp_err_t esp_eth_get_mac_instance(esp_eth_handle_t hdl, esp_eth_mac_t **mac)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_RETURN_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, TAG, "ethernet driver handle can't be null");
ESP_RETURN_ON_FALSE(mac != NULL, ESP_ERR_INVALID_ARG, TAG, "can't store MAC instance to null");
*mac = eth_driver->mac;
return ESP_OK;
}
esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;

View File

@ -1,358 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "sdkconfig.h"
#include "esp_rom_gpio.h"
#include "driver/gpio.h"
#include "soc/soc_caps.h"
#include "soc/gpio_sig_map.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_periph.h"
#include "esp_private/gpio.h"
#include "esp_private/eth_mac_esp_gpio.h"
#include "esp_log.h"
static const char *TAG = "esp.emac.gpio";
void emac_esp32_gpio_init_smi(emac_esp_smi_gpio_config_t *smi_gpio)
{
if (smi_gpio->mdc_num >= 0) {
/* Setup SMI MDC GPIO */
gpio_set_direction(smi_gpio->mdc_num, GPIO_MODE_OUTPUT);
#if CONFIG_IDF_TARGET_ESP32
esp_rom_gpio_connect_out_signal(smi_gpio->mdc_num, EMAC_MDC_O_IDX, false, false);
#elif CONFIG_IDF_TARGET_ESP32P4
esp_rom_gpio_connect_out_signal(smi_gpio->mdc_num, GMII_MDC_PAD_OUT_IDX, false, false);
#endif
gpio_func_sel(smi_gpio->mdc_num, PIN_FUNC_GPIO);
}
if (smi_gpio->mdio_num >= 0) {
/* Setup SMI MDIO GPIO */
gpio_set_direction(smi_gpio->mdio_num, GPIO_MODE_INPUT_OUTPUT);
#if CONFIG_IDF_TARGET_ESP32
esp_rom_gpio_connect_out_signal(smi_gpio->mdio_num, EMAC_MDO_O_IDX, false, false);
esp_rom_gpio_connect_in_signal(smi_gpio->mdio_num, EMAC_MDI_I_IDX, false);
#elif CONFIG_IDF_TARGET_ESP32P4
esp_rom_gpio_connect_out_signal(smi_gpio->mdio_num, GMII_MDO_PAD_OUT_IDX, false, false);
esp_rom_gpio_connect_in_signal(smi_gpio->mdio_num, GMII_MDI_PAD_IN_IDX, false);
#endif
gpio_func_sel(smi_gpio->mdio_num, PIN_FUNC_GPIO);
}
}
esp_err_t emac_esp_iomux_init_mii(emac_esp_mii_gpio_config_t *mii_gpio)
{
(void)mii_gpio;
#if CONFIG_IDF_TARGET_ESP32
/* TX_CLK to GPIO0 */
gpio_func_sel(0, FUNC_GPIO0_EMAC_TX_CLK);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
/* TX_EN to GPIO21 */
gpio_func_sel(21, FUNC_GPIO21_EMAC_TX_EN);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
/* TXD0 to GPIO19 */
gpio_func_sel(19, FUNC_GPIO19_EMAC_TXD0);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
/* TXD1 to GPIO22 */
gpio_func_sel(22, FUNC_GPIO22_EMAC_TXD1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
/* TXD2 to MTMS */
gpio_func_sel(14, FUNC_MTMS_EMAC_TXD2);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[14]);
/* TXD3 to MTDI */
gpio_func_sel(12, FUNC_MTDI_EMAC_TXD3);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[12]);
/* RX_CLK to GPIO5 */
gpio_func_sel(5, FUNC_GPIO5_EMAC_RX_CLK);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[5]);
/* RX_DV to GPIO27 */
gpio_func_sel(27, FUNC_GPIO27_EMAC_RX_DV);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
/* RXD0 to GPIO25 */
gpio_func_sel(25, FUNC_GPIO25_EMAC_RXD0);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
/* RXD1 to GPIO26 */
gpio_func_sel(26, FUNC_GPIO26_EMAC_RXD1);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
/* RXD2 to U0TXD */
gpio_func_sel(1, FUNC_U0TXD_EMAC_RXD2);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[1]);
/* RXD3 to MTDO */
gpio_func_sel(15, FUNC_MTDO_EMAC_RXD3);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[15]);
return ESP_OK;
#elif CONFIG_IDF_TARGET_ESP32P4
ESP_LOGW(TAG, "MII is currently not supported");
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t emac_esp_iomux_rmii_clk_input(int num)
{
#if CONFIG_IDF_TARGET_ESP32
if (num != 0) {
return ESP_ERR_INVALID_ARG;
}
/* REF_CLK(RMII mode) to GPIO0 */
gpio_func_sel(0, FUNC_GPIO0_EMAC_TX_CLK);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
#elif CONFIG_IDF_TARGET_ESP32P4
/* REF_CLK(RMII mode) to `num` */
switch(num) {
case 32:
gpio_func_sel(num, FUNC_GPIO32_GMAC_RMII_CLK_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[32]);
break;
case 44:
gpio_func_sel(num, FUNC_GPIO44_GMAC_RMII_CLK_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[44]);
break;
case 50:
gpio_func_sel(num, FUNC_GPIO50_GMAC_RMII_CLK_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[50]);
break;
default:
ESP_LOGE(TAG, "invalid RMII CLK input GPIO number. Expected [32, 44, 50], actual %i", num);
return ESP_ERR_INVALID_ARG;
}
#endif
return ESP_OK;
}
esp_err_t emac_esp_iomux_rmii_clk_ouput(int num)
{
#if CONFIG_IDF_TARGET_ESP32
switch (num) {
case 0:
/* APLL clock output to GPIO0 (must be configured to 50MHz!) */
gpio_func_sel(num, FUNC_GPIO0_CLK_OUT1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
break;
case 16:
/* RMII CLK (50MHz) output to GPIO16 */
gpio_func_sel(num, FUNC_GPIO16_EMAC_CLK_OUT);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
break;
case 17:
/* RMII CLK (50MHz) output to GPIO17 */
gpio_func_sel(num, FUNC_GPIO17_EMAC_CLK_OUT_180);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
break;
default:
ESP_LOGE(TAG, "invalid RMII CLK output GPIO number. Expected [0, 16, 17], actual %i", num);
return ESP_ERR_INVALID_ARG;
}
#elif CONFIG_IDF_TARGET_ESP32P4
/*RMII CLK output to num */
switch (num) {
case 23:
gpio_func_sel(num, FUNC_GPIO23_REF_50M_CLK_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[23]);
break;
case 39:
gpio_func_sel(num, FUNC_GPIO39_REF_50M_CLK_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[39]);
break;
default:
ESP_LOGE(TAG, "invalid RMII CLK input GPIO number. Expected [23, 39], actual %i", num);
return ESP_ERR_INVALID_ARG;
}
#endif
return ESP_OK;
}
esp_err_t emac_esp_iomux_init_rmii(emac_esp_rmii_gpio_config_t *rmii_gpio)
{
#if CONFIG_IDF_TARGET_ESP32
(void)rmii_gpio;
/* TX_EN to GPIO21 */
gpio_func_sel(21, FUNC_GPIO21_EMAC_TX_EN);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
/* TXD0 to GPIO19 */
gpio_func_sel(19, FUNC_GPIO19_EMAC_TXD0);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
/* TXD1 to GPIO22 */
gpio_func_sel(22, FUNC_GPIO22_EMAC_TXD1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
/* CRS_DV to GPIO27 */
gpio_func_sel(27, FUNC_GPIO27_EMAC_RX_DV);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
/* RXD0 to GPIO25 */
gpio_func_sel(25, FUNC_GPIO25_EMAC_RXD0);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
/* RXD1 to GPIO26 */
gpio_func_sel(26, FUNC_GPIO26_EMAC_RXD1);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
return ESP_OK;
#elif CONFIG_IDF_TARGET_ESP32P4
if (rmii_gpio == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* TX_EN */
switch(rmii_gpio->tx_en_num) {
case 33:
gpio_func_sel(rmii_gpio->tx_en_num, FUNC_GPIO33_GMAC_PHY_TXEN_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[33]);
break;
case 40:
gpio_func_sel(rmii_gpio->tx_en_num, FUNC_GPIO40_GMAC_PHY_TXEN_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[40]);
break;
case 49:
gpio_func_sel(rmii_gpio->tx_en_num, FUNC_GPIO49_GMAC_PHY_TXEN_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[49]);
break;
default:
ESP_LOGE(TAG, "invalid TX_EN GPIO number. Expected [33, 40, 49], actual %" PRIu8, rmii_gpio->tx_en_num);
return ESP_ERR_INVALID_ARG;
}
/* TXD0 */
switch(rmii_gpio->txd0_num) {
case 34:
gpio_func_sel(rmii_gpio->txd0_num, FUNC_GPIO34_GMAC_PHY_TXD0_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[34]);
break;
case 41:
gpio_func_sel(rmii_gpio->txd0_num, FUNC_GPIO41_GMAC_PHY_TXD0_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[41]);
break;
default:
ESP_LOGE(TAG, "invalid TXD0 GPIO number. Expected [34, 41], actual %" PRIu8, rmii_gpio->txd0_num);
return ESP_ERR_INVALID_ARG;
}
/* TXD1 */
switch(rmii_gpio->txd1_num) {
case 35:
gpio_func_sel(rmii_gpio->txd1_num, FUNC_GPIO35_GMAC_PHY_TXD1_PAD );
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[35]);
break;
case 42:
gpio_func_sel(rmii_gpio->txd1_num, FUNC_GPIO42_GMAC_PHY_TXD1_PAD );
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[42]);
break;
default:
ESP_LOGE(TAG, "invalid TXD1 GPIO number. Expected [35, 42], actual %" PRIu8, rmii_gpio->txd1_num);
return ESP_ERR_INVALID_ARG;
}
/* CRS_DV */
switch(rmii_gpio->crs_dv_num) {
case 28:
gpio_func_sel(rmii_gpio->crs_dv_num, FUNC_GPIO28_GMAC_PHY_RXDV_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[28]);
break;
case 45:
gpio_func_sel(rmii_gpio->crs_dv_num, FUNC_GPIO45_GMAC_PHY_RXDV_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[45]);
break;
case 51:
gpio_func_sel(rmii_gpio->crs_dv_num, FUNC_GPIO51_GMAC_PHY_RXDV_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[51]);
break;
default:
ESP_LOGE(TAG, "invalid CRS_DV GPIO number. Expected [28, 45, 51], actual %" PRIu8, rmii_gpio->crs_dv_num);
return ESP_ERR_INVALID_ARG;
}
/* RXD0 */
switch(rmii_gpio->rxd0_num) {
case 29:
gpio_func_sel(rmii_gpio->rxd0_num, FUNC_GPIO29_GMAC_PHY_RXD0_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[29]);
break;
case 46:
gpio_func_sel(rmii_gpio->rxd0_num, FUNC_GPIO46_GMAC_PHY_RXD0_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[46]);
break;
case 52:
gpio_func_sel(rmii_gpio->rxd0_num, FUNC_GPIO52_GMAC_PHY_RXD0_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[52]);
break;
default:
ESP_LOGE(TAG, "invalid RXD0 GPIO number. Expected [29, 46, 52], actual %" PRIu8, rmii_gpio->rxd0_num);
return ESP_ERR_INVALID_ARG;
}
/* RXD1 */
switch(rmii_gpio->rxd1_num) {
case 30:
gpio_func_sel(rmii_gpio->rxd1_num, FUNC_GPIO30_GMAC_PHY_RXD1_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[30]);
break;
case 47:
gpio_func_sel(rmii_gpio->rxd1_num, FUNC_GPIO47_GMAC_PHY_RXD1_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[47]);
break;
case 53:
gpio_func_sel(rmii_gpio->rxd1_num, FUNC_GPIO53_GMAC_PHY_RXD1_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[53]);
break;
default:
ESP_LOGE(TAG, "invalid RXD1 GPIO number. Expected [30, 47, 53], actual %" PRIu8, rmii_gpio->rxd1_num);
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
#endif
}
esp_err_t emac_esp_iomux_init_tx_er(int num)
{
#if CONFIG_IDF_TARGET_ESP32
(void)num;
/* TX_ER to GPIO4 */
gpio_func_sel(4, FUNC_GPIO4_EMAC_TX_ER);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[4]);
#elif CONFIG_IDF_TARGET_ESP32P4
/* TX_ER */
switch (num)
{
case 36:
gpio_func_sel(num, FUNC_GPIO36_GMAC_PHY_TXER_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[36]);
break;
case 43:
gpio_func_sel(num, FUNC_GPIO43_GMAC_PHY_TXER_PAD);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[43]);
break;
default:
ESP_LOGE(TAG, "invalid TX_ER GPIO number. Expected [36, 43], actual %i", num);
return ESP_ERR_INVALID_ARG;
}
#endif
return ESP_OK;
}
esp_err_t emac_esp_iomux_init_rx_er(int num)
{
#if CONFIG_IDF_TARGET_ESP32
(void)num;
/* RX_ER to MTCK */
gpio_func_sel(13, FUNC_MTCK_EMAC_RX_ER);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[13]);
#elif CONFIG_IDF_TARGET_ESP32P4
/* RX_ER */
switch (num)
{
case 31:
gpio_func_sel(num, FUNC_GPIO31_GMAC_PHY_RXER_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[31]);
break;
case 48:
gpio_func_sel(num, FUNC_GPIO48_GMAC_PHY_RXER_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[48]);
break;
case 54:
gpio_func_sel(num, FUNC_GPIO54_GMAC_PHY_RXER_PAD);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[54]);
break;
default:
ESP_LOGE(TAG, "invalid RX_ER GPIO number. Expected [31, 48, 54], actual %i", num);
return ESP_ERR_INVALID_ARG;
}
#endif
return ESP_OK;
}

View File

@ -6,7 +6,6 @@
#include <stdlib.h>
#include <inttypes.h>
#include "esp_netif.h"
#include "esp_eth_driver.h"
#include "esp_eth_netif_glue.h"
#include "esp_netif_net_stack.h"
#include "esp_event.h"

View File

@ -12,7 +12,6 @@
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_driver.h"
#include "esp_pm.h"
#include "esp_mac.h"
#include "esp_cpu.h"
@ -66,8 +65,6 @@ typedef struct {
uint32_t free_rx_descriptor;
uint32_t flow_control_high_water_mark;
uint32_t flow_control_low_water_mark;
emac_esp_smi_gpio_config_t smi_gpio;
eth_mac_clock_config_t clock_config;
uint8_t addr[ETH_ADDR_LEN];
bool isr_need_yield;
bool flow_ctrl_enabled; // indicates whether the user want to do flow control
@ -82,19 +79,10 @@ typedef struct {
#ifdef CONFIG_IDF_TARGET_ESP32
esp_clock_output_mapping_handle_t rmii_clk_hdl; // we use the esp_clock_output driver to output a pre-configured APLL clock as the RMII reference clock
#endif
#ifdef CONFIG_IDF_TARGET_ESP32P4
eth_mac_clock_config_t clock_config_out_in;
union
{
emac_esp_mii_gpio_config_t mii_gpio;
emac_esp_rmii_gpio_config_t rmii_gpio;
};
#endif // CONFIG_IDF_TARGET_ESP32P4
} emac_esp32_t;
static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl);
static void esp_emac_free_driver_obj(emac_esp32_t *emac);
static esp_err_t emac_esp_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl);
static void emac_esp_free_driver_obj(emac_esp32_t *emac);
static esp_err_t emac_esp32_start(esp_eth_mac_t *mac);
static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac);
@ -209,11 +197,11 @@ static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
// Set RMII clk_rx/clk_tx divider to get 25MHz for 100mbps mode or 2.5MHz for 10mbps mode
if (emac_hal_get_phy_intf(&emac->hal) == EMAC_DATA_INTERFACE_RMII) {
if (speed == ETH_SPEED_10M) {
EMAC_IF_RCC_ATOMIC () {
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_rmii_rx_tx_div(&emac->hal, RMII_10M_SPEED_RX_TX_CLK_DIV);
}
} else {
EMAC_IF_RCC_ATOMIC () {
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_rmii_rx_tx_div(&emac->hal, RMII_100M_SPEED_RX_TX_CLK_DIV);
}
}
@ -268,6 +256,28 @@ static esp_err_t emac_esp32_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t
return ESP_OK;
}
esp_err_t emac_esp_custom_ioctl(esp_eth_mac_t *mac, int cmd, void *data)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
switch (cmd)
{
case ETH_MAC_ESP_CMD_PTP_ENABLE:
return ESP_ERR_NOT_SUPPORTED;
case ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS:
ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "cannot set DMA tx desc flag to null");
emac_esp_dma_set_tdes0_ctrl_bits(emac->emac_dma_hndl, *(uint32_t *)data);
break;
case ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS:
ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "cannot clear DMA tx desc flag with null");
emac_esp_dma_clear_tdes0_ctrl_bits(emac->emac_dma_hndl, *(uint32_t *)data);
break;
default:
ESP_RETURN_ON_ERROR(ESP_ERR_INVALID_ARG, TAG, "unknown io command: %i", cmd);
}
return ESP_OK;
}
static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
{
esp_err_t ret = ESP_OK;
@ -304,7 +314,8 @@ static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *
uint32_t expected_len = *length;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
ESP_GOTO_ON_FALSE(buf && length, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf and length to null");
uint32_t receive_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buf, expected_len, &emac->frames_remain, &emac->free_rx_descriptor);
uint32_t receive_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buf, expected_len);
emac_esp_dma_get_remain_frames(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor);
/* we need to check the return value in case the buffer size is not enough */
ESP_GOTO_ON_FALSE(expected_len >= receive_len, ESP_ERR_INVALID_SIZE, err, TAG, "received buffer longer than expected");
*length = receive_len;
@ -327,12 +338,12 @@ static void emac_esp32_rx_task(void *arg)
buffer = emac_esp_dma_alloc_recv_buf(emac->emac_dma_hndl, &frame_len);
/* we have memory to receive the frame of maximal size previously defined */
if (buffer != NULL) {
uint32_t recv_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buffer, EMAC_HAL_BUF_SIZE_AUTO, &emac->frames_remain, &emac->free_rx_descriptor);
uint32_t recv_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buffer, EMAC_DMA_BUF_SIZE_AUTO);
if (recv_len == 0) {
ESP_LOGE(TAG, "frame copy error");
free(buffer);
/* ensure that interface to EMAC does not get stuck with unprocessed frames */
emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor);
emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl);
} else if (frame_len > recv_len) {
ESP_LOGE(TAG, "received frame was truncated");
free(buffer);
@ -344,8 +355,9 @@ static void emac_esp32_rx_task(void *arg)
} else if (frame_len) {
ESP_LOGE(TAG, "no mem for receive buffer");
/* ensure that interface to EMAC does not get stuck with unprocessed frames */
emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor);
emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl);
}
emac_esp_dma_get_remain_frames(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor);
#if CONFIG_ETH_SOFT_FLOW_CONTROL
// we need to do extra checking of remained frames in case there are no unhandled frames left, but pause frame is still undergoing
if ((emac->free_rx_descriptor < emac->flow_control_low_water_mark) && emac->do_flow_ctrl && emac->frames_remain) {
@ -401,8 +413,6 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
esp_eth_mediator_t *eth = emac->eth;
/* init gpio used by smi interface */
emac_esp32_gpio_init_smi(&emac->smi_gpio);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
/* software reset */
emac_hal_reset(&emac->hal);
@ -451,7 +461,7 @@ static esp_err_t emac_esp32_start(esp_eth_mac_t *mac)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
/* reset descriptor chain */
emac_esp_dma_reset_desc_chain(emac->emac_dma_hndl);
emac_esp_dma_reset(emac->emac_dma_hndl);
emac_hal_start(&emac->hal);
return ESP_OK;
}
@ -474,8 +484,9 @@ static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac)
static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
{
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
esp_emac_free_driver_obj(emac);
/// disable bus clock
emac_esp_free_driver_obj(emac);
emac_esp_gpio_deinit_all();
// disable bus clock
PERIPH_RCC_ATOMIC() {
emac_ll_enable_bus_clock(0, false);
}
@ -502,7 +513,7 @@ IRAM_ATTR void emac_isr_default_handler(void *args)
#endif
}
static void esp_emac_free_driver_obj(emac_esp32_t *emac)
static void emac_esp_free_driver_obj(emac_esp32_t *emac)
{
if (emac) {
if (emac->rx_task_hdl) {
@ -537,7 +548,7 @@ static void esp_emac_free_driver_obj(emac_esp32_t *emac)
}
}
static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl)
static esp_err_t emac_esp_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl)
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = NULL;
@ -548,8 +559,7 @@ static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_
}
ESP_GOTO_ON_FALSE(emac, ESP_ERR_NO_MEM, err, TAG, "no mem for esp emac object");
emac_esp_dma_config_t emac_dma_config;
ESP_GOTO_ON_ERROR(emac_esp_new_dma(&emac_dma_config, &emac->emac_dma_hndl), err, TAG, "create EMAC DMA object failed");
ESP_GOTO_ON_ERROR(emac_esp_new_dma(NULL, &emac->emac_dma_hndl), err, TAG, "create EMAC DMA object failed");
/* alloc PM lock */
#ifdef CONFIG_PM_ENABLE
@ -565,88 +575,65 @@ static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_
ESP_GOTO_ON_FALSE(xReturned == pdPASS, ESP_FAIL, err, TAG, "create emac_rx task failed");
*emac_out_hdl = emac;
return ESP_OK;
err:
esp_emac_free_driver_obj(emac);
return ret;
}
static esp_err_t esp_emac_config_data_interface(const eth_esp32_emac_config_t *esp32_emac_config, emac_esp32_t *emac)
static esp_err_t emac_esp_config_data_interface(const eth_esp32_emac_config_t *esp32_emac_config, emac_esp32_t *emac)
{
esp_err_t ret = ESP_OK;
switch (esp32_emac_config->interface) {
case EMAC_DATA_INTERFACE_MII:
emac->clock_config = esp32_emac_config->clock_config;
/* MII interface GPIO initialization */
ESP_GOTO_ON_ERROR(emac_esp_iomux_init_mii(NULL), err, TAG, "invalid EMAC MII data plane GPIO");
#if SOC_EMAC_MII_USE_GPIO_MATRIX
ESP_GOTO_ON_ERROR(emac_esp_gpio_matrix_init_mii(&esp32_emac_config->emac_dataif_gpio.mii), err, TAG, "failed to initialize EMAC MII GPIO Matrix");
#else
eth_mac_mii_gpio_config_t *mii_data_gpio = NULL;
#if SOC_EMAC_USE_MULTI_IO_MUX
mii_data_gpio = &esp32_emac_config->emac_dataif_gpio.mii;
#endif // SOC_EMAC_USE_MULTI_IO_MUX
ESP_GOTO_ON_ERROR(emac_esp_iomux_init_mii(mii_data_gpio), err, TAG, "invalid EMAC MII data plane GPIO");
#endif // SOC_EMAC_MII_USE_GPIO_MATRIX
/* Enable MII clock */
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_enable_mii(&emac->hal);
}
break;
case EMAC_DATA_INTERFACE_RMII:
// by default, the clock mode is selected at compile time (by Kconfig)
if (esp32_emac_config->clock_config.rmii.clock_mode == EMAC_CLK_DEFAULT) {
#ifdef CONFIG_IDF_TARGET_ESP32
#if CONFIG_ETH_RMII_CLK_INPUT
#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
emac->clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_IN_GPIO;
#else
#error "ESP32 EMAC only support input RMII clock to GPIO0"
#endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0
#elif CONFIG_ETH_RMII_CLK_OUTPUT
emac->clock_config.rmii.clock_mode = EMAC_CLK_OUT;
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
emac->clock_config.rmii.clock_gpio = 0;
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO
emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_OUT_GPIO;
#endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
#else
#error "Unsupported RMII clock mode"
#endif // CONFIG_ETH_RMII_CLK_INPUT
#else // EMAC_CLK_DEFAULT "not supported for ESP32P4" - this configuration has been kept due to compatibility reasons for ESP32
ESP_LOGE(TAG, "EMAC_CLK_DEFAULT options is only supported by ESP32");
return ESP_ERR_INVALID_ARG;
#endif // CONFIG_IDF_TARGET_ESP32
} else {
emac->clock_config = esp32_emac_config->clock_config;
#ifdef CONFIG_IDF_TARGET_ESP32P4
emac->clock_config_out_in = esp32_emac_config->clock_config_out_in;
#endif // CONFIG_IDF_TARGET_ESP32P4
}
/* RMII interface GPIO initialization */
#ifdef CONFIG_IDF_TARGET_ESP32
ESP_GOTO_ON_ERROR(emac_esp_iomux_init_rmii(NULL), err, TAG, "invalid EMAC RMII data plane GPIO");
#else
ESP_GOTO_ON_ERROR(emac_esp_iomux_init_rmii(&emac->rmii_gpio), err, TAG, "invalid EMAC RMII data plane GPIO");
#endif // CONFIG_IDF_TARGET_ESP32
const eth_mac_rmii_gpio_config_t *rmii_data_gpio = NULL;
#if SOC_EMAC_USE_MULTI_IO_MUX
rmii_data_gpio = &esp32_emac_config->emac_dataif_gpio.rmii;
#endif // SOC_EMAC_USE_MULTI_IO_MUX
ESP_GOTO_ON_ERROR(emac_esp_iomux_init_rmii(rmii_data_gpio), err, TAG, "invalid EMAC RMII data plane GPIO");
/* If ref_clk is configured as input */
if (emac->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) {
ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(emac->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO");
if (esp32_emac_config->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) {
ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(esp32_emac_config->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO");
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_enable_rmii_input(&emac->hal);
}
} else if (emac->clock_config.rmii.clock_mode == EMAC_CLK_OUT) {
} else if (esp32_emac_config->clock_config.rmii.clock_mode == EMAC_CLK_OUT) {
ESP_GOTO_ON_ERROR(emac_config_pll_clock(emac), err, TAG, "Configure (A/M)PLL for RMII failed");
#if CONFIG_IDF_TARGET_ESP32
#if CONFIG_IDF_TARGET_ESP32P4
/* Output RMII clock is routed back to input externally */
ESP_GOTO_ON_FALSE(esp32_emac_config->clock_config_out_in.rmii.clock_mode == EMAC_CLK_EXT_IN && esp32_emac_config->clock_config_out_in.rmii.clock_gpio >= 0,
ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC input of output clock mode");
ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(esp32_emac_config->clock_config_out_in.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO");
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_enable_rmii_input(&emac->hal);
}
#elif CONFIG_IDF_TARGET_ESP32
// we can also use the IOMUX to route the APLL clock to specific GPIO
if (emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) {
if (esp32_emac_config->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) {
ESP_GOTO_ON_ERROR(esp_clock_output_start(CLKOUT_SIG_APLL, EMAC_APPL_CLK_OUT_GPIO, &emac->rmii_clk_hdl),
err, TAG, "start APLL clock output failed");
}
#elif CONFIG_IDF_TARGET_ESP32P4
/* Output RMII clock is routed back to input externally */
ESP_GOTO_ON_FALSE(emac->clock_config_out_in.rmii.clock_mode == EMAC_CLK_EXT_IN && emac->clock_config_out_in.rmii.clock_gpio >= 0,
ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC input of output clock mode");
ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(emac->clock_config_out_in.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO");
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_enable_rmii_input(&emac->hal);
}
} else
#endif
ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_ouput(emac->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock output GPIO");
{
ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_ouput(esp32_emac_config->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock output GPIO");
}
/* Enable RMII Output clock */
EMAC_IF_RCC_ATOMIC () {
EMAC_IF_RCC_ATOMIC() {
emac_hal_clock_enable_rmii_output(&emac->hal);
}
} else {
@ -671,7 +658,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config
TAG, "invalid interrupt priority: %d", esp32_config->intr_priority);
}
ret_code = esp_emac_alloc_driver_obj(config, &emac);
ret_code = emac_esp_alloc_driver_obj(config, &emac);
ESP_RETURN_ON_FALSE(ret_code == ESP_OK, NULL, TAG, "alloc driver object failed");
// enable bus clock for the EMAC module, and reset the registers into default state
@ -697,21 +684,15 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config
emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed");
#ifdef SOC_EMAC_USE_IO_MUX
emac->rmii_gpio.tx_en_num = esp32_config->emac_dataif_gpio.rmii.tx_en_num;
emac->rmii_gpio.txd0_num = esp32_config->emac_dataif_gpio.rmii.txd0_num;
emac->rmii_gpio.txd1_num = esp32_config->emac_dataif_gpio.rmii.txd1_num;
emac->rmii_gpio.crs_dv_num = esp32_config->emac_dataif_gpio.rmii.crs_dv_num;
emac->rmii_gpio.rxd0_num = esp32_config->emac_dataif_gpio.rmii.rxd0_num;
emac->rmii_gpio.rxd1_num = esp32_config->emac_dataif_gpio.rmii.rxd1_num;
#endif // SOC_EMAC_USE_IO_MUX
ret_code = esp_emac_config_data_interface(esp32_config, emac);
/* init GPIO used by SMI interface */
ret_code = emac_esp_gpio_init_smi(&esp32_config->smi_gpio);
ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "SMI GPIO init failed");
/* init GPIO and CLK for data interface */
ret_code = emac_esp_config_data_interface(esp32_config, emac);
ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "config emac interface failed");
emac->dma_burst_len = esp32_config->dma_burst_len;
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
emac->smi_gpio.mdc_num = esp32_config->smi_mdc_gpio_num;
emac->smi_gpio.mdio_num = esp32_config->smi_mdio_gpio_num;
emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK;
emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK;
@ -734,9 +715,11 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config
emac->parent.transmit = emac_esp32_transmit;
emac->parent.transmit_vargs = emac_esp32_transmit_multiple_bufs;
emac->parent.receive = emac_esp32_receive;
emac->parent.custom_ioctl = emac_esp_custom_ioctl;
return &(emac->parent);
err:
esp_emac_free_driver_obj(emac);
emac_esp_free_driver_obj(emac);
emac_esp_gpio_deinit_all();
return ret;
}

View File

@ -16,13 +16,36 @@
#define ETH_CRC_LENGTH (4)
#define EMAC_HAL_BUF_MAGIC_ID 0x1E1C8416
#define EMAC_ALLOC_BUF_MAGIC_ID 0x1E1C8416
#define EMAC_TDES0_FS_CTRL_FLAGS_MASK 0x0FCC0000 // modifiable bits mask associated with the First Segment
#define EMAC_TDES0_LS_CTRL_FLAGS_MASK 0x40000000 // modifiable bits mask associated with the Last Segment
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define DMA_CACHE_WB(addr, size) do { \
esp_err_t msync_ret = esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); \
assert(msync_ret == ESP_OK); \
} while(0)
#else
#define DMA_CACHE_WB(addr, size)
#endif
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define DMA_CACHE_INVALIDATE(addr, size) do { \
esp_err_t msync_ret = esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); \
assert(msync_ret == ESP_OK); \
} while(0)
#else
#define DMA_CACHE_INVALIDATE(addr, size)
#endif
static const char *TAG = "esp.emac.dma";
struct emac_esp_dma_t
{
emac_hal_context_t hal;
uint32_t tx_desc_flags;
uint32_t rx_desc_flags;
void *descriptors;
eth_dma_rx_descriptor_t *rx_desc;
eth_dma_tx_descriptor_t *tx_desc;
@ -37,13 +60,8 @@ typedef struct {
uint32_t copy_len;
}__attribute__((packed)) emac_esp_dma_auto_buf_info_t;
void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma)
void emac_esp_dma_reset(emac_esp_dma_handle_t emac_esp_dma)
{
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len;
esp_err_t ret = ESP_OK;
#endif
/* reset DMA descriptors */
emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(emac_esp_dma->descriptors);
emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->descriptors +
@ -66,11 +84,7 @@ void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma)
if (i == CONFIG_ETH_DMA_RX_BUFFER_NUM - 1) {
emac_esp_dma->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(emac_esp_dma->rx_desc);
}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)&emac_esp_dma->rx_desc[i], cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(&emac_esp_dma->rx_desc[i], EMAC_HAL_DMA_DESC_SIZE);
}
/* init tx chain */
@ -79,10 +93,6 @@ void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma)
emac_esp_dma->tx_desc[i].TDES0.Own = EMAC_LL_DMADESC_OWNER_CPU;
emac_esp_dma->tx_desc[i].TDES0.SecondAddressChained = 1;
emac_esp_dma->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* Enable Ethernet DMA Tx Descriptor interrupt */
emac_esp_dma->tx_desc[1].TDES0.InterruptOnComplete = 1;
/* Enable Transmit Timestamp */
emac_esp_dma->tx_desc[i].TDES0.TransmitTimestampEnable = 1;
/* point to the buffer */
emac_esp_dma->tx_desc[i].Buffer1Addr = (uint32_t)(emac_esp_dma->tx_buf[i]);
/* point to next descriptor */
@ -92,24 +102,25 @@ void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma)
if (i == CONFIG_ETH_DMA_TX_BUFFER_NUM - 1) {
emac_esp_dma->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(emac_esp_dma->tx_desc);
}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_tx_descriptor_t);
ret = esp_cache_msync((void *)&emac_esp_dma->tx_desc[i], cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(&emac_esp_dma->tx_desc[i], EMAC_HAL_DMA_DESC_SIZE);
}
/* set base address of the first descriptor */
emac_hal_set_rx_tx_desc_addr(&emac_esp_dma->hal, emac_esp_dma->rx_desc, emac_esp_dma->tx_desc);
}
void emac_esp_dma_set_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t flag)
{
emac_esp_dma->tx_desc_flags |= flag;
}
void emac_esp_dma_clear_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t flag)
{
emac_esp_dma->tx_desc_flags &= ~flag;
}
uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t length)
{
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_err_t ret;
size_t cache_sync_len;
#endif
/* Get the number of Tx buffers to use for the frame */
uint32_t bufcount = 0;
uint32_t lastlen = length;
@ -128,11 +139,7 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t
eth_dma_tx_descriptor_t *desc_iter = emac_esp_dma->tx_desc;
/* A frame is transmitted in multiple descriptor */
for (size_t i = 0; i < bufcount; i++) {
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_tx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */
if (desc_iter->TDES0.Own != EMAC_LL_DMADESC_OWNER_CPU) {
goto err;
@ -140,17 +147,16 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t
/* Clear FIRST and LAST segment bits */
desc_iter->TDES0.FirstSegment = 0;
desc_iter->TDES0.LastSegment = 0;
desc_iter->TDES0.InterruptOnComplete = 0;
desc_iter->TDES0.Value &= ~(EMAC_TDES0_FS_CTRL_FLAGS_MASK | EMAC_TDES0_LS_CTRL_FLAGS_MASK);
if (i == 0) {
/* Setting the first segment bit */
desc_iter->TDES0.FirstSegment = 1;
//desc_iter->TDES0.DisableCRC = 1;
desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_FS_CTRL_FLAGS_MASK;
}
if (i == (bufcount - 1)) {
/* Setting the last segment bit */
desc_iter->TDES0.LastSegment = 1;
/* Enable transmit interrupt */
desc_iter->TDES0.InterruptOnComplete = 1;
desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_LS_CTRL_FLAGS_MASK;
/* Program size */
desc_iter->TDES1.TransmitBuffer1Size = lastlen;
/* copy data from uplayer stack buffer */
@ -163,11 +169,7 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE);
sentout += CONFIG_ETH_DMA_BUFFER_SIZE;
}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE;
ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE);
/* Point to next descriptor */
desc_iter = (eth_dma_tx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
@ -175,11 +177,7 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
for (size_t i = 0; i < bufcount; i++) {
emac_esp_dma->tx_desc->TDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_tx_descriptor_t);
ret = esp_cache_msync((void *)emac_esp_dma->tx_desc, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(emac_esp_dma->tx_desc, EMAC_HAL_DMA_DESC_SIZE);
emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->tx_desc->Buffer2NextDescAddr);
}
emac_hal_transmit_poll_demand(&emac_esp_dma->hal);
@ -190,11 +188,6 @@ err:
uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t **buffs, uint32_t *lengths, uint32_t buffs_cnt)
{
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_err_t ret;
size_t cache_sync_len;
#endif
/* Get the number of Tx buffers to use for the frame */
uint32_t dma_bufcount = 0;
uint32_t sentout = 0;
@ -205,11 +198,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp
eth_dma_tx_descriptor_t *desc_iter = emac_esp_dma->tx_desc;
/* A frame is transmitted in multiple descriptor */
while (dma_bufcount < CONFIG_ETH_DMA_TX_BUFFER_NUM) {
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_tx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */
if (desc_iter->TDES0.Own != EMAC_LL_DMADESC_OWNER_CPU) {
goto err;
@ -217,11 +206,12 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp
/* Clear FIRST and LAST segment bits */
desc_iter->TDES0.FirstSegment = 0;
desc_iter->TDES0.LastSegment = 0;
desc_iter->TDES0.InterruptOnComplete = 0;
desc_iter->TDES0.Value &= ~(EMAC_TDES0_FS_CTRL_FLAGS_MASK | EMAC_TDES0_LS_CTRL_FLAGS_MASK);
desc_iter->TDES1.TransmitBuffer1Size = 0;
if (dma_bufcount == 0) {
/* Setting the first segment bit */
desc_iter->TDES0.FirstSegment = 1;
desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_FS_CTRL_FLAGS_MASK;
}
while (buffs_cnt > 0) {
@ -259,11 +249,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp
break;
}
}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE;
ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE);
/* Increase counter of utilized DMA buffers */
dma_bufcount++;
@ -271,8 +257,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp
if (buffs_cnt == 0) {
/* Setting the last segment bit */
desc_iter->TDES0.LastSegment = 1;
/* Enable transmit interrupt */
desc_iter->TDES0.InterruptOnComplete = 1;
desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_LS_CTRL_FLAGS_MASK;
break;
}
@ -283,11 +268,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
for (size_t i = 0; i < dma_bufcount; i++) {
emac_esp_dma->tx_desc->TDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_tx_descriptor_t);
ret = esp_cache_msync((void *)emac_esp_dma->tx_desc, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(emac_esp_dma->tx_desc, EMAC_HAL_DMA_DESC_SIZE);
emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->tx_desc->Buffer2NextDescAddr);
}
@ -301,25 +282,20 @@ static esp_err_t emac_esp_dma_get_valid_recv_len(emac_esp_dma_handle_t emac_esp_
{
eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc;
uint32_t used_descs = 0;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* Traverse descriptors owned by CPU */
while ((desc_iter->RDES0.Own != EMAC_LL_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
while ((desc_iter->RDES0.Own == EMAC_LL_DMADESC_OWNER_CPU) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
used_descs++;
/* Last segment in frame */
if (desc_iter->RDES0.LastDescriptor) {
#if CONFIG_IDF_TARGET_ESP32P4
/* Since Store Forward must be disabled at ESP32P4, DMA descriptors may contain erroneous frames */
/* Since Store Forward must be disabled on some targets, DMA descriptors may contain erroneous frames */
/* In addition, "Descriptor Error" (no free descriptors) may truncate a frame even if Store Forward is enabled */
if (desc_iter->RDES0.ErrSummary) {
emac_esp_dma_flush_recv_frame(emac_esp_dma, NULL, NULL);
emac_esp_dma_flush_recv_frame(emac_esp_dma);
*ret_len = 0;
return ESP_FAIL;
}
#endif //CONFIG_IDF_TARGET_ESP32P4
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
*ret_len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
break;
@ -330,42 +306,31 @@ static esp_err_t emac_esp_dma_get_valid_recv_len(emac_esp_dma_handle_t emac_esp_
}
/* point to next descriptor */
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
}
return ESP_OK;
}
static void emac_esp_dma_get_remain_frames(emac_esp_dma_handle_t emac_esp_dma, uint32_t *remain_frames, uint32_t *used_descs)
void emac_esp_dma_get_remain_frames(emac_esp_dma_handle_t emac_esp_dma, uint32_t *remain_frames, uint32_t *free_descs)
{
eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc;
*remain_frames = 0;
*used_descs = 0;
uint32_t used_descs = 0;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* Traverse descriptors owned by CPU */
while ((desc_iter->RDES0.Own != EMAC_LL_DMADESC_OWNER_DMA) && (*used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
(*used_descs)++;
while ((desc_iter->RDES0.Own == EMAC_LL_DMADESC_OWNER_CPU) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
used_descs++;
/* Last segment in frame */
if (desc_iter->RDES0.LastDescriptor) {
(*remain_frames)++;
}
/* point to next descriptor */
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
}
*free_descs = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs;
}
uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_t *size)
@ -388,7 +353,7 @@ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_
/* no need to check allocated buffer min length prior writing since we know that EMAC DMA is configured to
not forward erroneous or undersized frames (less than 64B) on ESP32, see emac_hal_init_dma_default */
#ifndef NDEBUG
buff_info->magic_id = EMAC_HAL_BUF_MAGIC_ID;
buff_info->magic_id = EMAC_ALLOC_BUF_MAGIC_ID;
#endif // NDEBUG
buff_info->copy_len = copy_len;
}
@ -398,20 +363,14 @@ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_
return buf;
}
uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc)
uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size)
{
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len;
esp_err_t ret;
#endif
eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc;
eth_dma_rx_descriptor_t *first_desc = emac_esp_dma->rx_desc;
uint32_t ret_len = 0;
uint32_t copy_len = 0;
if (size != EMAC_HAL_BUF_SIZE_AUTO) {
if (size != EMAC_DMA_BUF_SIZE_AUTO) {
if (emac_esp_dma_get_valid_recv_len(emac_esp_dma, &ret_len) != ESP_OK) {
goto err;
return 0;
}
/* packets larger than expected will be truncated */
copy_len = ret_len > size ? size : ret_len;
@ -419,106 +378,75 @@ uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t
emac_esp_dma_auto_buf_info_t *buff_info = (emac_esp_dma_auto_buf_info_t *)buf;
#ifndef NDEBUG
/* check that buffer was allocated by emac_esp_dma_alloc_recv_buf */
assert(buff_info->magic_id == EMAC_HAL_BUF_MAGIC_ID);
assert(buff_info->magic_id == EMAC_ALLOC_BUF_MAGIC_ID);
#endif // NDEBUG
copy_len = buff_info->copy_len;
ret_len = copy_len;
}
if (copy_len) {
desc_iter = first_desc;
eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc;
while(copy_len > CONFIG_ETH_DMA_BUFFER_SIZE) {
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE;
ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE);
memcpy(buf, (void *)(desc_iter->Buffer1Addr), CONFIG_ETH_DMA_BUFFER_SIZE);
buf += CONFIG_ETH_DMA_BUFFER_SIZE;
copy_len -= CONFIG_ETH_DMA_BUFFER_SIZE;
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE // TODO cleanup (IDF-8993)
cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE;
ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert(ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE);
memcpy(buf, (void *)(desc_iter->Buffer1Addr), copy_len);
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* `copy_len` does not include CRC (which may be stored in separate buffer), hence check if we reached the last descriptor */
while (!desc_iter->RDES0.LastDescriptor) {
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert(ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
}
/* update rxdesc */
emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
/* poll rx demand */
emac_hal_receive_poll_demand(&emac_esp_dma->hal);
}
err:
/* check how many frames left to handle */
uint32_t used_descs = 0;
emac_esp_dma_get_remain_frames(emac_esp_dma, frames_remain, &used_descs);
*free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs;
return ret_len;
}
void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma, uint32_t *frames_remain, uint32_t *free_desc)
void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma)
{
eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t cache_sync_len;
esp_err_t ret;
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
assert (ret == ESP_OK);
#endif
DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* While not last descriptor => return back to DMA */
while (!desc_iter->RDES0.LastDescriptor) {
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert (ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
/* the last descriptor */
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
cache_sync_len = sizeof(eth_dma_rx_descriptor_t);
ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
assert (ret == ESP_OK);
#endif
DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE);
/* update rxdesc */
emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
/* poll rx demand */
emac_hal_receive_poll_demand(&emac_esp_dma->hal);
}
if (frames_remain != NULL && free_desc != NULL) {
/* check how many frames left to handle */
uint32_t used_descs = 0;
emac_esp_dma_get_remain_frames(emac_esp_dma, frames_remain, &used_descs);
*free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs;
esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma)
{
if (emac_esp_dma) {
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac_esp_dma->tx_buf[i]);
}
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac_esp_dma->rx_buf[i]);
}
free(emac_esp_dma->descriptors);
free(emac_esp_dma);
}
return ESP_OK;
}
esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_handle_t *ret_handle)
@ -551,20 +479,6 @@ esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_han
*ret_handle = emac_esp_dma;
return ESP_OK;
err:
emac_esp_del_dma(emac_esp_dma);
return ret;
}
esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma)
{
if (emac_esp_dma) {
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac_esp_dma->tx_buf[i]);
}
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac_esp_dma->rx_buf[i]);
}
free(emac_esp_dma->descriptors);
free(emac_esp_dma);
}
return ESP_OK;
}

View File

@ -0,0 +1,265 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include "esp_check.h"
#include "sdkconfig.h"
#include "esp_rom_gpio.h"
#include "driver/gpio.h"
#include "soc/soc_caps.h"
#include "soc/gpio_sig_map.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_periph.h"
#include "soc/emac_periph.h"
#include "esp_private/gpio.h"
#include "esp_private/eth_mac_esp_gpio.h"
#include "esp_private/esp_gpio_reserve.h"
#include "esp_log.h"
#define GET_GPIO_OR_SINGLE(cfg, num) cfg == NULL ? GPIO_NUM_MAX : cfg->num
static const char *TAG = "esp.emac.gpio";
static uint64_t s_emac_esp_used_gpio_mask = 0x0;
static esp_err_t emac_esp_gpio_matrix_init(gpio_num_t gpio_num, uint32_t signal_in_idx, uint32_t signal_out_idx, gpio_mode_t mode)
{
// silently skip when user don't want to connect the signal to GPIO pad
if (gpio_num == GPIO_NUM_NC) {
ESP_LOGD(TAG, "%s skipping signal in_idx %" PRIu32 ", out_idx %" PRIu32, __func__, signal_in_idx, signal_out_idx);
return ESP_OK;
}
ESP_RETURN_ON_ERROR(gpio_set_direction(gpio_num, mode), TAG, "failed to set direction %i at GPIO #%i", mode, gpio_num);
switch(mode) {
case GPIO_MODE_INPUT:
ESP_RETURN_ON_FALSE(signal_in_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED,
TAG, "requested periph signal cannot be connect via GPIO Matrix");
ESP_RETURN_ON_FALSE(esp_gpio_is_reserved(BIT64(gpio_num)) == false, ESP_ERR_INVALID_STATE,
TAG, "GPIO %i is reserved", gpio_num);
esp_rom_gpio_connect_in_signal(gpio_num, signal_in_idx, false);
break;
case GPIO_MODE_OUTPUT:
ESP_RETURN_ON_FALSE(signal_out_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED,
TAG, "requested periph signal cannot be connect via GPIO Matrix");
ESP_RETURN_ON_FALSE((esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num)) == 0, ESP_ERR_INVALID_STATE,
TAG, "GPIO %i is already reserved", gpio_num);
esp_rom_gpio_connect_out_signal(gpio_num, signal_out_idx, false, false);
break;
case GPIO_MODE_INPUT_OUTPUT:
ESP_RETURN_ON_FALSE(signal_in_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED,
TAG, "requested periph signal cannot be connect via GPIO Matrix");
ESP_RETURN_ON_FALSE(signal_out_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED,
TAG, "requested periph signal cannot be connect via GPIO Matrix");
ESP_RETURN_ON_FALSE((esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num)) == 0, ESP_ERR_INVALID_STATE,
TAG, "GPIO %i is already reserved", gpio_num);
esp_rom_gpio_connect_out_signal(gpio_num, signal_out_idx, false, false);
esp_rom_gpio_connect_in_signal(gpio_num, signal_in_idx, false);
break;
default:
return ESP_ERR_INVALID_ARG;
}
s_emac_esp_used_gpio_mask |= BIT64(gpio_num);
ESP_RETURN_ON_ERROR(gpio_set_pull_mode(gpio_num, GPIO_FLOATING), TAG, "failed to set pull mode at GPIO %i", gpio_num);
ESP_RETURN_ON_ERROR(gpio_func_sel(gpio_num, PIN_FUNC_GPIO), TAG, "failed to set GPIO function at GPIO #%i", gpio_num);
return ESP_OK;
}
static esp_err_t emac_esp_iomux_init(gpio_num_t gpio_num, const emac_iomux_info_t *iomux_info, bool is_input)
{
// silently skip undefined iomux functions (for example, ESP32 does not use MII COL_IN/CRS_IN)
if (iomux_info == NULL) {
ESP_LOGD(TAG, "%s skipping target undefined iomux periph function", __func__);
return ESP_OK;
}
// loop over target iomux_info until reached end of list indicated by invalid GPIO num
while (iomux_info->gpio_num != GPIO_NUM_MAX) {
// if requested GPIO number can be IO muxed or select single pad that can be muxed on the target
if(gpio_num == iomux_info->gpio_num || gpio_num == GPIO_NUM_MAX) {
ESP_RETURN_ON_FALSE((esp_gpio_reserve(BIT64(iomux_info->gpio_num)) & BIT64(iomux_info->gpio_num)) == 0, ESP_ERR_INVALID_STATE,
TAG, "GPIO %i is already reserved", iomux_info->gpio_num);
s_emac_esp_used_gpio_mask |= BIT64(iomux_info->gpio_num);
ESP_RETURN_ON_ERROR(gpio_func_sel(iomux_info->gpio_num, iomux_info->func), TAG, "failed to set GPIO function at GPIO %i", iomux_info->gpio_num);
if (is_input) {
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[iomux_info->gpio_num]);
} else {
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[iomux_info->gpio_num]);
}
ESP_RETURN_ON_ERROR(gpio_set_pull_mode(iomux_info->gpio_num, GPIO_FLOATING),
TAG, "failed to set pull mode at GPIO %i", iomux_info->gpio_num);
return ESP_OK;
}
iomux_info++;
}
return ESP_FAIL;
}
esp_err_t emac_esp_gpio_init_smi(const emac_esp_smi_gpio_config_t *smi_gpio)
{
if (smi_gpio->mdc_num >= 0) {
/* Setup SMI MDC GPIO */
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(smi_gpio->mdc_num, 0, emac_io_idx.mdc_idx, GPIO_MODE_OUTPUT),
TAG, "MDC GPIO matrix config failed");
}
if (smi_gpio->mdio_num >= 0) {
/* Setup SMI MDIO GPIO */
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(smi_gpio->mdio_num, emac_io_idx.mdi_idx, emac_io_idx.mdo_idx, GPIO_MODE_INPUT_OUTPUT),
TAG, "MDIO GPIO matrix config failed");
}
return ESP_OK;
}
esp_err_t emac_esp_gpio_matrix_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio)
{
ESP_RETURN_ON_FALSE(mii_gpio != NULL, ESP_ERR_INVALID_ARG, TAG, "MII IO matrix config cannot be NULL");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->tx_clk_num, emac_io_idx.mii_tx_clk_i_idx, 0, GPIO_MODE_INPUT),
TAG, "TX_CLK GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->tx_en_num, 0, emac_io_idx.mii_tx_en_o_idx, GPIO_MODE_OUTPUT),
TAG, "TX_EN GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd0_num, 0, emac_io_idx.mii_txd0_o_idx, GPIO_MODE_OUTPUT),
TAG, "TDX0 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd1_num, 0, emac_io_idx.mii_txd1_o_idx, GPIO_MODE_OUTPUT),
TAG, "TDX1 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd2_num, 0, emac_io_idx.mii_txd2_o_idx, GPIO_MODE_OUTPUT),
TAG, "TDX2 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd3_num, 0, emac_io_idx.mii_txd3_o_idx, GPIO_MODE_OUTPUT),
TAG, "TDX3 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rx_clk_num, emac_io_idx.mii_rx_clk_i_idx, 0, GPIO_MODE_INPUT),
TAG, "RX_CLK GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd0_num, emac_io_idx.mii_rxd0_i_idx, 0, GPIO_MODE_INPUT),
TAG, "RXD0 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd1_num, emac_io_idx.mii_rxd1_i_idx, 0, GPIO_MODE_INPUT),
TAG, "RXD1 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd2_num, emac_io_idx.mii_rxd2_i_idx, 0, GPIO_MODE_INPUT),
TAG, "RXD2 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd3_num, emac_io_idx.mii_rxd3_i_idx, 0, GPIO_MODE_INPUT),
TAG, "RXD3 GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->col_in_num, emac_io_idx.mii_col_i_idx, 0, GPIO_MODE_INPUT),
TAG, "COL_IN GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->crs_in_num, emac_io_idx.mii_crs_i_idx, 0, GPIO_MODE_INPUT),
TAG, "CRS_IN GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->tx_er_num, 0, emac_io_idx.mii_tx_er_o_idx, GPIO_MODE_OUTPUT),
TAG, "TX_ER GPIO matrix config failed");
ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rx_er_num, emac_io_idx.mii_rx_er_i_idx, 0, GPIO_MODE_INPUT),
TAG, "RX_ER GPIO matrix config failed");
return ESP_OK;
}
esp_err_t emac_esp_iomux_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio)
{
ESP_RETURN_ON_FALSE(emac_mii_iomux_pins.clk_tx != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support MII IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, tx_clk_num), emac_mii_iomux_pins.clk_tx, true),
TAG, "invalid TX_CLK GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, tx_en_num), emac_mii_iomux_pins.tx_en, false),
TAG, "invalid TX_EN GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd0_num), emac_mii_iomux_pins.txd0, false),
TAG, "invalid TXD0 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd1_num), emac_mii_iomux_pins.txd1, false),
TAG, "invalid TXD1 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd2_num), emac_mii_iomux_pins.txd2, false),
TAG, "invalid TXD2 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd3_num), emac_mii_iomux_pins.txd3, false),
TAG, "invalid TXD3 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rx_clk_num), emac_mii_iomux_pins.clk_rx, true),
TAG, "invalid RX_CLK GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rx_dv_num), emac_mii_iomux_pins.rx_dv, true),
TAG, "invalid RX_DV GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd0_num), emac_mii_iomux_pins.rxd0, true),
TAG, "invalid RXD0 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd1_num), emac_mii_iomux_pins.rxd1, true),
TAG, "invalid RXD1 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd2_num), emac_mii_iomux_pins.rxd2, true),
TAG, "invalid RXD2 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd3_num), emac_mii_iomux_pins.rxd3, true),
TAG, "invalid RXD3 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, col_in_num), emac_mii_iomux_pins.col_in, true),
TAG, "invalid COL_IN GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, crs_in_num), emac_mii_iomux_pins.crs_in, true),
TAG, "invalid CRS_IN GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_rmii_clk_input(int num)
{
ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.clki != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII CLKI IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.clki, true), TAG, "invalid RMII CLK input GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_rmii_clk_ouput(int num)
{
ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.clko != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII CLKO IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.clko, false), TAG, "invalid RMII CLK output GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_init_rmii(const eth_mac_rmii_gpio_config_t *rmii_gpio)
{
ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.clki != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, tx_en_num), emac_rmii_iomux_pins.tx_en, false),
TAG, "invalid TX_EN GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, txd0_num), emac_rmii_iomux_pins.txd0, false),
TAG, "invalid TXD0 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, txd1_num), emac_rmii_iomux_pins.txd1, false),
TAG, "invalid TXD1 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, crs_dv_num), emac_rmii_iomux_pins.crs_dv, true),
TAG,"invalid CRS_DV GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, rxd0_num), emac_rmii_iomux_pins.rxd0, true),
TAG,"invalid RXD0 GPIO number");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, rxd1_num), emac_rmii_iomux_pins.rxd1, true),
TAG,"invalid RXD1 GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_rmii_init_tx_er(int num)
{
ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.tx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII TX_ER IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.tx_er, false), TAG, "invalid TX_ER GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_rmii_init_rx_er(int num)
{
ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.rx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII RX_ER IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.rx_er, true), TAG, "invalid RX_ER GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_mii_init_tx_er(int num)
{
ESP_RETURN_ON_FALSE(emac_mii_iomux_pins.tx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support MII TX_ER IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_mii_iomux_pins.tx_er, false), TAG, "invalid TX_ER GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_iomux_mii_init_rx_er(int num)
{
ESP_RETURN_ON_FALSE(emac_mii_iomux_pins.rx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII RX_ER IOMUX");
ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_mii_iomux_pins.rx_er, true), TAG, "invalid RX_ER GPIO number");
return ESP_OK;
}
esp_err_t emac_esp_gpio_deinit_all(void)
{
for (int gpio_num = 0; gpio_num < 64; gpio_num++) {
if (BIT64(gpio_num) & s_emac_esp_used_gpio_mask) {
gpio_reset_pin(gpio_num);
esp_gpio_revoke(BIT64(gpio_num));
}
s_emac_esp_used_gpio_mask &= ~BIT64(gpio_num);
}
return ESP_OK;
}

View File

@ -21,12 +21,12 @@
#include "esp_log.h"
#include "esp_check.h"
#include "esp_cpu.h"
#include "esp_eth_driver.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "openeth.h"
#include "esp_mac.h"
#include "esp_eth_mac_openeth.h"
static const char *TAG = "opencores.emac";

View File

@ -11,7 +11,7 @@
#if CONFIG_IDF_TARGET_ESP32C3
/**
* @brief Since ESP32-C3 target in QEMU doesn't support Wifi, re-use its interrupt source for ethernet
* @brief Since ESP32-C3 target in QEMU doesn't support Wifi, reuse its interrupt source for ethernet
*/
#define ETS_ETH_MAC_INTR_SOURCE ETS_WIFI_MAC_INTR_SOURCE

View File

@ -114,7 +114,7 @@ extern "C" {
typedef struct {
uint16_t cs: 1; //!< Carrier sense lost (flag set by HW)
uint16_t df: 1; //!< Defer indication (flag set by HW)
uint16_t lc: 1; //!< Late collision occured (flag set by HW)
uint16_t lc: 1; //!< Late collision occurred (flag set by HW)
uint16_t rl: 1; //!< TX failed due to retransmission limit (flag set by HW)
uint16_t rtry: 4; //!< Number of retries before the frame was sent (set by HW)
uint16_t ur: 1; //!< Underrun status (flag set by HW)

View File

@ -62,7 +62,7 @@ typedef union {
*/
typedef union {
struct {
uint32_t op_mode : 3; /* Operation Mode Idicator */
uint32_t op_mode : 3; /* Operation Mode Indicator */
uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */
uint32_t reserved1 : 4; /* Reserved */
uint32_t link_up : 1; /* Indicate the link status is OK or FAIL */

View File

@ -8,12 +8,12 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include <inttypes.h>
#include "esp_eth_mac_spi.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_driver.h"
#include "esp_timer.h"
#include "esp_system.h"
#include "esp_intr_alloc.h"

View File

@ -67,7 +67,7 @@ typedef union {
uint32_t monsel1 : 1; /* Vendor monitor select */
uint32_t mdix_down : 1; /* Set 1 to disable HP Auto-MDIX */
uint32_t mdix_fix : 1; /* When mdix_down = 1, MDIX_CNTL value depend on the register value. */
uint32_t autoneg_lpbk : 1; /* Set 1 to enable autonegotioation loopback */
uint32_t autoneg_lpbk : 1; /* Set 1 to enable autonegotiation loopback */
uint32_t mdxi_cntl : 1; /* Polarity of MDI/MDIX value */
uint32_t reserved2 : 1; /* Reserved */
uint32_t nway_pwr : 1; /* Set 1 to enable power savings during autonegotiation period */
@ -195,7 +195,7 @@ static esp_err_t dm9051_loopback(esp_eth_phy_t *phy, bool enable)
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
esp_eth_mediator_t *eth = phy_802_3->eth;
/* Set Loopback function */
// Enable Auto-negotiation loopback in Speficic control register
// Enable Auto-negotiation loopback in Specific control register
bmcr_reg_t bmcr;
scr_reg_t scr;
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");

View File

@ -8,6 +8,7 @@
#include <string.h>
#include <inttypes.h>
#include "esp_eth_mac_spi.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_cpu.h"
@ -17,7 +18,6 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_eth_driver.h"
#include "ksz8851.h"
#include "esp_timer.h"

View File

@ -6,6 +6,7 @@
* SPDX-FileContributor: 2021-2024 Espressif Systems (Shanghai) CO LTD
*/
#include <stdlib.h>
#include "esp_eth_phy.h"
#include "esp_check.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
@ -13,7 +14,6 @@
#include "esp_rom_gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_eth_driver.h"
#include "ksz8851.h"
@ -149,7 +149,7 @@ err:
/**
* @note This function is responsible for restarting a new auto-negotiation,
* the result of negotiation won't be relected to uppler layers.
* the result of negotiation won't be reflected to upper layers.
* Instead, the negotiation result is fetched by linker timer, see `phy_ksz8851_get_link()`
*/
static esp_err_t phy_ksz8851_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat)

View File

@ -1,22 +1,11 @@
// Copyright (c) 2021 Vladimir Chistyakov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
/*
* SPDX-FileCopyrightText: 2021 Vladimir Chistyakov
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
*/
#pragma once
@ -314,7 +303,7 @@ typedef enum {
P1ANAR_ADV_10_HALF = 0x0020U, ///< RW Adv 10 Half
P1ANLPR_NEXT_PAGE = 0x8000U, ///< RO Next page (not supported)
P1ANLPR_LP_ACK = 0x4000U, ///< RO LP ACK (not suppported)
P1ANLPR_LP_ACK = 0x4000U, ///< RO LP ACK (not supported)
P1ANLPR_REMOTE_FAULT = 0x2000U, ///< RO Remote fault (not supported)
P1ANLPR_PAUSE = 0x0400U, ///< RO Pause
P1ANLPR_ADV_100_FULL = 0x0100U, ///< RO Adv 100 Full

View File

@ -7,12 +7,12 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include <inttypes.h>
#include "esp_eth_mac_spi.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_driver.h"
#include "esp_system.h"
#include "esp_intr_alloc.h"
#include "esp_heap_caps.h"
@ -550,7 +550,7 @@ static esp_err_t emac_w5500_enable_flow_ctrl(esp_eth_mac_t *mac, bool enable)
static esp_err_t emac_w5500_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t ability)
{
/* w5500 doesn't suppport PAUSE function, so accept any value */
/* w5500 doesn't support PAUSE function, so accept any value */
return ESP_ERR_NOT_SUPPORTED;
}
@ -823,7 +823,7 @@ static esp_err_t emac_w5500_init(esp_eth_mac_t *mac)
/* reset w5500 */
ESP_GOTO_ON_ERROR(w5500_reset(emac), err, TAG, "reset w5500 failed");
/* verify chip id */
ESP_GOTO_ON_ERROR(w5500_verify_id(emac), err, TAG, "vefiry chip ID failed");
ESP_GOTO_ON_ERROR(w5500_verify_id(emac), err, TAG, "verify chip ID failed");
/* default setup of internal registers */
ESP_GOTO_ON_ERROR(w5500_setup_default(emac), err, TAG, "w5500 default setup failed");
return ESP_OK;

View File

@ -6,9 +6,9 @@
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_eth_phy.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_driver.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

View File

@ -5,6 +5,6 @@ idf_component_register(SRCS "esp_eth_test_apps.c"
"esp_eth_test_main.c"
INCLUDE_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client esp_driver_gpio
EMBED_TXTFILES dl_espressif_com_root_cert.pem
WHOLE_ARCHIVE)

View File

@ -36,15 +36,15 @@ esp_eth_mac_t *mac_init(void *vendor_emac_config, eth_mac_config_t *mac_config)
#if CONFIG_TARGET_USE_INTERNAL_ETHERNET
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
#if !CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG
esp32_emac_config.smi_mdc_gpio_num = CONFIG_TARGET_IO_MDC;
esp32_emac_config.smi_mdio_gpio_num = CONFIG_TARGET_IO_MDIO;
esp32_emac_config.smi_gpio.mdc_num = CONFIG_TARGET_IO_MDC;
esp32_emac_config.smi_gpio.mdio_num = CONFIG_TARGET_IO_MDIO;
#endif // CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG
if (vendor_emac_config == NULL) {
vendor_emac_config = &esp32_emac_config;
}
mac = esp_eth_mac_new_esp32(vendor_emac_config, mac_config);
#elif CONFIG_TARGET_USE_SPI_ETHERNET
// Install GPIO ISR handler to be able to service SPI Eth modlues interrupts
// Install GPIO ISR handler to be able to service SPI Eth modules interrupts
gpio_install_isr_service(0);
spi_bus_config_t buscfg = {

View File

@ -9,10 +9,11 @@
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_eth_test_common.h"
#include "hal/emac_hal.h" // for MAC_HAL_TDES0_* control bits
#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via emac_hal_transmit_frame
#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers)
#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via emac_hal_transmit_multiple_buf_frame (3 buffers)
#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via _transmit_frame
#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via _transmit_multiple_buf_frame (2 buffers)
#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via _transmit_multiple_buf_frame (3 buffers)
#define MINIMUM_TEST_FRAME_SIZE 64
@ -36,12 +37,12 @@ static esp_err_t eth_recv_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffe
ESP_LOGI(TAG, "recv frame size: %" PRIu16, expected_size);
TEST_ASSERT_EQUAL(expected_size, length);
// frame transmitted via emac_hal_transmit_frame
// frame transmitted via _transmit_frame
if (pkt->proto == ETHERTYPE_TX_STD) {
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
TEST_ASSERT_EQUAL(pkt->data[i], i & 0xFF);
}
// frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers)
// frame transmitted via _multiple_buf_frame (2 buffers)
} else if (pkt->proto == ETHERTYPE_TX_MULTI_2) {
uint8_t *data_p = pkt->data;
for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) {
@ -357,15 +358,17 @@ TEST_CASE("internal emac interrupt priority", "[esp_emac]")
vEventGroupDelete(eth_event_group);
}
#if CONFIG_IDF_TARGET_ESP32P4 // IDF-8993
#include "hal/emac_hal.h"
#include "hal/emac_ll.h"
#include "soc/emac_mac_struct.h"
static esp_err_t eth_recv_err_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
#define TEST_FRAMES_NUM CONFIG_ETH_DMA_RX_BUFFER_NUM
static uint8_t *s_recv_frames[TEST_FRAMES_NUM];
static uint8_t s_recv_frames_cnt = 0;
static esp_err_t eth_recv_esp_emac_err_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv)
{
SemaphoreHandle_t mutex = (SemaphoreHandle_t)priv;
free(buffer);
xSemaphoreGive(mutex);
s_recv_frames[s_recv_frames_cnt++] = buffer;
if (s_recv_frames_cnt >= TEST_FRAMES_NUM)
xSemaphoreGive(mutex);
return ESP_OK;
}
@ -394,7 +397,7 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]")
bool loopback_en = true;
esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en);
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_err_esp_emac_check_cb, mutex));
TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_esp_emac_err_check_cb, mutex));
// start the driver
TEST_ESP_OK(esp_eth_start(eth_handle));
@ -413,23 +416,96 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]")
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, local_mac_addr));
memcpy(test_pkt->src, local_mac_addr, ETH_ADDR_LEN);
// fill with data
for (int i = 0; i < ETH_MAX_PAYLOAD_LEN; i++) {
int i;
for (i = 1; i < ETH_MAX_PAYLOAD_LEN; i++) {
test_pkt->data[i] = i & 0xFF;
}
emac_ll_checksum_offload_mode(&EMAC_MAC, ETH_CHECKSUM_SW);
size_t transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE;
uint8_t frame_id = 0;
size_t transmit_size = 1072;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
ESP_LOGI(TAG, "Verify non-failure frame condition");
for (i = 1; i <= TEST_FRAMES_NUM; i++) {
test_pkt->data[0] = frame_id++;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
// if we have only 10 or less Rx buffers, they can be all used pretty fast => wait to be freed prior next Tx
if (CONFIG_ETH_DMA_RX_BUFFER_NUM <= 10 && !(i % (CONFIG_ETH_DMA_RX_BUFFER_NUM / 2))) {
ESP_LOGI(TAG, "wait prior Tx (frame num %i)", i);
vTaskDelay(10);
}
}
ESP_LOGI(TAG, "num of sent frames: %d", TEST_FRAMES_NUM);
TEST_ASSERT(xSemaphoreTake(mutex, pdMS_TO_TICKS(500)));
ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt);
free(test_pkt);
for (i = 0; i < s_recv_frames_cnt; i++) {
emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i];
ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]);
free(recv_frame);
}
TEST_ASSERT_EQUAL_UINT8(TEST_FRAMES_NUM, s_recv_frames_cnt);
s_recv_frames_cnt = 0;
printf("\n");
ESP_LOGI(TAG, "Verify failure condition when every second frame has invalid CRC");
uint32_t emac_tx_dbg_flag = EMAC_HAL_TDES0_CRC_APPEND_DISABLE;
for (i = 1; i <= TEST_FRAMES_NUM; i++) {
test_pkt->data[0] = frame_id++;
// make every 2nd frame invalid
if (!(i % 2)) {
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS, &emac_tx_dbg_flag));
}
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
if (!(i % 2)) {
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS, &emac_tx_dbg_flag));
}
}
ESP_LOGI(TAG, "num of sent frames: %d (every 2nd invalid)", TEST_FRAMES_NUM);
TEST_ASSERT_FALSE(xSemaphoreTake(mutex, pdMS_TO_TICKS(500)));
ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt);
for (i = 0; i < s_recv_frames_cnt; i++) {
emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i];
ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]);
free(recv_frame);
}
TEST_ASSERT_EQUAL_UINT8(TEST_FRAMES_NUM / 2, s_recv_frames_cnt);
s_recv_frames_cnt = 0;
ESP_LOGI(TAG, "Verify full Rx DMA failure condition");
// suspend ETH Rx task so the DMA is filled
vTaskSuspend(xTaskGetHandle("emac_rx"));
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE - 4; // -4 bytes to the frame fit into one descriptor even with CRC
// fill the descriptors, keep one free
for (i = 1; i <= CONFIG_ETH_DMA_RX_BUFFER_NUM - 1; i++) {
test_pkt->data[0] = frame_id++;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
vTaskDelay(1); // to prevent "insufficient TX buffer size" error
}
transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE; // now, we will need 2 descriptors to store the frame (with CRC) but only one is free
test_pkt->data[0] = frame_id++;
TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size));
vTaskDelay(50);
vTaskResume(xTaskGetHandle("emac_rx"));
ESP_LOGI(TAG, "num of sent frames: %d", i);
TEST_ASSERT_FALSE(xSemaphoreTake(mutex, pdMS_TO_TICKS(500)));
ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt);
for (i = 0; i < s_recv_frames_cnt; i++) {
emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i];
ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]);
free(recv_frame);
}
TEST_ASSERT_EQUAL_INT(CONFIG_ETH_DMA_RX_BUFFER_NUM - 1, s_recv_frames_cnt); // one frame is missing due to "Descriptor Error"
s_recv_frames_cnt = 0;
// stop Ethernet driver
TEST_ESP_OK(esp_eth_stop(eth_handle));
/* wait for connection stop */
// wait for connection stop
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
free(test_pkt);
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
TEST_ESP_OK(phy->del(phy));
TEST_ESP_OK(mac->del(mac));
@ -439,4 +515,3 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]")
vEventGroupDelete(eth_event_group);
vSemaphoreDelete(mutex);
}
#endif

View File

@ -1,5 +1,7 @@
CONFIG_UNITY_ENABLE_FIXTURE=y
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
CONFIG_ETH_USE_ESP32_EMAC=y
CONFIG_ESP_NETIF_L2_TAP=y
CONFIG_LWIP_CHECK_THREAD_SAFETY=y

View File

@ -437,6 +437,11 @@ static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, b
dma_regs->dmaoperation_mode.rx_store_forward = enable;
}
static inline bool emac_ll_recv_store_forward_is_enabled(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmaoperation_mode.rx_store_forward;
}
static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable;

View File

@ -411,6 +411,11 @@ static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, b
dma_regs->dmaoperation_mode.rx_store_forward = enable;
}
static inline bool emac_ll_recv_store_forward_is_enabled(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmaoperation_mode.rx_store_forward;
}
static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable;

View File

@ -6,8 +6,6 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_assert.h"
@ -29,15 +27,28 @@ extern "C" {
#if CONFIG_IDF_TARGET_ESP32P4
// Descriptor must be 64B aligned for ESP32P4 due to cache arrangement
#define DMA_DESC_SIZE 64
// ESP32P4 EMAC interface clock configuration is shared among other modules in registers
#define EMAC_IF_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#define EMAC_HAL_DMA_DESC_SIZE (64)
#else
#define DMA_DESC_SIZE 32
#define EMAC_IF_RCC_ATOMIC()
#define EMAC_HAL_DMA_DESC_SIZE (32)
#endif
/* DMA descriptor control bits */
#define EMAC_HAL_TDES0_INTR_ON_COMPLET (1 << 30)
#define EMAC_HAL_TDES0_CRC_APPEND_DISABLE (1 << 27)
#define EMAC_HAL_TDES0_PAD_DISABLE (1 << 26)
#define EMAC_HAL_TDES0_TX_TS_ENABLE (1 << 25)
#define EMAC_HAL_TDES0_CRC_REPLACE_CTRL (1 << 24)
#define EMAC_HAL_TDES0_IP_CRC_INSERT_HDR (1 << 22)
#define EMAC_HAL_TDES0_IP_CRC_INSERT_HDR_PAYLOAD (2 << 22)
#define EMAC_HAL_TDES0_IP_CRC_INSERT_HDR_PAYLOAD_PSEUDO (3 << 22)
#define EMAC_HAL_TDES0_VLAN_REMOVE (1 << 18)
#define EMAC_HAL_TDES0_VLAN_INSERT (2 << 18)
#define EMAC_HAL_TDES0_VLAN_REPLACE (3 << 18)
#define EMAC_HAL_TDES0_IP_CRC_INSERT_DISABLE_MASK (3 << 22)
#define EMAC_HAL_TDES0_VLAN_INSERT_DISABLE_MASK (3 << 18)
/**
* @brief Ethernet DMA TX Descriptor
*
@ -65,7 +76,7 @@ typedef struct {
uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */
uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */
uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */
uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */
uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 hardware timestamping */
uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */
uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */
uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */
@ -91,25 +102,12 @@ typedef struct {
uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */
uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */
#if CONFIG_IDF_TARGET_ESP32P4
// TODO: must be 64B aligned for ESP32P4 (due to cache arrangement)
// Could be better optimized (EMAC DMA block supports 32/64/128)?
uint32_t Reserved8;
uint32_t Reserved9;
uint32_t Reserved10;
uint32_t Reserved11;
uint32_t Reserved12;
uint32_t Reserved13;
uint32_t Reserved14;
uint32_t Reserved15;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
// descriptor must be aligned (due to cache arrangement)
uint8_t CacheAlign[EMAC_HAL_DMA_DESC_SIZE - 32]; // 32 is size of EMAC DMA descriptor without alignment
#endif
} eth_dma_tx_descriptor_t;
#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */
#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */
ASSERT_TYPE_SIZE(eth_dma_tx_descriptor_t, DMA_DESC_SIZE);
ASSERT_TYPE_SIZE(eth_dma_tx_descriptor_t, EMAC_HAL_DMA_DESC_SIZE);
/**
* @brief Ethernet DMA RX Descriptor
@ -182,21 +180,13 @@ typedef struct {
uint32_t TimeStampLow; /*!< Receive frame timestamp low */
uint32_t TimeStampHigh; /*!< Receive frame timestamp high */
#if CONFIG_IDF_TARGET_ESP32P4
// TODO: must be 64B aligned for ESP32P4 (due to cache arrangement)
// Could be better optimized (EMAC DMA block supports 32/64/128)?
uint32_t Reserved8;
uint32_t Reserved9;
uint32_t Reserved10;
uint32_t Reserved11;
uint32_t Reserved12;
uint32_t Reserved13;
uint32_t Reserved14;
uint32_t Reserved15;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
// descriptor must be aligned (due to cache arrangement)
uint8_t CacheAlign[EMAC_HAL_DMA_DESC_SIZE - 32]; // 32 is size of EMAC DMA descriptor without alignment
#endif
} eth_dma_rx_descriptor_t;
ASSERT_TYPE_SIZE(eth_dma_rx_descriptor_t, DMA_DESC_SIZE);
ASSERT_TYPE_SIZE(eth_dma_rx_descriptor_t, EMAC_HAL_DMA_DESC_SIZE);
typedef struct emac_mac_dev_s *emac_mac_soc_regs_t;
typedef struct emac_dma_dev_s *emac_dma_soc_regs_t;
@ -278,72 +268,10 @@ void emac_hal_start(emac_hal_context_t *hal);
* @return
* - ESP_OK: succeed
* - ESP_ERR_INVALID_STATE: previous frame transmission/reception is not completed. When this error occurs,
* wait and reapeat the EMAC stop again.
* wait and repeat the EMAC stop again.
*/
esp_err_t emac_hal_stop(emac_hal_context_t *hal);
/**
* @brief Transmit data from buffer over EMAC
*
* @param[in] hal EMAC HAL context infostructure
* @param[in] buf buffer to be transmitted
* @param[in] length length of the buffer
* @return number of transmitted bytes when success
*/
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
/**
* @brief Transmit data from multiple buffers over EMAC in single Ethernet frame. Data will be joint into
* single frame in order in which the buffers are stored in input array.
*
* @param[in] hal EMAC HAL context infostructure
* @param[in] buffs array of pointers to buffers to be transmitted
* @param[in] lengths array of lengths of the buffers
* @param[in] inbuffs_cnt number of buffers (i.e. input arrays size)
* @return number of transmitted bytes when success
*
* @pre @p lengths array must have the same size as @p buffs array and their elements need to be stored in the same
* order, i.e. lengths[1] is a length assocaited with data buffer referenced at buffs[1] position.
*/
uint32_t emac_hal_transmit_multiple_buf_frame(emac_hal_context_t *hal, uint8_t **buffs, uint32_t *lengths, uint32_t inbuffs_cnt);
/**
* @brief Allocate buffer with size equal to actually received Ethernet frame size.
*
* @param[in] hal EMAC HAL context infostructure
* @param[in, out] size as an input defines maximum size of buffer to be allocated. As an output, indicates actual size of received
* Ethernet frame which is waiting to be processed. Returned size may be 0 when there is no waiting frame.
*
* @note If maximum allowed size of buffer to be allocated is less than actual size of received Ethernet frame, the buffer
* is allocated with that limit and the frame will be truncated by emac_hal_receive_frame.
*
* @return Pointer to allocated buffer
* NULL when allocation fails or when there is no waiting Ethernet frame
*/
uint8_t *emac_hal_alloc_recv_buf(emac_hal_context_t *hal, uint32_t *size);
/**
* @brief Copy received Ethernet frame from EMAC DMA memory space to application.
*
* @param[in] hal EMAC HAL context infostructure
* @param[in] buf buffer into which the Ethernet frame is to be copied
* @param[in] size buffer size. When buffer was allocated by ::emac_hal_alloc_recv_buf, this parameter needs to be set
* to EMAC_HAL_BUF_SIZE_AUTO
* @param[out] frames_remain number of frames remaining to be processed
* @param[out] free_desc muber of free DMA Rx descriptors
*
* @return number of copied bytes when success
* 0 when there is no waiting Ethernet frame or on error
*
* @note FCS field is never copied
* @note If buffer size is less than actual size of received Ethernet frame, the frame will be truncated.
* @note When this function is called with EMAC_HAL_BUF_SIZE_AUTO size parameter, buffer needs to be allocated by
* ::emac_hal_alloc_recv_buf function at first.
*/
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc);
uint32_t emac_hal_flush_recv_frame(emac_hal_context_t *hal, uint32_t *frames_remain, uint32_t *free_desc);
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable);
#define emac_hal_get_intr_enable_status(hal) emac_ll_get_intr_enable_status((hal)->dma_regs)

View File

@ -5,4 +5,4 @@ if(CONFIG_MQTT_PROTOCOL_5)
endif()
idf_component_register(SRCS "${srcs}"
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update esp_eth esp_netif spi_flash common)
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common)

View File

@ -1,4 +1,4 @@
set(srcs test_mqtt5_client_broker.c test_mqtt5.c)
idf_component_register(SRCS "${srcs}"
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update esp_eth esp_netif spi_flash common)
PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common)

View File

@ -39,6 +39,10 @@ if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED)
list(APPEND srcs "${target_folder}/dedic_gpio_periph.c")
endif()
if(CONFIG_SOC_EMAC_SUPPORTED)
list(APPEND srcs "${target_folder}/emac_periph.c")
endif()
if(CONFIG_SOC_GDMA_SUPPORTED)
list(APPEND srcs "${target_folder}/gdma_periph.c")
endif()

View File

@ -0,0 +1,224 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/emac_periph.h"
#include "soc/io_mux_reg.h"
const emac_io_info_t emac_io_idx = {
.mdc_idx = EMAC_MDC_O_IDX,
.mdo_idx = EMAC_MDO_O_IDX,
.mdi_idx = EMAC_MDI_I_IDX,
.mii_tx_clk_i_idx = SIG_GPIO_OUT_IDX, // indicates EMAC signal cannot be connected via GPIO Matrix on the target
.mii_tx_en_o_idx = SIG_GPIO_OUT_IDX,
.mii_txd0_o_idx = SIG_GPIO_OUT_IDX,
.mii_txd1_o_idx = SIG_GPIO_OUT_IDX,
.mii_txd2_o_idx = SIG_GPIO_OUT_IDX,
.mii_txd3_o_idx = SIG_GPIO_OUT_IDX,
.mii_rx_clk_i_idx = SIG_GPIO_OUT_IDX,
.mii_rx_dv_i_idx = SIG_GPIO_OUT_IDX,
.mii_rxd0_i_idx = SIG_GPIO_OUT_IDX,
.mii_rxd1_i_idx = SIG_GPIO_OUT_IDX,
.mii_rxd2_i_idx = SIG_GPIO_OUT_IDX,
.mii_rxd3_i_idx = SIG_GPIO_OUT_IDX,
.mii_col_i_idx = SIG_GPIO_OUT_IDX,
.mii_crs_i_idx = SIG_GPIO_OUT_IDX,
.mii_tx_er_o_idx = SIG_GPIO_OUT_IDX,
.mii_rx_er_i_idx = SIG_GPIO_OUT_IDX
};
static const emac_iomux_info_t emac_rmii_iomux_clki[] = {
[0] = {
.gpio_num = 0,
.func = FUNC_GPIO0_EMAC_TX_CLK,
},
[1] = {
.gpio_num = GPIO_NUM_MAX, // indicates end of list
}
};
static const emac_iomux_info_t emac_rmii_iomux_clko[] = {
[0] = {
.gpio_num = 16,
.func = FUNC_GPIO16_EMAC_CLK_OUT,
},
[1] = {
.gpio_num = 17,
.func = FUNC_GPIO17_EMAC_CLK_OUT_180,
},
[2] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_tx_en[] = {
[0] = {
.gpio_num = 21,
.func = FUNC_GPIO21_EMAC_TX_EN,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_txd0[] = {
[0] = {
.gpio_num = 19,
.func = FUNC_GPIO19_EMAC_TXD0,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_txd1[] = {
[0] = {
.gpio_num = 22,
.func = FUNC_GPIO22_EMAC_TXD1,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_crs_dv[] = {
[0] = {
.gpio_num = 27,
.func = FUNC_GPIO27_EMAC_RX_DV,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_rxd0[] = {
[0] = {
.gpio_num = 25,
.func = FUNC_GPIO25_EMAC_RXD0,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_rxd1[] = {
[0] = {
.gpio_num = 26,
.func = FUNC_GPIO26_EMAC_RXD1,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_tx_er[] = {
[0] = {
.gpio_num = 4,
.func = FUNC_GPIO4_EMAC_TX_ER,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_mii_iomux_rx_er[] = {
[0] = {
.gpio_num = 13,
.func = FUNC_MTCK_EMAC_RX_ER,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
// MII Specific
static const emac_iomux_info_t emac_mii_iomux_clk_tx[] = {
[0] = {
.gpio_num = 0,
.func = FUNC_GPIO0_EMAC_TX_CLK,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_mii_iomux_txd2[] = {
[0] = {
.gpio_num = 14,
.func = FUNC_MTMS_EMAC_TXD2,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_mii_iomux_txd3[] = {
[0] = {
.gpio_num = 12,
.func = FUNC_MTDI_EMAC_TXD3,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_mii_iomux_clk_rx[] = {
[0] = {
.gpio_num = 5,
.func = FUNC_GPIO5_EMAC_RX_CLK,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_mii_iomux_rxd2[] = {
[0] = {
.gpio_num = 1,
.func = FUNC_U0TXD_EMAC_RXD2,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_mii_iomux_rxd3[] = {
[0] = {
.gpio_num = 15,
.func = FUNC_MTDO_EMAC_RXD3,
},
[1] = {
.gpio_num = GPIO_NUM_MAX,
}
};
const emac_rmii_iomux_info_t emac_rmii_iomux_pins = {
.clki = emac_rmii_iomux_clki,
.clko = emac_rmii_iomux_clko,
.tx_en = emac_rmii_mii_iomux_tx_en,
.txd0 = emac_rmii_mii_iomux_txd0,
.txd1 = emac_rmii_mii_iomux_txd1,
.crs_dv = emac_rmii_mii_iomux_crs_dv,
.rxd0 = emac_rmii_mii_iomux_rxd0,
.rxd1 = emac_rmii_mii_iomux_rxd1,
.tx_er = emac_rmii_mii_iomux_tx_er,
.rx_er = emac_rmii_mii_iomux_rx_er,
};
const emac_mii_iomux_info_t emac_mii_iomux_pins = {
.clk_tx = emac_mii_iomux_clk_tx,
.tx_en = emac_rmii_mii_iomux_tx_en,
.txd0 = emac_rmii_mii_iomux_txd0,
.txd1 = emac_rmii_mii_iomux_txd1,
.txd2 = emac_mii_iomux_txd2,
.txd3 = emac_mii_iomux_txd3,
.clk_rx = emac_mii_iomux_clk_rx,
.rx_dv = emac_rmii_mii_iomux_crs_dv,
.rxd0 = emac_rmii_mii_iomux_rxd0,
.rxd1 = emac_rmii_mii_iomux_rxd1,
.rxd2 = emac_mii_iomux_rxd2,
.rxd3 = emac_mii_iomux_rxd3,
.tx_er = emac_rmii_mii_iomux_tx_er,
.rx_er = emac_rmii_mii_iomux_rx_er,
};

View File

@ -0,0 +1,208 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/emac_periph.h"
#include "soc/io_mux_reg.h"
const emac_io_info_t emac_io_idx = {
.mdc_idx = MII_MDC_PAD_OUT_IDX,
.mdo_idx = MII_MDO_PAD_OUT_IDX,
.mdi_idx = MII_MDI_PAD_IN_IDX,
.mii_tx_clk_i_idx = EMAC_TX_CLK_PAD_IN_IDX,
.mii_tx_en_o_idx = EMAC_PHY_TXEN_PAD_OUT_IDX,
.mii_txd0_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX,
.mii_txd1_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX,
.mii_txd2_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX,
.mii_txd3_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX,
.mii_rx_clk_i_idx = EMAC_RX_CLK_PAD_IN_IDX,
.mii_rx_dv_i_idx = EMAC_PHY_RXDV_PAD_IN_IDX,
.mii_rxd0_i_idx = EMAC_PHY_RXD0_PAD_IN_IDX,
.mii_rxd1_i_idx = EMAC_PHY_RXD1_PAD_IN_IDX,
.mii_rxd2_i_idx = EMAC_PHY_RXD2_PAD_IN_IDX,
.mii_rxd3_i_idx = EMAC_PHY_RXD3_PAD_IN_IDX,
.mii_col_i_idx = EMAC_PHY_COL_PAD_IN_IDX,
.mii_crs_i_idx = EMAC_PHY_CRS_PAD_IN_IDX,
.mii_tx_er_o_idx = EMAC_PHY_TXER_PAD_OUT_IDX,
.mii_rx_er_i_idx = EMAC_PHY_RXER_PAD_IN_IDX
};
static const emac_iomux_info_t emac_rmii_iomux_clki[] = {
[0] = {
.gpio_num = 32,
.func = FUNC_GPIO32_EMAC_RMII_CLK_PAD,
},
[1] = {
.gpio_num = 44,
.func = FUNC_GPIO44_EMAC_RMII_CLK_PAD,
},
[2] = {
.gpio_num = 50,
.func = FUNC_GPIO50_EMAC_RMII_CLK_PAD,
},
[3] = {
.gpio_num = GPIO_NUM_MAX, // indicates end of list
}
};
static const emac_iomux_info_t emac_rmii_iomux_clko[] = {
[0] = {
.gpio_num = 23,
.func = FUNC_GPIO23_REF_50M_CLK_PAD,
},
[1] = {
.gpio_num = 39,
.func = FUNC_GPIO39_REF_50M_CLK_PAD,
},
[2] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_tx_en[] = {
[0] = {
.gpio_num = 33,
.func = FUNC_GPIO33_EMAC_PHY_TXEN_PAD,
},
[1] = {
.gpio_num = 40,
.func = FUNC_GPIO40_EMAC_PHY_TXEN_PAD,
},
[2] = {
.gpio_num = 49,
.func = FUNC_GPIO40_EMAC_PHY_TXEN_PAD,
},
[3] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_txd0[] = {
[0] = {
.gpio_num = 34,
.func = FUNC_GPIO34_EMAC_PHY_TXD0_PAD,
},
[1] = {
.gpio_num = 41,
.func = FUNC_GPIO41_EMAC_PHY_TXD0_PAD,
},
[2] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_txd1[] = {
[0] = {
.gpio_num = 35,
.func = FUNC_GPIO35_EMAC_PHY_TXD1_PAD,
},
[1] = {
.gpio_num = 42,
.func = FUNC_GPIO42_EMAC_PHY_TXD1_PAD,
},
[2] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_crs_dv[] = {
[0] = {
.gpio_num = 28,
.func = FUNC_GPIO28_EMAC_PHY_RXDV_PAD,
},
[1] = {
.gpio_num = 45,
.func = FUNC_GPIO45_EMAC_PHY_RXDV_PAD,
},
[2] = {
.gpio_num = 51,
.func = FUNC_GPIO51_EMAC_PHY_RXDV_PAD,
},
[3] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_rxd0[] = {
[0] = {
.gpio_num = 29,
.func = FUNC_GPIO29_EMAC_PHY_RXD0_PAD,
},
[1] = {
.gpio_num = 46,
.func = FUNC_GPIO46_EMAC_PHY_RXD0_PAD,
},
[2] = {
.gpio_num = 52,
.func = FUNC_GPIO52_EMAC_PHY_RXD0_PAD,
},
[3] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_rxd1[] = {
[0] = {
.gpio_num = 30,
.func = FUNC_GPIO30_EMAC_PHY_RXD1_PAD,
},
[1] = {
.gpio_num = 47,
.func = FUNC_GPIO47_EMAC_PHY_RXD1_PAD,
},
[2] = {
.gpio_num = 53,
.func = FUNC_GPIO53_EMAC_PHY_RXD1_PAD,
},
[3] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_tx_er[] = {
[0] = {
.gpio_num = 36,
.func = FUNC_GPIO36_EMAC_PHY_TXER_PAD,
},
[1] = {
.gpio_num = 43,
.func = FUNC_GPIO43_EMAC_PHY_TXER_PAD,
},
[2] = {
.gpio_num = GPIO_NUM_MAX,
}
};
static const emac_iomux_info_t emac_rmii_iomux_rx_er[] = {
[0] = {
.gpio_num = 31,
.func = FUNC_GPIO31_EMAC_PHY_RXER_PAD,
},
[1] = {
.gpio_num = 48,
.func = FUNC_GPIO48_EMAC_PHY_RXER_PAD,
},
[2] = {
.gpio_num = 54,
.func = FUNC_GPIO54_EMAC_PHY_RXER_PAD,
},
[3] = {
.gpio_num = GPIO_NUM_MAX,
}
};
const emac_rmii_iomux_info_t emac_rmii_iomux_pins = {
.clki = emac_rmii_iomux_clki,
.clko = emac_rmii_iomux_clko,
.tx_en = emac_rmii_iomux_tx_en,
.txd0 = emac_rmii_iomux_txd0,
.txd1 = emac_rmii_iomux_txd1,
.crs_dv = emac_rmii_iomux_crs_dv,
.rxd0 = emac_rmii_iomux_rxd0,
.rxd1 = emac_rmii_iomux_rxd1,
.tx_er = emac_rmii_iomux_tx_er,
.rx_er = emac_rmii_iomux_rx_er,
};
const emac_mii_iomux_info_t emac_mii_iomux_pins = { 0 };

View File

@ -1571,7 +1571,15 @@ config SOC_ASYNCHRONOUS_BUS_ERROR_MODE
bool
default y
config SOC_EMAC_USE_IO_MUX
config SOC_EMAC_IEEE_1588_SUPPORT
bool
default y
config SOC_EMAC_USE_MULTI_IO_MUX
bool
default y
config SOC_EMAC_MII_USE_GPIO_MATRIX
bool
default y

View File

@ -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
*/
@ -207,12 +207,12 @@
#define TWAI0_STANDBY_PAD_OUT_IDX 105
#define PWM1_CAP2_PAD_IN_IDX 106
#define TWAI1_STANDBY_PAD_OUT_IDX 106
#define GMII_MDI_PAD_IN_IDX 107
#define MII_MDI_PAD_IN_IDX 107
#define TWAI2_STANDBY_PAD_OUT_IDX 107
#define GMAC_PHY_COL_PAD_IN_IDX 108
#define GMII_MDC_PAD_OUT_IDX 108
#define GMAC_PHY_CRS_PAD_IN_IDX 109
#define GMII_MDO_PAD_OUT_IDX 109
#define EMAC_PHY_COL_PAD_IN_IDX 108
#define MII_MDC_PAD_OUT_IDX 108
#define EMAC_PHY_CRS_PAD_IN_IDX 109
#define MII_MDO_PAD_OUT_IDX 109
#define USB_OTG11_IDDIG_PAD_IN_IDX 110
#define USB_SRP_DISCHRGVBUS_PAD_OUT_IDX 110
#define USB_OTG11_AVALID_PAD_IN_IDX 111
@ -339,21 +339,21 @@
#define LCD_DATA_OUT_PAD_OUT22_IDX 176
#define CAM_DATA_IN_PAD_IN15_IDX 177
#define LCD_DATA_OUT_PAD_OUT23_IDX 177
#define GMAC_PHY_RXDV_PAD_IN_IDX 178
#define GMAC_PHY_TXEN_PAD_OUT_IDX 178
#define GMAC_PHY_RXD0_PAD_IN_IDX 179
#define GMAC_PHY_TXD0_PAD_OUT_IDX 179
#define GMAC_PHY_RXD1_PAD_IN_IDX 180
#define GMAC_PHY_TXD1_PAD_OUT_IDX 180
#define GMAC_PHY_RXD2_PAD_IN_IDX 181
#define GMAC_PHY_TXD2_PAD_OUT_IDX 181
#define GMAC_PHY_RXD3_PAD_IN_IDX 182
#define GMAC_PHY_TXD3_PAD_OUT_IDX 182
#define GMAC_PHY_RXER_PAD_IN_IDX 183
#define GMAC_PHY_TXER_PAD_OUT_IDX 183
#define GMAC_RX_CLK_PAD_IN_IDX 184
#define EMAC_PHY_RXDV_PAD_IN_IDX 178
#define EMAC_PHY_TXEN_PAD_OUT_IDX 178
#define EMAC_PHY_RXD0_PAD_IN_IDX 179
#define EMAC_PHY_TXD0_PAD_OUT_IDX 179
#define EMAC_PHY_RXD1_PAD_IN_IDX 180
#define EMAC_PHY_TXD1_PAD_OUT_IDX 180
#define EMAC_PHY_RXD2_PAD_IN_IDX 181
#define EMAC_PHY_TXD2_PAD_OUT_IDX 181
#define EMAC_PHY_RXD3_PAD_IN_IDX 182
#define EMAC_PHY_TXD3_PAD_OUT_IDX 182
#define EMAC_PHY_RXER_PAD_IN_IDX 183
#define EMAC_PHY_TXER_PAD_OUT_IDX 183
#define EMAC_RX_CLK_PAD_IN_IDX 184
#define DBG_CH0_CLK_IDX 184
#define GMAC_TX_CLK_PAD_IN_IDX 185
#define EMAC_TX_CLK_PAD_IN_IDX 185
#define DBG_CH1_CLK_IDX 185
#define PARLIO_RX_CLK_PAD_IN_IDX 186
#define PARLIO_RX_CLK_PAD_OUT_IDX 186

View File

@ -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
*/
@ -154,20 +154,21 @@
#define GPIO_PAD_SET_DRV(num, drv) PIN_SET_DRV(IOMUX_REG_GPIO##num, drv)
// TODO: IDF-7499, IDF-7495
// Pins defined here are all wrong (Ln153-164). On P4, these pins are individual pins, don't use normal GPIO pins anymore.
// SPI pins defined here are all wrong. On P4, these pins are individual pins, don't use normal GPIO pins anymore.
// Please check iomux_mspi_pin_struct/reg.h
#define SPI_CS1_GPIO_NUM 26
#define SPI_HD_GPIO_NUM 27
#define SPI_WP_GPIO_NUM 28
#define SPI_CS0_GPIO_NUM 29
#define SPI_CLK_GPIO_NUM 30
#define SPI_Q_GPIO_NUM 31
#define SPI_D_GPIO_NUM 32
#define SPI_D4_GPIO_NUM 33
#define SPI_D5_GPIO_NUM 34
#define SPI_D6_GPIO_NUM 35
#define SPI_D7_GPIO_NUM 36
#define SPI_DQS_GPIO_NUM 37
#include "soc/gpio_num.h"
#define SPI_CS1_GPIO_NUM GPIO_NUM_MAX
#define SPI_HD_GPIO_NUM GPIO_NUM_MAX
#define SPI_WP_GPIO_NUM GPIO_NUM_MAX
#define SPI_CS0_GPIO_NUM GPIO_NUM_MAX
#define SPI_CLK_GPIO_NUM GPIO_NUM_MAX
#define SPI_Q_GPIO_NUM GPIO_NUM_MAX
#define SPI_D_GPIO_NUM GPIO_NUM_MAX
#define SPI_D4_GPIO_NUM GPIO_NUM_MAX
#define SPI_D5_GPIO_NUM GPIO_NUM_MAX
#define SPI_D6_GPIO_NUM GPIO_NUM_MAX
#define SPI_D7_GPIO_NUM GPIO_NUM_MAX
#define SPI_DQS_GPIO_NUM GPIO_NUM_MAX
#define SD_CLK_GPIO_NUM 43
#define SD_CMD_GPIO_NUM 44
@ -331,63 +332,63 @@
#define PERIPHS_IO_MUX_U_PAD_GPIO28 (REG_IO_MUX_BASE + 0x74)
#define FUNC_GPIO28_DBG_PSRAM_D_PAD 4
#define FUNC_GPIO28_GMAC_PHY_RXDV_PAD 3
#define FUNC_GPIO28_EMAC_PHY_RXDV_PAD 3
#define FUNC_GPIO28_SPI2_CS_PAD 2
#define FUNC_GPIO28_GPIO28 1
#define FUNC_GPIO28_GPIO28_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO29 (REG_IO_MUX_BASE + 0x78)
#define FUNC_GPIO29_DBG_PSRAM_Q_PAD 4
#define FUNC_GPIO29_GMAC_PHY_RXD0_PAD 3
#define FUNC_GPIO29_EMAC_PHY_RXD0_PAD 3
#define FUNC_GPIO29_SPI2_D_PAD 2
#define FUNC_GPIO29_GPIO29 1
#define FUNC_GPIO29_GPIO29_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO30 (REG_IO_MUX_BASE + 0x7C)
#define FUNC_GPIO30_DBG_PSRAM_WP_PAD 4
#define FUNC_GPIO30_GMAC_PHY_RXD1_PAD 3
#define FUNC_GPIO30_EMAC_PHY_RXD1_PAD 3
#define FUNC_GPIO30_SPI2_CK_PAD 2
#define FUNC_GPIO30_GPIO30 1
#define FUNC_GPIO30_GPIO30_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO31 (REG_IO_MUX_BASE + 0x80)
#define FUNC_GPIO31_DBG_PSRAM_HOLD_PAD 4
#define FUNC_GPIO31_GMAC_PHY_RXER_PAD 3
#define FUNC_GPIO31_EMAC_PHY_RXER_PAD 3
#define FUNC_GPIO31_SPI2_Q_PAD 2
#define FUNC_GPIO31_GPIO31 1
#define FUNC_GPIO31_GPIO31_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO32 (REG_IO_MUX_BASE + 0x84)
#define FUNC_GPIO32_DBG_PSRAM_DQ4_PAD 4
#define FUNC_GPIO32_GMAC_RMII_CLK_PAD 3
#define FUNC_GPIO32_EMAC_RMII_CLK_PAD 3
#define FUNC_GPIO32_SPI2_HOLD_PAD 2
#define FUNC_GPIO32_GPIO32 1
#define FUNC_GPIO32_GPIO32_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO33 (REG_IO_MUX_BASE + 0x88)
#define FUNC_GPIO33_DBG_PSRAM_DQ5_PAD 4
#define FUNC_GPIO33_GMAC_PHY_TXEN_PAD 3
#define FUNC_GPIO33_EMAC_PHY_TXEN_PAD 3
#define FUNC_GPIO33_SPI2_WP_PAD 2
#define FUNC_GPIO33_GPIO33 1
#define FUNC_GPIO33_GPIO33_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO34 (REG_IO_MUX_BASE + 0x8C)
#define FUNC_GPIO34_DBG_PSRAM_DQ6_PAD 4
#define FUNC_GPIO34_GMAC_PHY_TXD0_PAD 3
#define FUNC_GPIO34_EMAC_PHY_TXD0_PAD 3
#define FUNC_GPIO34_SPI2_IO4_PAD 2
#define FUNC_GPIO34_GPIO34 1
#define FUNC_GPIO34_GPIO34_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO35 (REG_IO_MUX_BASE + 0x90)
#define FUNC_GPIO35_DBG_PSRAM_DQ7_PAD 4
#define FUNC_GPIO35_GMAC_PHY_TXD1_PAD 3
#define FUNC_GPIO35_EMAC_PHY_TXD1_PAD 3
#define FUNC_GPIO35_SPI2_IO5_PAD 2
#define FUNC_GPIO35_GPIO35 1
#define FUNC_GPIO35_GPIO35_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO36 (REG_IO_MUX_BASE + 0x94)
#define FUNC_GPIO36_DBG_PSRAM_DQS_0_PAD 4
#define FUNC_GPIO36_GMAC_PHY_TXER_PAD 3
#define FUNC_GPIO36_EMAC_PHY_TXER_PAD 3
#define FUNC_GPIO36_SPI2_IO6_PAD 2
#define FUNC_GPIO36_GPIO36 1
#define FUNC_GPIO36_GPIO36_0 0
@ -411,99 +412,99 @@
#define PERIPHS_IO_MUX_U_PAD_GPIO40 (REG_IO_MUX_BASE + 0xA4)
#define FUNC_GPIO40_DBG_PSRAM_DQ9_PAD 4
#define FUNC_GPIO40_GMAC_PHY_TXEN_PAD 3
#define FUNC_GPIO40_EMAC_PHY_TXEN_PAD 3
#define FUNC_GPIO40_BIST_PAD 2
#define FUNC_GPIO40_GPIO40 1
#define FUNC_GPIO40_SD1_CDATA1_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO41 (REG_IO_MUX_BASE + 0xA8)
#define FUNC_GPIO41_DBG_PSRAM_DQ10_PAD 4
#define FUNC_GPIO41_GMAC_PHY_TXD0_PAD 3
#define FUNC_GPIO41_EMAC_PHY_TXD0_PAD 3
#define FUNC_GPIO41_BIST_PAD 2
#define FUNC_GPIO41_GPIO41 1
#define FUNC_GPIO41_SD1_CDATA2_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO42 (REG_IO_MUX_BASE + 0xAC)
#define FUNC_GPIO42_DBG_PSRAM_DQ11_PAD 4
#define FUNC_GPIO42_GMAC_PHY_TXD1_PAD 3
#define FUNC_GPIO42_EMAC_PHY_TXD1_PAD 3
#define FUNC_GPIO42_BIST_PAD 2
#define FUNC_GPIO42_GPIO42 1
#define FUNC_GPIO42_SD1_CDATA3_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO43 (REG_IO_MUX_BASE + 0xB0)
#define FUNC_GPIO43_DBG_PSRAM_DQ12_PAD 4
#define FUNC_GPIO43_GMAC_PHY_TXER_PAD 3
#define FUNC_GPIO43_EMAC_PHY_TXER_PAD 3
#define FUNC_GPIO43_BIST_PAD 2
#define FUNC_GPIO43_GPIO43 1
#define FUNC_GPIO43_SD1_CCLK_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO44 (REG_IO_MUX_BASE + 0xB4)
#define FUNC_GPIO44_DBG_PSRAM_DQ13_PAD 4
#define FUNC_GPIO44_GMAC_RMII_CLK_PAD 3
#define FUNC_GPIO44_EMAC_RMII_CLK_PAD 3
#define FUNC_GPIO44_BIST_PAD 2
#define FUNC_GPIO44_GPIO44 1
#define FUNC_GPIO44_SD1_CCMD_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO45 (REG_IO_MUX_BASE + 0xB8)
#define FUNC_GPIO45_DBG_PSRAM_DQ14_PAD 4
#define FUNC_GPIO45_GMAC_PHY_RXDV_PAD 3
#define FUNC_GPIO45_EMAC_PHY_RXDV_PAD 3
#define FUNC_GPIO45_BIST_PAD 2
#define FUNC_GPIO45_GPIO45 1
#define FUNC_GPIO45_SD1_CDATA4_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO46 (REG_IO_MUX_BASE + 0xBC)
#define FUNC_GPIO46_DBG_PSRAM_DQ15_PAD 4
#define FUNC_GPIO46_GMAC_PHY_RXD0_PAD 3
#define FUNC_GPIO46_EMAC_PHY_RXD0_PAD 3
#define FUNC_GPIO46_BIST_PAD 2
#define FUNC_GPIO46_GPIO46 1
#define FUNC_GPIO46_SD1_CDATA5_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO47 (REG_IO_MUX_BASE + 0xC0)
#define FUNC_GPIO47_DBG_PSRAM_DQS_1_PAD 4
#define FUNC_GPIO47_GMAC_PHY_RXD1_PAD 3
#define FUNC_GPIO47_EMAC_PHY_RXD1_PAD 3
#define FUNC_GPIO47_BIST_PAD 2
#define FUNC_GPIO47_GPIO47 1
#define FUNC_GPIO47_SD1_CDATA6_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO48 (REG_IO_MUX_BASE + 0xC4)
#define FUNC_GPIO48_GMAC_PHY_RXER_PAD 3
#define FUNC_GPIO48_EMAC_PHY_RXER_PAD 3
#define FUNC_GPIO48_BIST_PAD 2
#define FUNC_GPIO48_GPIO48 1
#define FUNC_GPIO48_SD1_CDATA7_PAD 0
#define PERIPHS_IO_MUX_U_PAD_GPIO49 (REG_IO_MUX_BASE + 0xC8)
#define FUNC_GPIO49_DBG_FLASH_CS_PAD 4
#define FUNC_GPIO49_GMAC_PHY_TXEN_PAD 3
#define FUNC_GPIO49_EMAC_PHY_TXEN_PAD 3
#define FUNC_GPIO49_GPIO49 1
#define FUNC_GPIO49_GPIO49_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO50 (REG_IO_MUX_BASE + 0xCC)
#define FUNC_GPIO50_DBG_FLASH_Q_PAD 4
#define FUNC_GPIO50_GMAC_RMII_CLK_PAD 3
#define FUNC_GPIO50_EMAC_RMII_CLK_PAD 3
#define FUNC_GPIO50_GPIO50 1
#define FUNC_GPIO50_GPIO50_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO51 (REG_IO_MUX_BASE + 0xD0)
#define FUNC_GPIO51_DBG_FLASH_WP_PAD 4
#define FUNC_GPIO51_GMAC_PHY_RXDV_PAD 3
#define FUNC_GPIO51_EMAC_PHY_RXDV_PAD 3
#define FUNC_GPIO51_GPIO51 1
#define FUNC_GPIO51_GPIO51_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO52 (REG_IO_MUX_BASE + 0xD4)
#define FUNC_GPIO52_DBG_FLASH_HOLD_PAD 4
#define FUNC_GPIO52_GMAC_PHY_RXD0_PAD 3
#define FUNC_GPIO52_EMAC_PHY_RXD0_PAD 3
#define FUNC_GPIO52_GPIO52 1
#define FUNC_GPIO52_GPIO52_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO53 (REG_IO_MUX_BASE + 0xD8)
#define FUNC_GPIO53_DBG_FLASH_CK_PAD 4
#define FUNC_GPIO53_GMAC_PHY_RXD1_PAD 3
#define FUNC_GPIO53_EMAC_PHY_RXD1_PAD 3
#define FUNC_GPIO53_GPIO53 1
#define FUNC_GPIO53_GPIO53_0 0
#define PERIPHS_IO_MUX_U_PAD_GPIO54 (REG_IO_MUX_BASE + 0xDC)
#define FUNC_GPIO54_DBG_FLASH_D_PAD 4
#define FUNC_GPIO54_GMAC_PHY_RXER_PAD 3
#define FUNC_GPIO54_EMAC_PHY_RXER_PAD 3
#define FUNC_GPIO54_GPIO54 1
#define FUNC_GPIO54_GPIO54_0 0

View File

@ -635,7 +635,9 @@
#define SOC_MEM_NON_CONTIGUOUS_SRAM (1)
#define SOC_ASYNCHRONOUS_BUS_ERROR_MODE (1)
/*--------------------------- EMAC --------------------------------*/
#define SOC_EMAC_USE_IO_MUX (1) /*!< GPIO matrix is used to select GPIO pads */
#define SOC_EMAC_IEEE_1588_SUPPORT (1) /*!< EMAC Supports IEEE1588 time stamping */
#define SOC_EMAC_USE_MULTI_IO_MUX (1) /*!< Multiple GPIO pad options exist to connect EMAC signal via IO_MUX */
#define SOC_EMAC_MII_USE_GPIO_MATRIX (1) /*!< EMAC MII signals are connected to GPIO pads via GPIO Matrix */
/*--------------------------- JPEG --------------------------------*/
#define SOC_JPEG_CODEC_SUPPORTED (1)

View File

@ -1,15 +1,89 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#include "soc/gpio_sig_map.h"
#include "soc/gpio_num.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_EMAC_SUPPORTED
/**
* This structure lists pin numbers
*/
typedef struct {
uint32_t mdc_idx;
uint32_t mdo_idx;
uint32_t mdi_idx;
uint32_t mii_tx_clk_i_idx;
uint32_t mii_tx_en_o_idx;
uint32_t mii_txd0_o_idx;
uint32_t mii_txd1_o_idx;
uint32_t mii_txd2_o_idx;
uint32_t mii_txd3_o_idx;
uint32_t mii_rx_clk_i_idx;
uint32_t mii_rx_dv_i_idx;
uint32_t mii_rxd0_i_idx;
uint32_t mii_rxd1_i_idx;
uint32_t mii_rxd2_i_idx;
uint32_t mii_rxd3_i_idx;
uint32_t mii_col_i_idx;
uint32_t mii_crs_i_idx;
uint32_t mii_rx_er_i_idx;
uint32_t mii_tx_er_o_idx;
} emac_io_info_t;
typedef struct {
gpio_num_t gpio_num;
uint32_t func;
} emac_iomux_info_t;
typedef struct {
const emac_iomux_info_t *clki;
const emac_iomux_info_t *clko;
const emac_iomux_info_t *tx_en;
const emac_iomux_info_t *txd0;
const emac_iomux_info_t *txd1;
const emac_iomux_info_t *crs_dv;
const emac_iomux_info_t *rxd0;
const emac_iomux_info_t *rxd1;
const emac_iomux_info_t *tx_er;
const emac_iomux_info_t *rx_er;
} emac_rmii_iomux_info_t;
typedef struct {
const emac_iomux_info_t *clk_tx;
const emac_iomux_info_t *tx_en;
const emac_iomux_info_t *txd0;
const emac_iomux_info_t *txd1;
const emac_iomux_info_t *txd2;
const emac_iomux_info_t *txd3;
const emac_iomux_info_t *clk_rx;
const emac_iomux_info_t *rx_dv;
const emac_iomux_info_t *rxd0;
const emac_iomux_info_t *rxd1;
const emac_iomux_info_t *rxd2;
const emac_iomux_info_t *rxd3;
const emac_iomux_info_t *tx_er;
const emac_iomux_info_t *rx_er;
const emac_iomux_info_t *col_in;
const emac_iomux_info_t *crs_in;
} emac_mii_iomux_info_t;
extern const emac_io_info_t emac_io_idx;
extern const emac_rmii_iomux_info_t emac_rmii_iomux_pins;
extern const emac_mii_iomux_info_t emac_mii_iomux_pins;
#endif // SOC_EMAC_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@ -149,6 +149,8 @@ INPUT = \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_com.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_driver.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_mac.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_mac_esp.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_mac_spi.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_netif_glue.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_phy_802_3.h \
$(PROJECT_PATH)/components/esp_eth/include/esp_eth_phy.h \

View File

@ -152,7 +152,7 @@ The Ethernet driver is composed of two parts: MAC and PHY.
.. only:: esp32
.. note::
The ``REF_CLK`` can be also configured via Project Configuration when :cpp:member:`eth_esp32_emac_config_t::clock_config::mode` of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_DEFAULT`. Choose appropriately ``CONFIG_ETH_RMII_CLK_INPUT`` or ``CONFIG_ETH_RMII_CLK_OUTPUT`` option under :ref:`CONFIG_ETH_RMII_CLK_MODE` configuration based on your design as discussed above.
The ``REF_CLK`` can be also configured via Project Configuration when :cpp:class:`eth_esp32_emac_config_t` is initialized using :c:macro:`ETH_ESP32_EMAC_DEFAULT_CONFIG` macro. In the Project Configuration, choose appropriately ``CONFIG_ETH_RMII_CLK_INPUT`` or ``CONFIG_ETH_RMII_CLK_OUTPUT`` option under :ref:`CONFIG_ETH_RMII_CLK_MODE` configuration based on your design as discussed above.
.. warning::
If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT` (or ``CONFIG_ETH_RMII_CLK_OUTPUT`` is selected), then ``GPIO0`` can be used to output the ``REF_CLK`` signal. See :cpp:enumerator:`emac_rmii_clock_gpio_t::EMAC_APPL_CLK_OUT_GPIO` or :ref:`CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0` for more information.
@ -190,12 +190,12 @@ The Ethernet driver is composed of two parts: MAC and PHY.
**No matter which RMII clock mode you select, you really need to take care of the signal integrity of REF_CLK in your hardware design!** Keep the trace as short as possible. Keep it away from RF devices and inductor elements.
.. only:: not SOC_EMAC_USE_IO_MUX
.. only:: not SOC_EMAC_USE_MULTI_IO_MUX
.. note::
Signals used in the data plane are fixed to specific GPIOs via IO_MUX, they can not be modified to other GPIOs. Signals used in the control plane can be routed to any free GPIOs via Matrix. Please refer to :doc:`ESP32-Ethernet-Kit <../../hw-reference/esp32/get-started-ethernet-kit>` for hardware design example.
.. only:: SOC_EMAC_USE_IO_MUX
.. only:: SOC_EMAC_USE_MULTI_IO_MUX
.. note::
Signals used in the data plane can be configured to predefined set of GPIOs via IO_MUX for the RMII, see below table. The data plane GPIO configuration is performed by the driver based on content of :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`. Signals used in the control plane can be routed to any free GPIOs via GPIO Matrix.
@ -252,7 +252,7 @@ Basic common configuration for MAC layer is described in :cpp:class:`eth_mac_con
* :cpp:member:`eth_esp32_emac_config_t::intr_priority`: sets the priority of the MAC interrupt. If it is set to ``0`` or a negative value, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. Note that *Low* and *Medium* interrupt priorities (1 to 3) can be set since these can be handled in C.
:SOC_EMAC_USE_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers.
:SOC_EMAC_USE_MULTI_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers.
:not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`: configuration of EMAC input interface clock when ``REF_CLK`` signal is generated internally and is looped back to the EMAC externally. The mode must be always configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`. This option is valid only when configuration of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`.
@ -551,12 +551,12 @@ Custom PHY Driver
There are multiple PHY manufacturers with wide portfolios of chips available. The ESP-IDF already supports several PHY chips however one can easily get to a point where none of them satisfies the user's actual needs due to price, features, stock availability, etc.
Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task.
Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task.
.. note::
Always consult with PHY datasheet since some PHY chips may not comply with IEEE 802.3, Section 22.2.4. It does not mean you are not able to create a custom PHY driver, but it just requires more effort. You will have to define all PHY management functions.
The majority of PHY management functionality required by the ESP-IDF Ethernet driver is covered by the :component_file:`esp_eth/src/esp_eth_phy_802_3.c`. However, the following may require developing chip-specific management functions:
The majority of PHY management functionality required by the ESP-IDF Ethernet driver is covered by the :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c`. However, the following may require developing chip-specific management functions:
* Link status which is almost always chip-specific
* Chip initialization, even though not strictly required, should be customized to at least ensure that the expected chip is used
@ -564,11 +564,11 @@ The majority of PHY management functionality required by the ESP-IDF Ethernet dr
**Steps to create a custom PHY driver:**
1. Define vendor-specific registry layout based on the PHY datasheet. See :component_file:`esp_eth/src/esp_eth_phy_ip101.c` as an example.
1. Define vendor-specific registry layout based on the PHY datasheet. See :component_file:`esp_eth/src/phy/esp_eth_phy_ip101.c` as an example.
2. Prepare derived PHY management object info structure which:
* must contain at least parent IEEE 802.3 :cpp:class:`phy_802_3_t` object
* optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality. See :component_file:`esp_eth/src/esp_eth_phy_ksz80xx.c` as an example.
* optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality. See :component_file:`esp_eth/src/phy/esp_eth_phy_ksz80xx.c` as an example.
3. Define chip-specific management call-back functions.
4. Initialize parent IEEE 802.3 object and re-assign chip-specific management call-back functions.
@ -585,6 +585,8 @@ API Reference
.. include-build-file:: inc/esp_eth_driver.inc
.. include-build-file:: inc/esp_eth_com.inc
.. include-build-file:: inc/esp_eth_mac.inc
.. include-build-file:: inc/esp_eth_mac_esp.inc
.. include-build-file:: inc/esp_eth_mac_spi.inc
.. include-build-file:: inc/esp_eth_phy.inc
.. include-build-file:: inc/esp_eth_phy_802_3.inc
.. include-build-file:: inc/esp_eth_netif_glue.inc

View File

@ -152,7 +152,7 @@
.. only:: esp32
.. note::
:cpp:member:`eth_esp32_emac_config_t::clock_config` 中的 :cpp:member:`eth_esp32_emac_config_t::clock_config::mode` 被设置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_DEFAULT` 时,也可以通过项目配置来配置 ``REF_CLK``根据上述个人设计,在 :ref:`CONFIG_ETH_RMII_CLK_MODE` 配置下选择适当的选项, ``CONFIG_ETH_RMII_CLK_INPUT`` 或是 ``CONFIG_ETH_RMII_CLK_OUTPUT``
使用 :c:macro:`ETH_ESP32_EMAC_DEFAULT_CONFIG` 宏初始化 :cpp:class:`eth_esp32_emac_config_t` 时,也可以通过项目配置来配置 ``REF_CLK``在项目配置中,根据上述个人设计,在 :ref:`CONFIG_ETH_RMII_CLK_MODE` 配置下选择适当的选项, ``CONFIG_ETH_RMII_CLK_INPUT`` 或是 ``CONFIG_ETH_RMII_CLK_OUTPUT``
.. warning::
如果配置 RMII 时钟模式为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT` (或是选择 ``CONFIG_ETH_RMII_CLK_OUTPUT``,那么就可以使用 ``GPIO0`` 输出 ``REF_CLK`` 信号。更多细节,请参见 :cpp:enumerator:`emac_rmii_clock_gpio_t::EMAC_APPL_CLK_OUT_GPIO` 或是 :ref:`CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0`
@ -190,12 +190,12 @@
**无论选择哪种 RMII 时钟模式,都请确保硬件设计中 REF_CLK 的信号完整性!** 信号线越短越好,并远离 RF 设备和电感。
.. only:: not SOC_EMAC_USE_IO_MUX
.. only:: not SOC_EMAC_USE_MULTI_IO_MUX
.. note::
数据平面中使用的信号通过 IO_MUX 连接至特定的 GPIO这些信号无法配置到其他 GPIO 上。控制平面中使用的信号可以通过矩阵路由到任何空闲的 GPIO 上。相关硬件设计示例,请参阅 :doc:`ESP32-Ethernet-Kit <../../hw-reference/esp32/get-started-ethernet-kit>`
.. only:: SOC_EMAC_USE_IO_MUX
.. only:: SOC_EMAC_USE_MULTI_IO_MUX
.. note::
数据平面中使用的信号可以通过 IO_MUX 配置为 RMII 预定义的 GPIO请参阅下表。数据平面 GPIO 配置由驱动程序根据 :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio` 的内容执行。控制平面中使用的信号可以通过 GPIO 矩阵路由到任何空闲的 GPIO。
@ -252,7 +252,7 @@ MAC 的相关配置可以在 :cpp:class:`eth_mac_config_t` 中找到,具体包
* :cpp:member:`eth_esp32_emac_config_t::intr_priority` 设置 MAC 中断的优先级。如果设置为 ``0`` 或负值,则驱动程序将分配一个具有默认优先级的中断。否则,驱动程序将使用给定的优先级。请注意,可以设置 **、 *中* 中断优先级1 到 3因为这可以在 C 中处理。
:SOC_EMAC_USE_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`EMAC MII/RMII 数据平面 GPIO 编号配置。
:SOC_EMAC_USE_MULTI_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`EMAC MII/RMII 数据平面 GPIO 编号配置。
:not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`:当 ``REF_CLK`` 信号在内部生成并从外部回环到 EMAC 时,配置 EMAC 输入接口时钟。必须始终将 EMAC 的模式配置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`。此选项仅在 :cpp:member:`eth_esp32_emac_config_t::clock_config` 的配置设置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT` 时有效。
@ -551,12 +551,12 @@ ESP-IDF 在宏 :c:macro:`ETH_DEFAULT_CONFIG` 中为安装驱动程序提供了
市面上有多家 PHY 芯片制造商提供各种类型的芯片。ESP-IDF 现已支持数种 PHY 芯片,但是由于价格、功能、库存等原因,有时用户还是无法找到一款能满足其实际需求的芯片。
好在 IEEE 802.3 在其 22.2.4 管理功能部分对 EMAC 和 PHY 之间的管理接口进行了标准化。该部分定义了所谓的 ”MII 管理接口”规范,用于控制 PHY 和收集 PHY 的状态,还定义了一组管理寄存器来控制芯片行为、链接属性、自动协商配置等。在 ESP-IDF 中,这项基本的管理功能是由 :component_file:`esp_eth/src/esp_eth_phy_802_3.c` 实现的,这也大大降低了创建新的自定义 PHY 芯片驱动的难度。
好在 IEEE 802.3 在其 22.2.4 管理功能部分对 EMAC 和 PHY 之间的管理接口进行了标准化。该部分定义了所谓的 ”MII 管理接口”规范,用于控制 PHY 和收集 PHY 的状态,还定义了一组管理寄存器来控制芯片行为、链接属性、自动协商配置等。在 ESP-IDF 中,这项基本的管理功能是由 :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` 实现的,这也大大降低了创建新的自定义 PHY 芯片驱动的难度。
.. note::
由于一些 PHY 芯片可能不符合 IEEE 802.3 第 22.2.4 节的规定,所以请首先查看 PHY 数据手册。不过,就算芯片不符合规定,依旧可以创建自定义 PHY 驱动程序,只是由于需要自行定义所有的 PHY 管理功能,这个过程将变得较为复杂。
ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 :component_file:`esp_eth/src/esp_eth_phy_802_3.c` 中。不过对于以下几项,可能仍需针对不同芯片开发具体的管理功能:
ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` 中。不过对于以下几项,可能仍需针对不同芯片开发具体的管理功能:
* 链接状态。此项总是由使用的具体芯片决定
* 芯片初始化。即使不存在严格的限制,也应进行自定义,以确保使用的是符合预期的芯片
@ -564,11 +564,11 @@ ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在
**创建自定义 PHY 驱动程序的步骤:**
1. 请根据 PHY 数据手册,定义针对供应商的特定注册表布局。示例请参见 :component_file:`esp_eth/src/esp_eth_phy_ip101.c`
1. 请根据 PHY 数据手册,定义针对供应商的特定注册表布局。示例请参见 :component_file:`esp_eth/src/phy/esp_eth_phy_ip101.c`
2. 准备衍生的 PHY 管理对象信息结构,该结构:
* 必须至少包含 IEEE 802.3 :cpp:class:`phy_802_3_t` 父对象
* 可选择包含额外的变量,以支持非 IEEE 802.3 或定制功能。示例请参见 :component_file:`esp_eth/src/esp_eth_phy_ksz80xx.c`
* 可选择包含额外的变量,以支持非 IEEE 802.3 或定制功能。示例请参见 :component_file:`esp_eth/src/phy/esp_eth_phy_ksz80xx.c`
3. 定义针对芯片的特定管理回调功能。
4. 初始化 IEEE 802.3 父对象并重新分配针对芯片的特定管理回调功能。
@ -585,6 +585,8 @@ API 参考
.. include-build-file:: inc/esp_eth_driver.inc
.. include-build-file:: inc/esp_eth_com.inc
.. include-build-file:: inc/esp_eth_mac.inc
.. include-build-file:: inc/esp_eth_mac_esp.inc
.. include-build-file:: inc/esp_eth_mac_spi.inc
.. include-build-file:: inc/esp_eth_phy.inc
.. include-build-file:: inc/esp_eth_phy_802_3.inc
.. include-build-file:: inc/esp_eth_netif_glue.inc

View File

@ -99,8 +99,8 @@ static esp_netif_t *eth_start(void)
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
#if CONFIG_EXAMPLE_ETH_PHY_IP101
s_phy = esp_eth_phy_new_ip101(&phy_config);

View File

@ -69,8 +69,8 @@ static esp_eth_handle_t eth_init_internal(esp_eth_mac_t **mac_out, esp_eth_phy_t
// Init vendor specific MAC config to default
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
// Update vendor specific MAC config based on board configuration
esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
// The DMA is shared resource between EMAC and the SPI. Therefore, adjust
// EMAC DMA burst length when SPI Ethernet is used along with EMAC.

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -24,6 +24,18 @@ extern "C" {
*/
esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out);
/**
* @brief De-initialize array of Ethernet drivers
* @note All Ethernet drivers in the array must be stopped prior calling this function.
*
* @param[in] eth_handles array of Ethernet drivers to be de-initialized
* @param[in] eth_cnt number of Ethernets drivers to be de-initialized
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG when passed invalid pointers
*/
esp_err_t example_eth_deinit(esp_eth_handle_t *eth_handles, uint8_t eth_cnt);
#ifdef __cplusplus
}
#endif

View File

@ -36,7 +36,7 @@
static const char *TAG = "example";
// Async reqeusts are queued here while they wait to
// Async requests are queued here while they wait to
// be processed by the workers
static QueueHandle_t async_req_queue;

View File

@ -397,9 +397,9 @@ static httpd_handle_t start_webserver(void)
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
#if CONFIG_IDF_TARGET_LINUX
// Setting port as 8001 when building for Linux. Port 80 can be used only by a priviliged user in linux.
// So when a unpriviliged user tries to run the application, it throws bind error and the server is not started.
// Port 8001 can be used by an unpriviliged user as well. So the application will not throw bind error and the
// Setting port as 8001 when building for Linux. Port 80 can be used only by a privileged user in linux.
// So when a unprivileged user tries to run the application, it throws bind error and the server is not started.
// Port 8001 can be used by an unprivileged user as well. So the application will not throw bind error and the
// server will be started.
config.server_port = 8001;
#endif // !CONFIG_IDF_TARGET_LINUX

View File

@ -11,7 +11,6 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
@ -89,13 +88,13 @@ static void app_multiple_handle(esp_ip4_addr_t *ip4_addr, esp_netif_t *esp_netif
ret = send(sock, payload, strlen(payload), 0);
if (ret < 0) {
ESP_LOGE(TAG, "\"%s\" Error occured during sending: errno %d", netif_name, errno);
ESP_LOGE(TAG, "\"%s\" Error occurred during sending: errno %d", netif_name, errno);
goto app_multiple_handle_fail;
}
ret = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (ret < 0) {
ESP_LOGE(TAG, "\"%s\" Error occured during receiving: errno %d", netif_name, errno);
ESP_LOGE(TAG, "\"%s\" Error occurred during receiving: errno %d", netif_name, errno);
} else if (ret > 0){
rx_buffer[ret] = 0; // Null-terminate whatever we received and treat like a string
ESP_LOGI(TAG, "\"%s\" Received Data %d bytes", netif_name, ret);

View File

@ -398,7 +398,6 @@ components/bt/host/bluedroid/stack/smp/smp_main.c
components/bt/host/bluedroid/stack/smp/smp_utils.c
components/console/linenoise/linenoise.c
components/console/linenoise/linenoise.h
components/esp_eth/src/ksz8851.h
components/esp_event/host_test/esp_event_unit_test/main/esp_event_test.cpp
components/esp_event/host_test/fixtures.hpp
components/esp_hid/include/esp_hidd.h
@ -718,7 +717,6 @@ components/soc/esp32s3/include/soc/wdev_reg.h
components/soc/esp32s3/ledc_periph.c
components/soc/esp32s3/uart_periph.c
components/soc/include/soc/dedic_gpio_periph.h
components/soc/include/soc/emac_periph.h
components/soc/include/soc/gpio_periph.h
components/soc/include/soc/ledc_periph.h
components/soc/lldesc.c