From 8bf8892ab34cc3f5688ab006312652c0161c847a Mon Sep 17 00:00:00 2001 From: Fabian Date: Mon, 10 Jul 2023 00:02:42 +0200 Subject: [PATCH] [Ethernet] ksz8081rna support (#4739) Co-authored-by: Your Name --- esphome/components/ethernet/__init__.py | 1 + .../ethernet/ethernet_component.cpp | 44 ++++++++++++++++++- .../components/ethernet/ethernet_component.h | 3 ++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index bedc0a4c30..6f0f3741dd 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -35,6 +35,7 @@ ETHERNET_TYPES = { "IP101": EthernetType.ETHERNET_TYPE_IP101, "JL1101": EthernetType.ETHERNET_TYPE_JL1101, "KSZ8081": EthernetType.ETHERNET_TYPE_KSZ8081, + "KSZ8081RNA": EthernetType.ETHERNET_TYPE_KSZ8081RNA, } emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index fc1068f2a8..3b5804abdd 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -84,7 +84,8 @@ void EthernetComponent::setup() { this->phy_ = esp_eth_phy_new_jl1101(&phy_config); break; } - case ETHERNET_TYPE_KSZ8081: { + case ETHERNET_TYPE_KSZ8081: + case ETHERNET_TYPE_KSZ8081RNA: { #if ESP_IDF_VERSION_MAJOR >= 5 this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); #else @@ -102,6 +103,12 @@ void EthernetComponent::setup() { this->eth_handle_ = nullptr; err = esp_eth_driver_install(ð_config, &this->eth_handle_); ESPHL_ERROR_CHECK(err, "ETH driver install error"); + + if (this->type_ == ETHERNET_TYPE_KSZ8081RNA && this->clk_mode_ == EMAC_CLK_OUT) { + // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide. + this->ksz8081_set_clock_reference_(mac); + } + /* attach Ethernet driver to TCP/IP stack */ err = esp_netif_attach(this->eth_netif_, esp_eth_new_netif_glue(this->eth_handle_)); ESPHL_ERROR_CHECK(err, "ETH netif attach error"); @@ -184,6 +191,10 @@ void EthernetComponent::dump_config() { eth_type = "KSZ8081"; break; + case ETHERNET_TYPE_KSZ8081RNA: + eth_type = "KSZ8081RNA"; + break; + default: eth_type = "Unknown"; break; @@ -385,6 +396,37 @@ bool EthernetComponent::powerdown() { return true; } +void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { +#define KSZ80XX_PC2R_REG_ADDR (0x1F) + + esp_err_t err; + + uint32_t phy_control_2; + err = mac->read_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, &(phy_control_2)); + ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed"); + ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); + + /* + * Bit 7 is `RMII Reference Clock Select`. Default is `0`. + * KSZ8081RNA: + * 0 - clock input to XI (Pin 8) is 25 MHz for RMII – 25 MHz clock mode. + * 1 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode. + * KSZ8081RND: + * 0 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode. + * 1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII – 25 MHz clock mode. + */ + if ((phy_control_2 & (1 << 7)) != (1 << 7)) { + phy_control_2 |= 1 << 7; + err = mac->write_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, phy_control_2); + ESPHL_ERROR_CHECK(err, "Write PHY Control 2 failed"); + err = mac->read_phy_reg(mac, this->phy_addr_, KSZ80XX_PC2R_REG_ADDR, &(phy_control_2)); + ESPHL_ERROR_CHECK(err, "Read PHY Control 2 failed"); + ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str()); + } + +#undef KSZ80XX_PC2R_REG_ADDR +} + } // namespace ethernet } // namespace esphome diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 918e47212f..f6b67f3f82 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -21,6 +21,7 @@ enum EthernetType { ETHERNET_TYPE_IP101, ETHERNET_TYPE_JL1101, ETHERNET_TYPE_KSZ8081, + ETHERNET_TYPE_KSZ8081RNA, }; struct ManualIP { @@ -67,6 +68,8 @@ class EthernetComponent : public Component { void start_connect_(); void dump_connect_params_(); + /// @brief Set `RMII Reference Clock Select` bit for KSZ8081. + void ksz8081_set_clock_reference_(esp_eth_mac_t *mac); std::string use_address_; uint8_t phy_addr_{0};