From 9d7ba4c49a7901d37b628cc85d41ddb6cc2d8998 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 12 Mar 2021 14:35:42 +0800 Subject: [PATCH 1/3] eth_phy: fix wrong register bit order in ksz8041 --- components/esp_eth/src/esp_eth_phy_ksz8041.c | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/esp_eth/src/esp_eth_phy_ksz8041.c b/components/esp_eth/src/esp_eth_phy_ksz8041.c index 24e262bc98d..cc75e335829 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz8041.c +++ b/components/esp_eth/src/esp_eth_phy_ksz8041.c @@ -41,20 +41,20 @@ static const char *TAG = "ksz8041"; */ typedef union { struct { - uint32_t hp_mdix : 1; /* HP Auto MDI/MDI-X Mode */ - uint32_t mdi_x_select : 1; /* MDI/MDI-X Select */ - uint32_t pairswap_dis : 1; /* Disable Auto MDI/MDI-X */ - uint32_t energy_det : 1; /* Presence of Signal on RX+/- Wire Pair */ - uint32_t force_link : 1; /* Force Link Pass */ - uint32_t power_saving : 1; /* Enable Powering Saving */ - uint32_t irq_level : 1; /* Interrupt Pin Active Level */ - uint32_t jabber : 1; /* Enable Jabber Counter */ - uint32_t auto_nego_comp : 1; /* Auto Negotiation Complete */ - uint32_t flow_ctl_cap : 1; /* Flow Control Capable */ - uint32_t phy_iso : 1; /* PHY in Isolate Mode */ - uint32_t op_mode_ind : 3; /* Operation Mode Indication */ - uint32_t en_sqe_test : 1; /* Enable SQE Test */ - uint32_t dis_data_scr: 1; /* Disable Scrambler */ + uint32_t dis_data_scr: 1; /* Disable Scrambler */ + uint32_t en_sqe_test : 1; /* Enable SQE Test */ + uint32_t op_mode : 3; /* Operation Mode */ + uint32_t phy_iso : 1; /* PHY Isolate */ + uint32_t en_flow_ctrl : 1; /* Enable Flow Control */ + uint32_t auto_nego_comp : 1; /* Auto Negotiation Complete */ + uint32_t en_jabber : 1; /* Enable Jabber Counter */ + uint32_t irq_level : 1; /* Interrupt Pin Active Level */ + uint32_t power_saving : 1; /* Enable Powering Saving */ + uint32_t force_link : 1; /* Force Link Pass */ + uint32_t energy_det : 1; /* Presence of Signal on RX+/- Wire Pair */ + uint32_t pairswap_dis : 1; /* Disable Auto MDI/MDI-X */ + uint32_t mdix_select : 1; /* MDI/MDI-X Select */ + uint32_t hp_mdix : 1; /* HP Auto MDI/MDI-X Mode */ }; uint32_t val; } pc2r_reg_t; @@ -90,7 +90,7 @@ static esp_err_t ksz8041_update_link_duplex_speed(phy_ksz8041_t *ksz8041) if (link == ETH_LINK_UP) { PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK, "read PC2R failed", err); - switch (pc2r.op_mode_ind) { + switch (pc2r.op_mode) { case 1: //10Base-T half-duplex speed = ETH_SPEED_10M; duplex = ETH_DUPLEX_HALF; From 98a4c70af94acdfb93baf48d7d25fe4d1560e4df Mon Sep 17 00:00:00 2001 From: Patrick Wieder Date: Fri, 19 Feb 2021 16:12:06 +0100 Subject: [PATCH 2/3] Added support for Ethernet PHY KSZ8081 Merges https://github.com/espressif/esp-idf/pull/6578 --- components/esp_eth/CMakeLists.txt | 1 + components/esp_eth/include/esp_eth_phy.h | 11 + components/esp_eth/src/esp_eth_phy_ksz8081.c | 361 ++++++++++++++++++ .../ethernet/basic/main/Kconfig.projbuild | 6 + .../basic/main/ethernet_example_main.c | 2 + 5 files changed, 381 insertions(+) create mode 100644 components/esp_eth/src/esp_eth_phy_ksz8081.c diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 061e0d5198d..088f5e786cf 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -23,6 +23,7 @@ if(CONFIG_ETH_ENABLED) "src/esp_eth_phy_dp83848.c" "src/esp_eth_phy_ip101.c" "src/esp_eth_phy_ksz8041.c" + "src/esp_eth_phy_ksz8081.c" "src/esp_eth_phy_lan8720.c" "src/esp_eth_phy_rtl8201.c") endif() diff --git a/components/esp_eth/include/esp_eth_phy.h b/components/esp_eth/include/esp_eth_phy.h index e401901066e..9dbc2ef9cde 100644 --- a/components/esp_eth/include/esp_eth_phy.h +++ b/components/esp_eth/include/esp_eth_phy.h @@ -264,6 +264,17 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config); */ esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config); +/** +* @brief Create a PHY instance of KSZ8081 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_ksz8081(const eth_phy_config_t *config); + #if CONFIG_ETH_SPI_ETHERNET_DM9051 /** * @brief Create a PHY instance of DM9051 diff --git a/components/esp_eth/src/esp_eth_phy_ksz8081.c b/components/esp_eth/src/esp_eth_phy_ksz8081.c new file mode 100644 index 00000000000..2dbdf476b1d --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_ksz8081.c @@ -0,0 +1,361 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_rom_gpio.h" +#include "esp_rom_sys.h" + +static const char *TAG = "ksz8081"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ +/** + * @brief PC1R(PHY Control 1 Register) + * + */ +typedef union { + struct { + uint32_t op_mode : 3; /* Operation Mode Indication */ + uint32_t phy_iso : 1; /* PHY in Isolate Mode */ + uint32_t energy_det: 1; /* Signal presence on RX pair */ + uint32_t mdix_state : 1; /* MDI/MDI-X state */ + uint32_t reserved_6 : 1; /* Reserved */ + uint32_t polarity_status : 1; /* Polarity status */ + uint32_t link_status : 1; /* Link status */ + uint32_t en_flow_ctrl : 1; /* Flow control */ + uint32_t reserved_15_10 : 6; /* Reserved */ + }; + uint32_t val; +} pc1r_reg_t; +#define ETH_PHY_PC1R_REG_ADDR (0x1E) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + int addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; + int reset_gpio_num; +} phy_ksz8081_t; + +static esp_err_t ksz8081_update_link_duplex_speed(phy_ksz8081_t *ksz8081) +{ + esp_eth_mediator_t *eth = ksz8081->eth; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + uint32_t peer_pause_ability = false; + anlpar_reg_t anlpar; + bmsr_reg_t bmsr; + pc1r_reg_t pc1r; + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, + "read ANLPAR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + /* check if link status changed */ + if (ksz8081->link_status != link) { + /* when link up, read negotiation result */ + if (link == ETH_LINK_UP) { + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_PC1R_REG_ADDR, &(pc1r.val)) == ESP_OK, + "read PC1R failed", err); + switch (pc1r.op_mode) { + case 1: //10Base-T half-duplex + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_HALF; + break; + case 2: //100Base-TX half-duplex + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_HALF; + break; + case 5: //10Base-T full-duplex + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_FULL; + break; + case 6: //100Base-TX full-duplex + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_FULL; + break; + default: + break; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, + "change speed failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, + "change duplex failed", err); + /* if we're in duplex mode, and peer has the flow control ability */ + if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { + peer_pause_ability = 1; + } else { + peer_pause_ability = 0; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, + "change pause ability failed", err); + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, + "change link failed", err); + ksz8081->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator to null", err); + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + ksz8081->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t ksz8081_get_link(esp_eth_phy_t *phy) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + /* Update information about link, speed, duplex */ + PHY_CHECK(ksz8081_update_link_duplex_speed(ksz8081) == ESP_OK, "update link duplex speed failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_reset(esp_eth_phy_t *phy) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + ksz8081->link_status = ETH_LINK_DOWN; + esp_eth_mediator_t *eth = ksz8081->eth; + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + /* wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < ksz8081->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); + if (!bmcr.reset) { + break; + } + } + PHY_CHECK(to < ksz8081->reset_timeout_ms / 10, "reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_reset_hw(esp_eth_phy_t *phy) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + if (ksz8081->reset_gpio_num >= 0) { + esp_rom_gpio_pad_select_gpio(ksz8081->reset_gpio_num); + gpio_set_direction(ksz8081->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(ksz8081->reset_gpio_num, 0); + esp_rom_delay_us(100); // insert min input assert time + gpio_set_level(ksz8081->reset_gpio_num, 1); + } + return ESP_OK; +} + +static esp_err_t ksz8081_negotiate(esp_eth_phy_t *phy) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + esp_eth_mediator_t *eth = ksz8081->eth; + /* Restart auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + uint32_t to = 0; + for (to = 0; to < ksz8081->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + "read BMSR failed", err); + if (bmsr.auto_nego_complete) { + break; + } + } + /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ + if (to >= ksz8081->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "auto negotiation timeout"); + } + /* Updata information about link, speed, duplex */ + PHY_CHECK(ksz8081_update_link_duplex_speed(ksz8081) == ESP_OK, "update link duplex speed failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + esp_eth_mediator_t *eth = ksz8081->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); + if (!enable) { + /* General Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Normal operation Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + "write BMCR failed", err); + if (!enable) { + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + /* wait for power up complete */ + uint32_t to = 0; + for (to = 0; to < ksz8081->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + "read BMCR failed", err); + if (bmcr.power_down == 0) { + break; + } + } + PHY_CHECK(to < ksz8081->reset_timeout_ms / 10, "power up timeout", err); + } + + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + ksz8081->addr = addr; + return ESP_OK; +} + +static esp_err_t ksz8081_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "addr can't be null", err); + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + *addr = ksz8081->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t ksz8081_del(esp_eth_phy_t *phy) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + free(ksz8081); + return ESP_OK; +} + +static esp_err_t ksz8081_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + esp_eth_mediator_t *eth = ksz8081->eth; + /* Set PAUSE function ability */ + anar_reg_t anar; + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, + "read ANAR failed", err); + if (ability) { + anar.asymmetric_pause = 1; + anar.symmetric_pause = 1; + } else { + anar.asymmetric_pause = 0; + anar.symmetric_pause = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, + "write ANAR failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_init(esp_eth_phy_t *phy) +{ + phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); + esp_eth_mediator_t *eth = ksz8081->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(ksz8081_pwrctl(phy, true) == ESP_OK, "power control failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(ksz8081_reset(phy) == ESP_OK, "reset failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, + "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, + "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == 0x16, "wrong chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ksz8081_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(ksz8081_pwrctl(phy, false) == ESP_OK, "power control failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_ksz8081(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + phy_ksz8081_t *ksz8081 = calloc(1, sizeof(phy_ksz8081_t)); + PHY_CHECK(ksz8081, "calloc ksz8081 failed", err); + ksz8081->addr = config->phy_addr; + ksz8081->reset_gpio_num = config->reset_gpio_num; + ksz8081->reset_timeout_ms = config->reset_timeout_ms; + ksz8081->link_status = ETH_LINK_DOWN; + ksz8081->autonego_timeout_ms = config->autonego_timeout_ms; + ksz8081->parent.reset = ksz8081_reset; + ksz8081->parent.reset_hw = ksz8081_reset_hw; + ksz8081->parent.init = ksz8081_init; + ksz8081->parent.deinit = ksz8081_deinit; + ksz8081->parent.set_mediator = ksz8081_set_mediator; + ksz8081->parent.negotiate = ksz8081_negotiate; + ksz8081->parent.get_link = ksz8081_get_link; + ksz8081->parent.pwrctl = ksz8081_pwrctl; + ksz8081->parent.get_addr = ksz8081_get_addr; + ksz8081->parent.set_addr = ksz8081_set_addr; + ksz8081->parent.advertise_pause_ability = ksz8081_advertise_pause_ability; + ksz8081->parent.del = ksz8081_del; + + return &(ksz8081->parent); +err: + return NULL; +} diff --git a/examples/ethernet/basic/main/Kconfig.projbuild b/examples/ethernet/basic/main/Kconfig.projbuild index ba7eec45c6a..7a974d51baa 100644 --- a/examples/ethernet/basic/main/Kconfig.projbuild +++ b/examples/ethernet/basic/main/Kconfig.projbuild @@ -70,6 +70,12 @@ menu "Example Configuration" help The KSZ8041 is a single supply 10Base-T/100Base-TX Physical Layer Transceiver. Goto https://www.microchip.com/wwwproducts/en/KSZ8041 for more information about it. + + config EXAMPLE_ETH_PHY_KSZ8081 + bool "KSZ8081" + help + The KSZ8081 is a single supply 10Base-T/100Base-TX Physical Layer Transceiver. + Goto https://www.microchip.com/wwwproducts/en/KSZ8081 for more information about it. endchoice # EXAMPLE_ETH_PHY_MODEL config EXAMPLE_ETH_MDC_GPIO diff --git a/examples/ethernet/basic/main/ethernet_example_main.c b/examples/ethernet/basic/main/ethernet_example_main.c index 63d82e79c35..e448797d142 100644 --- a/examples/ethernet/basic/main/ethernet_example_main.c +++ b/examples/ethernet/basic/main/ethernet_example_main.c @@ -98,6 +98,8 @@ void app_main(void) esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config); #elif CONFIG_EXAMPLE_ETH_PHY_KSZ8041 esp_eth_phy_t *phy = esp_eth_phy_new_ksz8041(&phy_config); +#elif CONFIG_EXAMPLE_ETH_PHY_KSZ8081 + esp_eth_phy_t *phy = esp_eth_phy_new_ksz8081(&phy_config); #endif #elif CONFIG_ETH_USE_SPI_ETHERNET gpio_install_isr_service(0); From 2a34b0496c923ee72c2a28105d7bdaa21f1766a9 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 15 Mar 2021 12:50:39 +0800 Subject: [PATCH 3/3] esp_eth: refactor ksz8041 driver into ksz80xx --- components/esp_eth/CMakeLists.txt | 3 +- components/esp_eth/src/esp_eth_phy_ksz8081.c | 361 ------------------ ...th_phy_ksz8041.c => esp_eth_phy_ksz80xx.c} | 255 ++++++++----- 3 files changed, 158 insertions(+), 461 deletions(-) delete mode 100644 components/esp_eth/src/esp_eth_phy_ksz8081.c rename components/esp_eth/src/{esp_eth_phy_ksz8041.c => esp_eth_phy_ksz80xx.c} (53%) diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 088f5e786cf..621cc70580e 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -22,8 +22,7 @@ if(CONFIG_ETH_ENABLED) list(APPEND srcs "src/esp_eth_mac_esp32.c" "src/esp_eth_phy_dp83848.c" "src/esp_eth_phy_ip101.c" - "src/esp_eth_phy_ksz8041.c" - "src/esp_eth_phy_ksz8081.c" + "src/esp_eth_phy_ksz80xx.c" "src/esp_eth_phy_lan8720.c" "src/esp_eth_phy_rtl8201.c") endif() diff --git a/components/esp_eth/src/esp_eth_phy_ksz8081.c b/components/esp_eth/src/esp_eth_phy_ksz8081.c deleted file mode 100644 index 2dbdf476b1d..00000000000 --- a/components/esp_eth/src/esp_eth_phy_ksz8081.c +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2021 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include -#include -#include -#include "esp_log.h" -#include "esp_eth.h" -#include "eth_phy_regs_struct.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/gpio.h" -#include "esp_rom_gpio.h" -#include "esp_rom_sys.h" - -static const char *TAG = "ksz8081"; -#define PHY_CHECK(a, str, goto_tag, ...) \ - do { \ - if (!(a)) \ - { \ - ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - goto goto_tag; \ - } \ - } while (0) - -/***************Vendor Specific Register***************/ -/** - * @brief PC1R(PHY Control 1 Register) - * - */ -typedef union { - struct { - uint32_t op_mode : 3; /* Operation Mode Indication */ - uint32_t phy_iso : 1; /* PHY in Isolate Mode */ - uint32_t energy_det: 1; /* Signal presence on RX pair */ - uint32_t mdix_state : 1; /* MDI/MDI-X state */ - uint32_t reserved_6 : 1; /* Reserved */ - uint32_t polarity_status : 1; /* Polarity status */ - uint32_t link_status : 1; /* Link status */ - uint32_t en_flow_ctrl : 1; /* Flow control */ - uint32_t reserved_15_10 : 6; /* Reserved */ - }; - uint32_t val; -} pc1r_reg_t; -#define ETH_PHY_PC1R_REG_ADDR (0x1E) - -typedef struct { - esp_eth_phy_t parent; - esp_eth_mediator_t *eth; - int addr; - uint32_t reset_timeout_ms; - uint32_t autonego_timeout_ms; - eth_link_t link_status; - int reset_gpio_num; -} phy_ksz8081_t; - -static esp_err_t ksz8081_update_link_duplex_speed(phy_ksz8081_t *ksz8081) -{ - esp_eth_mediator_t *eth = ksz8081->eth; - eth_speed_t speed = ETH_SPEED_10M; - eth_duplex_t duplex = ETH_DUPLEX_HALF; - uint32_t peer_pause_ability = false; - anlpar_reg_t anlpar; - bmsr_reg_t bmsr; - pc1r_reg_t pc1r; - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, - "read ANLPAR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, - "read BMSR failed", err); - eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - /* check if link status changed */ - if (ksz8081->link_status != link) { - /* when link up, read negotiation result */ - if (link == ETH_LINK_UP) { - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_PC1R_REG_ADDR, &(pc1r.val)) == ESP_OK, - "read PC1R failed", err); - switch (pc1r.op_mode) { - case 1: //10Base-T half-duplex - speed = ETH_SPEED_10M; - duplex = ETH_DUPLEX_HALF; - break; - case 2: //100Base-TX half-duplex - speed = ETH_SPEED_100M; - duplex = ETH_DUPLEX_HALF; - break; - case 5: //10Base-T full-duplex - speed = ETH_SPEED_10M; - duplex = ETH_DUPLEX_FULL; - break; - case 6: //100Base-TX full-duplex - speed = ETH_SPEED_100M; - duplex = ETH_DUPLEX_FULL; - break; - default: - break; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, - "change speed failed", err); - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, - "change duplex failed", err); - /* if we're in duplex mode, and peer has the flow control ability */ - if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { - peer_pause_ability = 1; - } else { - peer_pause_ability = 0; - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, - "change pause ability failed", err); - } - PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, - "change link failed", err); - ksz8081->link_status = link; - } - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) -{ - PHY_CHECK(eth, "can't set mediator to null", err); - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - ksz8081->eth = eth; - return ESP_OK; -err: - return ESP_ERR_INVALID_ARG; -} - -static esp_err_t ksz8081_get_link(esp_eth_phy_t *phy) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - /* Update information about link, speed, duplex */ - PHY_CHECK(ksz8081_update_link_duplex_speed(ksz8081) == ESP_OK, "update link duplex speed failed", err); - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_reset(esp_eth_phy_t *phy) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - ksz8081->link_status = ETH_LINK_DOWN; - esp_eth_mediator_t *eth = ksz8081->eth; - bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, - "write BMCR failed", err); - /* wait for reset complete */ - uint32_t to = 0; - for (to = 0; to < ksz8081->reset_timeout_ms / 10; to++) { - vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, - "read BMCR failed", err); - if (!bmcr.reset) { - break; - } - } - PHY_CHECK(to < ksz8081->reset_timeout_ms / 10, "reset timeout", err); - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_reset_hw(esp_eth_phy_t *phy) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - if (ksz8081->reset_gpio_num >= 0) { - esp_rom_gpio_pad_select_gpio(ksz8081->reset_gpio_num); - gpio_set_direction(ksz8081->reset_gpio_num, GPIO_MODE_OUTPUT); - gpio_set_level(ksz8081->reset_gpio_num, 0); - esp_rom_delay_us(100); // insert min input assert time - gpio_set_level(ksz8081->reset_gpio_num, 1); - } - return ESP_OK; -} - -static esp_err_t ksz8081_negotiate(esp_eth_phy_t *phy) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - esp_eth_mediator_t *eth = ksz8081->eth; - /* Restart auto negotiation */ - bmcr_reg_t bmcr = { - .speed_select = 1, /* 100Mbps */ - .duplex_mode = 1, /* Full Duplex */ - .en_auto_nego = 1, /* Auto Negotiation */ - .restart_auto_nego = 1 /* Restart Auto Negotiation */ - }; - PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); - /* Wait for auto negotiation complete */ - bmsr_reg_t bmsr; - uint32_t to = 0; - for (to = 0; to < ksz8081->autonego_timeout_ms / 10; to++) { - vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, - "read BMSR failed", err); - if (bmsr.auto_nego_complete) { - break; - } - } - /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= ksz8081->autonego_timeout_ms / 10) { - ESP_LOGW(TAG, "auto negotiation timeout"); - } - /* Updata information about link, speed, duplex */ - PHY_CHECK(ksz8081_update_link_duplex_speed(ksz8081) == ESP_OK, "update link duplex speed failed", err); - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_pwrctl(esp_eth_phy_t *phy, bool enable) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - esp_eth_mediator_t *eth = ksz8081->eth; - bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, - "read BMCR failed", err); - if (!enable) { - /* General Power Down Mode */ - bmcr.power_down = 1; - } else { - /* Normal operation Mode */ - bmcr.power_down = 0; - } - PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, - "write BMCR failed", err); - if (!enable) { - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, - "read BMCR failed", err); - PHY_CHECK(bmcr.power_down == 1, "power down failed", err); - } else { - /* wait for power up complete */ - uint32_t to = 0; - for (to = 0; to < ksz8081->reset_timeout_ms / 10; to++) { - vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, - "read BMCR failed", err); - if (bmcr.power_down == 0) { - break; - } - } - PHY_CHECK(to < ksz8081->reset_timeout_ms / 10, "power up timeout", err); - } - - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_set_addr(esp_eth_phy_t *phy, uint32_t addr) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - ksz8081->addr = addr; - return ESP_OK; -} - -static esp_err_t ksz8081_get_addr(esp_eth_phy_t *phy, uint32_t *addr) -{ - PHY_CHECK(addr, "addr can't be null", err); - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - *addr = ksz8081->addr; - return ESP_OK; -err: - return ESP_ERR_INVALID_ARG; -} - -static esp_err_t ksz8081_del(esp_eth_phy_t *phy) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - free(ksz8081); - return ESP_OK; -} - -static esp_err_t ksz8081_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - esp_eth_mediator_t *eth = ksz8081->eth; - /* Set PAUSE function ability */ - anar_reg_t anar; - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, - "read ANAR failed", err); - if (ability) { - anar.asymmetric_pause = 1; - anar.symmetric_pause = 1; - } else { - anar.asymmetric_pause = 0; - anar.symmetric_pause = 0; - } - PHY_CHECK(eth->phy_reg_write(eth, ksz8081->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, - "write ANAR failed", err); - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_init(esp_eth_phy_t *phy) -{ - phy_ksz8081_t *ksz8081 = __containerof(phy, phy_ksz8081_t, parent); - esp_eth_mediator_t *eth = ksz8081->eth; - /* Power on Ethernet PHY */ - PHY_CHECK(ksz8081_pwrctl(phy, true) == ESP_OK, "power control failed", err); - /* Reset Ethernet PHY */ - PHY_CHECK(ksz8081_reset(phy) == ESP_OK, "reset failed", err); - /* Check PHY ID */ - phyidr1_reg_t id1; - phyidr2_reg_t id2; - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, - "read ID1 failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ksz8081->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, - "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == 0x16, "wrong chip ID", err); - return ESP_OK; -err: - return ESP_FAIL; -} - -static esp_err_t ksz8081_deinit(esp_eth_phy_t *phy) -{ - /* Power off Ethernet PHY */ - PHY_CHECK(ksz8081_pwrctl(phy, false) == ESP_OK, "power control failed", err); - return ESP_OK; -err: - return ESP_FAIL; -} - -esp_eth_phy_t *esp_eth_phy_new_ksz8081(const eth_phy_config_t *config) -{ - PHY_CHECK(config, "can't set phy config to null", err); - phy_ksz8081_t *ksz8081 = calloc(1, sizeof(phy_ksz8081_t)); - PHY_CHECK(ksz8081, "calloc ksz8081 failed", err); - ksz8081->addr = config->phy_addr; - ksz8081->reset_gpio_num = config->reset_gpio_num; - ksz8081->reset_timeout_ms = config->reset_timeout_ms; - ksz8081->link_status = ETH_LINK_DOWN; - ksz8081->autonego_timeout_ms = config->autonego_timeout_ms; - ksz8081->parent.reset = ksz8081_reset; - ksz8081->parent.reset_hw = ksz8081_reset_hw; - ksz8081->parent.init = ksz8081_init; - ksz8081->parent.deinit = ksz8081_deinit; - ksz8081->parent.set_mediator = ksz8081_set_mediator; - ksz8081->parent.negotiate = ksz8081_negotiate; - ksz8081->parent.get_link = ksz8081_get_link; - ksz8081->parent.pwrctl = ksz8081_pwrctl; - ksz8081->parent.get_addr = ksz8081_get_addr; - ksz8081->parent.set_addr = ksz8081_set_addr; - ksz8081->parent.advertise_pause_ability = ksz8081_advertise_pause_ability; - ksz8081->parent.del = ksz8081_del; - - return &(ksz8081->parent); -err: - return NULL; -} diff --git a/components/esp_eth/src/esp_eth_phy_ksz8041.c b/components/esp_eth/src/esp_eth_phy_ksz80xx.c similarity index 53% rename from components/esp_eth/src/esp_eth_phy_ksz8041.c rename to components/esp_eth/src/esp_eth_phy_ksz80xx.c index cc75e335829..2712d519d1a 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz8041.c +++ b/components/esp_eth/src/esp_eth_phy_ksz80xx.c @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2019-2021 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,10 +23,9 @@ #include "esp_rom_gpio.h" #include "esp_rom_sys.h" -static const char *TAG = "ksz8041"; +static const char *TAG = "ksz80xx"; #define PHY_CHECK(a, str, goto_tag, ...) \ - do \ - { \ + do { \ if (!(a)) \ { \ ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ @@ -34,9 +33,12 @@ static const char *TAG = "ksz8041"; } \ } while (0) +#define KSZ8041_MODEL_ID (0x11) +#define KSZ8081_MODEL_ID (0x16) + /***************Vendor Specific Register***************/ /** - * @brief PC2R(PHY Control 2 Register) + * @brief PC2R(PHY Control 2 Register) for KSZ8041 * */ typedef union { @@ -57,8 +59,28 @@ typedef union { uint32_t hp_mdix : 1; /* HP Auto MDI/MDI-X Mode */ }; uint32_t val; -} pc2r_reg_t; -#define ETH_PHY_PC2R_REG_ADDR (0x1F) +} ksz8041_pc2r_reg_t; +#define KSZ8041_PC2R_ERG_ADDR (0x1F) + +/** + * @brief PC1R(PHY Control 1 Register) for KSZ8081 + * + */ +typedef union { + struct { + uint32_t op_mode : 3; /* Operation Mode Indication */ + uint32_t phy_iso : 1; /* PHY in Isolate Mode */ + uint32_t energy_det: 1; /* Signal presence on RX pair */ + uint32_t mdix_state : 1; /* MDI/MDI-X state */ + uint32_t reserved_6 : 1; /* Reserved */ + uint32_t polarity_status : 1; /* Polarity status */ + uint32_t link_status : 1; /* Link status */ + uint32_t en_flow_ctrl : 1; /* Flow control */ + uint32_t reserved_15_10 : 6; /* Reserved */ + }; + uint32_t val; +} ksz8081_pc1r_reg_t; +#define KSZ8081_PC1R_REG_ADDR (0x1E) typedef struct { esp_eth_phy_t parent; @@ -68,29 +90,39 @@ typedef struct { uint32_t autonego_timeout_ms; eth_link_t link_status; int reset_gpio_num; -} phy_ksz8041_t; + int vendor_model; +} phy_ksz80xx_t; -static esp_err_t ksz8041_update_link_duplex_speed(phy_ksz8041_t *ksz8041) +static esp_err_t ksz80xx_update_link_duplex_speed(phy_ksz80xx_t *ksz80xx) { - esp_eth_mediator_t *eth = ksz8041->eth; + esp_eth_mediator_t *eth = ksz80xx->eth; eth_speed_t speed = ETH_SPEED_10M; eth_duplex_t duplex = ETH_DUPLEX_HALF; uint32_t peer_pause_ability = false; anlpar_reg_t anlpar; bmsr_reg_t bmsr; - pc2r_reg_t pc2r; - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, "read ANLPAR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; /* check if link status changed */ - if (ksz8041->link_status != link) { + if (ksz80xx->link_status != link) { /* when link up, read negotiation result */ if (link == ETH_LINK_UP) { - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK, - "read PC2R failed", err); - switch (pc2r.op_mode) { + int op_mode = 0; + if (ksz80xx->vendor_model == KSZ8041_MODEL_ID) { + ksz8041_pc2r_reg_t pc2r; + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, KSZ8041_PC2R_ERG_ADDR, &(pc2r.val)) == ESP_OK, + "read PC2R failed", err); + op_mode = pc2r.op_mode; + } else if (ksz80xx->vendor_model == KSZ8081_MODEL_ID) { + ksz8081_pc1r_reg_t pc1r; + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, KSZ8081_PC1R_REG_ADDR, &(pc1r.val)) == ESP_OK, + "read PC1R failed", err); + op_mode = pc1r.op_mode; + } + switch (op_mode) { case 1: //10Base-T half-duplex speed = ETH_SPEED_10M; duplex = ETH_DUPLEX_HALF; @@ -125,74 +157,74 @@ static esp_err_t ksz8041_update_link_duplex_speed(phy_ksz8041_t *ksz8041) } PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "change link failed", err); - ksz8041->link_status = link; + ksz80xx->link_status = link; } return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +static esp_err_t ksz80xx_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) { PHY_CHECK(eth, "can't set mediator to null", err); - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - ksz8041->eth = eth; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + ksz80xx->eth = eth; return ESP_OK; err: return ESP_ERR_INVALID_ARG; } -static esp_err_t ksz8041_get_link(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_get_link(esp_eth_phy_t *phy) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); /* Update information about link, speed, duplex */ - PHY_CHECK(ksz8041_update_link_duplex_speed(ksz8041) == ESP_OK, "update link duplex speed failed", err); + PHY_CHECK(ksz80xx_update_link_duplex_speed(ksz80xx) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_reset(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_reset(esp_eth_phy_t *phy) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - ksz8041->link_status = ETH_LINK_DOWN; - esp_eth_mediator_t *eth = ksz8041->eth; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + ksz80xx->link_status = ETH_LINK_DOWN; + esp_eth_mediator_t *eth = ksz80xx->eth; bmcr_reg_t bmcr = {.reset = 1}; - PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); /* wait for reset complete */ uint32_t to = 0; - for (to = 0; to < ksz8041->reset_timeout_ms / 10; to++) { + for (to = 0; to < ksz80xx->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); if (!bmcr.reset) { break; } } - PHY_CHECK(to < ksz8041->reset_timeout_ms / 10, "reset timeout", err); + PHY_CHECK(to < ksz80xx->reset_timeout_ms / 10, "reset timeout", err); return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_reset_hw(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_reset_hw(esp_eth_phy_t *phy) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - if (ksz8041->reset_gpio_num >= 0) { - esp_rom_gpio_pad_select_gpio(ksz8041->reset_gpio_num); - gpio_set_direction(ksz8041->reset_gpio_num, GPIO_MODE_OUTPUT); - gpio_set_level(ksz8041->reset_gpio_num, 0); + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + if (ksz80xx->reset_gpio_num >= 0) { + esp_rom_gpio_pad_select_gpio(ksz80xx->reset_gpio_num); + gpio_set_direction(ksz80xx->reset_gpio_num, GPIO_MODE_OUTPUT); + gpio_set_level(ksz80xx->reset_gpio_num, 0); esp_rom_delay_us(100); // insert min input assert time - gpio_set_level(ksz8041->reset_gpio_num, 1); + gpio_set_level(ksz80xx->reset_gpio_num, 1); } return ESP_OK; } -static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_negotiate(esp_eth_phy_t *phy) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - esp_eth_mediator_t *eth = ksz8041->eth; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + esp_eth_mediator_t *eth = ksz80xx->eth; /* Restart auto negotiation */ bmcr_reg_t bmcr = { .speed_select = 1, /* 100Mbps */ @@ -200,38 +232,35 @@ static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy) .en_auto_nego = 1, /* Auto Negotiation */ .restart_auto_nego = 1 /* Restart Auto Negotiation */ }; - PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); /* Wait for auto negotiation complete */ bmsr_reg_t bmsr; - pc2r_reg_t pc2r; uint32_t to = 0; - for (to = 0; to < ksz8041->autonego_timeout_ms / 10; to++) { + for (to = 0; to < ksz80xx->autonego_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK, - "read PC2R failed", err); - if (bmsr.auto_nego_complete && pc2r.auto_nego_comp) { + if (bmsr.auto_nego_complete) { break; } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= ksz8041->autonego_timeout_ms / 10) { + if (to >= ksz80xx->autonego_timeout_ms / 10) { ESP_LOGW(TAG, "auto negotiation timeout"); } /* Updata information about link, speed, duplex */ - PHY_CHECK(ksz8041_update_link_duplex_speed(ksz8041) == ESP_OK, "update link duplex speed failed", err); + PHY_CHECK(ksz80xx_update_link_duplex_speed(ksz80xx) == ESP_OK, "update link duplex speed failed", err); return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_pwrctl(esp_eth_phy_t *phy, bool enable) +static esp_err_t ksz80xx_pwrctl(esp_eth_phy_t *phy, bool enable) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - esp_eth_mediator_t *eth = ksz8041->eth; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + esp_eth_mediator_t *eth = ksz80xx->eth; bmcr_reg_t bmcr; - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); if (!enable) { /* General Power Down Mode */ @@ -240,61 +269,61 @@ static esp_err_t ksz8041_pwrctl(esp_eth_phy_t *phy, bool enable) /* Normal operation Mode */ bmcr.power_down = 0; } - PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, + PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); if (!enable) { - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); PHY_CHECK(bmcr.power_down == 1, "power down failed", err); } else { /* wait for power up complete */ uint32_t to = 0; - for (to = 0; to < ksz8041->reset_timeout_ms / 10; to++) { + for (to = 0; to < ksz80xx->reset_timeout_ms / 10; to++) { vTaskDelay(pdMS_TO_TICKS(10)); - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); if (bmcr.power_down == 0) { break; } } - PHY_CHECK(to < ksz8041->reset_timeout_ms / 10, "power up timeout", err); + PHY_CHECK(to < ksz80xx->reset_timeout_ms / 10, "power up timeout", err); } return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_set_addr(esp_eth_phy_t *phy, uint32_t addr) +static esp_err_t ksz80xx_set_addr(esp_eth_phy_t *phy, uint32_t addr) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - ksz8041->addr = addr; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + ksz80xx->addr = addr; return ESP_OK; } -static esp_err_t ksz8041_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +static esp_err_t ksz80xx_get_addr(esp_eth_phy_t *phy, uint32_t *addr) { PHY_CHECK(addr, "addr can't be null", err); - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - *addr = ksz8041->addr; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + *addr = ksz80xx->addr; return ESP_OK; err: return ESP_ERR_INVALID_ARG; } -static esp_err_t ksz8041_del(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_del(esp_eth_phy_t *phy) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - free(ksz8041); + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + free(ksz80xx); return ESP_OK; } -static esp_err_t ksz8041_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) +static esp_err_t ksz80xx_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - esp_eth_mediator_t *eth = ksz8041->eth; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + esp_eth_mediator_t *eth = ksz80xx->eth; /* Set PAUSE function ability */ anar_reg_t anar; - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, "read ANAR failed", err); if (ability) { anar.asymmetric_pause = 1; @@ -303,38 +332,38 @@ static esp_err_t ksz8041_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ab anar.asymmetric_pause = 0; anar.symmetric_pause = 0; } - PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, + PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, "write ANAR failed", err); return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_init(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_init(esp_eth_phy_t *phy) { - phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); - esp_eth_mediator_t *eth = ksz8041->eth; + phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent); + esp_eth_mediator_t *eth = ksz80xx->eth; /* Power on Ethernet PHY */ - PHY_CHECK(ksz8041_pwrctl(phy, true) == ESP_OK, "power control failed", err); + PHY_CHECK(ksz80xx_pwrctl(phy, true) == ESP_OK, "power control failed", err); /* Reset Ethernet PHY */ - PHY_CHECK(ksz8041_reset(phy) == ESP_OK, "reset failed", err); + PHY_CHECK(ksz80xx_reset(phy) == ESP_OK, "reset failed", err); /* Check PHY ID */ phyidr1_reg_t id1; phyidr2_reg_t id2; - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); - PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, + PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); - PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == 0x11, "wrong chip ID", err); + PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == ksz80xx->vendor_model, "wrong chip ID", err); return ESP_OK; err: return ESP_FAIL; } -static esp_err_t ksz8041_deinit(esp_eth_phy_t *phy) +static esp_err_t ksz80xx_deinit(esp_eth_phy_t *phy) { /* Power off Ethernet PHY */ - PHY_CHECK(ksz8041_pwrctl(phy, false) == ESP_OK, "power control failed", err); + PHY_CHECK(ksz80xx_pwrctl(phy, false) == ESP_OK, "power control failed", err); return ESP_OK; err: return ESP_FAIL; @@ -343,27 +372,57 @@ static esp_err_t ksz8041_deinit(esp_eth_phy_t *phy) esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config) { PHY_CHECK(config, "can't set phy config to null", err); - phy_ksz8041_t *ksz8041 = calloc(1, sizeof(phy_ksz8041_t)); - PHY_CHECK(ksz8041, "calloc ksz8041 failed", err); + phy_ksz80xx_t *ksz8041 = calloc(1, sizeof(phy_ksz80xx_t)); + PHY_CHECK(ksz8041, "calloc ksz80xx failed", err); + ksz8041->vendor_model = KSZ8041_MODEL_ID; ksz8041->addr = config->phy_addr; ksz8041->reset_gpio_num = config->reset_gpio_num; ksz8041->reset_timeout_ms = config->reset_timeout_ms; ksz8041->link_status = ETH_LINK_DOWN; ksz8041->autonego_timeout_ms = config->autonego_timeout_ms; - ksz8041->parent.reset = ksz8041_reset; - ksz8041->parent.reset_hw = ksz8041_reset_hw; - ksz8041->parent.init = ksz8041_init; - ksz8041->parent.deinit = ksz8041_deinit; - ksz8041->parent.set_mediator = ksz8041_set_mediator; - ksz8041->parent.negotiate = ksz8041_negotiate; - ksz8041->parent.get_link = ksz8041_get_link; - ksz8041->parent.pwrctl = ksz8041_pwrctl; - ksz8041->parent.get_addr = ksz8041_get_addr; - ksz8041->parent.set_addr = ksz8041_set_addr; - ksz8041->parent.advertise_pause_ability = ksz8041_advertise_pause_ability; - ksz8041->parent.del = ksz8041_del; + ksz8041->parent.reset = ksz80xx_reset; + ksz8041->parent.reset_hw = ksz80xx_reset_hw; + ksz8041->parent.init = ksz80xx_init; + ksz8041->parent.deinit = ksz80xx_deinit; + ksz8041->parent.set_mediator = ksz80xx_set_mediator; + ksz8041->parent.negotiate = ksz80xx_negotiate; + ksz8041->parent.get_link = ksz80xx_get_link; + ksz8041->parent.pwrctl = ksz80xx_pwrctl; + ksz8041->parent.get_addr = ksz80xx_get_addr; + ksz8041->parent.set_addr = ksz80xx_set_addr; + ksz8041->parent.advertise_pause_ability = ksz80xx_advertise_pause_ability; + ksz8041->parent.del = ksz80xx_del; return &(ksz8041->parent); err: return NULL; } + +esp_eth_phy_t *esp_eth_phy_new_ksz8081(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + phy_ksz80xx_t *ksz8081 = calloc(1, sizeof(phy_ksz80xx_t)); + PHY_CHECK(ksz8081, "calloc ksz8081 failed", err); + ksz8081->vendor_model = KSZ8081_MODEL_ID; + ksz8081->addr = config->phy_addr; + ksz8081->reset_gpio_num = config->reset_gpio_num; + ksz8081->reset_timeout_ms = config->reset_timeout_ms; + ksz8081->link_status = ETH_LINK_DOWN; + ksz8081->autonego_timeout_ms = config->autonego_timeout_ms; + ksz8081->parent.reset = ksz80xx_reset; + ksz8081->parent.reset_hw = ksz80xx_reset_hw; + ksz8081->parent.init = ksz80xx_init; + ksz8081->parent.deinit = ksz80xx_deinit; + ksz8081->parent.set_mediator = ksz80xx_set_mediator; + ksz8081->parent.negotiate = ksz80xx_negotiate; + ksz8081->parent.get_link = ksz80xx_get_link; + ksz8081->parent.pwrctl = ksz80xx_pwrctl; + ksz8081->parent.get_addr = ksz80xx_get_addr; + ksz8081->parent.set_addr = ksz80xx_set_addr; + ksz8081->parent.advertise_pause_ability = ksz80xx_advertise_pause_ability; + ksz8081->parent.del = ksz80xx_del; + + return &(ksz8081->parent); +err: + return NULL; +}