mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
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.
This commit is contained in:
@@ -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;
|
||||
|
||||
|
@@ -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:
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
*/
|
||||
@@ -173,6 +173,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;
|
||||
@@ -184,6 +201,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:
|
||||
|
@@ -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 <stdlib.h>
|
||||
#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 {
|
||||
|
@@ -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:
|
||||
|
@@ -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:
|
||||
|
Reference in New Issue
Block a user