net: dsa: bcm_sf2: add suspend/resume callbacks

Implement the suspend/resume callbacks for the Broadcom Starfighter 2
switch driver. Suspending the switch requires masking interrupts and
shutting down ports. Resuming the switch requires a software reset since
we do not know which power-sate we might be coming from, and re-enabling
the physical ports that are used.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Florian Fainelli 2014-09-18 17:31:23 -07:00 committed by David S. Miller
parent 2446254915
commit 8cfa94984c

View File

@ -606,6 +606,89 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
status->pause = 1; status->pause = 1;
} }
static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
unsigned int port;
intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
/* Disable all ports physically present including the IMP
* port, the other ones have already been disabled during
* bcm_sf2_sw_setup
*/
for (port = 0; port < DSA_MAX_PORTS; port++) {
if ((1 << port) & ds->phys_port_mask ||
dsa_is_cpu_port(ds, port))
bcm_sf2_port_disable(ds, port);
}
return 0;
}
static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
{
unsigned int timeout = 1000;
u32 reg;
reg = core_readl(priv, CORE_WATCHDOG_CTRL);
reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
core_writel(priv, reg, CORE_WATCHDOG_CTRL);
do {
reg = core_readl(priv, CORE_WATCHDOG_CTRL);
if (!(reg & SOFTWARE_RESET))
break;
usleep_range(1000, 2000);
} while (timeout-- > 0);
if (timeout == 0)
return -ETIMEDOUT;
return 0;
}
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);
if (ret) {
pr_err("%s: failed to software reset switch\n", __func__);
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);
}
for (port = 0; port < DSA_MAX_PORTS; port++) {
if ((1 << port) & ds->phys_port_mask)
bcm_sf2_port_setup(ds, port);
else if (dsa_is_cpu_port(ds, port))
bcm_sf2_imp_setup(ds, port);
}
return 0;
}
static struct dsa_switch_driver bcm_sf2_switch_driver = { static struct dsa_switch_driver bcm_sf2_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_BRCM, .tag_protocol = DSA_TAG_PROTO_BRCM,
.priv_size = sizeof(struct bcm_sf2_priv), .priv_size = sizeof(struct bcm_sf2_priv),
@ -620,6 +703,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.get_sset_count = bcm_sf2_sw_get_sset_count, .get_sset_count = bcm_sf2_sw_get_sset_count,
.adjust_link = bcm_sf2_sw_adjust_link, .adjust_link = bcm_sf2_sw_adjust_link,
.fixed_link_update = bcm_sf2_sw_fixed_link_update, .fixed_link_update = bcm_sf2_sw_fixed_link_update,
.suspend = bcm_sf2_sw_suspend,
.resume = bcm_sf2_sw_resume,
}; };
static int __init bcm_sf2_init(void) static int __init bcm_sf2_init(void)