From 6bc957ee4f436540d8edf2f3de2dc777aef16557 Mon Sep 17 00:00:00 2001 From: Bogdan Kolendovskyy Date: Wed, 2 Aug 2023 12:28:18 +0200 Subject: [PATCH 1/8] esp_eth: add loopback test, change chip drivers to reflect chip specific behaviour In esp_eth_test_apps.c: Add test of loopback functionality. Change speed/duplex/autonegotiation test - remove need to enable loopback (required for it to work on some phys supported by ESP-IDF) In Kconfig.projbuild: Add parameters to select which configuration is used - standard or custom. Add for custom configuration parameters to select MDC and MDIO pins (required to work with WESP-32 and other boards that use non-standard pin assignments). In esp_eth_test_common.c: Add code to support changes made in Kconfig In sdkconfig.ci.default_rtl8201: Change config which is used. Now custom is used and MDC is gpio 16, MDIO is gpio 17. Reuqired to work with WESP-32 In esp_eth_phy_802_3.h: Make 802.3 API public. In esp_eth_phy_802_3.c: Add loopback check in eth_phy_802_3_set_duplex(). Now ESP_ERR_INVALID_STATE is invoked on attempt to set duplex to half when loopback is enabled. Remove static property from esp_eth_phy_802_3_autonego_ctrl and esp_eth_phy_802_3_loopback. In esp_eth_phy_dm9051.c: Add dm9051_loopback() because DM9051 requires setting additional bit to enable auto-negotiation loopback for data to be received. Add dm9051_set_speed() which invokes ESP_ERR_INVALID_STATE on attempt to set speed to 10 Mbps when loopback is enabled because such speed configuration is unsupported. In esp_eth_phy_ksz80xx.c: Add ksz80xx_set_speed() which invokes ESP_ERR_INVALID_STATE on attempt to set speed to 10 Mbps when loopback is enabled because such speed configuration is unsupported. In esp_eth_phy_ksz8851snl.c: Change phy_ksz8851_set_duplex() to invoke ESP_ERR_INVALID_STATE on attempt to set duplex to half when loopback is enabled. In esp_eth_phy_dp83848.c, esp_eth_phy_rtl8201.c: Add autonego_ctrl implementation which prevents enabling autonegotiation when loopback is enabled. Add loopback implementation which disables autonegotiation prior to enabling loopback. In esp_eth_phy_lan87xx.c: Add autonego_ctrl implementation which prevents enabling autonegotiation when loopback is enabled. Add loopback implementation which disables autonegotiation prior to enabling loopback. Fix link indicating being down when loopback is enabled by force setting link up. --- .../esp_eth/include/esp_eth_phy_802_3.h | 145 ++++++++++++++- .../esp_eth/include/eth_phy_802_3_regs.h | 2 +- components/esp_eth/src/esp_eth_phy_802_3.c | 175 +++++++++++++----- components/esp_eth/src/esp_eth_phy_dm9051.c | 70 ++++++- components/esp_eth/src/esp_eth_phy_dp83848.c | 31 +++- components/esp_eth/src/esp_eth_phy_ksz80xx.c | 20 +- .../esp_eth/src/esp_eth_phy_ksz8851snl.c | 7 +- components/esp_eth/src/esp_eth_phy_lan87xx.c | 40 +++- components/esp_eth/src/esp_eth_phy_rtl8201.c | 31 +++- .../esp_eth/test_apps/main/Kconfig.projbuild | 15 ++ .../test_apps/main/esp_eth_test_apps.c | 154 ++++++++++++++- .../test_apps/main/esp_eth_test_common.c | 6 +- .../test_apps/sdkconfig.ci.default_rtl8201 | 4 + 13 files changed, 628 insertions(+), 72 deletions(-) diff --git a/components/esp_eth/include/esp_eth_phy_802_3.h b/components/esp_eth/include/esp_eth_phy_802_3.h index 9b808044c8..5eabdba53d 100644 --- a/components/esp_eth/include/esp_eth_phy_802_3.h +++ b/components/esp_eth/include/esp_eth_phy_802_3.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,6 +28,144 @@ typedef struct { int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */ } phy_802_3_t; +/** + * @brief Set Ethernet mediator + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param eth Ethernet mediator pointer + * @return + * - ESP_OK: Ethermet mediator set successfuly + * - 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); + +/** + * @brief Reset PHY + * + * @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_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3); + +/** + * @brief Control autonegotiation mode of Ethernet PHY + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @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_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); + +/** + * @brief Power control of Ethernet PHY + * + * @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_err_t esp_eth_phy_802_3_pwrctl(phy_802_3_t *phy_802_3, bool enable); + +/** + * @brief Set Ethernet PHY address + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param addr new PHY address + * @return + * - ESP_OK: Ethernet PHY address set + */ +esp_err_t esp_eth_phy_802_3_set_addr(phy_802_3_t *phy_802_3, uint32_t addr); + +/** + * @brief Get Ethernet PHY address + * + * @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_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); + +/** + * @brief Advertise pause function ability + * + * @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_err_t esp_eth_phy_802_3_advertise_pause_ability(phy_802_3_t *phy_802_3, uint32_t ability); + +/** + * @brief Set Ethernet PHY loopback mode + * + * @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_err_t esp_eth_phy_802_3_loopback(phy_802_3_t *phy_802_3, bool enable); + +/** + * @brief Set Ethernet PHY speed + * + * @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_err_t esp_eth_phy_802_3_set_speed(phy_802_3_t *phy_802_3, eth_speed_t speed); + +/** + * @brief Set Ethernet PHY duplex mode + * + * @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_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_err_t esp_eth_phy_802_3_set_duplex(phy_802_3_t *phy_802_3, eth_duplex_t duplex); + +/** + * @brief Initialize Ethernet PHY + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @return + * - ESP_OK: Ethernet PHY initialized successfuly + */ +esp_err_t esp_eth_phy_802_3_init(phy_802_3_t *phy_802_3); + +/** + * @brief Power off Eternet PHY + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @return + * - ESP_OK: Ethernet PHY powered off successfuly + */ +esp_err_t esp_eth_phy_802_3_deinit(phy_802_3_t *phy_802_3); + +/** + * @brief Delete Ethernet PHY infostructure + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @return + * - ESP_OK: Ethrnet PHY infostructure deleted + */ +esp_err_t esp_eth_phy_802_3_del(phy_802_3_t *phy_802_3); + /** * @brief Performs hardware reset with specific reset pin assertion time * @@ -116,7 +254,10 @@ esp_err_t esp_eth_phy_802_3_read_manufac_info(phy_802_3_t *phy_802_3, uint8_t *m * @return phy_802_3_t* * - address to parent IEEE 802.3 PHY object infostructure */ -phy_802_3_t *esp_eth_phy_into_phy_802_3(esp_eth_phy_t *phy); +inline __attribute__((always_inline)) phy_802_3_t *esp_eth_phy_into_phy_802_3(esp_eth_phy_t *phy) +{ + return __containerof(phy, phy_802_3_t, parent); +} /** * @brief Initializes configuration of parent IEEE 802.3 PHY object infostructure diff --git a/components/esp_eth/include/eth_phy_802_3_regs.h b/components/esp_eth/include/eth_phy_802_3_regs.h index d953ea09d0..bdecddf0c4 100644 --- a/components/esp_eth/include/eth_phy_802_3_regs.h +++ b/components/esp_eth/include/eth_phy_802_3_regs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/esp_eth/src/esp_eth_phy_802_3.c b/components/esp_eth/src/esp_eth_phy_802_3.c index b9725ae337..4157f02011 100644 --- a/components/esp_eth/src/esp_eth_phy_802_3.c +++ b/components/esp_eth/src/esp_eth_phy_802_3.c @@ -16,12 +16,98 @@ #include "esp_rom_sys.h" #include "esp_eth_phy_802_3.h" +// Default reset assertion time is selected to be 100us as it is most commonly used value among PHY chips. +#define PHY_RESET_ASSERTION_TIME_US 100 + static const char *TAG = "eth_phy_802_3"; -static esp_err_t eth_phy_802_3_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +static esp_err_t set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_set_mediator(phy_802_3, eth); +} + +static esp_err_t reset(esp_eth_phy_t *phy) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_reset(phy_802_3); +} + +static esp_err_t reset_hw_default(esp_eth_phy_t *phy) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_reset_hw(phy_802_3, PHY_RESET_ASSERTION_TIME_US); +} + +static esp_err_t autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat); +} + +static esp_err_t pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_pwrctl(phy_802_3, enable); +} + +static esp_err_t set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_set_addr(phy_802_3, addr); +} + +static esp_err_t get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_get_addr(phy_802_3, addr); +} + +static esp_err_t advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_advertise_pause_ability(phy_802_3, ability); +} + +static esp_err_t loopback(esp_eth_phy_t *phy, bool enable) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_loopback(phy_802_3, enable); +} + +static esp_err_t set_speed(esp_eth_phy_t *phy, eth_speed_t speed) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_set_speed(phy_802_3, speed); +} + +static esp_err_t set_duplex(esp_eth_phy_t *phy, eth_duplex_t duplex) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_set_duplex(phy_802_3, duplex); +} + +static esp_err_t init(esp_eth_phy_t *phy) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_init(phy_802_3); +} + +static esp_err_t deinit(esp_eth_phy_t *phy) +{ + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + return esp_eth_phy_802_3_deinit(phy_802_3); +} + +static esp_err_t del(esp_eth_phy_t *phy) +{ + free(phy); + return ESP_OK; +} + +esp_err_t esp_eth_phy_802_3_set_mediator(phy_802_3_t *phy_802_3, esp_eth_mediator_t *eth) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "mediator can't be null"); phy_802_3->eth = eth; return ESP_OK; @@ -29,10 +115,9 @@ err: return ret; } -static esp_err_t eth_phy_802_3_reset(esp_eth_phy_t *phy) +esp_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); phy_802_3->link_status = ETH_LINK_DOWN; esp_eth_mediator_t *eth = phy_802_3->eth; bmcr_reg_t bmcr = {.reset = 1}; @@ -62,16 +147,14 @@ err: * @return * - ESP_OK on success */ -static esp_err_t eth_phy_802_3_reset_hw_default(esp_eth_phy_t *phy) +esp_err_t esp_eth_phy_802_3_reset_hw_default(phy_802_3_t *phy_802_3) { - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); - return esp_eth_phy_802_3_reset_hw(phy_802_3, 100); + return esp_eth_phy_802_3_reset_hw(phy_802_3, PHY_RESET_ASSERTION_TIME_US); } -static esp_err_t eth_phy_802_3_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat) +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) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); esp_eth_mediator_t *eth = phy_802_3->eth; bmcr_reg_t bmcr; @@ -131,10 +214,9 @@ err: return ret; } -static esp_err_t eth_phy_802_3_pwrctl(esp_eth_phy_t *phy, bool enable) +esp_err_t esp_eth_phy_802_3_pwrctl(phy_802_3_t *phy_802_3, bool enable) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); esp_eth_mediator_t *eth = phy_802_3->eth; bmcr_reg_t bmcr; 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"); @@ -166,17 +248,15 @@ err: return ret; } -static esp_err_t eth_phy_802_3_set_addr(esp_eth_phy_t *phy, uint32_t addr) +esp_err_t esp_eth_phy_802_3_set_addr(phy_802_3_t *phy_802_3, uint32_t addr) { - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); phy_802_3->addr = addr; return ESP_OK; } -static esp_err_t eth_phy_802_3_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +esp_err_t esp_eth_phy_802_3_get_addr(phy_802_3_t *phy_802_3, uint32_t *addr) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null"); *addr = phy_802_3->addr; return ESP_OK; @@ -184,10 +264,9 @@ err: return ret; } -static esp_err_t eth_phy_802_3_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) +esp_err_t esp_eth_phy_802_3_advertise_pause_ability(phy_802_3_t *phy_802_3, uint32_t ability) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); esp_eth_mediator_t *eth = phy_802_3->eth; /* Set PAUSE function ability */ anar_reg_t anar; @@ -205,10 +284,9 @@ err: return ret; } -static esp_err_t eth_phy_802_3_loopback(esp_eth_phy_t *phy, bool enable) +esp_err_t esp_eth_phy_802_3_loopback(phy_802_3_t *phy_802_3, bool enable) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); esp_eth_mediator_t *eth = phy_802_3->eth; /* Set Loopback function */ bmcr_reg_t bmcr; @@ -222,12 +300,12 @@ static esp_err_t eth_phy_802_3_loopback(esp_eth_phy_t *phy, bool enable) return ESP_OK; err: return ret; + } -static esp_err_t eth_phy_802_3_set_speed(esp_eth_phy_t *phy, eth_speed_t speed) +esp_err_t esp_eth_phy_802_3_set_speed(phy_802_3_t *phy_802_3, eth_speed_t speed) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); esp_eth_mediator_t *eth = phy_802_3->eth; /* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */ @@ -244,10 +322,9 @@ err: return ret; } -static esp_err_t eth_phy_802_3_set_duplex(esp_eth_phy_t *phy, eth_duplex_t duplex) +esp_err_t esp_eth_phy_802_3_set_duplex(phy_802_3_t *phy_802_3, eth_duplex_t duplex) { esp_err_t ret = ESP_OK; - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); esp_eth_mediator_t *eth = phy_802_3->eth; /* Since the link is going to be reconfigured, consider it down to be status updated once the driver re-started */ @@ -256,6 +333,9 @@ static esp_err_t eth_phy_802_3_set_duplex(esp_eth_phy_t *phy, eth_duplex_t duple /* Set duplex mode */ bmcr_reg_t bmcr; 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"); + if (bmcr.en_loopback) { + ESP_GOTO_ON_FALSE(duplex == ETH_DUPLEX_FULL, ESP_ERR_INVALID_STATE, err, TAG, "Duplex mode must be FULL for loopback operation"); + } bmcr.duplex_mode = duplex; ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed"); @@ -264,21 +344,19 @@ err: return ret; } -static esp_err_t eth_phy_802_3_init(esp_eth_phy_t *phy) +esp_err_t esp_eth_phy_802_3_init(phy_802_3_t *phy_802_3) { - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); return esp_eth_phy_802_3_basic_phy_init(phy_802_3); } -static esp_err_t eth_phy_802_3_deinit(esp_eth_phy_t *phy) +esp_err_t esp_eth_phy_802_3_deinit(phy_802_3_t *phy_802_3) { - phy_802_3_t *phy_802_3 = __containerof(phy, phy_802_3_t, parent); return esp_eth_phy_802_3_basic_phy_deinit(phy_802_3); } -static esp_err_t eth_phy_802_3_del(esp_eth_phy_t *phy) +esp_err_t esp_eth_phy_802_3_del(phy_802_3_t *phy_802_3) { - free(phy); + free(phy_802_3); return ESP_OK; } @@ -326,9 +404,9 @@ esp_err_t esp_eth_phy_802_3_basic_phy_init(phy_802_3_t *phy_802_3) ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_detect_phy_addr(phy_802_3->eth, &phy_802_3->addr), err, TAG, "Detect PHY address failed"); } /* Power on Ethernet PHY */ - ESP_GOTO_ON_ERROR(eth_phy_802_3_pwrctl(&phy_802_3->parent, true), err, TAG, "power control failed"); + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_pwrctl(phy_802_3, true), err, TAG, "power control failed"); /* Reset Ethernet PHY */ - ESP_GOTO_ON_ERROR(eth_phy_802_3_reset(&phy_802_3->parent), err, TAG, "reset failed"); + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_reset(phy_802_3), err, TAG, "reset failed"); return ESP_OK; err: @@ -339,7 +417,7 @@ esp_err_t esp_eth_phy_802_3_basic_phy_deinit(phy_802_3_t *phy_802_3) { esp_err_t ret = ESP_OK; /* Power off Ethernet PHY */ - ESP_GOTO_ON_ERROR(eth_phy_802_3_pwrctl(&phy_802_3->parent, false), err, TAG, "power control failed"); + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_pwrctl(phy_802_3, false), err, TAG, "power control failed"); return ESP_OK; err: return ret; @@ -385,11 +463,6 @@ err: return ret; } -phy_802_3_t *esp_eth_phy_into_phy_802_3(esp_eth_phy_t *phy) -{ - return __containerof(phy, phy_802_3_t, parent); -} - esp_err_t esp_eth_phy_802_3_obj_config_init(phy_802_3_t *phy_802_3, const eth_phy_config_t *config) { esp_err_t ret = ESP_OK; @@ -402,20 +475,20 @@ esp_err_t esp_eth_phy_802_3_obj_config_init(phy_802_3_t *phy_802_3, const eth_ph phy_802_3->reset_gpio_num = config->reset_gpio_num; phy_802_3->autonego_timeout_ms = config->autonego_timeout_ms; - phy_802_3->parent.reset = eth_phy_802_3_reset; - phy_802_3->parent.reset_hw = eth_phy_802_3_reset_hw_default; - phy_802_3->parent.init = eth_phy_802_3_init; - phy_802_3->parent.deinit = eth_phy_802_3_deinit; - phy_802_3->parent.set_mediator = eth_phy_802_3_set_mediator; - phy_802_3->parent.autonego_ctrl = eth_phy_802_3_autonego_ctrl; - phy_802_3->parent.pwrctl = eth_phy_802_3_pwrctl; - phy_802_3->parent.get_addr = eth_phy_802_3_get_addr; - phy_802_3->parent.set_addr = eth_phy_802_3_set_addr; - phy_802_3->parent.advertise_pause_ability = eth_phy_802_3_advertise_pause_ability; - phy_802_3->parent.loopback = eth_phy_802_3_loopback; - phy_802_3->parent.set_speed = eth_phy_802_3_set_speed; - phy_802_3->parent.set_duplex = eth_phy_802_3_set_duplex; - phy_802_3->parent.del = eth_phy_802_3_del; + phy_802_3->parent.reset = reset; + phy_802_3->parent.reset_hw = reset_hw_default; + phy_802_3->parent.init = init; + phy_802_3->parent.deinit = deinit; + phy_802_3->parent.set_mediator = set_mediator; + phy_802_3->parent.autonego_ctrl = autonego_ctrl; + phy_802_3->parent.pwrctl = pwrctl; + phy_802_3->parent.get_addr = get_addr; + phy_802_3->parent.set_addr = set_addr; + phy_802_3->parent.advertise_pause_ability = advertise_pause_ability; + phy_802_3->parent.loopback = loopback; + phy_802_3->parent.set_speed = set_speed; + phy_802_3->parent.set_duplex = set_duplex; + phy_802_3->parent.del = del; phy_802_3->parent.get_link = NULL; phy_802_3->parent.custom_ioctl = NULL; diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c index 3f711854e8..d8f9bad9fc 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -59,6 +59,29 @@ typedef union { } dscsr_reg_t; #define ETH_PHY_DSCSR_REG_ADDR (0x11) +typedef union { + struct { + uint32_t pd_value : 1; /* 1 in this bit indicates power down */ + uint32_t reserved1 : 1; /* Reserved */ + uint32_t monsel0 : 1; /* Vendor monitor select */ + 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 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 */ + uint32_t tx10m_pwr : 1; /* Set 1 to enable transmit power savings in 10BASE-T mode */ + uint32_t preamblex : 1; /* When tx10m_pwr is set, the 10BASE-T transmit preamble count is reduced */ + uint32_t force_fef : 1; /* Vendor test select control */ + uint32_t force_txsd : 1; /* Set 1 to force SD signal OK in 100M */ + uint32_t tstse0 : 1; /* Vendor test select control */ + uint32_t tstse1 : 1; /* Vendor test select control */ + }; + uint32_t val; +} scr_reg_t; +#define ETH_PHY_SCR_REG_ADDR 0x14 + typedef struct { phy_802_3_t phy_802_3; } phy_dm9051_t; @@ -174,18 +197,61 @@ err: return ret; } +static esp_err_t dm9051_loopback(esp_eth_phy_t *phy, bool enable) +{ + esp_err_t ret = ESP_OK; + 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 + 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"); + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_SCR_REG_ADDR, &(scr.val)), err, TAG, "read SCR failed"); + if (enable) { + bmcr.en_loopback = 1; + scr.autoneg_lpbk = 1; + } else { + bmcr.en_loopback = 0; + scr.autoneg_lpbk = 0; + } + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed"); + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_SCR_REG_ADDR, scr.val), err, TAG, "write SCR failed"); + return ESP_OK; +err: + return ret; +} + +static esp_err_t dm9051_set_speed(esp_eth_phy_t *phy, eth_speed_t speed) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + esp_eth_mediator_t *eth = phy_802_3->eth; + + /* Check if loopback is enabled, and if so, can it work with proposed speed or not */ + bmcr_reg_t bmcr; + 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"); + ESP_GOTO_ON_FALSE(bmcr.en_loopback & (speed == ETH_SPEED_100M), ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation"); + + return esp_eth_phy_802_3_set_speed(phy_802_3, speed); +err: + return ret; +} + esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) { esp_eth_phy_t *ret = NULL; phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t)); ESP_GOTO_ON_FALSE(dm9051, NULL, err, TAG, "calloc dm9051 failed"); ESP_GOTO_ON_FALSE(esp_eth_phy_802_3_obj_config_init(&dm9051->phy_802_3, config) == ESP_OK, - NULL, err, TAG, "configuration initialization of PHY 802.3 failed"); + NULL, err, TAG, "configuration initialization of PHY 802.3 failed"); // redefine functions which need to be customized for sake of dm9051 dm9051->phy_802_3.parent.init = dm9051_init; dm9051->phy_802_3.parent.reset = dm9051_reset; dm9051->phy_802_3.parent.get_link = dm9051_get_link; + dm9051->phy_802_3.parent.loopback = dm9051_loopback; + dm9051->phy_802_3.parent.set_speed = dm9051_set_speed; return &dm9051->phy_802_3.parent; err: diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c index e494a2221c..fc771b072f 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -123,6 +123,33 @@ err: return ret; } +static esp_err_t dp83848_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + esp_eth_mediator_t *eth = phy_802_3->eth; + if (cmd == ESP_ETH_PHY_AUTONEGO_EN) { + bmcr_reg_t bmcr; + 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"); + ESP_GOTO_ON_FALSE(bmcr.en_loopback == 0, ESP_ERR_INVALID_STATE, err, TAG, "Autonegotiation can't be enabled while in loopback operation"); + } + return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat); +err: + return ret; +} + +static esp_err_t dp83848_loopback(esp_eth_phy_t *phy, bool enable) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + bool auto_nego_en = true; + ESP_GOTO_ON_ERROR(dp83848_autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, &auto_nego_en), err, TAG, "get status of autonegotiation failed"); + ESP_GOTO_ON_FALSE(!(auto_nego_en && enable), ESP_ERR_INVALID_STATE, err, TAG, "Unable to set loopback while autonegotiation is enabled. Disable it to use loopback"); + return esp_eth_phy_802_3_loopback(phy_802_3, enable); +err: + return ret; +} + static esp_err_t dp83848_init(esp_eth_phy_t *phy) { esp_err_t ret = ESP_OK; @@ -154,6 +181,8 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config) // redefine functions which need to be customized for sake of dp83848 dp83848->phy_802_3.parent.init = dp83848_init; dp83848->phy_802_3.parent.get_link = dp83848_get_link; + dp83848->phy_802_3.parent.autonego_ctrl = dp83848_autonego_ctrl; + dp83848->phy_802_3.parent.loopback = dp83848_loopback; return &dp83848->phy_802_3.parent; err: diff --git a/components/esp_eth/src/esp_eth_phy_ksz80xx.c b/components/esp_eth/src/esp_eth_phy_ksz80xx.c index 62ca742d14..0c61e3347c 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz80xx.c +++ b/components/esp_eth/src/esp_eth_phy_ksz80xx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -177,6 +177,23 @@ err: return ret; } +static esp_err_t ksz80xx_set_speed(esp_eth_phy_t *phy, eth_speed_t speed) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + esp_eth_mediator_t *eth = phy_802_3->eth; + + /* Check if loopback is enabled, and if so, can it work with proposed speed or not */ + bmcr_reg_t bmcr; + 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"); + ESP_GOTO_ON_FALSE(bmcr.en_loopback & (speed == ETH_SPEED_100M), ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation"); + + return esp_eth_phy_802_3_set_speed(phy_802_3, speed); +err: + return ret; +} + + esp_eth_phy_t *esp_eth_phy_new_ksz80xx(const eth_phy_config_t *config) { esp_eth_phy_t *ret = NULL; @@ -188,6 +205,7 @@ esp_eth_phy_t *esp_eth_phy_new_ksz80xx(const eth_phy_config_t *config) // redefine functions which need to be customized for sake of ksz80xx ksz80xx->phy_802_3.parent.init = ksz80xx_init; ksz80xx->phy_802_3.parent.get_link = ksz80xx_get_link; + ksz80xx->phy_802_3.parent.set_speed = ksz80xx_set_speed; return &ksz80xx->phy_802_3.parent; err: diff --git a/components/esp_eth/src/esp_eth_phy_ksz8851snl.c b/components/esp_eth/src/esp_eth_phy_ksz8851snl.c index 52446d9b21..3739b63a0b 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz8851snl.c +++ b/components/esp_eth/src/esp_eth_phy_ksz8851snl.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2021-2023 Espressif Systems (Shanghai) CO LTD */ #include #include "esp_check.h" @@ -317,7 +317,12 @@ static esp_err_t phy_ksz8851_set_duplex(esp_eth_phy_t *phy, eth_duplex_t duplex) /* Set duplex mode */ uint32_t control; + uint32_t mbcr; ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1CR, &control), err, TAG, "P1CR read failed"); + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz8851->addr, KSZ8851_P1MBCR, &mbcr), err, TAG, "P1MBCR read failed"); + if (mbcr & P1MBCR_LOCAL_LOOPBACK) { + ESP_GOTO_ON_FALSE(duplex == ETH_DUPLEX_FULL, ESP_ERR_INVALID_STATE, err, TAG, "Duplex mode must be FULL for loopback operation"); + } if (duplex == ETH_DUPLEX_FULL) { control |= P1CR_FORCE_DUPLEX; } else { diff --git a/components/esp_eth/src/esp_eth_phy_lan87xx.c b/components/esp_eth/src/esp_eth_phy_lan87xx.c index 031265b384..621f0b7478 100644 --- a/components/esp_eth/src/esp_eth_phy_lan87xx.c +++ b/components/esp_eth/src/esp_eth_phy_lan87xx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -217,12 +217,20 @@ static esp_err_t lan87xx_update_link_duplex_speed(phy_lan87xx_t *lan87xx) eth_speed_t speed = ETH_SPEED_10M; eth_duplex_t duplex = ETH_DUPLEX_HALF; bmsr_reg_t bmsr; + bmcr_reg_t bmcr; pscsr_reg_t pscsr; uint32_t peer_pause_ability = false; anlpar_reg_t anlpar; ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed"); ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed"); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed"); + /* link status is forced up because LAN87xx reports link down when loopback is enabled and cable is unplugged */ + eth_link_t link; + if(bmcr.en_loopback) { + link = ETH_LINK_UP; + } else { + link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + } /* check if link status changed */ if (lan87xx->phy_802_3.link_status != link) { /* when link up, read negotiation result */ @@ -282,6 +290,32 @@ static esp_err_t lan87xx_reset_hw(esp_eth_phy_t *phy) /* It was observed that assert nRST signal on LAN87xx needs to be a little longer than the minimum specified in datasheet */ return esp_eth_phy_802_3_reset_hw(esp_eth_phy_into_phy_802_3(phy), 150); } +static esp_err_t lan87xx_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + esp_eth_mediator_t *eth = phy_802_3->eth; + if (cmd == ESP_ETH_PHY_AUTONEGO_EN) { + bmcr_reg_t bmcr; + 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"); + ESP_GOTO_ON_FALSE(bmcr.en_loopback == 0, ESP_ERR_INVALID_STATE, err, TAG, "Autonegotiation can't be enabled while in loopback operation"); + } + return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat); +err: + return ret; +} + +static esp_err_t lan87xx_loopback(esp_eth_phy_t *phy, bool enable) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + bool auto_nego_en; + ESP_GOTO_ON_ERROR(lan87xx_autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, &auto_nego_en), err, TAG, "get status of autonegotiation failed"); + ESP_GOTO_ON_FALSE(!(auto_nego_en && enable), ESP_ERR_INVALID_STATE, err, TAG, "Unable to set loopback while autonegotiation is enabled. Disable it to use loopback"); + return esp_eth_phy_802_3_loopback(phy_802_3, enable); +err: + return ret; +} static esp_err_t lan87xx_init(esp_eth_phy_t *phy) { @@ -323,6 +357,8 @@ esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config) lan87xx->phy_802_3.parent.reset_hw = lan87xx_reset_hw; lan87xx->phy_802_3.parent.init = lan87xx_init; lan87xx->phy_802_3.parent.get_link = lan87xx_get_link; + lan87xx->phy_802_3.parent.autonego_ctrl = lan87xx_autonego_ctrl; + lan87xx->phy_802_3.parent.loopback = lan87xx_loopback; return &lan87xx->phy_802_3.parent; err: diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/esp_eth_phy_rtl8201.c index 2cc42753ba..1464fc6acf 100644 --- a/components/esp_eth/src/esp_eth_phy_rtl8201.c +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -117,6 +117,33 @@ err: return ret; } +static esp_err_t rtl8201_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + esp_eth_mediator_t *eth = phy_802_3->eth; + if (cmd == ESP_ETH_PHY_AUTONEGO_EN) { + bmcr_reg_t bmcr; + 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"); + ESP_GOTO_ON_FALSE(bmcr.en_loopback == 0, ESP_ERR_INVALID_STATE, err, TAG, "Autonegotiation can't be enabled while in loopback operation"); + } + return esp_eth_phy_802_3_autonego_ctrl(phy_802_3, cmd, autonego_en_stat); +err: + return ret; +} + +static esp_err_t rtl8201_loopback(esp_eth_phy_t *phy, bool enable) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + bool auto_nego_en; + ESP_GOTO_ON_ERROR(rtl8201_autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, &auto_nego_en), err, TAG, "get status of autonegotiation failed"); + ESP_GOTO_ON_FALSE(!(auto_nego_en && enable), ESP_ERR_INVALID_STATE, err, TAG, "Unable to set loopback while autonegotiation is enabled. Disable it to use loopback"); + return esp_eth_phy_802_3_loopback(phy_802_3, enable); +err: + return ret; +} + static esp_err_t rtl8201_init(esp_eth_phy_t *phy) { esp_err_t ret = ESP_OK; @@ -148,6 +175,8 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config) // redefine functions which need to be customized for sake of RTL8201 rtl8201->phy_802_3.parent.init = rtl8201_init; rtl8201->phy_802_3.parent.get_link = rtl8201_get_link; + rtl8201->phy_802_3.parent.autonego_ctrl = rtl8201_autonego_ctrl; + rtl8201->phy_802_3.parent.loopback = rtl8201_loopback; return &rtl8201->phy_802_3.parent; err: diff --git a/components/esp_eth/test_apps/main/Kconfig.projbuild b/components/esp_eth/test_apps/main/Kconfig.projbuild index 119bf8b3c3..46ddb64c9f 100644 --- a/components/esp_eth/test_apps/main/Kconfig.projbuild +++ b/components/esp_eth/test_apps/main/Kconfig.projbuild @@ -13,6 +13,7 @@ menu "esp_eth TEST_APPS Configuration" help Use internal Ethernet MAC controller. + config TARGET_USE_SPI_ETHERNET bool "SPI Ethernet" select ETH_USE_SPI_ETHERNET @@ -38,6 +39,20 @@ menu "esp_eth TEST_APPS Configuration" config TARGET_ETH_PHY_DEVICE_DP83848 bool "DP83848" endchoice # TARGET_ETH_PHY_DEVICE + + config TARGET_USE_DEFAULT_EMAC_CONFIG + default y + bool "Use default EMAC config" + + if !TARGET_USE_DEFAULT_EMAC_CONFIG + config TARGET_IO_MDC + int "SMI MDC GPIO number" + default 23 + config TARGET_IO_MDIO + int "SMI MDIO GPIO number" + default 18 + endif + endif # TARGET_USE_INTERNAL_ETHERNET if TARGET_USE_SPI_ETHERNET diff --git a/components/esp_eth/test_apps/main/esp_eth_test_apps.c b/components/esp_eth/test_apps/main/esp_eth_test_apps.c index 6a49315ecf..3532df46c4 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_apps.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_apps.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -14,6 +14,8 @@ #include "esp_rom_md5.h" #include "esp_eth_test_common.h" +#define LOOPBACK_TEST_PACKET_SIZE 256 + static const char *TAG = "esp32_eth_test"; extern const char dl_espressif_com_root_cert_pem_start[] asm("_binary_dl_espressif_com_root_cert_pem_start"); @@ -92,13 +94,13 @@ TEST_CASE("ethernet io test", "[ethernet]") extra_cleanup(); } +// This test expects autonegotiation to be enabled on the other node. TEST_CASE("ethernet io speed/duplex/autonegotiation", "[ethernet]") { EventBits_t bits = 0; EventGroupHandle_t eth_event_group = xEventGroupCreate(); TEST_ASSERT(eth_event_group != NULL); TEST_ESP_OK(esp_event_loop_create_default()); - TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group)); eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); mac_config.flags = ETH_MAC_FLAG_PIN_TO_CORE; // pin to core esp_eth_mac_t *mac = mac_init(NULL, &mac_config); @@ -109,13 +111,7 @@ TEST_CASE("ethernet io speed/duplex/autonegotiation", "[ethernet]") esp_eth_handle_t eth_handle = NULL; TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); extra_eth_config(eth_handle); - - // Set PHY to loopback mode so we do not have to take care about link configuration of the other node. - // The reason behind is improbable, however, if the other node was configured to e.g. 100 Mbps and we - // tried to change the speed at ESP node to 10 Mbps, we could get into trouble to establish a link. - // TODO: this test in this configuration may not work for all the chips (JIRA IDF-6186) - bool loopback_en = true; - esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group)); // this test only test layer2, so don't need to register input callback (i.e. esp_eth_update_input_path) TEST_ESP_OK(esp_eth_start(eth_handle)); @@ -274,6 +270,146 @@ TEST_CASE("ethernet io speed/duplex/autonegotiation", "[ethernet]") vEventGroupDelete(eth_event_group); } +static SemaphoreHandle_t loopback_test_case_data_received; +static esp_err_t loopback_test_case_incoming_handler(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv) +{ + TEST_ASSERT(memcmp(priv, buffer, LOOPBACK_TEST_PACKET_SIZE) == 0) + xSemaphoreGive(loopback_test_case_data_received); + free(buffer); + return ESP_OK; +} + +TEST_CASE("ethernet io loopback", "[ethernet]") +{ + loopback_test_case_data_received = xSemaphoreCreateBinary(); + // init everything else + EventBits_t bits = 0; + EventGroupHandle_t eth_event_group = xEventGroupCreate(); + TEST_ASSERT(eth_event_group != NULL); + TEST_ESP_OK(esp_event_loop_create_default()); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac_config.flags = ETH_MAC_FLAG_PIN_TO_CORE; // pin to core + esp_eth_mac_t *mac = mac_init(NULL, &mac_config); + TEST_ASSERT_NOT_NULL(mac); + esp_eth_phy_t *phy = phy_init(NULL); + TEST_ASSERT_NOT_NULL(phy); + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + esp_eth_handle_t eth_handle = NULL; + TEST_ESP_OK(esp_eth_driver_install(ð_config, ð_handle)); + extra_eth_config(eth_handle); + // Disable autonegotiation to manually set speed and duplex mode + bool auto_nego_en = false; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); + bool loopback_en = true; +// *** W5500 deviation *** +// Rationale: does not support loopback +#ifdef CONFIG_TARGET_ETH_PHY_DEVICE_W5500 + TEST_ASSERT(esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en) == ESP_ERR_NOT_SUPPORTED); + goto cleanup; +#else + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en)); +#endif + + eth_duplex_t duplex_modes[] = {ETH_DUPLEX_HALF, ETH_DUPLEX_FULL}; + eth_speed_t speeds[] = {ETH_SPEED_10M, ETH_SPEED_100M}; + emac_frame_t* test_packet = malloc(LOOPBACK_TEST_PACKET_SIZE); + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, test_packet->src); + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, test_packet->dest); + for(size_t i = 0; i < LOOPBACK_TEST_PACKET_SIZE-ETH_HEADER_LEN; i++){ + test_packet->data[i] = rand() & 0xff; + } + TEST_ESP_OK(esp_eth_update_input_path(eth_handle, loopback_test_case_incoming_handler, test_packet)); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group)); + + for (int i = 0; i < sizeof(speeds) / sizeof(eth_speed_t); i++) { + eth_speed_t expected_speed = speeds[i]; + for (int j = 0; j < sizeof(duplex_modes) / sizeof(eth_duplex_t); j++) { + eth_duplex_t expected_duplex = duplex_modes[j]; + ESP_LOGI(TAG, "Test with %s Mbps %s duplex.", expected_speed == ETH_SPEED_10M ? "10" : "100", expected_duplex == ETH_DUPLEX_HALF ? "half" : "full"); +// *** KSZ80XX, KSZ8851SNL and DM9051 deviation *** +// Rationale: do not support loopback at 10 Mbps +#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DM9051) + if ((expected_speed == ETH_SPEED_10M)) { + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &expected_speed)); + continue; + } else if (expected_speed == ETH_SPEED_100M) { + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &expected_speed)); + } +#else + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &expected_speed)); +#endif + if ((expected_duplex == ETH_DUPLEX_HALF)) { + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &expected_duplex)); + continue; + } else if (expected_duplex == ETH_DUPLEX_FULL) { + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_DUPLEX_MODE, &expected_duplex)); + } + + TEST_ESP_OK(esp_eth_start(eth_handle)); + bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); + + eth_speed_t actual_speed = -1; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &actual_speed)); + TEST_ASSERT_EQUAL(expected_speed, actual_speed); + + eth_duplex_t actual_duplex = -1; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_DUPLEX_MODE, &actual_duplex)); + TEST_ASSERT_EQUAL(expected_duplex, actual_duplex); + + TEST_ESP_OK(esp_eth_transmit(eth_handle, test_packet, LOOPBACK_TEST_PACKET_SIZE)); + TEST_ASSERT(xSemaphoreTake(loopback_test_case_data_received, pdMS_TO_TICKS(10000)) == pdTRUE); + TEST_ESP_OK(esp_eth_stop(eth_handle)); + } + } + + // Test enabling autonegotiation when loopback is disabled + ESP_LOGI(TAG, "Test enabling autonegotiation without loopback."); + loopback_en = false; + auto_nego_en = true; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en)); + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); + auto_nego_en = false; + loopback_en = true; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en)); + // Test with enabled autonegotiaton + ESP_LOGI(TAG, "Test with enabled autonegotiation."); + auto_nego_en = true; +// *** RTL8201, DP83848 and LAN87xx deviation *** +// Rationale: do not support autonegotiation with loopback enabled. +#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DP83848) || \ + defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX) + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); + goto cleanup; +#endif + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); + TEST_ESP_OK(esp_eth_start(eth_handle)); + bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); + + TEST_ESP_OK(esp_eth_transmit(eth_handle, test_packet, LOOPBACK_TEST_PACKET_SIZE)); + TEST_ASSERT(xSemaphoreTake(loopback_test_case_data_received, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)) == pdTRUE); + + free(test_packet); + loopback_en = false; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en)); + TEST_ESP_OK(esp_eth_stop(eth_handle)); + 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); +// *** W5500, LAN87xx, RTL8201 and DP83848 deviation *** +// Rationale: in those cases 'goto cleanup' is used to skip part of the test code. Incasing in #if block is done to prevent unused label error +#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_W5500) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX) || \ + defined(CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DP83848) +cleanup: +#endif + TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + TEST_ESP_OK(phy->del(phy)); + TEST_ESP_OK(mac->del(mac)); + TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); + TEST_ESP_OK(esp_event_loop_delete_default()); + extra_cleanup(); + vEventGroupDelete(eth_event_group); +} + TEST_CASE("ethernet event test", "[ethernet]") { EventBits_t bits = 0; diff --git a/components/esp_eth/test_apps/main/esp_eth_test_common.c b/components/esp_eth/test_apps/main/esp_eth_test_common.c index e45c29b942..0a04d9561e 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_common.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -35,6 +35,10 @@ 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; +#endif // CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG if (vendor_emac_config == NULL) { vendor_emac_config = &esp32_emac_config; } diff --git a/components/esp_eth/test_apps/sdkconfig.ci.default_rtl8201 b/components/esp_eth/test_apps/sdkconfig.ci.default_rtl8201 index d9730475ac..15be08d2fc 100644 --- a/components/esp_eth/test_apps/sdkconfig.ci.default_rtl8201 +++ b/components/esp_eth/test_apps/sdkconfig.ci.default_rtl8201 @@ -7,3 +7,7 @@ CONFIG_ESP_TASK_WDT=n CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201=y + +CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=n +CONFIG_TARGET_IO_MDC=16 +CONFIG_TARGET_IO_MDIO=17 From 6fda9fe2071aa0d999918334e6478516a7410259 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Mon, 2 Oct 2023 12:37:19 +0200 Subject: [PATCH 2/8] fix(esp_eth): various Ethernet driver fixes ksz8851snl: enabled reception of multicast frames Internal EMAC: fixed APLL CLK deinitialization DM9051 and KSZ80xx: fixed speed configuration when not in loopback mode phy_802_3: added multiple attempts when autodetecting PHY address --- components/esp_eth/src/esp_eth_mac_esp.c | 1 - .../esp_eth/src/esp_eth_mac_ksz8851snl.c | 12 +++++------ components/esp_eth/src/esp_eth_phy_802_3.c | 20 ++++++++++--------- components/esp_eth/src/esp_eth_phy_dm9051.c | 20 +++++++------------ components/esp_eth/src/esp_eth_phy_ksz80xx.c | 4 +++- 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_esp.c b/components/esp_eth/src/esp_eth_mac_esp.c index a1dd3c157f..e9d20d1ef0 100644 --- a/components/esp_eth/src/esp_eth_mac_esp.c +++ b/components/esp_eth/src/esp_eth_mac_esp.c @@ -628,7 +628,6 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config emac->smi_mdio_gpio_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; - emac->use_apll = false; emac->parent.set_mediator = emac_esp32_set_mediator; emac->parent.init = emac_esp32_init; emac->parent.deinit = emac_esp32_deinit; diff --git a/components/esp_eth/src/esp_eth_mac_ksz8851snl.c b/components/esp_eth/src/esp_eth_mac_ksz8851snl.c index b6aea4df90..f19600a59e 100644 --- a/components/esp_eth/src/esp_eth_mac_ksz8851snl.c +++ b/components/esp_eth/src/esp_eth_mac_ksz8851snl.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2021-2023 Espressif Systems (Shanghai) CO LTD */ #include @@ -226,7 +226,7 @@ static esp_err_t init_set_defaults(emac_ksz8851snl_t *emac) ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXDTTR, RXDTTR_INIT_VALUE), err, TAG, "RXDTTR write failed"); ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXDBCTR, RXDBCTR_INIT_VALUE), err, TAG, "RXDBCTR write failed"); ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXCR1, - RXCR1_RXUDPFCC | RXCR1_RXTCPFCC | RXCR1_RXIPFCC | RXCR1_RXPAFMA | RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME), err, TAG, "RXCR1 write failed"); + RXCR1_RXUDPFCC | RXCR1_RXTCPFCC | RXCR1_RXIPFCC | RXCR1_RXPAFMA | RXCR1_RXFCE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXMAFMA | RXCR1_RXAE), err, TAG, "RXCR1 write failed"); ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXCR2, (4 << RXCR2_SRDBL_SHIFT) | RXCR2_IUFFP | RXCR2_RXIUFCEZ | RXCR2_UDPLFE | RXCR2_RXICMPFCC), err, TAG, "RXCR2 write failed"); ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXQCR, RXQCR_RXFCTE | RXQCR_ADRFE), err, TAG, "RXQCR write failed"); @@ -599,13 +599,13 @@ static esp_err_t emac_ksz8851_set_promiscuous(esp_eth_mac_t *mac, bool enable) if (enable) { // NOTE(v.chistyakov): set promiscuous mode ESP_LOGD(TAG, "setting promiscuous mode"); - rxcr1 |= RXCR1_RXINVF | RXCR1_RXAE; + rxcr1 |= RXCR1_RXAE | RXCR1_RXINVF; rxcr1 &= ~(RXCR1_RXPAFMA | RXCR1_RXMAFMA); } else { // NOTE(v.chistyakov): set hash perfect (default) - ESP_LOGD(TAG, "setting hash perfect mode"); - rxcr1 |= RXCR1_RXPAFMA; - rxcr1 &= ~(RXCR1_RXINVF | RXCR1_RXAE | RXCR1_RXMAFMA); + ESP_LOGD(TAG, "setting perfect with multicast passed"); + rxcr1 |= RXCR1_RXAE| RXCR1_RXPAFMA | RXCR1_RXMAFMA; + rxcr1 &= ~RXCR1_RXINVF; } ESP_GOTO_ON_ERROR(ksz8851_write_reg(emac, KSZ8851_RXCR1, rxcr1), err, TAG, "RXCR1 write failed"); err: diff --git a/components/esp_eth/src/esp_eth_phy_802_3.c b/components/esp_eth/src/esp_eth_phy_802_3.c index 4157f02011..d8db761433 100644 --- a/components/esp_eth/src/esp_eth_phy_802_3.c +++ b/components/esp_eth/src/esp_eth_phy_802_3.c @@ -380,16 +380,18 @@ esp_err_t esp_eth_phy_802_3_detect_phy_addr(esp_eth_mediator_t *eth, int *detect } int addr_try = 0; uint32_t reg_value = 0; - for (; addr_try < 16; addr_try++) { - eth->phy_reg_read(eth, addr_try, ETH_PHY_IDR1_REG_ADDR, ®_value); - if (reg_value != 0xFFFF && reg_value != 0x00) { - *detected_addr = addr_try; - break; + for (int i = 0; i < 3; i++){ + for (addr_try = 0; addr_try < 32; addr_try++) { + eth->phy_reg_read(eth, addr_try, ETH_PHY_IDR1_REG_ADDR, ®_value); + if (reg_value != 0xFFFF && reg_value != 0x00) { + *detected_addr = addr_try; + break; + } + } + if (addr_try < 32) { + ESP_LOGD(TAG, "Found PHY address: %d", addr_try); + return ESP_OK; } - } - if (addr_try < 16) { - ESP_LOGD(TAG, "Found PHY address: %d", addr_try); - return ESP_OK; } ESP_LOGE(TAG, "No PHY device detected"); return ESP_ERR_NOT_FOUND; diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c index d8f9bad9fc..6db49f8fad 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -95,7 +95,7 @@ static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051) eth_duplex_t duplex = ETH_DUPLEX_HALF; uint32_t peer_pause_ability = false; bmsr_reg_t bmsr; - dscsr_reg_t dscsr; + bmcr_reg_t bmcr; anlpar_reg_t anlpar; // BMSR is a latch low register // after power up, the first latched value must be 0, which means down @@ -108,17 +108,9 @@ static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051) if (dm9051->phy_802_3.link_status != link) { /* when link up, read negotiation result */ if (link == ETH_LINK_UP) { - ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)), err, TAG, "read DSCSR failed"); - if (dscsr.fdx100 || dscsr.hdx100) { - speed = ETH_SPEED_100M; - } else { - speed = ETH_SPEED_10M; - } - if (dscsr.fdx100 || dscsr.fdx10) { - duplex = ETH_DUPLEX_FULL; - } else { - duplex = ETH_DUPLEX_HALF; - } + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed"); + speed = bmcr.speed_select == 1 ? ETH_SPEED_100M : ETH_SPEED_10M; + duplex = bmcr.duplex_mode == 1 ? ETH_DUPLEX_FULL : ETH_DUPLEX_HALF; ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed"); ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed"); /* if we're in duplex mode, and peer has the flow control ability */ @@ -231,7 +223,9 @@ static esp_err_t dm9051_set_speed(esp_eth_phy_t *phy, eth_speed_t speed) /* Check if loopback is enabled, and if so, can it work with proposed speed or not */ bmcr_reg_t bmcr; 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"); - ESP_GOTO_ON_FALSE(bmcr.en_loopback & (speed == ETH_SPEED_100M), ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation"); + if (bmcr.en_loopback) { + ESP_GOTO_ON_FALSE(speed == ETH_SPEED_100M, ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation"); + } return esp_eth_phy_802_3_set_speed(phy_802_3, speed); err: diff --git a/components/esp_eth/src/esp_eth_phy_ksz80xx.c b/components/esp_eth/src/esp_eth_phy_ksz80xx.c index 0c61e3347c..2102acdf88 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz80xx.c +++ b/components/esp_eth/src/esp_eth_phy_ksz80xx.c @@ -186,7 +186,9 @@ static esp_err_t ksz80xx_set_speed(esp_eth_phy_t *phy, eth_speed_t speed) /* Check if loopback is enabled, and if so, can it work with proposed speed or not */ bmcr_reg_t bmcr; 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"); - ESP_GOTO_ON_FALSE(bmcr.en_loopback & (speed == ETH_SPEED_100M), ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation"); + if (bmcr.en_loopback) { + ESP_GOTO_ON_FALSE(speed == ETH_SPEED_100M, ESP_ERR_INVALID_STATE, err, TAG, "Speed must be 100M for loopback operation"); + } return esp_eth_phy_802_3_set_speed(phy_802_3, speed); err: From 1215fca04ee13f6f8266cd055ba077db62d25332 Mon Sep 17 00:00:00 2001 From: Ondrej Date: Tue, 31 Oct 2023 19:27:30 +0000 Subject: [PATCH 3/8] ci(esp_eth): added tests of all supported Etherent chips --- .gitlab/ci/dependencies/dependencies.yml | 10 -- .gitlab/ci/rules.yml | 15 --- .gitlab/ci/target-test.yml | 45 ++++++- .../esp_eth/test_apps/main/Kconfig.projbuild | 2 +- .../esp_eth/test_apps/main/esp_eth_test_l2.c | 18 ++- .../esp_eth/test_apps/pytest_esp_eth.py | 111 ++++++++++++++---- .../test_apps/sdkconfig.ci.default_dp83848 | 2 + ...t_ksz80xx => sdkconfig.ci.default_ksz8041} | 2 - conftest.py | 10 +- 9 files changed, 160 insertions(+), 55 deletions(-) rename components/esp_eth/test_apps/{sdkconfig.ci.default_ksz80xx => sdkconfig.ci.default_ksz8041} (78%) diff --git a/.gitlab/ci/dependencies/dependencies.yml b/.gitlab/ci/dependencies/dependencies.yml index 1e198c49fb..31f538a479 100644 --- a/.gitlab/ci/dependencies/dependencies.yml +++ b/.gitlab/ci/dependencies/dependencies.yml @@ -190,13 +190,3 @@ "labels:nvs_coverage": # host_test labels: - nvs_coverage - -"labels-protected:lan8720": # UT # FIXME: IDFCI-1176 temporary run this on master/release or with label - labels: - - lan8720 - included_in: - - build:unit_test - - build:unit_test-esp32 - - build:target_test - - build:component_ut - - build:component_ut-esp32 diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index be02549a57..71962a7a99 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -528,9 +528,6 @@ .if-label-host_test: &if-label-host_test if: '$BOT_LABEL_HOST_TEST || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*host_test(?:,[^,\n\r]+)*$/i' -.if-label-lan8720: &if-label-lan8720 - if: '$BOT_LABEL_LAN8720 || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*lan8720(?:,[^,\n\r]+)*$/i' - .if-label-macos: &if-label-macos if: '$BOT_LABEL_MACOS || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*macos(?:,[^,\n\r]+)*$/i' @@ -600,7 +597,6 @@ - <<: *if-label-component_ut_esp32h2 - <<: *if-label-component_ut_esp32s2 - <<: *if-label-component_ut_esp32s3 - - <<: *if-label-lan8720 - <<: *if-label-target_test - <<: *if-label-unit_test - <<: *if-label-unit_test_esp32 @@ -641,7 +637,6 @@ - <<: *if-label-build - <<: *if-label-component_ut - <<: *if-label-component_ut_esp32 - - <<: *if-label-lan8720 - <<: *if-label-target_test - <<: *if-label-unit_test - <<: *if-label-unit_test_esp32 @@ -1491,7 +1486,6 @@ - <<: *if-label-example_test_esp32h2 - <<: *if-label-example_test_esp32s2 - <<: *if-label-example_test_esp32s3 - - <<: *if-label-lan8720 - <<: *if-label-target_test - <<: *if-label-unit_test - <<: *if-label-unit_test_esp32 @@ -1556,7 +1550,6 @@ when: never - <<: *if-protected - <<: *if-label-build - - <<: *if-label-lan8720 - <<: *if-label-target_test - <<: *if-label-unit_test - <<: *if-label-unit_test_esp32 @@ -1593,7 +1586,6 @@ when: never - <<: *if-protected - <<: *if-label-build - - <<: *if-label-lan8720 - <<: *if-label-target_test - <<: *if-label-unit_test - <<: *if-label-unit_test_esp32 @@ -1798,13 +1790,6 @@ - <<: *if-dev-push changes: *patterns-unit_test-sdio -.rules:labels-protected:lan8720: - rules: - - <<: *if-revert-branch - when: never - - <<: *if-protected - - <<: *if-label-lan8720 - .rules:labels:nvs_coverage: rules: - <<: *if-revert-branch diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index 317a67746c..d4b1844947 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -577,10 +577,51 @@ pytest_components_esp32_ip101: pytest_components_esp32_lan8720: extends: - .pytest_components_dir_template - - .rules:labels-protected:lan8720 # FIXME: IDFCI-1176 needs: - build_pytest_components_esp32 - tags: [ esp32, lan8720 ] + tags: [ esp32, eth_lan8720 ] + +pytest_components_esp32_rtl8201: + extends: + - .pytest_components_dir_template + needs: + - build_pytest_components_esp32 + tags: [ esp32, eth_rtl8201 ] + +pytest_components_esp32_w5500: + extends: + - .pytest_components_dir_template + needs: + - build_pytest_components_esp32 + tags: [ esp32, eth_w5500 ] + +pytest_components_esp32_ksz8851snl: + extends: + - .pytest_components_dir_template + needs: + - build_pytest_components_esp32 + tags: [ esp32, eth_ksz8851snl ] + +pytest_components_esp32_dm9051: + extends: + - .pytest_components_dir_template + needs: + - build_pytest_components_esp32 + tags: [ esp32, eth_dm9051 ] + +pytest_components_esp32_ksz8041: + extends: + - .pytest_components_dir_template + needs: + - build_pytest_components_esp32 + tags: [ esp32, eth_ksz8041 ] + +pytest_components_esp32_dp83848: + extends: + - .pytest_components_dir_template + needs: + - build_pytest_components_esp32 + tags: [ esp32, eth_dp83848 ] pytest_components_esp32_ethernet: extends: diff --git a/components/esp_eth/test_apps/main/Kconfig.projbuild b/components/esp_eth/test_apps/main/Kconfig.projbuild index 46ddb64c9f..b9ac8825db 100644 --- a/components/esp_eth/test_apps/main/Kconfig.projbuild +++ b/components/esp_eth/test_apps/main/Kconfig.projbuild @@ -76,7 +76,7 @@ menu "esp_eth TEST_APPS Configuration" config TARGET_SPI_CLOCK_MHZ int "SPI clock speed (MHz)" range 5 80 - default 12 + default 20 help Set the clock speed (MHz) of SPI interface. diff --git a/components/esp_eth/test_apps/main/esp_eth_test_l2.c b/components/esp_eth/test_apps/main/esp_eth_test_l2.c index b8712e644e..a174e5574b 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_l2.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_l2.c @@ -243,7 +243,18 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") TEST_CASE("ethernet start/stop stress test under heavy traffic", "[ethernet_l2]") { +// *** SPI Ethernet modules deviation *** +// Rationale: The SPI bus is bottleneck when reading received frames from the module. The Rx Task would +// occupy all the resources under heavy Rx traffic and it would not be possible to access +// the Ethernet module to stop it. Therfore, the Rx task priority is set lower than "test" task +// to be able to be preempted. +#if CONFIG_TARGET_USE_SPI_ETHERNET + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac_config.rx_task_prio = uxTaskPriorityGet(NULL) - 1; + esp_eth_mac_t *mac = mac_init(NULL, &mac_config); +#else esp_eth_mac_t *mac = mac_init(NULL, NULL); +#endif // CONFIG_TARGET_USE_SPI_ETHERNET TEST_ASSERT_NOT_NULL(mac); esp_eth_phy_t *phy = phy_init(NULL); TEST_ASSERT_NOT_NULL(phy); @@ -292,8 +303,13 @@ TEST_CASE("ethernet start/stop stress test under heavy traffic", "[ethernet_l2]" // this also serves as main PASS/FAIL criteria poke_and_wait(eth_handle, &tx_i, sizeof(tx_i), eth_event_rx_group); - // generate heavy Tx traffic +// *** SPI Ethernet modules deviation *** +// Rationale: Transmit errors are expected only for internal EMAC since it is possible to try to queue more +// data than it is able to process at a time. +#if !CONFIG_TARGET_USE_SPI_ETHERNET printf("Note: transmit errors are expected...\n"); +#endif + // generate heavy Tx traffic for (int j = 0; j < 150; j++) { // return value is not checked on purpose since it is expected that it may fail time to time because // we may try to queue more packets than hardware is able to handle diff --git a/components/esp_eth/test_apps/pytest_esp_eth.py b/components/esp_eth/test_apps/pytest_esp_eth.py index 806445fc94..e6b83c4980 100644 --- a/components/esp_eth/test_apps/pytest_esp_eth.py +++ b/components/esp_eth/test_apps/pytest_esp_eth.py @@ -9,7 +9,7 @@ from multiprocessing import Pipe, Process, connection from typing import Iterator import pytest -from pytest_embedded import Dut +from pytest_embedded_idf import IdfDut from scapy.all import Ether, raw ETH_TYPE = 0x3300 @@ -24,6 +24,7 @@ class EthTestIntf(object): def find_target_if(self, my_if: str = '') -> None: # try to determine which interface to use netifs = os.listdir('/sys/class/net/') + netifs.sort(reverse=True) logging.info('detected interfaces: %s', str(netifs)) for netif in netifs: @@ -100,25 +101,15 @@ class EthTestIntf(object): raise e -def ethernet_test(dut: Dut) -> None: - dut.expect_exact('Press ENTER to see the list of tests') - dut.write('\n') - - dut.expect_exact('Enter test for running.') - dut.write('[ethernet]') - dut.expect_unity_test_output(timeout=980) +def ethernet_test(dut: IdfDut) -> None: + dut.run_all_single_board_cases(group='ethernet', timeout=980) -def ethernet_int_emac_hal_test(dut: Dut) -> None: - dut.expect_exact('Press ENTER to see the list of tests') - dut.write('\n') - - dut.expect_exact('Enter test for running.') - dut.write('[emac_hal]') - dut.expect_unity_test_output() +def ethernet_int_emac_hal_test(dut: IdfDut) -> None: + dut.run_all_single_board_cases(group='emac_hal') -def ethernet_l2_test(dut: Dut) -> None: +def ethernet_l2_test(dut: IdfDut) -> None: target_if = EthTestIntf(ETH_TYPE) dut.expect_exact('Press ENTER to see the list of tests') @@ -159,7 +150,7 @@ def ethernet_l2_test(dut: Dut) -> None: # (there might be slight delay due to the RSTP execution) target_if.recv_resp_poke(mac=dut_mac) target_if.send_eth_packet('ff:ff:ff:ff:ff:ff') # broadcast frame - target_if.send_eth_packet('01:00:00:00:00:00') # multicast frame + target_if.send_eth_packet('01:00:5e:00:00:00') # IPv4 multicast frame (some SPI Eth modules filter multicast other than IP) target_if.send_eth_packet(mac=dut_mac) # unicast frame dut.expect_unity_test_output(extra_before=res.group(1)) @@ -189,6 +180,7 @@ def ethernet_l2_test(dut: Dut) -> None: dut.expect_unity_test_output(extra_before=res.group(1)) +# ----------- IP101 ----------- @pytest.mark.esp32 @pytest.mark.ethernet @pytest.mark.parametrize('config', [ @@ -197,7 +189,7 @@ def ethernet_l2_test(dut: Dut) -> None: 'single_core_ip101' ], indirect=True) @pytest.mark.flaky(reruns=3, reruns_delay=5) -def test_esp_ethernet(dut: Dut) -> None: +def test_esp_ethernet(dut: IdfDut) -> None: ethernet_test(dut) @@ -206,7 +198,7 @@ def test_esp_ethernet(dut: Dut) -> None: @pytest.mark.parametrize('config', [ 'default_ip101', ], indirect=True) -def test_esp_emac_hal(dut: Dut) -> None: +def test_esp_emac_hal(dut: IdfDut) -> None: ethernet_int_emac_hal_test(dut) @@ -215,14 +207,89 @@ def test_esp_emac_hal(dut: Dut) -> None: @pytest.mark.parametrize('config', [ 'default_ip101', ], indirect=True) -def test_esp_eth_ip101(dut: Dut) -> None: +def test_esp_eth_ip101(dut: IdfDut) -> None: ethernet_l2_test(dut) +# ----------- LAN8720 ----------- @pytest.mark.esp32 -@pytest.mark.lan8720 +@pytest.mark.eth_lan8720 @pytest.mark.parametrize('config', [ 'default_lan8720', ], indirect=True) -def test_esp_eth_lan8720(dut: Dut) -> None: +def test_esp_eth_lan8720(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() + ethernet_l2_test(dut) + + +# ----------- RTL8201 ----------- +@pytest.mark.esp32 +@pytest.mark.eth_rtl8201 +@pytest.mark.parametrize('config', [ + 'default_rtl8201', +], indirect=True) +def test_esp_eth_rtl8201(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() + ethernet_l2_test(dut) + + +# ----------- KSZ8041 ----------- +@pytest.mark.esp32 +@pytest.mark.eth_ksz8041 +@pytest.mark.parametrize('config', [ + 'default_ksz8041', +], indirect=True) +def test_esp_eth_ksz8041(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() + ethernet_l2_test(dut) + + +# ----------- DP83848 ----------- +@pytest.mark.esp32 +@pytest.mark.eth_dp83848 +@pytest.mark.parametrize('config', [ + 'default_dp83848', +], indirect=True) +def test_esp_eth_dp83848(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() + ethernet_l2_test(dut) + + +# ----------- W5500 ----------- +@pytest.mark.esp32 +@pytest.mark.eth_w5500 +@pytest.mark.parametrize('config', [ + 'default_w5500', +], indirect=True) +def test_esp_eth_w5500(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() + ethernet_l2_test(dut) + + +# ----------- KSZ8851SNL ----------- +@pytest.mark.esp32 +@pytest.mark.eth_ksz8851snl +@pytest.mark.parametrize('config', [ + 'default_ksz8851snl', +], indirect=True) +def test_esp_eth_ksz8851snl(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() + ethernet_l2_test(dut) + + +# ----------- DM9051 ----------- +@pytest.mark.esp32 +@pytest.mark.eth_dm9051 +@pytest.mark.parametrize('config', [ + 'default_dm9051', +], indirect=True) +def test_esp_eth_dm9051(dut: IdfDut) -> None: + ethernet_test(dut) + dut.serial.hard_reset() ethernet_l2_test(dut) diff --git a/components/esp_eth/test_apps/sdkconfig.ci.default_dp83848 b/components/esp_eth/test_apps/sdkconfig.ci.default_dp83848 index 5d2b6a4687..20f63f4651 100644 --- a/components/esp_eth/test_apps/sdkconfig.ci.default_dp83848 +++ b/components/esp_eth/test_apps/sdkconfig.ci.default_dp83848 @@ -7,3 +7,5 @@ CONFIG_ESP_TASK_WDT=n CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_ETH_PHY_DEVICE_DP83848=y +CONFIG_ETH_RMII_CLK_OUTPUT=y +CONFIG_ETH_RMII_CLK_OUT_GPIO=17 diff --git a/components/esp_eth/test_apps/sdkconfig.ci.default_ksz80xx b/components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 similarity index 78% rename from components/esp_eth/test_apps/sdkconfig.ci.default_ksz80xx rename to components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 index f81cc10f95..ecb0066f5e 100644 --- a/components/esp_eth/test_apps/sdkconfig.ci.default_ksz80xx +++ b/components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 @@ -7,5 +7,3 @@ CONFIG_ESP_TASK_WDT=n CONFIG_TARGET_USE_INTERNAL_ETHERNET=y CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX=y -CONFIG_ETH_RMII_CLK_OUTPUT=y -CONFIG_ETH_RMII_CLK_OUT_GPIO=17 diff --git a/conftest.py b/conftest.py index 85a5d373ef..7768c28b0f 100644 --- a/conftest.py +++ b/conftest.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 # pylint: disable=W0621 # redefined-outer-name @@ -80,7 +80,13 @@ ENV_MARKERS = { 'generic': 'tests should be run on generic runners', 'flash_suspend': 'support flash suspend feature', 'ip101': 'connected via wired 10/100M ethernet', - 'lan8720': 'connected via LAN8720 ethernet transceiver', + 'eth_lan8720': 'connected via LAN8720 ethernet transceiver', + 'eth_rtl8201': 'connected via RTL8201 ethernet transceiver', + 'eth_ksz8041': 'connected via KSZ8041 ethernet transceiver', + 'eth_dp83848': 'connected via DP83848 ethernet transceiver', + 'eth_w5500': 'SPI Ethernet module with two W5500', + 'eth_ksz8851snl': 'SPI Ethernet module with two KSZ8851SNL', + 'eth_dm9051': 'SPI Ethernet module with two DM9051', 'quad_psram': 'runners with quad psram', 'octal_psram': 'runners with octal psram', 'usb_host': 'usb host runners', From 50a54194b761f4284137b98f9b59699332fd96ef Mon Sep 17 00:00:00 2001 From: Chen Yudong Date: Fri, 13 Oct 2023 21:14:56 +0800 Subject: [PATCH 4/8] ci: fix pytest components ethernet rules --- .gitlab/ci/target-test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index d4b1844947..9bdb5612b7 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -577,6 +577,7 @@ pytest_components_esp32_ip101: pytest_components_esp32_lan8720: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_lan8720 ] @@ -584,6 +585,7 @@ pytest_components_esp32_lan8720: pytest_components_esp32_rtl8201: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_rtl8201 ] @@ -591,6 +593,7 @@ pytest_components_esp32_rtl8201: pytest_components_esp32_w5500: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_w5500 ] @@ -598,6 +601,7 @@ pytest_components_esp32_w5500: pytest_components_esp32_ksz8851snl: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_ksz8851snl ] @@ -605,6 +609,7 @@ pytest_components_esp32_ksz8851snl: pytest_components_esp32_dm9051: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_dm9051 ] @@ -612,6 +617,7 @@ pytest_components_esp32_dm9051: pytest_components_esp32_ksz8041: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_ksz8041 ] @@ -619,6 +625,7 @@ pytest_components_esp32_ksz8041: pytest_components_esp32_dp83848: extends: - .pytest_components_dir_template + - .rules:test:component_ut-esp32 needs: - build_pytest_components_esp32 tags: [ esp32, eth_dp83848 ] From 1d3e466c6177f4ff62b6ac556d3430edebce25a3 Mon Sep 17 00:00:00 2001 From: Ondrej Date: Thu, 26 Oct 2023 11:38:28 +0000 Subject: [PATCH 5/8] ci(esp_eth): make additional Ethernet chips test as nightly run --- components/esp_eth/test_apps/pytest_esp_eth.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/esp_eth/test_apps/pytest_esp_eth.py b/components/esp_eth/test_apps/pytest_esp_eth.py index e6b83c4980..921636f441 100644 --- a/components/esp_eth/test_apps/pytest_esp_eth.py +++ b/components/esp_eth/test_apps/pytest_esp_eth.py @@ -214,6 +214,7 @@ def test_esp_eth_ip101(dut: IdfDut) -> None: # ----------- LAN8720 ----------- @pytest.mark.esp32 @pytest.mark.eth_lan8720 +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_lan8720', ], indirect=True) @@ -226,6 +227,7 @@ def test_esp_eth_lan8720(dut: IdfDut) -> None: # ----------- RTL8201 ----------- @pytest.mark.esp32 @pytest.mark.eth_rtl8201 +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_rtl8201', ], indirect=True) @@ -238,6 +240,7 @@ def test_esp_eth_rtl8201(dut: IdfDut) -> None: # ----------- KSZ8041 ----------- @pytest.mark.esp32 @pytest.mark.eth_ksz8041 +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_ksz8041', ], indirect=True) @@ -250,6 +253,7 @@ def test_esp_eth_ksz8041(dut: IdfDut) -> None: # ----------- DP83848 ----------- @pytest.mark.esp32 @pytest.mark.eth_dp83848 +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_dp83848', ], indirect=True) @@ -262,6 +266,7 @@ def test_esp_eth_dp83848(dut: IdfDut) -> None: # ----------- W5500 ----------- @pytest.mark.esp32 @pytest.mark.eth_w5500 +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_w5500', ], indirect=True) @@ -274,6 +279,7 @@ def test_esp_eth_w5500(dut: IdfDut) -> None: # ----------- KSZ8851SNL ----------- @pytest.mark.esp32 @pytest.mark.eth_ksz8851snl +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_ksz8851snl', ], indirect=True) @@ -286,6 +292,7 @@ def test_esp_eth_ksz8851snl(dut: IdfDut) -> None: # ----------- DM9051 ----------- @pytest.mark.esp32 @pytest.mark.eth_dm9051 +@pytest.mark.nightly_run @pytest.mark.parametrize('config', [ 'default_dm9051', ], indirect=True) From 99d4c1d13c1520dfdf30c9ccae70b84cd97193b6 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Mon, 6 Nov 2023 14:43:26 +0100 Subject: [PATCH 6/8] feat(esp_eth): added ioctl option to read/write PHY registers LAN87xx: Added extra delay after setting PHY speed --- components/esp_eth/include/esp_eth_driver.h | 13 ++++++++++++- components/esp_eth/src/esp_eth.c | 20 ++++++++++++++++++-- components/esp_eth/src/esp_eth_phy_lan87xx.c | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/components/esp_eth/include/esp_eth_driver.h b/components/esp_eth/include/esp_eth_driver.h index f6f358f015..068a911dfb 100644 --- a/components/esp_eth/include/esp_eth_driver.h +++ b/components/esp_eth/include/esp_eth_driver.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -121,6 +121,15 @@ typedef struct { esp_err_t (*write_phy_reg)(esp_eth_handle_t eth_handle, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value); } esp_eth_config_t; +/** + * @brief Data structure to Read/Write PHY register via ioctl API + * + */ +typedef struct { + uint32_t reg_addr; /*!< PHY register address */ + uint32_t *reg_value_p; /*!< Pointer to a memory where the register value is read/written */ +} esp_eth_phy_reg_rw_data_t; + /** * @brief Command list for ioctl API * @@ -139,6 +148,8 @@ typedef enum { ETH_CMD_G_DUPLEX_MODE, /*!< Get Duplex mode */ ETH_CMD_S_DUPLEX_MODE, /*!< Set Duplex mode */ ETH_CMD_S_PHY_LOOPBACK, /*!< Set PHY loopback */ + 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 diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index 90cc8a229f..6590ae15e9 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -466,7 +466,23 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data) case ETH_CMD_S_PHY_LOOPBACK: ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set loopback to null"); ESP_GOTO_ON_ERROR(phy->loopback(phy, *(bool *)data), err, TAG, "configuration of phy loopback mode failed"); - + break; + case ETH_CMD_READ_PHY_REG: + uint32_t phy_addr; + ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info"); + esp_eth_phy_reg_rw_data_t *phy_r_data = (esp_eth_phy_reg_rw_data_t *)data; + ESP_GOTO_ON_FALSE(phy_r_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't read registers to null"); + ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed"); + ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_read(ð_driver->mediator, + phy_addr, phy_r_data->reg_addr, phy_r_data->reg_value_p), err, TAG, "failed to read PHY register"); + break; + case ETH_CMD_WRITE_PHY_REG: + ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info"); + esp_eth_phy_reg_rw_data_t *phy_w_data = (esp_eth_phy_reg_rw_data_t *)data; + ESP_GOTO_ON_FALSE(phy_w_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't write registers from null"); + ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed"); + ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_write(ð_driver->mediator, + phy_addr, phy_w_data->reg_addr, *(phy_w_data->reg_value_p)), err, TAG, "failed to write PHY register"); break; default: if (phy->custom_ioctl != NULL && cmd >= ETH_CMD_CUSTOM_PHY_CMDS) { diff --git a/components/esp_eth/src/esp_eth_phy_lan87xx.c b/components/esp_eth/src/esp_eth_phy_lan87xx.c index 621f0b7478..b63242d660 100644 --- a/components/esp_eth/src/esp_eth_phy_lan87xx.c +++ b/components/esp_eth/src/esp_eth_phy_lan87xx.c @@ -6,6 +6,8 @@ #include #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "esp_log.h" #include "esp_check.h" #include "esp_eth_phy_802_3.h" @@ -317,6 +319,19 @@ err: return ret; } +static esp_err_t lan87xx_set_speed(esp_eth_phy_t *phy, eth_speed_t speed) +{ + esp_err_t ret = ESP_OK; + phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); + + /* It was observed that a delay needs to be introduced after setting speed and prior driver's start. + Otherwise, the very first read of PHY registers is not valid data (0xFFFF's). */ + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_set_speed(phy_802_3, speed), err, TAG, "set speed failed"); + vTaskDelay(pdMS_TO_TICKS(10)); +err: + return ret; +} + static esp_err_t lan87xx_init(esp_eth_phy_t *phy) { esp_err_t ret = ESP_OK; @@ -359,6 +374,7 @@ esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config) lan87xx->phy_802_3.parent.get_link = lan87xx_get_link; lan87xx->phy_802_3.parent.autonego_ctrl = lan87xx_autonego_ctrl; lan87xx->phy_802_3.parent.loopback = lan87xx_loopback; + lan87xx->phy_802_3.parent.set_speed = lan87xx_set_speed; return &lan87xx->phy_802_3.parent; err: From 0df97644c4b57602884e5ee5546f93fd85acad18 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Mon, 6 Nov 2023 14:43:48 +0100 Subject: [PATCH 7/8] ci(esp_eth): addressed LAN8720 errata in CI test --- .../esp_eth/test_apps/main/Kconfig.projbuild | 6 ++-- .../test_apps/main/esp_eth_test_apps.c | 36 +++++++++++++++++-- .../test_apps/main/esp_eth_test_common.c | 4 +-- .../test_apps/sdkconfig.ci.default_ksz8041 | 2 +- .../test_apps/sdkconfig.ci.default_lan8720 | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/components/esp_eth/test_apps/main/Kconfig.projbuild b/components/esp_eth/test_apps/main/Kconfig.projbuild index b9ac8825db..61b15841e7 100644 --- a/components/esp_eth/test_apps/main/Kconfig.projbuild +++ b/components/esp_eth/test_apps/main/Kconfig.projbuild @@ -30,10 +30,10 @@ menu "esp_eth TEST_APPS Configuration" config TARGET_ETH_PHY_DEVICE_IP101 bool "IP101" - config TARGET_ETH_PHY_DEVICE_LAN87XX + config TARGET_ETH_PHY_DEVICE_LAN8720 bool "LAN8720" - config TARGET_ETH_PHY_DEVICE_KSZ80XX - bool "KSZ80xx" + config TARGET_ETH_PHY_DEVICE_KSZ8041 + bool "KSZ8041" config TARGET_ETH_PHY_DEVICE_RTL8201 bool "RTL8201" config TARGET_ETH_PHY_DEVICE_DP83848 diff --git a/components/esp_eth/test_apps/main/esp_eth_test_apps.c b/components/esp_eth/test_apps/main/esp_eth_test_apps.c index 3532df46c4..9a58b7b5fe 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_apps.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_apps.c @@ -164,6 +164,23 @@ TEST_CASE("ethernet io speed/duplex/autonegotiation", "[ethernet]") // set new speed TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &speed)); +// *** LAN8720 deviation *** +// Rationale: When the device is in manual 100BASE-TX or 10BASE-T modes with Auto-MDIX enabled, the PHY does not link to a +// link partner that is configured for auto-negotiation. See LAN8720 errata for more details. +#ifdef CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720 + esp_eth_phy_reg_rw_data_t reg; + uint32_t reg_val; + reg.reg_addr = 27; + reg.reg_value_p = ®_val; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_READ_PHY_REG, ®)); + reg_val |= 0x8000; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_WRITE_PHY_REG, ®)); + uint32_t reg_val_act; + reg.reg_value_p = ®_val_act; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_READ_PHY_REG, ®)); + TEST_ASSERT_EQUAL(reg_val, reg_val_act); +#endif + // start the driver and wait for connection establish esp_eth_start(eth_handle); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); @@ -242,6 +259,19 @@ TEST_CASE("ethernet io speed/duplex/autonegotiation", "[ethernet]") esp_eth_stop(eth_handle); auto_nego_en = true; esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en); + +// *** LAN8720 deviation *** +// Rationale: See above +#ifdef CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720 + reg.reg_value_p = ®_val; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_READ_PHY_REG, ®)); + reg_val &= ~0x8000; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_WRITE_PHY_REG, ®)); + reg.reg_value_p = ®_val_act; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_READ_PHY_REG, ®)); + TEST_ASSERT_EQUAL(reg_val, reg_val_act); +#endif + esp_eth_start(eth_handle); bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); @@ -328,7 +358,7 @@ TEST_CASE("ethernet io loopback", "[ethernet]") ESP_LOGI(TAG, "Test with %s Mbps %s duplex.", expected_speed == ETH_SPEED_10M ? "10" : "100", expected_duplex == ETH_DUPLEX_HALF ? "half" : "full"); // *** KSZ80XX, KSZ8851SNL and DM9051 deviation *** // Rationale: do not support loopback at 10 Mbps -#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DM9051) +#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8041) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DM9051) if ((expected_speed == ETH_SPEED_10M)) { TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_SPEED, &expected_speed)); continue; @@ -378,7 +408,7 @@ TEST_CASE("ethernet io loopback", "[ethernet]") // *** RTL8201, DP83848 and LAN87xx deviation *** // Rationale: do not support autonegotiation with loopback enabled. #if defined(CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DP83848) || \ - defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX) + defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720) TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_eth_ioctl(eth_handle, ETH_CMD_S_AUTONEGO, &auto_nego_en)); goto cleanup; #endif @@ -397,7 +427,7 @@ TEST_CASE("ethernet io loopback", "[ethernet]") TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); // *** W5500, LAN87xx, RTL8201 and DP83848 deviation *** // Rationale: in those cases 'goto cleanup' is used to skip part of the test code. Incasing in #if block is done to prevent unused label error -#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_W5500) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX) || \ +#if defined(CONFIG_TARGET_ETH_PHY_DEVICE_W5500) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720) || \ defined(CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201) || defined(CONFIG_TARGET_ETH_PHY_DEVICE_DP83848) cleanup: #endif diff --git a/components/esp_eth/test_apps/main/esp_eth_test_common.c b/components/esp_eth/test_apps/main/esp_eth_test_common.c index 0a04d9561e..69f5577abd 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_common.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_common.c @@ -96,9 +96,9 @@ esp_eth_phy_t *phy_init(eth_phy_config_t *phy_config) phy_config->phy_addr = ESP_ETH_PHY_ADDR_AUTO; #if CONFIG_TARGET_ETH_PHY_DEVICE_IP101 phy = esp_eth_phy_new_ip101(phy_config); -#elif CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX +#elif CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720 phy = esp_eth_phy_new_lan87xx(phy_config); -#elif CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX +#elif CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8041 phy = esp_eth_phy_new_ksz80xx(phy_config); #elif CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201 phy = esp_eth_phy_new_rtl8201(phy_config); diff --git a/components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 b/components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 index ecb0066f5e..6a6547adf7 100644 --- a/components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 +++ b/components/esp_eth/test_apps/sdkconfig.ci.default_ksz8041 @@ -6,4 +6,4 @@ CONFIG_ETH_USE_ESP32_EMAC=y CONFIG_ESP_TASK_WDT=n CONFIG_TARGET_USE_INTERNAL_ETHERNET=y -CONFIG_TARGET_ETH_PHY_DEVICE_KSZ80XX=y +CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8041=y diff --git a/components/esp_eth/test_apps/sdkconfig.ci.default_lan8720 b/components/esp_eth/test_apps/sdkconfig.ci.default_lan8720 index 1539599da0..c13b8b5f2c 100644 --- a/components/esp_eth/test_apps/sdkconfig.ci.default_lan8720 +++ b/components/esp_eth/test_apps/sdkconfig.ci.default_lan8720 @@ -6,6 +6,6 @@ CONFIG_ETH_USE_ESP32_EMAC=y CONFIG_ESP_TASK_WDT_EN=n CONFIG_TARGET_USE_INTERNAL_ETHERNET=y -CONFIG_TARGET_ETH_PHY_DEVICE_LAN87XX=y +CONFIG_TARGET_ETH_PHY_DEVICE_LAN8720=y CONFIG_ETH_RMII_CLK_OUTPUT=y CONFIG_ETH_RMII_CLK_OUT_GPIO=17 From d23b41c7cb51052c1c8ba257707cbb89072bd3af Mon Sep 17 00:00:00 2001 From: Ondrej Date: Thu, 16 Nov 2023 13:35:08 +0000 Subject: [PATCH 8/8] fix(esp_eth): fixed ETH_CMD_READ/WRITE_PHY_REG build issue --- components/esp_eth/src/esp_eth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index 6590ae15e9..5634c106db 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -467,7 +467,7 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data) ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set loopback to null"); ESP_GOTO_ON_ERROR(phy->loopback(phy, *(bool *)data), err, TAG, "configuration of phy loopback mode failed"); break; - case ETH_CMD_READ_PHY_REG: + case ETH_CMD_READ_PHY_REG: { uint32_t phy_addr; ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info"); esp_eth_phy_reg_rw_data_t *phy_r_data = (esp_eth_phy_reg_rw_data_t *)data; @@ -475,14 +475,17 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data) ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed"); ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_read(ð_driver->mediator, phy_addr, phy_r_data->reg_addr, phy_r_data->reg_value_p), err, TAG, "failed to read PHY register"); + } break; - case ETH_CMD_WRITE_PHY_REG: + case ETH_CMD_WRITE_PHY_REG: { + uint32_t phy_addr; ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info"); esp_eth_phy_reg_rw_data_t *phy_w_data = (esp_eth_phy_reg_rw_data_t *)data; ESP_GOTO_ON_FALSE(phy_w_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't write registers from null"); ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed"); ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_write(ð_driver->mediator, phy_addr, phy_w_data->reg_addr, *(phy_w_data->reg_value_p)), err, TAG, "failed to write PHY register"); + } break; default: if (phy->custom_ioctl != NULL && cmd >= ETH_CMD_CUSTOM_PHY_CMDS) {