Commit 2150f984 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 3c09e92f 9af197a8
...@@ -233,6 +233,35 @@ static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable) ...@@ -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); 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, static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
struct phy_device *phy) struct phy_device *phy)
{ {
...@@ -248,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, ...@@ -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 */ /* Clear the Rx and Tx disable bits and set to no spanning tree */
core_writel(priv, 0, CORE_G_PCTL_PORT(port)); 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 */ /* Enable port 7 interrupts to get notified */
if (port == 7) if (port == 7)
intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); 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,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); 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)) if (dsa_is_cpu_port(ds, port))
off = CORE_IMP_CTL; off = CORE_IMP_CTL;
else else
...@@ -771,7 +821,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) ...@@ -771,7 +821,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
{ {
struct bcm_sf2_priv *priv = ds_to_priv(ds); struct bcm_sf2_priv *priv = ds_to_priv(ds);
unsigned int port; unsigned int port;
u32 reg;
int ret; int ret;
ret = bcm_sf2_sw_rst(priv); ret = bcm_sf2_sw_rst(priv);
...@@ -780,17 +829,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) ...@@ -780,17 +829,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
return ret; return ret;
} }
/* Reinitialize the single GPHY */ if (priv->hw_params.num_gphy == 1)
if (priv->hw_params.num_gphy == 1) { bcm_sf2_gphy_enable_set(ds, true);
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);
}
for (port = 0; port < DSA_MAX_PORTS; port++) { for (port = 0; port < DSA_MAX_PORTS; port++) {
if ((1 << port) & ds->phys_port_mask) if ((1 << port) & ds->phys_port_mask)
......
...@@ -61,6 +61,10 @@ ...@@ -61,6 +61,10 @@
#define LPI_COUNT_SHIFT 9 #define LPI_COUNT_SHIFT 9
#define LPI_COUNT_MASK 0x3F #define LPI_COUNT_MASK 0x3F
#define REG_LED_CNTRL_BASE 0x90
#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4)
#define SPDLNK_SRC_SEL (1 << 24)
/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */ /* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
#define INTRL2_CPU_STATUS 0x00 #define INTRL2_CPU_STATUS 0x00
#define INTRL2_CPU_SET 0x04 #define INTRL2_CPU_SET 0x04
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment