Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 28 additions & 18 deletions drivers/ethernet/phy/phy_mii.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand 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)
Expand All @@ -273,26 +275,30 @@ 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;
}
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);

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down
45 changes: 30 additions & 15 deletions include/zephyr/net/mii.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down