mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 16:38:16 +01:00
[ethernet] Add config option to set arbitrary PHY register values (#6836)
This commit is contained in:
parent
f7742cdf19
commit
594856899a
3 changed files with 60 additions and 39 deletions
|
@ -11,6 +11,7 @@ from esphome.components.esp32.const import (
|
|||
from esphome.const import (
|
||||
CONF_DOMAIN,
|
||||
CONF_ID,
|
||||
CONF_VALUE,
|
||||
CONF_MANUAL_IP,
|
||||
CONF_STATIC_IP,
|
||||
CONF_TYPE,
|
||||
|
@ -26,6 +27,8 @@ from esphome.const import (
|
|||
CONF_INTERRUPT_PIN,
|
||||
CONF_RESET_PIN,
|
||||
CONF_SPI,
|
||||
CONF_PAGE_ID,
|
||||
CONF_ADDRESS,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.components.network import IPAddress
|
||||
|
@ -36,11 +39,13 @@ DEPENDENCIES = ["esp32"]
|
|||
AUTO_LOAD = ["network"]
|
||||
|
||||
ethernet_ns = cg.esphome_ns.namespace("ethernet")
|
||||
PHYRegister = ethernet_ns.struct("PHYRegister")
|
||||
CONF_PHY_ADDR = "phy_addr"
|
||||
CONF_MDC_PIN = "mdc_pin"
|
||||
CONF_MDIO_PIN = "mdio_pin"
|
||||
CONF_CLK_MODE = "clk_mode"
|
||||
CONF_POWER_PIN = "power_pin"
|
||||
CONF_PHY_REGISTERS = "phy_registers"
|
||||
|
||||
CONF_CLOCK_SPEED = "clock_speed"
|
||||
|
||||
|
@ -117,6 +122,13 @@ BASE_SCHEMA = cv.Schema(
|
|||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
PHY_REGISTER_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ADDRESS): cv.hex_int,
|
||||
cv.Required(CONF_VALUE): cv.hex_int,
|
||||
cv.Optional(CONF_PAGE_ID): cv.hex_int,
|
||||
}
|
||||
)
|
||||
RMII_SCHEMA = BASE_SCHEMA.extend(
|
||||
cv.Schema(
|
||||
{
|
||||
|
@ -127,6 +139,7 @@ RMII_SCHEMA = BASE_SCHEMA.extend(
|
|||
),
|
||||
cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31),
|
||||
cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Optional(CONF_PHY_REGISTERS): cv.ensure_list(PHY_REGISTER_SCHEMA),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -198,6 +211,15 @@ def manual_ip(config):
|
|||
)
|
||||
|
||||
|
||||
def phy_register(address: int, value: int, page: int):
|
||||
return cg.StructInitializer(
|
||||
PHYRegister,
|
||||
("address", address),
|
||||
("value", value),
|
||||
("page", page),
|
||||
)
|
||||
|
||||
|
||||
@coroutine_with_priority(60.0)
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
|
@ -225,6 +247,13 @@ async def to_code(config):
|
|||
cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]]))
|
||||
if CONF_POWER_PIN in config:
|
||||
cg.add(var.set_power_pin(config[CONF_POWER_PIN]))
|
||||
for register_value in config.get(CONF_PHY_REGISTERS, []):
|
||||
reg = phy_register(
|
||||
register_value.get(CONF_ADDRESS),
|
||||
register_value.get(CONF_VALUE),
|
||||
register_value.get(CONF_PAGE_ID),
|
||||
)
|
||||
cg.add(var.add_phy_register(reg))
|
||||
|
||||
cg.add(var.set_type(ETHERNET_TYPES[config[CONF_TYPE]]))
|
||||
cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
|
||||
|
|
|
@ -195,9 +195,9 @@ void EthernetComponent::setup() {
|
|||
// KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide.
|
||||
this->ksz8081_set_clock_reference_(mac);
|
||||
}
|
||||
if (this->type_ == ETHERNET_TYPE_RTL8201 && this->clk_mode_ == EMAC_CLK_EXT_IN) {
|
||||
// Change in default behavior of RTL8201FI may require register setting to enable external clock
|
||||
this->rtl8201_set_rmii_mode_(mac);
|
||||
|
||||
for (const auto &phy_register : this->phy_registers_) {
|
||||
this->write_phy_register_(mac, phy_register);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -527,6 +527,7 @@ void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_
|
|||
this->clk_mode_ = clk_mode;
|
||||
this->clk_gpio_ = clk_gpio;
|
||||
}
|
||||
void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); }
|
||||
#endif
|
||||
void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
|
||||
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
|
||||
|
@ -613,44 +614,27 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) {
|
|||
ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str());
|
||||
}
|
||||
}
|
||||
constexpr uint8_t RTL8201_RMSR_REG_ADDR = 0x10;
|
||||
void EthernetComponent::rtl8201_set_rmii_mode_(esp_eth_mac_t *mac) {
|
||||
|
||||
void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data) {
|
||||
esp_err_t err;
|
||||
uint32_t phy_rmii_mode;
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x07);
|
||||
ESPHL_ERROR_CHECK(err, "Setting Page 7 failed");
|
||||
constexpr uint8_t eth_phy_psr_reg_addr = 0x1F;
|
||||
|
||||
/*
|
||||
* RTL8201 RMII Mode Setting Register (RMSR)
|
||||
* Page 7 Register 16
|
||||
*
|
||||
* bit 0 Reserved 0
|
||||
* bit 1 Rg_rmii_rxdsel 1 (default)
|
||||
* bit 2 Rg_rmii_rxdv_sel: 0 (default)
|
||||
* bit 3 RMII Mode: 1 (RMII Mode)
|
||||
* bit 4~7 Rg_rmii_rx_offset: 1111 (default)
|
||||
* bit 8~11 Rg_rmii_tx_offset: 1111 (default)
|
||||
* bit 12 Rg_rmii_clkdir: 1 (Input)
|
||||
* bit 13~15 Reserved 000
|
||||
*
|
||||
* Binary: 0001 1111 1111 1010
|
||||
* Hex: 0x1FFA
|
||||
*
|
||||
*/
|
||||
if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
|
||||
ESP_LOGD(TAG, "Select PHY Register Page: 0x%02" PRIX32, register_data.page);
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, register_data.page);
|
||||
ESPHL_ERROR_CHECK(err, "Select PHY Register page failed");
|
||||
}
|
||||
|
||||
err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode));
|
||||
ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed");
|
||||
ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04" PRIX32, phy_rmii_mode);
|
||||
ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32, register_data.address);
|
||||
ESP_LOGD(TAG, "Writing to PHY Register Value: 0x%04" PRIX32, register_data.value);
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value);
|
||||
ESPHL_ERROR_CHECK(err, "Writing PHY Register failed");
|
||||
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, 0x1FFA);
|
||||
ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed");
|
||||
|
||||
err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode));
|
||||
ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed");
|
||||
ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04" PRIX32, phy_rmii_mode);
|
||||
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x0);
|
||||
ESPHL_ERROR_CHECK(err, "Setting Page 0 failed");
|
||||
if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
|
||||
ESP_LOGD(TAG, "Select PHY Register Page 0x%02" PRIX32, 0x0);
|
||||
err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0);
|
||||
ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,12 @@ struct ManualIP {
|
|||
network::IPAddress dns2; ///< The second DNS server. 0.0.0.0 for default.
|
||||
};
|
||||
|
||||
struct PHYRegister {
|
||||
uint32_t address;
|
||||
uint32_t value;
|
||||
uint32_t page;
|
||||
};
|
||||
|
||||
enum class EthernetComponentState {
|
||||
STOPPED,
|
||||
CONNECTING,
|
||||
|
@ -66,6 +72,7 @@ class EthernetComponent : public Component {
|
|||
void set_mdc_pin(uint8_t mdc_pin);
|
||||
void set_mdio_pin(uint8_t mdio_pin);
|
||||
void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio);
|
||||
void add_phy_register(PHYRegister register_value);
|
||||
#endif
|
||||
void set_type(EthernetType type);
|
||||
void set_manual_ip(const ManualIP &manual_ip);
|
||||
|
@ -91,8 +98,8 @@ class EthernetComponent : public Component {
|
|||
void dump_connect_params_();
|
||||
/// @brief Set `RMII Reference Clock Select` bit for KSZ8081.
|
||||
void ksz8081_set_clock_reference_(esp_eth_mac_t *mac);
|
||||
/// @brief Set `RMII Mode Setting Register` for RTL8201.
|
||||
void rtl8201_set_rmii_mode_(esp_eth_mac_t *mac);
|
||||
/// @brief Set arbitratry PHY registers from config.
|
||||
void write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data);
|
||||
|
||||
std::string use_address_;
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
|
@ -111,6 +118,7 @@ class EthernetComponent : public Component {
|
|||
uint8_t mdio_pin_{18};
|
||||
emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
|
||||
emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
|
||||
std::vector<PHYRegister> phy_registers_{};
|
||||
#endif
|
||||
EthernetType type_{ETHERNET_TYPE_UNKNOWN};
|
||||
optional<ManualIP> manual_ip_{};
|
||||
|
|
Loading…
Reference in a new issue