aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-02-08 01:38:45 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-08 01:38:45 -0500
commit2150f984258e7909327cb90115c8ff41b4e9acb5 (patch)
tree95f757336beda2400a803524c21a5ea2e2207119
parent3c09e92fb6b94b7597442c1f232a260c35b30698 (diff)
parent9af197a8f6ecab8c22e4ad0167616151fce5a4cb (diff)
Merge branch 'dsa-next'
Florian Fainelli says: ==================== net: dsa: bcm_sf2: GPHY power down This patch series implement GPHY power up and down in the SF2 switch driver in order to conserve power whenever possible (e.g: port is brought down or unused during Wake-on-LAN). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/bcm_sf2.c64
-rw-r--r--drivers/net/dsa/bcm_sf2_regs.h4
2 files changed, 56 insertions, 12 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 09f6b3cc1f66..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
@@ -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)
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