|
@@ -233,6 +233,35 @@ static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
|
|
|
core_writel(priv, reg, CORE_EEE_EN_CTRL);
|
|
|
}
|
|
|
|
|
|
+static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
|
|
|
+{
|
|
|
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
|
|
|
+ u32 reg;
|
|
|
+
|
|
|
+ reg = reg_readl(priv, REG_SPHY_CNTRL);
|
|
|
+ if (enable) {
|
|
|
+ reg |= PHY_RESET;
|
|
|
+ reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS);
|
|
|
+ reg_writel(priv, reg, REG_SPHY_CNTRL);
|
|
|
+ udelay(21);
|
|
|
+ reg = reg_readl(priv, REG_SPHY_CNTRL);
|
|
|
+ reg &= ~PHY_RESET;
|
|
|
+ } else {
|
|
|
+ reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET;
|
|
|
+ reg_writel(priv, reg, REG_SPHY_CNTRL);
|
|
|
+ mdelay(1);
|
|
|
+ reg |= CK25_DIS;
|
|
|
+ }
|
|
|
+ reg_writel(priv, reg, REG_SPHY_CNTRL);
|
|
|
+
|
|
|
+ /* Use PHY-driven LED signaling */
|
|
|
+ if (!enable) {
|
|
|
+ reg = reg_readl(priv, REG_LED_CNTRL(0));
|
|
|
+ reg |= SPDLNK_SRC_SEL;
|
|
|
+ reg_writel(priv, reg, REG_LED_CNTRL(0));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
|
|
|
struct phy_device *phy)
|
|
|
{
|
|
@@ -248,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
|
|
|
/* Clear the Rx and Tx disable bits and set to no spanning tree */
|
|
|
core_writel(priv, 0, CORE_G_PCTL_PORT(port));
|
|
|
|
|
|
+ /* Re-enable the GPHY and re-apply workarounds */
|
|
|
+ if (port == 0 && priv->hw_params.num_gphy == 1) {
|
|
|
+ bcm_sf2_gphy_enable_set(ds, true);
|
|
|
+ if (phy) {
|
|
|
+ /* if phy_stop() has been called before, phy
|
|
|
+ * will be in halted state, and phy_start()
|
|
|
+ * will call resume.
|
|
|
+ *
|
|
|
+ * the resume path does not configure back
|
|
|
+ * autoneg settings, and since we hard reset
|
|
|
+ * the phy manually here, we need to reset the
|
|
|
+ * state machine also.
|
|
|
+ */
|
|
|
+ phy->state = PHY_READY;
|
|
|
+ phy_init_hw(phy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* Enable port 7 interrupts to get notified */
|
|
|
if (port == 7)
|
|
|
intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
|
|
@@ -281,6 +328,9 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
|
|
|
intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR);
|
|
|
}
|
|
|
|
|
|
+ if (port == 0 && priv->hw_params.num_gphy == 1)
|
|
|
+ bcm_sf2_gphy_enable_set(ds, false);
|
|
|
+
|
|
|
if (dsa_is_cpu_port(ds, port))
|
|
|
off = CORE_IMP_CTL;
|
|
|
else
|
|
@@ -771,7 +821,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
|
|
|
{
|
|
|
struct bcm_sf2_priv *priv = ds_to_priv(ds);
|
|
|
unsigned int port;
|
|
|
- u32 reg;
|
|
|
int ret;
|
|
|
|
|
|
ret = bcm_sf2_sw_rst(priv);
|
|
@@ -780,17 +829,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- /* Reinitialize the single GPHY */
|
|
|
- if (priv->hw_params.num_gphy == 1) {
|
|
|
- reg = reg_readl(priv, REG_SPHY_CNTRL);
|
|
|
- reg |= PHY_RESET;
|
|
|
- reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS);
|
|
|
- reg_writel(priv, reg, REG_SPHY_CNTRL);
|
|
|
- udelay(21);
|
|
|
- reg = reg_readl(priv, REG_SPHY_CNTRL);
|
|
|
- reg &= ~PHY_RESET;
|
|
|
- reg_writel(priv, reg, REG_SPHY_CNTRL);
|
|
|
- }
|
|
|
+ if (priv->hw_params.num_gphy == 1)
|
|
|
+ bcm_sf2_gphy_enable_set(ds, true);
|
|
|
|
|
|
for (port = 0; port < DSA_MAX_PORTS; port++) {
|
|
|
if ((1 << port) & ds->phys_port_mask)
|