int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
{ /* The register must be written to both the Shadow Register Select and * the Shadow Read Register Selector
*/
phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MASK |
regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT); return phy_read(phydev, MII_BCM54XX_AUX_CTL);
}
EXPORT_SYMBOL_GPL(bcm54xx_auxctl_read);
int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
{ return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
}
EXPORT_SYMBOL(bcm54xx_auxctl_write);
int bcm_phy_write_misc(struct phy_device *phydev,
u16 reg, u16 chl, u16 val)
{ int rc; int tmp;
/* If a bit from the Interrupt Mask register is set, the corresponding * bit from the Interrupt Status register is masked. So read the IMR * and then flip the bits to get the list of possible interrupt * sources.
*/
irq_mask = phy_read(phydev, MII_BCM54XX_IMR); if (irq_mask < 0) {
phy_error(phydev); return IRQ_NONE;
}
irq_mask = ~irq_mask;
int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count)
{ int val;
val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); if (val < 0) return val;
/* Check if wirespeed is enabled or not */ if (!(val & MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN)) {
*count = DOWNSHIFT_DEV_DISABLE; return 0;
}
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2); if (val < 0) return val;
/* Downgrade after one link attempt */ if (val & BCM54XX_SHD_SCR2_WSPD_RTRY_DIS) {
*count = 1;
} else { /* Downgrade after configured retry count */
val >>= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
val &= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK;
*count = val + BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET;
}
int bcm_phy_downshift_set(struct phy_device *phydev, u8 count)
{ int val = 0, ret = 0;
/* Range check the number given */ if (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET >
BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK &&
count != DOWNSHIFT_DEV_DEFAULT_COUNT) { return -ERANGE;
}
val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); if (val < 0) return val;
/* Se the write enable bit */
val |= MII_BCM54XX_AUXCTL_MISC_WREN;
if (count == DOWNSHIFT_DEV_DISABLE) {
val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN; return bcm54xx_auxctl_write(phydev,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
val);
} else {
val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN;
ret = bcm54xx_auxctl_write(phydev,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
val); if (ret < 0) return ret;
}
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2);
val &= ~(BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK <<
BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT |
BCM54XX_SHD_SCR2_WSPD_RTRY_DIS);
switch (count) { case 1:
val |= BCM54XX_SHD_SCR2_WSPD_RTRY_DIS; break; case DOWNSHIFT_DEV_DEFAULT_COUNT:
val |= 1 << BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT; break; default:
val |= (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET) <<
BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT; break;
}
for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
ethtool_puts(&data, bcm_phy_hw_stats[i].string);
}
EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
/* Caller is supposed to provide appropriate storage for the library code to * access the shadow copy
*/ static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow, unsignedint i)
{ struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i]; int val;
u64 ret;
if (stat.devad < 0)
val = phy_read(phydev, stat.reg); else
val = phy_read_mmd(phydev, stat.devad, stat.reg); if (val < 0) {
ret = U64_MAX;
} else {
val >>= stat.shift;
val = val & ((1 << stat.bits) - 1);
shadow[i] += val;
ret = shadow[i];
}
int bcm_phy_28nm_a0b0_afe_config_init(struct phy_device *phydev)
{ /* Increase VCO range to prevent unlocking problem of PLL at low * temp
*/
bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
/* Change Ki to 011 */
bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
/* Disable loading of TVCO buffer to bandgap, set bandgap trim * to 111
*/
bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
/* Adjust bias current trim by -3 */
bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
/* Switch to CORE_BASE1E */
phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd);
int bcm_phy_enable_jumbo(struct phy_device *phydev)
{ int ret;
ret = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL); if (ret < 0) return ret;
/* Enable extended length packet reception */
ret = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
ret | MII_BCM54XX_AUXCTL_ACTL_EXT_PKT_LEN); if (ret < 0) return ret;
/* Enable the elastic FIFO for raising the transmission limit from * 4.5KB to 10KB, at the expense of an additional 16 ns in propagation * latency.
*/ return phy_set_bits(phydev, MII_BCM54XX_ECR, MII_BCM54XX_ECR_FIFOE);
}
EXPORT_SYMBOL_GPL(bcm_phy_enable_jumbo);
/* Auto-negotiation must be enabled for cable diagnostics to work, but * don't advertise any capabilities.
*/
phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
phy_write(phydev, MII_CTRL1000, 0);
phy_lock_mdio_bus(phydev); if (is_rdb) {
ret = __bcm_phy_enable_legacy_access(phydev); if (ret) goto out;
}
if (bcm_phy_distance_valid(pair_a))
bcm_phy_report_length(phydev, 0); if (bcm_phy_distance_valid(pair_b))
bcm_phy_report_length(phydev, 1); if (bcm_phy_distance_valid(pair_c))
bcm_phy_report_length(phydev, 2); if (bcm_phy_distance_valid(pair_d))
bcm_phy_report_length(phydev, 3);
ret = 0;
*finished = true;
out: /* re-enable the RDB access even if there was an error */ if (is_rdb)
ret = __bcm_phy_enable_rdb_access(phydev) ? : ret;
/** * 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(unsignedlong *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);
}
EXPORT_SYMBOL_GPL(bcm_phy_cable_test_start);
/* We assume that all PHYs which support RDB access can be switched to legacy * mode. If, in the future, this is not true anymore, we have to re-implement * this with RDB access.
*/ int bcm_phy_cable_test_start_rdb(struct phy_device *phydev)
{ return _bcm_phy_cable_test_start(phydev, true);
}
EXPORT_SYMBOL_GPL(bcm_phy_cable_test_start_rdb);
/* Allow a MAC driver to play through its own Wake-on-LAN * implementation
*/ if (wol->wolopts & ~BCM54XX_WOL_SUPPORTED_MASK) return -EOPNOTSUPP;
/* The PHY supports passwords of 4, 6 and 8 bytes in size, but Linux's * ethtool only supports 6, for now.
*/
BUILD_BUG_ON(sizeof(wol->sopass) != ETH_ALEN);
/* Clear previous interrupts */
ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); if (ret < 0) return ret;
ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); if (ret < 0) return ret;
ctl = ret;
if (!wol->wolopts) { if (phy_interrupt_is_valid(phydev))
disable_irq_wake(phydev->irq);
/* Leave all interrupts disabled */
ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK,
BCM54XX_WOL_ALL_INTRS); if (ret < 0) return ret;
/* Disable the global Wake-on-LAN enable bit */
ctl &= ~BCM54XX_WOL_EN;
/* Clear the previously configured mode and mask mode for Wake-on-LAN */
ctl &= ~(BCM54XX_WOL_MODE_MASK << BCM54XX_WOL_MODE_SHIFT);
ctl &= ~(BCM54XX_WOL_MASK_MODE_MASK << BCM54XX_WOL_MASK_MODE_SHIFT);
ctl &= ~BCM54XX_WOL_DIR_PKT_EN;
ctl &= ~(BCM54XX_WOL_SECKEY_OPT_MASK << BCM54XX_WOL_SECKEY_OPT_SHIFT);
/* When using WAKE_MAGIC, we program the magic pattern filter to match * the device's MAC address and we accept any MAC DA in the Ethernet * frame. * * When using WAKE_UCAST, WAKE_BCAST or WAKE_MCAST, we program the * following: * - WAKE_UCAST -> MAC DA is the device's MAC with a perfect match * - WAKE_MCAST -> MAC DA is X1:XX:XX:XX:XX:XX where XX is don't care * - WAKE_BCAST -> MAC DA is FF:FF:FF:FF:FF:FF with a perfect match * * Note that the Broadcast MAC DA is inherently going to match the * multicast pattern being matched.
*/
memset(mask, 0, sizeof(mask));
int bcm_phy_led_brightness_set(struct phy_device *phydev,
u8 index, enum led_brightness value)
{
u8 led_num; int ret;
u16 reg;
if (index >= 4) return -EINVAL;
/* Two LEDS per register */
led_num = index % 2;
reg = index >= 2 ? BCM54XX_SHD_LEDS2 : BCM54XX_SHD_LEDS1;
ret = bcm_phy_read_shadow(phydev, reg); if (ret < 0) return ret;
ret &= ~(BCM_LED_SRC_MASK << BCM54XX_SHD_LEDS_SHIFT(led_num)); if (value == LED_OFF)
ret |= BCM_LED_SRC_OFF << BCM54XX_SHD_LEDS_SHIFT(led_num); else
ret |= BCM_LED_SRC_ON << BCM54XX_SHD_LEDS_SHIFT(led_num); return bcm_phy_write_shadow(phydev, reg, ret);
}
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;
}
/** * 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);
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.