static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) { u32 val, orig; 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 = bcm54xx_shadow_read(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 == false || (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) bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); if (val < 0) return; orig = val; if (clk125en == false || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) val |= BCM54XX_SHD_APD_EN; else val &= ~BCM54XX_SHD_APD_EN; if (orig != val) bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); }
static int bcm7xxx_apd_enable(struct phy_device *phydev) { int val; /* Enable powering down of the DLL during auto-power down */ val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3); if (val < 0) return val; val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val); /* Enable auto-power down */ val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD); if (val < 0) return val; val |= BCM54XX_SHD_APD_EN; return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val); }
static int bcm54xx_config_init(struct phy_device *phydev) { int reg, err; reg = phy_read(phydev, MII_BCM54XX_ECR); if (reg < 0) return reg; /* Mask interrupts globally. */ reg |= MII_BCM54XX_ECR_IM; err = phy_write(phydev, MII_BCM54XX_ECR, reg); if (err < 0) return err; /* Unmask events we are interested in. */ reg = ~(MII_BCM54XX_INT_DUPLEX | MII_BCM54XX_INT_SPEED | MII_BCM54XX_INT_LINK); err = phy_write(phydev, MII_BCM54XX_IMR, reg); if (err < 0) return err; if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0); if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) bcm54xx_adjust_rxrefclk(phydev); bcm54xx_phydsp_config(phydev); 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 = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD); bcm54xx_shadow_write(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 = bcm54xx_exp_read(phydev, reg); if (err < 0) return err; err = bcm54xx_exp_write(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 = bcm54xx_exp_read(phydev, reg); if (err < 0) return err; err = bcm54xx_exp_write(phydev, reg, err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); if (err < 0) return err; /* * Select 1000BASE-X register set (primary SerDes) */ reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE); bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE, reg | BCM5482_SHD_MODE_1000BX); /* * LED1=ACTIVITYLED, LED3=LINKSPD[2] * (Use LED1 as secondary SerDes ACTIVITY LED) */ bcm54xx_shadow_write(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; }