mirror of
https://github.com/esphome/esphome.git
synced 2024-09-25 03:43:41 +02:00
[ethernet] Add config option to set arbitrary PHY register values (#6836)
This commit is contained in:
parent
f7742cdf19
commit
594856899a
@ -11,6 +11,7 @@ from esphome.components.esp32.const import (
|
|||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DOMAIN,
|
CONF_DOMAIN,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_VALUE,
|
||||||
CONF_MANUAL_IP,
|
CONF_MANUAL_IP,
|
||||||
CONF_STATIC_IP,
|
CONF_STATIC_IP,
|
||||||
CONF_TYPE,
|
CONF_TYPE,
|
||||||
@ -26,6 +27,8 @@ from esphome.const import (
|
|||||||
CONF_INTERRUPT_PIN,
|
CONF_INTERRUPT_PIN,
|
||||||
CONF_RESET_PIN,
|
CONF_RESET_PIN,
|
||||||
CONF_SPI,
|
CONF_SPI,
|
||||||
|
CONF_PAGE_ID,
|
||||||
|
CONF_ADDRESS,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
from esphome.components.network import IPAddress
|
from esphome.components.network import IPAddress
|
||||||
@ -36,11 +39,13 @@ DEPENDENCIES = ["esp32"]
|
|||||||
AUTO_LOAD = ["network"]
|
AUTO_LOAD = ["network"]
|
||||||
|
|
||||||
ethernet_ns = cg.esphome_ns.namespace("ethernet")
|
ethernet_ns = cg.esphome_ns.namespace("ethernet")
|
||||||
|
PHYRegister = ethernet_ns.struct("PHYRegister")
|
||||||
CONF_PHY_ADDR = "phy_addr"
|
CONF_PHY_ADDR = "phy_addr"
|
||||||
CONF_MDC_PIN = "mdc_pin"
|
CONF_MDC_PIN = "mdc_pin"
|
||||||
CONF_MDIO_PIN = "mdio_pin"
|
CONF_MDIO_PIN = "mdio_pin"
|
||||||
CONF_CLK_MODE = "clk_mode"
|
CONF_CLK_MODE = "clk_mode"
|
||||||
CONF_POWER_PIN = "power_pin"
|
CONF_POWER_PIN = "power_pin"
|
||||||
|
CONF_PHY_REGISTERS = "phy_registers"
|
||||||
|
|
||||||
CONF_CLOCK_SPEED = "clock_speed"
|
CONF_CLOCK_SPEED = "clock_speed"
|
||||||
|
|
||||||
@ -117,6 +122,13 @@ BASE_SCHEMA = cv.Schema(
|
|||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_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(
|
RMII_SCHEMA = BASE_SCHEMA.extend(
|
||||||
cv.Schema(
|
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_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_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)
|
@coroutine_with_priority(60.0)
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
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]]))
|
cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]]))
|
||||||
if CONF_POWER_PIN in config:
|
if CONF_POWER_PIN in config:
|
||||||
cg.add(var.set_power_pin(config[CONF_POWER_PIN]))
|
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_type(ETHERNET_TYPES[config[CONF_TYPE]]))
|
||||||
cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
|
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.
|
// KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide.
|
||||||
this->ksz8081_set_clock_reference_(mac);
|
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
|
for (const auto &phy_register : this->phy_registers_) {
|
||||||
this->rtl8201_set_rmii_mode_(mac);
|
this->write_phy_register_(mac, phy_register);
|
||||||
}
|
}
|
||||||
#endif
|
#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_mode_ = clk_mode;
|
||||||
this->clk_gpio_ = clk_gpio;
|
this->clk_gpio_ = clk_gpio;
|
||||||
}
|
}
|
||||||
|
void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); }
|
||||||
#endif
|
#endif
|
||||||
void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
|
void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
|
||||||
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
|
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());
|
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;
|
esp_err_t err;
|
||||||
uint32_t phy_rmii_mode;
|
constexpr uint8_t eth_phy_psr_reg_addr = 0x1F;
|
||||||
err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x07);
|
|
||||||
ESPHL_ERROR_CHECK(err, "Setting Page 7 failed");
|
|
||||||
|
|
||||||
/*
|
if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
|
||||||
* RTL8201 RMII Mode Setting Register (RMSR)
|
ESP_LOGD(TAG, "Select PHY Register Page: 0x%02" PRIX32, register_data.page);
|
||||||
* Page 7 Register 16
|
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");
|
||||||
* 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
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode));
|
ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32, register_data.address);
|
||||||
ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed");
|
ESP_LOGD(TAG, "Writing to PHY Register Value: 0x%04" PRIX32, register_data.value);
|
||||||
ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04" PRIX32, phy_rmii_mode);
|
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);
|
if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
|
||||||
ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed");
|
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);
|
||||||
err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode));
|
ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,6 +35,12 @@ struct ManualIP {
|
|||||||
network::IPAddress dns2; ///< The second DNS server. 0.0.0.0 for default.
|
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 {
|
enum class EthernetComponentState {
|
||||||
STOPPED,
|
STOPPED,
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
@ -66,6 +72,7 @@ class EthernetComponent : public Component {
|
|||||||
void set_mdc_pin(uint8_t mdc_pin);
|
void set_mdc_pin(uint8_t mdc_pin);
|
||||||
void set_mdio_pin(uint8_t mdio_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 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
|
#endif
|
||||||
void set_type(EthernetType type);
|
void set_type(EthernetType type);
|
||||||
void set_manual_ip(const ManualIP &manual_ip);
|
void set_manual_ip(const ManualIP &manual_ip);
|
||||||
@ -91,8 +98,8 @@ class EthernetComponent : public Component {
|
|||||||
void dump_connect_params_();
|
void dump_connect_params_();
|
||||||
/// @brief Set `RMII Reference Clock Select` bit for KSZ8081.
|
/// @brief Set `RMII Reference Clock Select` bit for KSZ8081.
|
||||||
void ksz8081_set_clock_reference_(esp_eth_mac_t *mac);
|
void ksz8081_set_clock_reference_(esp_eth_mac_t *mac);
|
||||||
/// @brief Set `RMII Mode Setting Register` for RTL8201.
|
/// @brief Set arbitratry PHY registers from config.
|
||||||
void rtl8201_set_rmii_mode_(esp_eth_mac_t *mac);
|
void write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data);
|
||||||
|
|
||||||
std::string use_address_;
|
std::string use_address_;
|
||||||
#ifdef USE_ETHERNET_SPI
|
#ifdef USE_ETHERNET_SPI
|
||||||
@ -111,6 +118,7 @@ class EthernetComponent : public Component {
|
|||||||
uint8_t mdio_pin_{18};
|
uint8_t mdio_pin_{18};
|
||||||
emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
|
emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
|
||||||
emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
|
emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
|
||||||
|
std::vector<PHYRegister> phy_registers_{};
|
||||||
#endif
|
#endif
|
||||||
EthernetType type_{ETHERNET_TYPE_UNKNOWN};
|
EthernetType type_{ETHERNET_TYPE_UNKNOWN};
|
||||||
optional<ManualIP> manual_ip_{};
|
optional<ManualIP> manual_ip_{};
|
||||||
|
Loading…
Reference in New Issue
Block a user