Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8cfa9498 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller
Browse files

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: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 24462549
Loading
Loading
Loading
Loading
+85 −0
Original line number Original line Diff line number Diff line
@@ -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)