/* Hibernation yields lower power consumpiton in contrast with normal operation mode. * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s.
*/ #define QCA808X_DBG_AN_TEST 0xb #define QCA808X_HIBERNATION_EN BIT(15)
#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a /* QSDK sets by default 0x46 to this reg that sets BIT 6 for * LED to active high. It's not clear what BIT 3 and BIT 4 does.
*/ #define QCA808X_LED_ACTIVE_HIGH BIT(6)
/* Default to LED Active High if active-low not in DT */ if (priv->led_polarity_mode == -1) {
ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN,
QCA808X_MMD7_LED_POLARITY_CTRL,
QCA808X_LED_ACTIVE_HIGH); if (ret) return ret;
}
/* Active adc&vga on 802.3az for the link 1000M and 100M */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); if (ret) return ret;
/* Adjust the threshold on 802.3az for the link 1000M */
ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
QCA808X_MMD3_AZ_TRAINING_VAL); if (ret) return ret;
if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { /* Config the fast retrain for the link 2500M */
ret = qca808x_phy_fast_retrain_config(phydev); if (ret) return ret;
ret = genphy_read_master_slave(phydev); if (ret < 0) return ret;
if (!qca808x_is_prefer_master(phydev)) { /* Enable seed and configure lower ramdom seed to make phy * linked as slave mode.
*/
ret = qca808x_phy_ms_seed_enable(phydev, true); if (ret) return ret;
}
}
qca808x_fill_possible_interfaces(phydev);
ret = qcom_phy_counter_config(phydev); if (ret) return ret;
/* Configure adc threshold as 100mv for the link 10M */ return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
QCA808X_ADC_THRESHOLD_MASK,
QCA808X_ADC_THRESHOLD_100MV);
}
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); if (ret < 0) return ret;
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
ret & MDIO_AN_10GBT_STAT_LP2_5G);
ret = genphy_read_status(phydev); if (ret) return ret;
/* qca8081 takes the different bits for speed value from at803x */
ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
ret = at803x_read_specific_status(phydev, ss_mask); if (ret < 0) return ret;
if (phydev->link) { if (phydev->speed == SPEED_2500)
phydev->interface = PHY_INTERFACE_MODE_2500BASEX; else
phydev->interface = PHY_INTERFACE_MODE_SGMII;
} else { /* generate seed as a lower random value to make PHY linked as SLAVE easily, * except for master/slave configuration fault detected or the master mode * preferred. * * the reason for not putting this code into the function link_change_notify is * the corner case where the link partner is also the qca8081 PHY and the seed * value is configured as the same value, the link can't be up and no link change * occurs.
*/ if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
qca808x_is_prefer_master(phydev)) {
qca808x_phy_ms_seed_enable(phydev, false);
} else {
qca808x_phy_ms_seed_enable(phydev, true);
}
}
}
return 0;
}
staticint qca808x_soft_reset(struct phy_device *phydev)
{ int ret;
ret = genphy_soft_reset(phydev); if (ret < 0) return ret;
if (qca808x_has_fast_retrain_or_slave_seed(phydev))
ret = qca808x_phy_ms_seed_enable(phydev, true);
return ret;
}
staticint qca808x_cable_test_start(struct phy_device *phydev)
{ int ret;
/* perform CDT with the following configs: * 1. disable hibernation. * 2. force PHY working in MDI mode. * 3. for PHY working in 1000BaseT. * 4. configure the threshold.
*/
ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); if (ret < 0) return ret;
ret = at803x_config_mdix(phydev, ETH_TP_MDI); if (ret < 0) return ret;
/* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */
phydev->duplex = DUPLEX_FULL;
phydev->speed = SPEED_1000;
ret = genphy_c45_pma_setup_forced(phydev); if (ret < 0) return ret;
ret = genphy_setup_forced(phydev); if (ret < 0) return ret;
/* configure the thresholds for open, short, pair ok test */
phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040);
phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040);
phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060);
phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050);
phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060);
phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060);
return 0;
}
staticint qca808x_get_features(struct phy_device *phydev)
{ int ret;
ret = genphy_c45_pma_read_abilities(phydev); if (ret) return ret;
/* The autoneg ability is not existed in bit3 of MMD7.1, * but it is supported by qca808x PHY, so we add it here * manually.
*/
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
/* As for the qca8081 1G version chip, the 2500baseT ability is also * existed in the bit0 of MMD1.21, we need to remove it manually if * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d.
*/ if (qca808x_is_1g_only(phydev))
linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported);
return 0;
}
staticint qca808x_config_aneg(struct phy_device *phydev)
{ int phy_ctrl = 0; int ret;
ret = at803x_prepare_config_aneg(phydev); if (ret) return ret;
/* The reg MII_BMCR also needs to be configured for force mode, the * genphy_config_aneg is also needed.
*/ if (phydev->autoneg == AUTONEG_DISABLE)
genphy_c45_pma_setup_forced(phydev);
if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); if (ret < 0) return ret;
return __genphy_config_aneg(phydev, ret);
}
staticvoid qca808x_link_change_notify(struct phy_device *phydev)
{ /* Assert interface sgmii fifo on link down, deassert it on link up, * the interface device address is always phy address added by 1.
*/
mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
QCA8081_PHY_FIFO_RSTN,
phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
}
staticint qca808x_led_parse_netdev(struct phy_device *phydev, unsignedlong rules,
u16 *offload_trigger)
{ /* Parsing specific to netdev trigger */ if (test_bit(TRIGGER_NETDEV_TX, &rules))
*offload_trigger |= QCA808X_LED_TX_BLINK; if (test_bit(TRIGGER_NETDEV_RX, &rules))
*offload_trigger |= QCA808X_LED_RX_BLINK; if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
*offload_trigger |= QCA808X_LED_SPEED10_ON; if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
*offload_trigger |= QCA808X_LED_SPEED100_ON; if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
*offload_trigger |= QCA808X_LED_SPEED1000_ON; if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules))
*offload_trigger |= QCA808X_LED_SPEED2500_ON; if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
*offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
*offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
if (rules && !*offload_trigger) return -EOPNOTSUPP;
/* Enable BLINK_CHECK_BYPASS by default to make the LED * blink even with duplex or speed mode not enabled.
*/
*offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS;
/* PHY polarity is global and can't be set per LED. * To detect this, check if last requested polarity mode * match the new one.
*/ if (priv->led_polarity_mode >= 0 &&
priv->led_polarity_mode != active_low) {
phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); return -EINVAL;
}
/* Save the last PHY polarity mode */
priv->led_polarity_mode = active_low;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.