static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port, phy_interface_t interface, bool link) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); u32 reg; if (!phy_interface_mode_is_rgmii(interface) && interface != PHY_INTERFACE_MODE_MII && interface != PHY_INTERFACE_MODE_REVMII) return; /* If the link is down, just disable the interface to conserve power */ reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); if (link) reg |= RGMII_MODE_EN; else reg &= ~RGMII_MODE_EN; reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); }
static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phydev) { struct bcm_sf2_priv *priv = ds_to_priv(ds); u32 id_mode_dis = 0, port_mode; const char *str = NULL; u32 reg; switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: str = "RGMII (no delay)"; id_mode_dis = 1; case PHY_INTERFACE_MODE_RGMII_TXID: if (!str) str = "RGMII (TX delay)"; port_mode = EXT_GPHY; break; case PHY_INTERFACE_MODE_MII: str = "MII"; port_mode = EXT_EPHY; break; case PHY_INTERFACE_MODE_REVMII: str = "Reverse MII"; port_mode = EXT_REVMII; break; default: /* All other PHYs: internal and MoCA */ goto force_link; } /* If the link is down, just disable the interface to conserve power */ if (!phydev->link) { reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); reg &= ~RGMII_MODE_EN; reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); goto force_link; } /* Clear id_mode_dis bit, and the existing port mode, but * make sure we enable the RGMII block for data to pass */ reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); reg &= ~ID_MODE_DIS; reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT); reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); reg |= port_mode | RGMII_MODE_EN; if (id_mode_dis) reg |= ID_MODE_DIS; if (phydev->pause) { if (phydev->asym_pause) reg |= TX_PAUSE_EN; reg |= RX_PAUSE_EN; } reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); pr_info("Port %d configured for %s\n", port, str); force_link: /* Force link settings detected from the PHY */ reg = SW_OVERRIDE; switch (phydev->speed) { case SPEED_1000: reg |= SPDSTS_1000 << SPEED_SHIFT; break; case SPEED_100: reg |= SPDSTS_100 << SPEED_SHIFT; break; } if (phydev->link) reg |= LINK_STS; if (phydev->duplex == DUPLEX_FULL) reg |= DUPLX_MODE; core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port)); }
static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); u32 id_mode_dis = 0, port_mode; u32 reg, offset; if (priv->type == BCM7445_DEVICE_ID) offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); else offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); switch (state->interface) { case PHY_INTERFACE_MODE_RGMII: id_mode_dis = 1; /* fallthrough */ case PHY_INTERFACE_MODE_RGMII_TXID: port_mode = EXT_GPHY; break; case PHY_INTERFACE_MODE_MII: port_mode = EXT_EPHY; break; case PHY_INTERFACE_MODE_REVMII: port_mode = EXT_REVMII; break; default: /* all other PHYs: internal and MoCA */ goto force_link; } /* Clear id_mode_dis bit, and the existing port mode, let * RGMII_MODE_EN bet set by mac_link_{up,down} */ reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); reg &= ~ID_MODE_DIS; reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT); reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); reg |= port_mode; if (id_mode_dis) reg |= ID_MODE_DIS; if (state->pause & MLO_PAUSE_TXRX_MASK) { if (state->pause & MLO_PAUSE_TX) reg |= TX_PAUSE_EN; reg |= RX_PAUSE_EN; } reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); force_link: /* Force link settings detected from the PHY */ reg = SW_OVERRIDE; switch (state->speed) { case SPEED_1000: reg |= SPDSTS_1000 << SPEED_SHIFT; break; case SPEED_100: reg |= SPDSTS_100 << SPEED_SHIFT; break; } if (state->link) reg |= LINK_STS; if (state->duplex == DUPLEX_FULL) reg |= DUPLX_MODE; core_writel(priv, reg, offset); }