diff --git a/drivers/ethernet/phy/phy_mii.c b/drivers/ethernet/phy/phy_mii.c index aeda0187a34d5..0b812c06924d2 100644 --- a/drivers/ethernet/phy/phy_mii.c +++ b/drivers/ethernet/phy/phy_mii.c @@ -64,13 +64,15 @@ struct phy_mii_dev_data { static void invoke_link_cb(const struct device *dev); #if ANY_DYNAMIC_LINK +static int check_autonegotiation_completion(const struct device *dev); + static inline int phy_mii_reg_read(const struct device *dev, uint16_t reg_addr, uint16_t *value) { const struct phy_mii_dev_config *const cfg = dev->config; /* if there is no mdio (fixed-link) it is not supported to read */ - if (cfg->fixed) { + if (ANY_FIXED_LINK && cfg->fixed) { return -ENOTSUP; } @@ -87,7 +89,7 @@ static inline int phy_mii_reg_write(const struct device *dev, uint16_t reg_addr, const struct phy_mii_dev_config *const cfg = dev->config; /* if there is no mdio (fixed-link) it is not supported to write */ - if (cfg->fixed) { + if (ANY_FIXED_LINK && cfg->fixed) { return -ENOTSUP; } @@ -210,8 +212,7 @@ static int update_link_state(const struct device *dev) return -EIO; } - link_up = (bmsr_reg & MII_BMSR_LINK_STATUS) != 0U; - + link_up = IS_BIT_SET(bmsr_reg, MII_BMSR_LINK_STATUS_BIT); /* If link is down, we can stop here. */ if (!link_up) { data->state.speed = 0; @@ -228,7 +229,7 @@ static int update_link_state(const struct device *dev) } /* If auto-negotiation is not enabled, we only need to check the link speed */ - if ((bmcr_reg & MII_BMCR_AUTONEG_ENABLE) == 0U) { + if (!IS_BIT_SET(bmcr_reg, MII_BMCR_AUTONEG_ENABLE_BIT)) { enum phy_link_speed new_speed = phy_mii_get_link_speed_bmcr_reg(dev, bmcr_reg); if ((data->state.speed != new_speed) || !data->state.is_up) { @@ -259,7 +260,8 @@ static int update_link_state(const struct device *dev) LOG_DBG("PHY (%d) Starting MII PHY auto-negotiate sequence", cfg->phy_addr); data->autoneg_timeout = sys_timepoint_calc(K_MSEC(CONFIG_PHY_AUTONEG_TIMEOUT_MS)); - return -EINPROGRESS; + + return check_autonegotiation_completion(dev); } static int check_autonegotiation_completion(const struct device *dev) @@ -273,19 +275,11 @@ static int check_autonegotiation_completion(const struct device *dev) uint16_t c1kt_reg = 0; uint16_t s1kt_reg = 0; - /* On some PHY chips, the BMSR bits are latched, so the first read may - * show incorrect status. A second read ensures correct values. - */ if (phy_mii_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { return -EIO; } - /* Second read, clears the latched bits and gives the correct status */ - if (phy_mii_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { - return -EIO; - } - - if ((bmsr_reg & MII_BMSR_AUTONEG_COMPLETE) == 0U) { + if (!IS_BIT_SET(bmsr_reg, MII_BMSR_AUTONEG_COMPLETE_BIT)) { if (sys_timepoint_expired(data->autoneg_timeout)) { LOG_DBG("PHY (%d) auto-negotiate timeout", cfg->phy_addr); return -ETIMEDOUT; @@ -293,6 +287,18 @@ static int check_autonegotiation_completion(const struct device *dev) return -EINPROGRESS; } + /* Link status bit is latched low, so read it again to get current status */ + if (unlikely(!IS_BIT_SET(bmsr_reg, MII_BMSR_LINK_STATUS_BIT))) { + /* Second read, clears the latched bits and gives the correct status */ + if (phy_mii_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { + return -EIO; + } + + if (!IS_BIT_SET(bmsr_reg, MII_BMSR_LINK_STATUS_BIT)) { + return -EAGAIN; + } + } + LOG_DBG("PHY (%d) auto-negotiate sequence completed", cfg->phy_addr); @@ -332,7 +338,7 @@ static int check_autonegotiation_completion(const struct device *dev) data->state.speed = LINK_HALF_10BASE; } - data->state.is_up = (bmsr_reg & MII_BMSR_LINK_STATUS) != 0U; + data->state.is_up = true; LOG_INF("PHY (%d) Link speed %s Mb, %s duplex", cfg->phy_addr, @@ -394,7 +400,7 @@ static int phy_mii_cfg_link(const struct device *dev, enum phy_link_speed adv_sp int ret = 0; /* if there is no mdio (fixed-link) it is not supported to configure link */ - if (cfg->fixed) { + if (ANY_FIXED_LINK && cfg->fixed) { return -ENOTSUP; } @@ -560,7 +566,11 @@ static int phy_mii_initialize_dynamic_link(const struct device *dev) k_work_init_delayable(&data->monitor_work, monitor_work_handler); /* Advertise default speeds */ - phy_mii_cfg_link(dev, cfg->default_speeds, 0); + ret = phy_mii_cfg_link(dev, cfg->default_speeds, 0); + if (ret == -EALREADY) { + data->autoneg_in_progress = true; + data->autoneg_timeout = sys_timepoint_calc(K_MSEC(CONFIG_PHY_AUTONEG_TIMEOUT_MS)); + } /* This will schedule the monitor work, if not already scheduled by phy_mii_cfg_link(). */ k_work_schedule(&data->monitor_work, K_NO_WAIT); diff --git a/include/zephyr/net/mii.h b/include/zephyr/net/mii.h index 5d4532a26c49b..30959cb8cb0b5 100644 --- a/include/zephyr/net/mii.h +++ b/include/zephyr/net/mii.h @@ -91,36 +91,51 @@ #define MII_BMCR_SPEED_1000 BIT(MII_BMCR_SPEED_MSB_BIT) /* Basic Mode Status Register (BMSR) bit definitions */ +#define MII_BMSR_100BASE_T4_BIT 15 +#define MII_BMSR_100BASE_X_FULL_BIT 14 +#define MII_BMSR_100BASE_X_HALF_BIT 13 +#define MII_BMSR_10_FULL_BIT 12 +#define MII_BMSR_10_HALF_BIT 11 +#define MII_BMSR_100BASE_T2_FULL_BIT 10 +#define MII_BMSR_100BASE_T2_HALF_BIT 9 +#define MII_BMSR_EXTEND_STATUS_BIT 8 +#define MII_BMSR_MF_PREAMB_SUPPR_BIT 6 +#define MII_BMSR_AUTONEG_COMPLETE_BIT 5 +#define MII_BMSR_REMOTE_FAULT_BIT 4 +#define MII_BMSR_AUTONEG_ABILITY_BIT 3 +#define MII_BMSR_LINK_STATUS_BIT 2 +#define MII_BMSR_JABBER_DETECT_BIT 1 +#define MII_BMSR_EXTEND_CAPAB_BIT 0 /** 100BASE-T4 capable */ -#define MII_BMSR_100BASE_T4 BIT(15) +#define MII_BMSR_100BASE_T4 BIT(MII_BMSR_100BASE_T4_BIT) /** 100BASE-X full duplex capable */ -#define MII_BMSR_100BASE_X_FULL BIT(14) +#define MII_BMSR_100BASE_X_FULL BIT(MII_BMSR_100BASE_X_FULL_BIT) /** 100BASE-X half duplex capable */ -#define MII_BMSR_100BASE_X_HALF BIT(13) +#define MII_BMSR_100BASE_X_HALF BIT(MII_BMSR_100BASE_X_HALF_BIT) /** 10 Mb/s full duplex capable */ -#define MII_BMSR_10_FULL BIT(12) +#define MII_BMSR_10_FULL BIT(MII_BMSR_10_FULL_BIT) /** 10 Mb/s half duplex capable */ -#define MII_BMSR_10_HALF BIT(11) +#define MII_BMSR_10_HALF BIT(MII_BMSR_10_HALF_BIT) /** 100BASE-T2 full duplex capable */ -#define MII_BMSR_100BASE_T2_FULL BIT(10) +#define MII_BMSR_100BASE_T2_FULL BIT(MII_BMSR_100BASE_T2_FULL_BIT) /** 100BASE-T2 half duplex capable */ -#define MII_BMSR_100BASE_T2_HALF BIT(9) +#define MII_BMSR_100BASE_T2_HALF BIT(MII_BMSR_100BASE_T2_HALF_BIT) /** extend status information in reg 15 */ -#define MII_BMSR_EXTEND_STATUS BIT(8) +#define MII_BMSR_EXTEND_STATUS BIT(MII_BMSR_EXTEND_STATUS_BIT) /** PHY accepts management frames with preamble suppressed */ -#define MII_BMSR_MF_PREAMB_SUPPR BIT(6) +#define MII_BMSR_MF_PREAMB_SUPPR BIT(MII_BMSR_MF_PREAMB_SUPPR_BIT) /** Auto-negotiation process completed */ -#define MII_BMSR_AUTONEG_COMPLETE BIT(5) +#define MII_BMSR_AUTONEG_COMPLETE BIT(MII_BMSR_AUTONEG_COMPLETE_BIT) /** remote fault detected */ -#define MII_BMSR_REMOTE_FAULT BIT(4) +#define MII_BMSR_REMOTE_FAULT BIT(MII_BMSR_REMOTE_FAULT_BIT) /** PHY is able to perform Auto-Negotiation */ -#define MII_BMSR_AUTONEG_ABILITY BIT(3) +#define MII_BMSR_AUTONEG_ABILITY BIT(MII_BMSR_AUTONEG_ABILITY_BIT) /** link is up */ -#define MII_BMSR_LINK_STATUS BIT(2) +#define MII_BMSR_LINK_STATUS BIT(MII_BMSR_LINK_STATUS_BIT) /** jabber condition detected */ -#define MII_BMSR_JABBER_DETECT BIT(1) +#define MII_BMSR_JABBER_DETECT BIT(MII_BMSR_JABBER_DETECT_BIT) /** extended register capabilities */ -#define MII_BMSR_EXTEND_CAPAB BIT(0) +#define MII_BMSR_EXTEND_CAPAB BIT(MII_BMSR_EXTEND_CAPAB_BIT) /* Auto-negotiation Advertisement Register (ANAR) bit definitions */ /* Auto-negotiation Link Partner Ability Register (ANLPAR) bit definitions */