int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down) { int val; if (dll_pwr_down) { val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); if (val < 0) return val; val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); } val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); if (val < 0) return val; /* Clear APD bits */ val &= BCM_APD_CLR_MASK; if (phydev->autoneg == AUTONEG_ENABLE) val |= BCM54XX_SHD_APD_EN; else val |= BCM_NO_ANEG_APD_EN; /* Enable energy detect single link pulse for easy wakeup */ val |= BCM_APD_SINGLELP_EN; /* Enable Auto Power-Down (APD) for the PHY */ return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); }
static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) { u32 orig; int val; bool clk125en = true; /* Abort if we are using an untested phy. */ if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) return; val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); if (val < 0) return; orig = val; if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && BRCM_PHY_REV(phydev) >= 0x3) { /* * Here, bit 0 _disables_ CLK125 when set. * This bit is set by default. */ clk125en = false; } else { if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { /* Here, bit 0 _enables_ CLK125 when set */ val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; clk125en = false; } } if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; else val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) val |= BCM54XX_SHD_SCR3_TRDDAPD; if (orig != val) bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); if (val < 0) return; orig = val; if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) val |= BCM54XX_SHD_APD_EN; else val &= ~BCM54XX_SHD_APD_EN; if (orig != val) bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); }
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; } return 0; }
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; } return bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR2, val); }
static int bcm54210e_config_init(struct phy_device *phydev) { int val; val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; val |= MII_BCM54XX_AUXCTL_MISC_WREN; bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { val = phy_read(phydev, MII_CTRL1000); val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; phy_write(phydev, MII_CTRL1000, val); } return 0; }
static int bcm5481x_config(struct phy_device *phydev) { int rc, val; /* handling PHY's internal RX clock delay */ val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); val |= MII_BCM54XX_AUXCTL_MISC_WREN; if (phydev->interface == PHY_INTERFACE_MODE_RGMII || phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { /* Disable RGMII RXC-RXD skew */ val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; } if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { /* Enable RGMII RXC-RXD skew */ val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; } rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); if (rc < 0) return rc; /* handling PHY's internal TX clock delay */ val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); if (phydev->interface == PHY_INTERFACE_MODE_RGMII || phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { /* Disable internal TX clock delay */ val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; } if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { /* Enable internal TX clock delay */ val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN; } rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); if (rc < 0) return rc; return 0; }
static int bcm5482_config_init(struct phy_device *phydev) { int err, reg; err = bcm54xx_config_init(phydev); if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { /* * Enable secondary SerDes and its use as an LED source */ reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD); bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD, reg | BCM5482_SHD_SSD_LEDM | BCM5482_SHD_SSD_EN); /* * Enable SGMII slave mode and auto-detection */ reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; err = bcm_phy_read_exp(phydev, reg); if (err < 0) return err; err = bcm_phy_write_exp(phydev, reg, err | BCM5482_SSD_SGMII_SLAVE_EN | BCM5482_SSD_SGMII_SLAVE_AD); if (err < 0) return err; /* * Disable secondary SerDes powerdown */ reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; err = bcm_phy_read_exp(phydev, reg); if (err < 0) return err; err = bcm_phy_write_exp(phydev, reg, err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); if (err < 0) return err; /* * Select 1000BASE-X register set (primary SerDes) */ reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE); bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, reg | BCM5482_SHD_MODE_1000BX); /* * LED1=ACTIVITYLED, LED3=LINKSPD[2] * (Use LED1 as secondary SerDes ACTIVITY LED) */ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); /* * Auto-negotiation doesn't seem to work quite right * in this mode, so we disable it and force it to the * right speed/duplex setting. Only 'link status' * is important. */ phydev->autoneg = AUTONEG_DISABLE; phydev->speed = SPEED_1000; phydev->duplex = DUPLEX_FULL; } return err; }