mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
Merge branch 'net-phy-bcm5481x-add-support-for-broadr-reach-mode'
Kamil Horák says: ==================== net: phy: bcm5481x: add support for BroadR-Reach mode PATCH 1 - Add the 10baseT1BRR_Full link mode PATCH 2 - Add the definitions of LRE registers, necessary to use BroadR-Reach modes on the BCM5481x PHY PATCH 3 - Add brr-mode flag to switch between IEEE802.3 and BroadR-Reach PATCH 4 - Implementation of the BroadR-Reach modes for the Broadcom PHYs ==================== Link: https://patch.msgid.link/20240712150709.3134474-1-kamilh@axis.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
217b953a8c
|
|
@ -93,6 +93,14 @@ properties:
|
|||
the turn around line low at end of the control phase of the
|
||||
MDIO transaction.
|
||||
|
||||
brr-mode:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
If set, indicates the network cable interface is an alternative one as
|
||||
defined in the BroadR-Reach link mode specification under 1BR-100 and
|
||||
1BR-10 names. The PHY must be configured to operate in BroadR-Reach mode
|
||||
by software.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -794,6 +794,49 @@ static int _bcm_phy_cable_test_get_status(struct phy_device *phydev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int bcm_setup_lre_forced(struct phy_device *phydev)
|
||||
{
|
||||
u16 ctl = 0;
|
||||
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
|
||||
if (phydev->speed == SPEED_100)
|
||||
ctl |= LRECR_SPEED100;
|
||||
|
||||
if (phydev->duplex != DUPLEX_FULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return phy_modify(phydev, MII_BCM54XX_LRECR, LRECR_SPEED100, ctl);
|
||||
}
|
||||
|
||||
/**
|
||||
* bcm_linkmode_adv_to_lre_adv_t - translate linkmode advertisement to LDS
|
||||
* @advertising: the linkmode advertisement settings
|
||||
* Return: LDS Auto-Negotiation Advertised Ability register value
|
||||
*
|
||||
* A small helper function that translates linkmode advertisement
|
||||
* settings to phy LDS autonegotiation advertisements for the
|
||||
* MII_BCM54XX_LREANAA register of Broadcom PHYs capable of LDS
|
||||
*/
|
||||
static u32 bcm_linkmode_adv_to_lre_adv_t(unsigned long *advertising)
|
||||
{
|
||||
u32 result = 0;
|
||||
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT,
|
||||
advertising))
|
||||
result |= LREANAA_10_1PAIR;
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
|
||||
advertising))
|
||||
result |= LREANAA_100_1PAIR;
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising))
|
||||
result |= LRELPA_PAUSE;
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising))
|
||||
result |= LRELPA_PAUSE_ASYM;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int bcm_phy_cable_test_start(struct phy_device *phydev)
|
||||
{
|
||||
return _bcm_phy_cable_test_start(phydev, false);
|
||||
|
|
@ -1066,6 +1109,78 @@ int bcm_phy_led_brightness_set(struct phy_device *phydev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bcm_phy_led_brightness_set);
|
||||
|
||||
int bcm_setup_lre_master_slave(struct phy_device *phydev)
|
||||
{
|
||||
u16 ctl = 0;
|
||||
|
||||
switch (phydev->master_slave_set) {
|
||||
case MASTER_SLAVE_CFG_MASTER_PREFERRED:
|
||||
case MASTER_SLAVE_CFG_MASTER_FORCE:
|
||||
ctl = LRECR_MASTER;
|
||||
break;
|
||||
case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
|
||||
case MASTER_SLAVE_CFG_SLAVE_FORCE:
|
||||
break;
|
||||
case MASTER_SLAVE_CFG_UNKNOWN:
|
||||
case MASTER_SLAVE_CFG_UNSUPPORTED:
|
||||
return 0;
|
||||
default:
|
||||
phydev_warn(phydev, "Unsupported Master/Slave mode\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return phy_modify_changed(phydev, MII_BCM54XX_LRECR, LRECR_MASTER, ctl);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcm_setup_lre_master_slave);
|
||||
|
||||
int bcm_config_lre_aneg(struct phy_device *phydev, bool changed)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (genphy_config_eee_advert(phydev))
|
||||
changed = true;
|
||||
|
||||
err = bcm_setup_lre_master_slave(phydev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err)
|
||||
changed = true;
|
||||
|
||||
if (phydev->autoneg != AUTONEG_ENABLE)
|
||||
return bcm_setup_lre_forced(phydev);
|
||||
|
||||
err = bcm_config_lre_advert(phydev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err)
|
||||
changed = true;
|
||||
|
||||
return genphy_check_and_restart_aneg(phydev, changed);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcm_config_lre_aneg);
|
||||
|
||||
/**
|
||||
* bcm_config_lre_advert - sanitize and advertise Long-Distance Signaling
|
||||
* auto-negotiation parameters
|
||||
* @phydev: target phy_device struct
|
||||
* Return: 0 if the PHY's advertisement hasn't changed, < 0 on error,
|
||||
* > 0 if it has changed
|
||||
*
|
||||
* Writes MII_BCM54XX_LREANAA with the appropriate values. The values are to be
|
||||
* sanitized before, to make sure we only advertise what is supported.
|
||||
* The sanitization is done already in phy_ethtool_ksettings_set()
|
||||
*/
|
||||
int bcm_config_lre_advert(struct phy_device *phydev)
|
||||
{
|
||||
u32 adv = bcm_linkmode_adv_to_lre_adv_t(phydev->advertising);
|
||||
|
||||
/* Setup BroadR-Reach mode advertisement */
|
||||
return phy_modify_changed(phydev, MII_BCM54XX_LREANAA,
|
||||
LRE_ADVERTISE_ALL | LREANAA_PAUSE |
|
||||
LREANAA_PAUSE_ASYM, adv);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bcm_config_lre_advert);
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom PHY Library");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Broadcom Corporation");
|
||||
|
|
|
|||
|
|
@ -121,4 +121,8 @@ irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id);
|
|||
int bcm_phy_led_brightness_set(struct phy_device *phydev,
|
||||
u8 index, enum led_brightness value);
|
||||
|
||||
int bcm_setup_lre_master_slave(struct phy_device *phydev);
|
||||
int bcm_config_lre_aneg(struct phy_device *phydev, bool changed);
|
||||
int bcm_config_lre_advert(struct phy_device *phydev);
|
||||
|
||||
#endif /* _LINUX_BCM_PHY_LIB_H */
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
|
||||
* transceivers.
|
||||
*
|
||||
* Broadcom BCM54810, BCM54811 BroadR-Reach transceivers.
|
||||
*
|
||||
* Copyright (c) 2006 Maciej W. Rozycki
|
||||
*
|
||||
* Inspired by code written by Amy Fong.
|
||||
|
|
@ -36,6 +38,29 @@ struct bcm54xx_phy_priv {
|
|||
struct bcm_ptp_private *ptp;
|
||||
int wake_irq;
|
||||
bool wake_irq_enabled;
|
||||
bool brr_mode;
|
||||
};
|
||||
|
||||
/* Link modes for BCM58411 PHY */
|
||||
static const int bcm54811_linkmodes[] = {
|
||||
ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10baseT_Half_BIT
|
||||
};
|
||||
|
||||
/* Long-Distance Signaling (BroadR-Reach mode aneg) relevant linkmode bits */
|
||||
static const int lds_br_bits[] = {
|
||||
ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100baseT1_Full_BIT
|
||||
};
|
||||
|
||||
static bool bcm54xx_phy_can_wakeup(struct phy_device *phydev)
|
||||
|
|
@ -347,6 +372,61 @@ static void bcm54xx_ptp_config_init(struct phy_device *phydev)
|
|||
bcm_ptp_config_init(phydev);
|
||||
}
|
||||
|
||||
static int bcm5481x_set_brrmode(struct phy_device *phydev, bool on)
|
||||
{
|
||||
int reg;
|
||||
int err;
|
||||
u16 val;
|
||||
|
||||
reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
|
||||
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
|
||||
if (on)
|
||||
reg |= BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
|
||||
else
|
||||
reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
|
||||
|
||||
err = bcm_phy_write_exp(phydev,
|
||||
BCM54810_EXP_BROADREACH_LRE_MISC_CTL, reg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Ensure LRE or IEEE register set is accessed according to the brr
|
||||
* on/off, thus set the override
|
||||
*/
|
||||
val = BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_EN;
|
||||
if (!on)
|
||||
val |= BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_OVERRIDE_VAL;
|
||||
|
||||
return bcm_phy_write_exp(phydev,
|
||||
BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL, val);
|
||||
}
|
||||
|
||||
static int bcm54811_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct bcm54xx_phy_priv *priv = phydev->priv;
|
||||
int err, reg;
|
||||
|
||||
/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
|
||||
if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
|
||||
reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
|
||||
BCM54612E_LED4_CLK125OUT_EN | reg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* With BCM54811, BroadR-Reach implies no autoneg */
|
||||
if (priv->brr_mode)
|
||||
phydev->autoneg = 0;
|
||||
|
||||
return bcm5481x_set_brrmode(phydev, priv->brr_mode);
|
||||
}
|
||||
|
||||
static int bcm54xx_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int reg, err, val;
|
||||
|
|
@ -399,6 +479,9 @@ static int bcm54xx_config_init(struct phy_device *phydev)
|
|||
BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
|
||||
val);
|
||||
break;
|
||||
case PHY_ID_BCM54811:
|
||||
err = bcm54811_config_init(phydev);
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -553,52 +636,117 @@ static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int bcm54811_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int err, reg;
|
||||
|
||||
/* Disable BroadR-Reach function. */
|
||||
reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
|
||||
reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
|
||||
err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
|
||||
reg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = bcm54xx_config_init(phydev);
|
||||
|
||||
/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
|
||||
if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
|
||||
reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
|
||||
err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
|
||||
BCM54612E_LED4_CLK125OUT_EN | reg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bcm5481_config_aneg(struct phy_device *phydev)
|
||||
/**
|
||||
* bcm5481x_read_abilities - read PHY abilities from LRESR or Clause 22
|
||||
* (BMSR) registers, based on whether the PHY is in BroadR-Reach or IEEE mode
|
||||
* @phydev: target phy_device struct
|
||||
*
|
||||
* Description: Reads the PHY's abilities and populates phydev->supported
|
||||
* accordingly. The register to read the abilities from is determined by
|
||||
* the brr mode setting of the PHY as read from the device tree.
|
||||
* Note that the LRE and IEEE sets of abilities are disjunct, in other words,
|
||||
* not only the link modes differ, but also the auto-negotiation and
|
||||
* master-slave setup is controlled differently.
|
||||
*
|
||||
* Returns: 0 on success, < 0 on failure
|
||||
*/
|
||||
static int bcm5481x_read_abilities(struct phy_device *phydev)
|
||||
{
|
||||
struct device_node *np = phydev->mdio.dev.of_node;
|
||||
int ret;
|
||||
struct bcm54xx_phy_priv *priv = phydev->priv;
|
||||
int i, val, err;
|
||||
|
||||
/* Aneg firstly. */
|
||||
ret = genphy_config_aneg(phydev);
|
||||
for (i = 0; i < ARRAY_SIZE(bcm54811_linkmodes); i++)
|
||||
linkmode_clear_bit(bcm54811_linkmodes[i], phydev->supported);
|
||||
|
||||
/* Then we can set up the delay. */
|
||||
priv->brr_mode = of_property_read_bool(np, "brr-mode");
|
||||
|
||||
/* Set BroadR-Reach mode as configured in the DT. */
|
||||
err = bcm5481x_set_brrmode(phydev, priv->brr_mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->brr_mode) {
|
||||
linkmode_set_bit_array(phy_basic_ports_array,
|
||||
ARRAY_SIZE(phy_basic_ports_array),
|
||||
phydev->supported);
|
||||
|
||||
val = phy_read(phydev, MII_BCM54XX_LRESR);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
|
||||
phydev->supported,
|
||||
val & LRESR_LDSABILITY);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
|
||||
phydev->supported,
|
||||
val & LRESR_100_1PAIR);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT,
|
||||
phydev->supported,
|
||||
val & LRESR_10_1PAIR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return genphy_read_abilities(phydev);
|
||||
}
|
||||
|
||||
static int bcm5481x_config_delay_swap(struct phy_device *phydev)
|
||||
{
|
||||
struct device_node *np = phydev->mdio.dev.of_node;
|
||||
|
||||
/* Set up the delay. */
|
||||
bcm54xx_config_clock_delay(phydev);
|
||||
|
||||
if (of_property_read_bool(np, "enet-phy-lane-swap")) {
|
||||
/* Lane Swap - Undocumented register...magic! */
|
||||
ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
|
||||
0x11B);
|
||||
int ret = bcm_phy_write_exp(phydev,
|
||||
MII_BCM54XX_EXP_SEL_ER + 0x9,
|
||||
0x11B);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm5481_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
struct bcm54xx_phy_priv *priv = phydev->priv;
|
||||
int ret;
|
||||
|
||||
/* Aneg firstly. */
|
||||
if (priv->brr_mode)
|
||||
ret = bcm_config_lre_aneg(phydev, false);
|
||||
else
|
||||
ret = genphy_config_aneg(phydev);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Then we can set up the delay and swap. */
|
||||
return bcm5481x_config_delay_swap(phydev);
|
||||
}
|
||||
|
||||
static int bcm54811_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
struct bcm54xx_phy_priv *priv = phydev->priv;
|
||||
int ret;
|
||||
|
||||
/* Aneg firstly. */
|
||||
if (priv->brr_mode) {
|
||||
/* BCM54811 is only capable of autonegotiation in IEEE mode */
|
||||
phydev->autoneg = 0;
|
||||
ret = bcm_config_lre_aneg(phydev, false);
|
||||
} else {
|
||||
ret = genphy_config_aneg(phydev);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Then we can set up the delay and swap. */
|
||||
return bcm5481x_config_delay_swap(phydev);
|
||||
}
|
||||
|
||||
struct bcm54616s_phy_priv {
|
||||
|
|
@ -1062,6 +1210,203 @@ static void bcm54xx_link_change_notify(struct phy_device *phydev)
|
|||
bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret);
|
||||
}
|
||||
|
||||
static int lre_read_master_slave(struct phy_device *phydev)
|
||||
{
|
||||
int cfg = MASTER_SLAVE_CFG_UNKNOWN, state;
|
||||
int val;
|
||||
|
||||
/* In BroadR-Reach mode we are always capable of master-slave
|
||||
* and there is no preferred master or slave configuration
|
||||
*/
|
||||
phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
|
||||
phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
|
||||
|
||||
val = phy_read(phydev, MII_BCM54XX_LRECR);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if ((val & LRECR_LDSEN) == 0) {
|
||||
if (val & LRECR_MASTER)
|
||||
cfg = MASTER_SLAVE_CFG_MASTER_FORCE;
|
||||
else
|
||||
cfg = MASTER_SLAVE_CFG_SLAVE_FORCE;
|
||||
}
|
||||
|
||||
val = phy_read(phydev, MII_BCM54XX_LRELDSE);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val & LDSE_MASTER)
|
||||
state = MASTER_SLAVE_STATE_MASTER;
|
||||
else
|
||||
state = MASTER_SLAVE_STATE_SLAVE;
|
||||
|
||||
phydev->master_slave_get = cfg;
|
||||
phydev->master_slave_state = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read LDS Link Partner Ability in BroadR-Reach mode */
|
||||
static int lre_read_lpa(struct phy_device *phydev)
|
||||
{
|
||||
int i, lrelpa;
|
||||
|
||||
if (phydev->autoneg != AUTONEG_ENABLE) {
|
||||
if (!phydev->autoneg_complete) {
|
||||
/* aneg not yet done, reset all relevant bits */
|
||||
for (i = 0; i < ARRAY_SIZE(lds_br_bits); i++)
|
||||
linkmode_clear_bit(lds_br_bits[i],
|
||||
phydev->lp_advertising);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Long-Distance Signaling Link Partner Ability */
|
||||
lrelpa = phy_read(phydev, MII_BCM54XX_LRELPA);
|
||||
if (lrelpa < 0)
|
||||
return lrelpa;
|
||||
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->lp_advertising,
|
||||
lrelpa & LRELPA_PAUSE_ASYM);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->lp_advertising,
|
||||
lrelpa & LRELPA_PAUSE);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
|
||||
phydev->lp_advertising,
|
||||
lrelpa & LRELPA_100_1PAIR);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT,
|
||||
phydev->lp_advertising,
|
||||
lrelpa & LRELPA_10_1PAIR);
|
||||
} else {
|
||||
linkmode_zero(phydev->lp_advertising);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lre_read_status_fixed(struct phy_device *phydev)
|
||||
{
|
||||
int lrecr = phy_read(phydev, MII_BCM54XX_LRECR);
|
||||
|
||||
if (lrecr < 0)
|
||||
return lrecr;
|
||||
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
|
||||
if (lrecr & LRECR_SPEED100)
|
||||
phydev->speed = SPEED_100;
|
||||
else
|
||||
phydev->speed = SPEED_10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lre_update_link - update link status in @phydev
|
||||
* @phydev: target phy_device struct
|
||||
* Return: 0 on success, < 0 on error
|
||||
*
|
||||
* Description: Update the value in phydev->link to reflect the
|
||||
* current link value. In order to do this, we need to read
|
||||
* the status register twice, keeping the second value.
|
||||
* This is a genphy_update_link modified to work on LRE registers
|
||||
* of BroadR-Reach PHY
|
||||
*/
|
||||
static int lre_update_link(struct phy_device *phydev)
|
||||
{
|
||||
int status = 0, lrecr;
|
||||
|
||||
lrecr = phy_read(phydev, MII_BCM54XX_LRECR);
|
||||
if (lrecr < 0)
|
||||
return lrecr;
|
||||
|
||||
/* Autoneg is being started, therefore disregard BMSR value and
|
||||
* report link as down.
|
||||
*/
|
||||
if (lrecr & BMCR_ANRESTART)
|
||||
goto done;
|
||||
|
||||
/* The link state is latched low so that momentary link
|
||||
* drops can be detected. Do not double-read the status
|
||||
* in polling mode to detect such short link drops except
|
||||
* the link was already down.
|
||||
*/
|
||||
if (!phy_polling_mode(phydev) || !phydev->link) {
|
||||
status = phy_read(phydev, MII_BCM54XX_LRESR);
|
||||
if (status < 0)
|
||||
return status;
|
||||
else if (status & LRESR_LSTATUS)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Read link and autonegotiation status */
|
||||
status = phy_read(phydev, MII_BCM54XX_LRESR);
|
||||
if (status < 0)
|
||||
return status;
|
||||
done:
|
||||
phydev->link = status & LRESR_LSTATUS ? 1 : 0;
|
||||
phydev->autoneg_complete = status & LRESR_LDSCOMPLETE ? 1 : 0;
|
||||
|
||||
/* Consider the case that autoneg was started and "aneg complete"
|
||||
* bit has been reset, but "link up" bit not yet.
|
||||
*/
|
||||
if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
|
||||
phydev->link = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the status in BroadRReach mode just like genphy_read_status does
|
||||
* in normal mode
|
||||
*/
|
||||
static int bcm54811_lre_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int err, old_link = phydev->link;
|
||||
|
||||
/* Update the link, but return if there was an error */
|
||||
err = lre_update_link(phydev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* why bother the PHY if nothing can have changed */
|
||||
if (phydev->autoneg ==
|
||||
AUTONEG_ENABLE && old_link && phydev->link)
|
||||
return 0;
|
||||
|
||||
phydev->speed = SPEED_UNKNOWN;
|
||||
phydev->duplex = DUPLEX_UNKNOWN;
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
|
||||
err = lre_read_master_slave(phydev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Read LDS Link Partner Ability */
|
||||
err = lre_read_lpa(phydev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
|
||||
phy_resolve_aneg_linkmode(phydev);
|
||||
else if (phydev->autoneg == AUTONEG_DISABLE)
|
||||
err = lre_read_status_fixed(phydev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bcm54811_read_status(struct phy_device *phydev)
|
||||
{
|
||||
struct bcm54xx_phy_priv *priv = phydev->priv;
|
||||
|
||||
if (priv->brr_mode)
|
||||
return bcm54811_lre_read_status(phydev);
|
||||
|
||||
return genphy_read_status(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver broadcom_drivers[] = {
|
||||
{
|
||||
.phy_id = PHY_ID_BCM5411,
|
||||
|
|
@ -1211,10 +1556,12 @@ static struct phy_driver broadcom_drivers[] = {
|
|||
.get_strings = bcm_phy_get_strings,
|
||||
.get_stats = bcm54xx_get_stats,
|
||||
.probe = bcm54xx_phy_probe,
|
||||
.config_init = bcm54811_config_init,
|
||||
.config_aneg = bcm5481_config_aneg,
|
||||
.config_init = bcm54xx_config_init,
|
||||
.config_aneg = bcm54811_config_aneg,
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
.handle_interrupt = bcm_phy_handle_interrupt,
|
||||
.read_status = bcm54811_read_status,
|
||||
.get_features = bcm5481x_read_abilities,
|
||||
.suspend = bcm54xx_suspend,
|
||||
.resume = bcm54xx_resume,
|
||||
.link_change_notify = bcm54xx_link_change_notify,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
const char *phy_speed_to_str(int speed)
|
||||
{
|
||||
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102,
|
||||
BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 103,
|
||||
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
|
||||
"If a speed or mode has been added please update phy_speed_to_str "
|
||||
"and the PHY settings array.\n");
|
||||
|
|
@ -266,6 +266,7 @@ static const struct phy_setting settings[] = {
|
|||
PHY_SETTING( 10, FULL, 10baseT1S_Full ),
|
||||
PHY_SETTING( 10, HALF, 10baseT1S_Half ),
|
||||
PHY_SETTING( 10, HALF, 10baseT1S_P2MP_Half ),
|
||||
PHY_SETTING( 10, FULL, 10baseT1BRR_Full ),
|
||||
};
|
||||
#undef PHY_SETTING
|
||||
|
||||
|
|
|
|||
|
|
@ -271,12 +271,100 @@
|
|||
#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
|
||||
#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */
|
||||
|
||||
/* BroadR-Reach LRE Registers. */
|
||||
#define MII_BCM54XX_LRECR 0x00 /* LRE Control Register */
|
||||
#define MII_BCM54XX_LRESR 0x01 /* LRE Status Register */
|
||||
#define MII_BCM54XX_LREPHYSID1 0x02 /* LRE PHYS ID 1 */
|
||||
#define MII_BCM54XX_LREPHYSID2 0x03 /* LRE PHYS ID 2 */
|
||||
#define MII_BCM54XX_LREANAA 0x04 /* LDS Auto-Negotiation Advertised Ability */
|
||||
#define MII_BCM54XX_LREANAC 0x05 /* LDS Auto-Negotiation Advertised Control */
|
||||
#define MII_BCM54XX_LREANPT 0x06 /* LDS Ability Next Page Transmit */
|
||||
#define MII_BCM54XX_LRELPA 0x07 /* LDS Link Partner Ability */
|
||||
#define MII_BCM54XX_LRELPNPM 0x08 /* LDS Link Partner Next Page Message */
|
||||
#define MII_BCM54XX_LRELPNPC 0x09 /* LDS Link Partner Next Page Control */
|
||||
#define MII_BCM54XX_LRELDSE 0x0a /* LDS Expansion Register */
|
||||
#define MII_BCM54XX_LREES 0x0f /* LRE Extended Status */
|
||||
|
||||
/* LRE control register. */
|
||||
#define LRECR_RESET 0x8000 /* Reset to default state */
|
||||
#define LRECR_LOOPBACK 0x4000 /* Internal Loopback */
|
||||
#define LRECR_LDSRES 0x2000 /* Restart LDS Process */
|
||||
#define LRECR_LDSEN 0x1000 /* LDS Enable */
|
||||
#define LRECR_PDOWN 0x0800 /* Enable low power state */
|
||||
#define LRECR_ISOLATE 0x0400 /* Isolate data paths from MII */
|
||||
#define LRECR_SPEED100 0x0200 /* Select 100 Mbps */
|
||||
#define LRECR_SPEED10 0x0000 /* Select 10 Mbps */
|
||||
#define LRECR_4PAIRS 0x0020 /* Select 4 Pairs */
|
||||
#define LRECR_2PAIRS 0x0010 /* Select 2 Pairs */
|
||||
#define LRECR_1PAIR 0x0000 /* Select 1 Pair */
|
||||
#define LRECR_MASTER 0x0008 /* Force Master when LDS disabled */
|
||||
#define LRECR_SLAVE 0x0000 /* Force Slave when LDS disabled */
|
||||
|
||||
/* LRE status register. */
|
||||
#define LRESR_100_1PAIR 0x2000 /* Can do 100Mbps 1 Pair */
|
||||
#define LRESR_100_4PAIR 0x1000 /* Can do 100Mbps 4 Pairs */
|
||||
#define LRESR_100_2PAIR 0x0800 /* Can do 100Mbps 2 Pairs */
|
||||
#define LRESR_10_2PAIR 0x0400 /* Can do 10Mbps 2 Pairs */
|
||||
#define LRESR_10_1PAIR 0x0200 /* Can do 10Mbps 1 Pair */
|
||||
#define LRESR_ESTATEN 0x0100 /* Extended Status in R15 */
|
||||
#define LRESR_RESV 0x0080 /* Unused... */
|
||||
#define LRESR_MFPS 0x0040 /* Can suppress Management Frames Preamble */
|
||||
#define LRESR_LDSCOMPLETE 0x0020 /* LDS Auto-negotiation complete */
|
||||
#define LRESR_8023 0x0010 /* Has IEEE 802.3 Support */
|
||||
#define LRESR_LDSABILITY 0x0008 /* LDS auto-negotiation capable */
|
||||
#define LRESR_LSTATUS 0x0004 /* Link status */
|
||||
#define LRESR_JCD 0x0002 /* Jabber detected */
|
||||
#define LRESR_ERCAP 0x0001 /* Ext-reg capability */
|
||||
|
||||
/* LDS Auto-Negotiation Advertised Ability. */
|
||||
#define LREANAA_PAUSE_ASYM 0x8000 /* Can pause asymmetrically */
|
||||
#define LREANAA_PAUSE 0x4000 /* Can pause */
|
||||
#define LREANAA_100_1PAIR 0x0020 /* Can do 100Mbps 1 Pair */
|
||||
#define LREANAA_100_4PAIR 0x0010 /* Can do 100Mbps 4 Pair */
|
||||
#define LREANAA_100_2PAIR 0x0008 /* Can do 100Mbps 2 Pair */
|
||||
#define LREANAA_10_2PAIR 0x0004 /* Can do 10Mbps 2 Pair */
|
||||
#define LREANAA_10_1PAIR 0x0002 /* Can do 10Mbps 1 Pair */
|
||||
|
||||
#define LRE_ADVERTISE_FULL (LREANAA_100_1PAIR | LREANAA_100_4PAIR | \
|
||||
LREANAA_100_2PAIR | LREANAA_10_2PAIR | \
|
||||
LREANAA_10_1PAIR)
|
||||
|
||||
#define LRE_ADVERTISE_ALL LRE_ADVERTISE_FULL
|
||||
|
||||
/* LDS Link Partner Ability. */
|
||||
#define LRELPA_PAUSE_ASYM 0x8000 /* Supports asymmetric pause */
|
||||
#define LRELPA_PAUSE 0x4000 /* Supports pause capability */
|
||||
#define LRELPA_100_1PAIR 0x0020 /* 100Mbps 1 Pair capable */
|
||||
#define LRELPA_100_4PAIR 0x0010 /* 100Mbps 4 Pair capable */
|
||||
#define LRELPA_100_2PAIR 0x0008 /* 100Mbps 2 Pair capable */
|
||||
#define LRELPA_10_2PAIR 0x0004 /* 10Mbps 2 Pair capable */
|
||||
#define LRELPA_10_1PAIR 0x0002 /* 10Mbps 1 Pair capable */
|
||||
|
||||
/* LDS Expansion register. */
|
||||
#define LDSE_DOWNGRADE 0x8000 /* Can do LDS Speed Downgrade */
|
||||
#define LDSE_MASTER 0x4000 /* Master / Slave */
|
||||
#define LDSE_PAIRS_MASK 0x3000 /* Pair Count Mask */
|
||||
#define LDSE_PAIRS_SHIFT 12
|
||||
#define LDSE_4PAIRS (2 << LDSE_PAIRS_SHIFT) /* 4 Pairs Connection */
|
||||
#define LDSE_2PAIRS (1 << LDSE_PAIRS_SHIFT) /* 2 Pairs Connection */
|
||||
#define LDSE_1PAIR (0 << LDSE_PAIRS_SHIFT) /* 1 Pair Connection */
|
||||
#define LDSE_CABLEN_MASK 0x0FFF /* Cable Length Mask */
|
||||
|
||||
/* BCM54810 Registers */
|
||||
#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL (MII_BCM54XX_EXP_SEL_ER + 0x90)
|
||||
#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN (1 << 0)
|
||||
#define BCM54810_SHD_CLK_CTL 0x3
|
||||
#define BCM54810_SHD_CLK_CTL_GTXCLK_EN (1 << 9)
|
||||
|
||||
/* BCM54811 Registers */
|
||||
#define BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL (MII_BCM54XX_EXP_SEL_ER + 0x9A)
|
||||
/* Access Control Override Enable */
|
||||
#define BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_EN BIT(15)
|
||||
/* Access Control Override Value */
|
||||
#define BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_OVERRIDE_VAL BIT(14)
|
||||
/* Access Control Value */
|
||||
#define BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_VAL BIT(13)
|
||||
|
||||
/* BCM54612E Registers */
|
||||
#define BCM54612E_EXP_SPARE0 (MII_BCM54XX_EXP_SEL_ETC + 0x34)
|
||||
#define BCM54612E_LED4_CLK125OUT_EN (1 << 1)
|
||||
|
|
|
|||
|
|
@ -2054,6 +2054,7 @@ enum ethtool_link_mode_bit_indices {
|
|||
ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99,
|
||||
ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100,
|
||||
ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101,
|
||||
ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT = 102,
|
||||
|
||||
/* must be last entry */
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ const char link_mode_names[][ETH_GSTRING_LEN] = {
|
|||
__DEFINE_LINK_MODE_NAME(10, T1S, Full),
|
||||
__DEFINE_LINK_MODE_NAME(10, T1S, Half),
|
||||
__DEFINE_LINK_MODE_NAME(10, T1S_P2MP, Half),
|
||||
__DEFINE_LINK_MODE_NAME(10, T1BRR, Full),
|
||||
};
|
||||
static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
|
||||
|
|
@ -251,6 +252,7 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
|||
#define __LINK_MODE_LANES_T1S_P2MP 1
|
||||
#define __LINK_MODE_LANES_VR8 8
|
||||
#define __LINK_MODE_LANES_DR8_2 8
|
||||
#define __LINK_MODE_LANES_T1BRR 1
|
||||
|
||||
#define __DEFINE_LINK_MODE_PARAMS(_speed, _type, _duplex) \
|
||||
[ETHTOOL_LINK_MODE(_speed, _type, _duplex)] = { \
|
||||
|
|
@ -374,6 +376,7 @@ const struct link_mode_info link_mode_params[] = {
|
|||
__DEFINE_LINK_MODE_PARAMS(10, T1S, Full),
|
||||
__DEFINE_LINK_MODE_PARAMS(10, T1S, Half),
|
||||
__DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half),
|
||||
__DEFINE_LINK_MODE_PARAMS(10, T1BRR, Full),
|
||||
};
|
||||
static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user