mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
parent
ee8a9e8410
commit
d15a9c2c48
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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.
|
||||
|
@ -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 doesn’t have directly relationship with EMAC peripheral. Sometimes this clock won’t 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, don’t 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
|
||||
|
296
components/esp_eth/include/esp_eth_mac_esp.h
Normal file
296
components/esp_eth/include/esp_eth_mac_esp.h
Normal 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 doesn’t have directly relationship with EMAC peripheral. Sometimes this clock won’t 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, don’t 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
|
31
components/esp_eth/include/esp_eth_mac_openeth.h
Normal file
31
components/esp_eth/include/esp_eth_mac_openeth.h
Normal 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
|
236
components/esp_eth/include/esp_eth_mac_spi.h
Normal file
236
components/esp_eth/include/esp_eth_mac_spi.h
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
265
components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c
Normal file
265
components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c
Normal 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;
|
||||
}
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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)
|
@ -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 */
|
@ -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"
|
@ -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");
|
@ -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"
|
||||
|
@ -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)
|
@ -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
|
@ -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;
|
@ -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"
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
224
components/soc/esp32/emac_periph.c
Normal file
224
components/soc/esp32/emac_periph.c
Normal 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,
|
||||
};
|
208
components/soc/esp32p4/emac_periph.c
Normal file
208
components/soc/esp32p4/emac_periph.c
Normal 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 };
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user