aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dsa/bcm_sf2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/bcm_sf2.c')
-rw-r--r--drivers/net/dsa/bcm_sf2.c88
1 files changed, 64 insertions, 24 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index feb29c4526f7..4daffb284931 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -233,6 +233,35 @@ static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
233 core_writel(priv, reg, CORE_EEE_EN_CTRL); 233 core_writel(priv, reg, CORE_EEE_EN_CTRL);
234} 234}
235 235
236static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
237{
238 struct bcm_sf2_priv *priv = ds_to_priv(ds);
239 u32 reg;
240
241 reg = reg_readl(priv, REG_SPHY_CNTRL);
242 if (enable) {
243 reg |= PHY_RESET;
244 reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS);
245 reg_writel(priv, reg, REG_SPHY_CNTRL);
246 udelay(21);
247 reg = reg_readl(priv, REG_SPHY_CNTRL);
248 reg &= ~PHY_RESET;
249 } else {
250 reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET;
251 reg_writel(priv, reg, REG_SPHY_CNTRL);
252 mdelay(1);
253 reg |= CK25_DIS;
254 }
255 reg_writel(priv, reg, REG_SPHY_CNTRL);
256
257 /* Use PHY-driven LED signaling */
258 if (!enable) {
259 reg = reg_readl(priv, REG_LED_CNTRL(0));
260 reg |= SPDLNK_SRC_SEL;
261 reg_writel(priv, reg, REG_LED_CNTRL(0));
262 }
263}
264
236static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, 265static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
237 struct phy_device *phy) 266 struct phy_device *phy)
238{ 267{
@@ -248,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
248 /* Clear the Rx and Tx disable bits and set to no spanning tree */ 277 /* Clear the Rx and Tx disable bits and set to no spanning tree */
249 core_writel(priv, 0, CORE_G_PCTL_PORT(port)); 278 core_writel(priv, 0, CORE_G_PCTL_PORT(port));
250 279
280 /* Re-enable the GPHY and re-apply workarounds */
281 if (port == 0 && priv->hw_params.num_gphy == 1) {
282 bcm_sf2_gphy_enable_set(ds, true);
283 if (phy) {
284 /* if phy_stop() has been called before, phy
285 * will be in halted state, and phy_start()
286 * will call resume.
287 *
288 * the resume path does not configure back
289 * autoneg settings, and since we hard reset
290 * the phy manually here, we need to reset the
291 * state machine also.
292 */
293 phy->state = PHY_READY;
294 phy_init_hw(phy);
295 }
296 }
297
251 /* Enable port 7 interrupts to get notified */ 298 /* Enable port 7 interrupts to get notified */
252 if (port == 7) 299 if (port == 7)
253 intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); 300 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,
281 intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR); 328 intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR);
282 } 329 }
283 330
331 if (port == 0 && priv->hw_params.num_gphy == 1)
332 bcm_sf2_gphy_enable_set(ds, false);
333
284 if (dsa_is_cpu_port(ds, port)) 334 if (dsa_is_cpu_port(ds, port))
285 off = CORE_IMP_CTL; 335 off = CORE_IMP_CTL;
286 else 336 else
@@ -400,6 +450,16 @@ static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
400 return 0; 450 return 0;
401} 451}
402 452
453static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv)
454{
455 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
456 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
457 intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
458 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
459 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
460 intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
461}
462
403static int bcm_sf2_sw_setup(struct dsa_switch *ds) 463static int bcm_sf2_sw_setup(struct dsa_switch *ds)
404{ 464{
405 const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; 465 const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
@@ -440,12 +500,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
440 } 500 }
441 501
442 /* Disable all interrupts and request them */ 502 /* Disable all interrupts and request them */
443 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); 503 bcm_sf2_intr_disable(priv);
444 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
445 intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
446 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
447 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
448 intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
449 504
450 ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0, 505 ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
451 "switch_0", priv); 506 "switch_0", priv);
@@ -747,12 +802,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
747 struct bcm_sf2_priv *priv = ds_to_priv(ds); 802 struct bcm_sf2_priv *priv = ds_to_priv(ds);
748 unsigned int port; 803 unsigned int port;
749 804
750 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); 805 bcm_sf2_intr_disable(priv);
751 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
752 intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
753 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
754 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
755 intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
756 806
757 /* Disable all ports physically present including the IMP 807 /* Disable all ports physically present including the IMP
758 * port, the other ones have already been disabled during 808 * port, the other ones have already been disabled during
@@ -771,7 +821,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
771{ 821{
772 struct bcm_sf2_priv *priv = ds_to_priv(ds); 822 struct bcm_sf2_priv *priv = ds_to_priv(ds);
773 unsigned int port; 823 unsigned int port;
774 u32 reg;
775 int ret; 824 int ret;
776 825
777 ret = bcm_sf2_sw_rst(priv); 826 ret = bcm_sf2_sw_rst(priv);
@@ -780,17 +829,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
780 return ret; 829 return ret;
781 } 830 }
782 831
783 /* Reinitialize the single GPHY */ 832 if (priv->hw_params.num_gphy == 1)
784 if (priv->hw_params.num_gphy == 1) { 833 bcm_sf2_gphy_enable_set(ds, true);
785 reg = reg_readl(priv, REG_SPHY_CNTRL);
786 reg |= PHY_RESET;
787 reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS);
788 reg_writel(priv, reg, REG_SPHY_CNTRL);
789 udelay(21);
790 reg = reg_readl(priv, REG_SPHY_CNTRL);
791 reg &= ~PHY_RESET;
792 reg_writel(priv, reg, REG_SPHY_CNTRL);
793 }
794 834
795 for (port = 0; port < DSA_MAX_PORTS; port++) { 835 for (port = 0; port < DSA_MAX_PORTS; port++) {
796 if ((1 << port) & ds->phys_port_mask) 836 if ((1 << port) & ds->phys_port_mask)