aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2015-02-05 14:40:42 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-08 01:38:40 -0500
commit9af197a8f6ecab8c22e4ad0167616151fce5a4cb (patch)
tree95f757336beda2400a803524c21a5ea2e2207119 /drivers/net
parentb083668c93e5bf889e6ec4761540be1accc3f1b1 (diff)
net: dsa: bcm_sf2: implement GPHY power down
Implement the power on/off recommended procedure for the Single GPHY we have on our Starfighter 2 switch. In order to make sure we get proper LED link/activity signaling during suspend, switch the link indication from the Switch/MAC to the PHY. Finally, since the GPHY needs to be reset to be put in low power mode, we will loose any context applied to it: workarounds, EEE etc.. so we need to call phy_init_hw() to get our fixups re-applied successfully. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/dsa/bcm_sf2.c50
-rw-r--r--drivers/net/dsa/bcm_sf2_regs.h4
2 files changed, 45 insertions, 9 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 45c0e2b97f5f..4daffb284931 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -238,17 +238,28 @@ static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
238 struct bcm_sf2_priv *priv = ds_to_priv(ds); 238 struct bcm_sf2_priv *priv = ds_to_priv(ds);
239 u32 reg; 239 u32 reg;
240 240
241 if (!enable)
242 return;
243
244 reg = reg_readl(priv, REG_SPHY_CNTRL);
245 reg |= PHY_RESET;
246 reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS);
247 reg_writel(priv, reg, REG_SPHY_CNTRL);
248 udelay(21);
249 reg = reg_readl(priv, REG_SPHY_CNTRL); 241 reg = reg_readl(priv, REG_SPHY_CNTRL);
250 reg &= ~PHY_RESET; 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 }
251 reg_writel(priv, reg, REG_SPHY_CNTRL); 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 }
252} 263}
253 264
254static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, 265static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
@@ -266,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
266 /* 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 */
267 core_writel(priv, 0, CORE_G_PCTL_PORT(port)); 278 core_writel(priv, 0, CORE_G_PCTL_PORT(port));
268 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
269 /* Enable port 7 interrupts to get notified */ 298 /* Enable port 7 interrupts to get notified */
270 if (port == 7) 299 if (port == 7)
271 intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); 300 intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
@@ -299,6 +328,9 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
299 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);
300 } 329 }
301 330
331 if (port == 0 && priv->hw_params.num_gphy == 1)
332 bcm_sf2_gphy_enable_set(ds, false);
333
302 if (dsa_is_cpu_port(ds, port)) 334 if (dsa_is_cpu_port(ds, port))
303 off = CORE_IMP_CTL; 335 off = CORE_IMP_CTL;
304 else 336 else
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
index 1bb49cb699ab..cabdfa5e217a 100644
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -61,6 +61,10 @@
61#define LPI_COUNT_SHIFT 9 61#define LPI_COUNT_SHIFT 9
62#define LPI_COUNT_MASK 0x3F 62#define LPI_COUNT_MASK 0x3F
63 63
64#define REG_LED_CNTRL_BASE 0x90
65#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4)
66#define SPDLNK_SRC_SEL (1 << 24)
67
64/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */ 68/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
65#define INTRL2_CPU_STATUS 0x00 69#define INTRL2_CPU_STATUS 0x00
66#define INTRL2_CPU_SET 0x04 70#define INTRL2_CPU_SET 0x04