diff --git a/drivers/ethernet/phy/phy_microchip_ksz8081.c b/drivers/ethernet/phy/phy_microchip_ksz8081.c index 04ffafef763..b3563f7429f 100644 --- a/drivers/ethernet/phy/phy_microchip_ksz8081.c +++ b/drivers/ethernet/phy/phy_microchip_ksz8081.c @@ -23,6 +23,8 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); +#include "phy_mii.h" + #define PHY_MC_KSZ8081_OMSO_REG 0x16 #define PHY_MC_KSZ8081_OMSO_FACTORY_MODE_MASK BIT(15) #define PHY_MC_KSZ8081_OMSO_NAND_TREE_MASK BIT(5) @@ -339,7 +341,6 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, struct mc_ksz8081_data *data = dev->data; struct phy_link_state state = {}; int ret; - uint32_t anar; /* Lock mutex */ ret = k_mutex_lock(&data->mutex, K_FOREVER); @@ -357,39 +358,9 @@ static int phy_mc_ksz8081_cfg_link(const struct device *dev, goto done; } - /* Read ANAR register to write back */ - ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); - if (ret) { - LOG_ERR("Error reading phy (%d) advertising register", config->addr); - goto done; - } - - /* Setup advertising register */ - if (speeds & LINK_FULL_100BASE) { - anar |= MII_ADVERTISE_100_FULL; - } else { - anar &= ~MII_ADVERTISE_100_FULL; - } - if (speeds & LINK_HALF_100BASE) { - anar |= MII_ADVERTISE_100_HALF; - } else { - anar &= ~MII_ADVERTISE_100_HALF; - } - if (speeds & LINK_FULL_10BASE) { - anar |= MII_ADVERTISE_10_FULL; - } else { - anar &= ~MII_ADVERTISE_10_FULL; - } - if (speeds & LINK_HALF_10BASE) { - anar |= MII_ADVERTISE_10_HALF; - } else { - anar &= ~MII_ADVERTISE_10_HALF; - } - - /* Write capabilities to advertising register */ - ret = phy_mc_ksz8081_write(dev, MII_ANAR, anar); - if (ret) { - LOG_ERR("Error writing phy (%d) advertising register", config->addr); + ret = phy_mii_set_anar_reg(dev, speeds); + if ((ret < 0) && (ret != -EALREADY)) { + LOG_ERR("Error setting ANAR register for phy (%d)", config->addr); goto done; } diff --git a/drivers/ethernet/phy/phy_mii.c b/drivers/ethernet/phy/phy_mii.c index 3b177cb546b..0de6cd5cb98 100644 --- a/drivers/ethernet/phy/phy_mii.c +++ b/drivers/ethernet/phy/phy_mii.c @@ -18,6 +18,8 @@ #include LOG_MODULE_REGISTER(phy_mii, CONFIG_PHY_LOG_LEVEL); +#include "phy_mii.h" + #define ANY_DYNAMIC_LINK UTIL_NOT(DT_ALL_INST_HAS_PROP_STATUS_OKAY(fixed_link)) #define ANY_FIXED_LINK DT_ANY_INST_HAS_PROP_STATUS_OKAY(fixed_link) @@ -350,11 +352,7 @@ static int phy_mii_cfg_link(const struct device *dev, { struct phy_mii_dev_data *const data = dev->data; const struct phy_mii_dev_config *const cfg = dev->config; - uint16_t anar_reg; - uint16_t anar_reg_old; uint16_t bmcr_reg; - uint16_t c1kt_reg; - uint16_t c1kt_reg_old; int ret = 0; /* if there is no mdio (fixed-link) it is not supported to configure link */ @@ -368,79 +366,30 @@ static int phy_mii_cfg_link(const struct device *dev, k_sem_take(&data->sem, K_FOREVER); - if (phy_mii_reg_read(dev, MII_ANAR, &anar_reg) < 0) { - ret = -EIO; - goto cfg_link_end; - } - anar_reg_old = anar_reg; - if (phy_mii_reg_read(dev, MII_BMCR, &bmcr_reg) < 0) { ret = -EIO; goto cfg_link_end; } if (data->gigabit_supported) { - if (phy_mii_reg_read(dev, MII_1KTCR, &c1kt_reg) < 0) { - ret = -EIO; + ret = phy_mii_set_c1kt_reg(dev, adv_speeds); + if (ret == -EALREADY) { + /* If the C1KT register is already set, we don't need to do anything */ + ret = 0; + } else if (ret < 0) { goto cfg_link_end; - } - } - - if (adv_speeds & LINK_FULL_10BASE) { - anar_reg |= MII_ADVERTISE_10_FULL; - } else { - anar_reg &= ~MII_ADVERTISE_10_FULL; - } - - if (adv_speeds & LINK_HALF_10BASE) { - anar_reg |= MII_ADVERTISE_10_HALF; - } else { - anar_reg &= ~MII_ADVERTISE_10_HALF; - } - - if (adv_speeds & LINK_FULL_100BASE) { - anar_reg |= MII_ADVERTISE_100_FULL; - } else { - anar_reg &= ~MII_ADVERTISE_100_FULL; - } - - if (adv_speeds & LINK_HALF_100BASE) { - anar_reg |= MII_ADVERTISE_100_HALF; - } else { - anar_reg &= ~MII_ADVERTISE_100_HALF; - } - - if (data->gigabit_supported) { - c1kt_reg_old = c1kt_reg; - - if (adv_speeds & LINK_FULL_1000BASE) { - c1kt_reg |= MII_ADVERTISE_1000_FULL; } else { - c1kt_reg &= ~MII_ADVERTISE_1000_FULL; - } - - if (adv_speeds & LINK_HALF_1000BASE) { - c1kt_reg |= MII_ADVERTISE_1000_HALF; - } else { - c1kt_reg &= ~MII_ADVERTISE_1000_HALF; - } - - if (c1kt_reg != c1kt_reg_old) { - if (phy_mii_reg_write(dev, MII_1KTCR, c1kt_reg) < 0) { - ret = -EIO; - goto cfg_link_end; - } - data->restart_autoneg = true; } } - if (anar_reg != anar_reg_old) { - if (phy_mii_reg_write(dev, MII_ANAR, anar_reg) < 0) { - ret = -EIO; - goto cfg_link_end; - } - + ret = phy_mii_set_anar_reg(dev, adv_speeds); + if (ret == -EALREADY) { + /* If the ANAR register is already set, we don't need to do anything */ + ret = 0; + } else if (ret < 0) { + goto cfg_link_end; + } else { data->restart_autoneg = true; } diff --git a/drivers/ethernet/phy/phy_mii.h b/drivers/ethernet/phy/phy_mii.h new file mode 100644 index 00000000000..5b56b4668b3 --- /dev/null +++ b/drivers/ethernet/phy/phy_mii.h @@ -0,0 +1,63 @@ +/* + * Copyright The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_PHY_MII_H_ +#define ZEPHYR_PHY_MII_H_ + +#include +#include +#include + +static inline int phy_mii_set_anar_reg(const struct device *dev, enum phy_link_speed adv_speeds) +{ + uint32_t anar_reg = 0U; + uint32_t anar_reg_old; + + if (phy_read(dev, MII_ANAR, &anar_reg) < 0) { + return -EIO; + } + anar_reg_old = anar_reg; + + WRITE_BIT(anar_reg, MII_ADVERTISE_10_FULL_BIT, (adv_speeds & LINK_FULL_10BASE) != 0U); + WRITE_BIT(anar_reg, MII_ADVERTISE_10_HALF_BIT, (adv_speeds & LINK_HALF_10BASE) != 0U); + WRITE_BIT(anar_reg, MII_ADVERTISE_100_FULL_BIT, (adv_speeds & LINK_FULL_100BASE) != 0U); + WRITE_BIT(anar_reg, MII_ADVERTISE_100_HALF_BIT, (adv_speeds & LINK_HALF_100BASE) != 0U); + + if (anar_reg == anar_reg_old) { + return -EALREADY; + } + + if (phy_write(dev, MII_ANAR, anar_reg) < 0) { + return -EIO; + } + + return 0; +} + +static inline int phy_mii_set_c1kt_reg(const struct device *dev, enum phy_link_speed adv_speeds) +{ + uint32_t c1kt_reg = 0U; + uint32_t c1kt_reg_old; + + if (phy_read(dev, MII_1KTCR, &c1kt_reg) < 0) { + return -EIO; + } + c1kt_reg_old = c1kt_reg; + + WRITE_BIT(c1kt_reg, MII_ADVERTISE_1000_FULL_BIT, (adv_speeds & LINK_FULL_1000BASE) != 0U); + WRITE_BIT(c1kt_reg, MII_ADVERTISE_1000_HALF_BIT, (adv_speeds & LINK_HALF_1000BASE) != 0U); + + if (c1kt_reg == c1kt_reg_old) { + return -EALREADY; + } + + if (phy_write(dev, MII_1KTCR, c1kt_reg) < 0) { + return -EIO; + } + + return 0; +} +#endif /* ZEPHYR_PHY_MII_H_ */ diff --git a/drivers/ethernet/phy/phy_qualcomm_ar8031.c b/drivers/ethernet/phy/phy_qualcomm_ar8031.c index 04cf0feb4b3..744735e422c 100644 --- a/drivers/ethernet/phy/phy_qualcomm_ar8031.c +++ b/drivers/ethernet/phy/phy_qualcomm_ar8031.c @@ -22,6 +22,8 @@ #include LOG_MODULE_REGISTER(phy_qc_ar8031, CONFIG_PHY_LOG_LEVEL); +#include "phy_mii.h" + #define AR8031_PHY_ID1 0x004DU #define PHY_READID_TIMEOUT_COUNT 1000U @@ -255,68 +257,24 @@ static void monitor_work_handler(struct k_work *work) static int qc_ar8031_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds) { - uint32_t anar_reg; uint32_t bmcr_reg; - uint32_t c1kt_reg; - - if (qc_ar8031_read(dev, MII_ANAR, &anar_reg) < 0) { - return -EIO; - } if (qc_ar8031_read(dev, MII_BMCR, &bmcr_reg) < 0) { return -EIO; } - if (qc_ar8031_read(dev, MII_1KTCR, &c1kt_reg) < 0) { + ret = phy_mii_set_anar_reg(dev, speeds); + if ((ret < 0) && (ret != -EALREADY)) { return -EIO; } - if (adv_speeds & LINK_FULL_10BASE) { - anar_reg |= MII_ADVERTISE_10_FULL; - } else { - anar_reg &= ~MII_ADVERTISE_10_FULL; - } - - if (adv_speeds & LINK_HALF_10BASE) { - anar_reg |= MII_ADVERTISE_10_HALF; - } else { - anar_reg &= ~MII_ADVERTISE_10_HALF; - } - - if (adv_speeds & LINK_FULL_100BASE) { - anar_reg |= MII_ADVERTISE_100_FULL; - } else { - anar_reg &= ~MII_ADVERTISE_100_FULL; - } - - if (adv_speeds & LINK_HALF_100BASE) { - anar_reg |= MII_ADVERTISE_100_HALF; - } else { - anar_reg &= ~MII_ADVERTISE_100_HALF; - } - - if (adv_speeds & LINK_FULL_1000BASE) { - c1kt_reg |= MII_ADVERTISE_1000_FULL; - } else { - c1kt_reg &= ~MII_ADVERTISE_1000_FULL; - } - - if (adv_speeds & LINK_HALF_1000BASE) { - c1kt_reg |= MII_ADVERTISE_1000_HALF; - } else { - c1kt_reg &= ~MII_ADVERTISE_1000_HALF; - } - - if (qc_ar8031_write(dev, MII_1KTCR, c1kt_reg) < 0) { + ret = phy_mii_set_c1kt_reg(dev, speeds); + if ((ret < 0) && (ret != -EALREADY)) { return -EIO; } bmcr_reg |= MII_BMCR_AUTONEG_ENABLE | MII_BMCR_AUTONEG_RESTART; - if (qc_ar8031_write(dev, MII_ANAR, anar_reg) < 0) { - return -EIO; - } - if (qc_ar8031_write(dev, MII_BMCR, bmcr_reg) < 0) { return -EIO; } diff --git a/drivers/ethernet/phy/phy_realtek_rtl8211f.c b/drivers/ethernet/phy/phy_realtek_rtl8211f.c index 9ce8bfdfa26..703fc48b9c5 100644 --- a/drivers/ethernet/phy/phy_realtek_rtl8211f.c +++ b/drivers/ethernet/phy/phy_realtek_rtl8211f.c @@ -25,6 +25,8 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); +#include "phy_mii.h" + #define REALTEK_OUI_MSB (0x1CU) #define PHY_RT_RTL8211F_PHYSR_REG (0x1A) @@ -283,8 +285,6 @@ static int phy_rt_rtl8211f_cfg_link(const struct device *dev, { const struct rt_rtl8211f_config *config = dev->config; struct rt_rtl8211f_data *data = dev->data; - uint32_t anar; - uint32_t gbcr; int ret; /* Lock mutex */ @@ -303,60 +303,15 @@ static int phy_rt_rtl8211f_cfg_link(const struct device *dev, k_work_cancel_delayable(&data->phy_monitor_work); #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */ - /* Read ANAR register to write back */ - ret = phy_rt_rtl8211f_read(dev, MII_ANAR, &anar); - if (ret) { - LOG_ERR("Error reading phy (%d) advertising register", config->addr); + ret = phy_mii_set_anar_reg(dev, speeds); + if (ret < 0 && ret != -EALREADY) { + LOG_ERR("Error setting ANAR register for phy (%d)", config->addr); goto done; } - /* Read GBCR register to write back */ - ret = phy_rt_rtl8211f_read(dev, MII_1KTCR, &gbcr); - if (ret) { - LOG_ERR("Error reading phy (%d) 1000Base-T control register", config->addr); - goto done; - } - - /* Setup advertising register */ - if (speeds & LINK_FULL_100BASE) { - anar |= MII_ADVERTISE_100_FULL; - } else { - anar &= ~MII_ADVERTISE_100_FULL; - } - if (speeds & LINK_HALF_100BASE) { - anar |= MII_ADVERTISE_100_HALF; - } else { - anar &= ~MII_ADVERTISE_100_HALF; - } - if (speeds & LINK_FULL_10BASE) { - anar |= MII_ADVERTISE_10_FULL; - } else { - anar &= ~MII_ADVERTISE_10_FULL; - } - if (speeds & LINK_HALF_10BASE) { - anar |= MII_ADVERTISE_10_HALF; - } else { - anar &= ~MII_ADVERTISE_10_HALF; - } - - /* Setup 1000Base-T control register */ - if (speeds & LINK_FULL_1000BASE) { - gbcr |= MII_ADVERTISE_1000_FULL; - } else { - gbcr &= ~MII_ADVERTISE_1000_FULL; - } - - /* Write capabilities to advertising register */ - ret = phy_rt_rtl8211f_write(dev, MII_ANAR, anar); - if (ret) { - LOG_ERR("Error writing phy (%d) advertising register", config->addr); - goto done; - } - - /* Write capabilities to 1000Base-T control register */ - ret = phy_rt_rtl8211f_write(dev, MII_1KTCR, gbcr); - if (ret) { - LOG_ERR("Error writing phy (%d) 1000Base-T control register", config->addr); + ret = phy_mii_set_c1kt_reg(dev, speeds); + if (ret < 0 && ret != -EALREADY) { + LOG_ERR("Error setting C1KT register for phy (%d)", config->addr); goto done; } diff --git a/drivers/ethernet/phy/phy_ti_dp83825.c b/drivers/ethernet/phy/phy_ti_dp83825.c index 6c03da42805..288f3d3f5d3 100644 --- a/drivers/ethernet/phy/phy_ti_dp83825.c +++ b/drivers/ethernet/phy/phy_ti_dp83825.c @@ -22,6 +22,8 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); +#include "phy_mii.h" + #define PHY_TI_DP83825_PHYSCR_REG 0x11 #define PHY_TI_DP83825_PHYSCR_REG_IE BIT(1) #define PHY_TI_DP83825_PHYSCR_REG_IOE BIT(0) @@ -363,7 +365,6 @@ static int phy_ti_dp83825_cfg_link(const struct device *dev, enum phy_link_speed const struct ti_dp83825_config *config = dev->config; struct ti_dp83825_data *data = dev->data; int ret; - uint32_t anar; /* Lock mutex */ ret = k_mutex_lock(&data->mutex, K_FOREVER); @@ -393,42 +394,9 @@ static int phy_ti_dp83825_cfg_link(const struct device *dev, enum phy_link_speed goto done; } - /* Read ANAR register to write back */ - ret = phy_ti_dp83825_read(dev, MII_ANAR, &anar); - if (ret) { - LOG_ERR("Error reading phy (%d) advertising register", config->addr); - goto done; - } - - /* Setup advertising register */ - if (speeds & LINK_FULL_100BASE) { - anar |= MII_ADVERTISE_100_FULL; - } else { - anar &= ~MII_ADVERTISE_100_FULL; - } - - if (speeds & LINK_HALF_100BASE) { - anar |= MII_ADVERTISE_100_HALF; - } else { - anar &= ~MII_ADVERTISE_100_HALF; - } - - if (speeds & LINK_FULL_10BASE) { - anar |= MII_ADVERTISE_10_FULL; - } else { - anar &= ~MII_ADVERTISE_10_FULL; - } - - if (speeds & LINK_HALF_10BASE) { - anar |= MII_ADVERTISE_10_HALF; - } else { - anar &= ~MII_ADVERTISE_10_HALF; - } - - /* Write capabilities to advertising register */ - ret = phy_ti_dp83825_write(dev, MII_ANAR, anar); - if (ret) { - LOG_ERR("Error writing phy (%d) advertising register", config->addr); + ret = phy_mii_set_anar_reg(dev, speeds); + if ((ret < 0) && (ret != -EALREADY)) { + LOG_ERR("Error setting ANAR register for phy (%d)", config->addr); goto done; } diff --git a/drivers/ethernet/phy/phy_ti_dp83867.c b/drivers/ethernet/phy/phy_ti_dp83867.c index 173b0aa40bd..ef60fa6b09b 100644 --- a/drivers/ethernet/phy/phy_ti_dp83867.c +++ b/drivers/ethernet/phy/phy_ti_dp83867.c @@ -20,6 +20,8 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL); +#include "phy_mii.h" + #define PHY_TI_DP83867_PHYSTS 0x11 #define PHY_TI_DP83867_PHYSTS_LINKSTATUS_MASK BIT(10) #define PHY_TI_DP83867_PHYSTS_LINKDUPLEX_MASK BIT(13) @@ -309,7 +311,7 @@ static int phy_ti_dp83867_cfg_link(const struct device *dev, enum phy_link_speed const struct ti_dp83867_config *config = dev->config; struct ti_dp83867_data *data = dev->data; int ret; - uint32_t anar, cfg1, val; + uint32_t val; /* Lock mutex */ ret = k_mutex_lock(&data->mutex, K_FOREVER); @@ -356,60 +358,15 @@ static int phy_ti_dp83867_cfg_link(const struct device *dev, enum phy_link_speed k_work_cancel_delayable(&data->phy_monitor_work); #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) */ - /* Read ANAR register to write back */ - ret = phy_ti_dp83867_read(dev, MII_ANAR, &anar); - if (ret) { - LOG_ERR("Error reading phy (%d) advertising register", config->addr); + ret = phy_mii_set_anar_reg(dev, speeds); + if ((ret < 0) && (ret != -EALREADY)) { + LOG_ERR("Error setting ANAR register for phy (%d)", config->addr); goto done; } - /* Read CFG1 register to write back */ - ret = phy_ti_dp83867_read(dev, MII_1KTCR, &cfg1); - if (ret) { - LOG_ERR("Error reading phy (%d) 1000Base-T control register", config->addr); - goto done; - } - - /* Setup advertising register */ - if (speeds & LINK_FULL_100BASE) { - anar |= MII_ADVERTISE_100_FULL; - } else { - anar &= ~MII_ADVERTISE_100_FULL; - } - if (speeds & LINK_HALF_100BASE) { - anar |= MII_ADVERTISE_100_HALF; - } else { - anar &= ~MII_ADVERTISE_100_HALF; - } - if (speeds & LINK_FULL_10BASE) { - anar |= MII_ADVERTISE_10_FULL; - } else { - anar &= ~MII_ADVERTISE_10_FULL; - } - if (speeds & LINK_HALF_10BASE) { - anar |= MII_ADVERTISE_10_HALF; - } else { - anar &= ~MII_ADVERTISE_10_HALF; - } - - /* Setup 1000Base-T control register */ - if (speeds & LINK_FULL_1000BASE) { - cfg1 |= MII_ADVERTISE_1000_FULL; - } else { - cfg1 &= ~MII_ADVERTISE_1000_FULL; - } - - /* Write capabilities to advertising register */ - ret = phy_ti_dp83867_write(dev, MII_ANAR, anar); - if (ret) { - LOG_ERR("Error writing phy (%d) advertising register", config->addr); - goto done; - } - - /* Write capabilities to 1000Base-T control register */ - ret = phy_ti_dp83867_write(dev, MII_1KTCR, cfg1); - if (ret) { - LOG_ERR("Error writing phy (%d) 1000Base-T control register", config->addr); + ret = phy_mii_set_c1kt_reg(dev, speeds); + if ((ret < 0) && (ret != -EALREADY)) { + LOG_ERR("Error setting C1KT register for phy (%d)", config->addr); goto done; }