diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2014-09-18 20:31:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-22 14:41:23 -0400 |
commit | 8cfa94984c9cfdd5f5af2af4f161176cb7256d44 (patch) | |
tree | 8a41b591a41f652361fde48ca0916da8fd466497 /drivers/net/dsa/bcm_sf2.c | |
parent | 2446254915a7d6f08bba9a755a34cc0402880472 (diff) |
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>
Diffstat (limited to 'drivers/net/dsa/bcm_sf2.c')
-rw-r--r-- | drivers/net/dsa/bcm_sf2.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index a97ba2548ea5..29ceee366e44 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c | |||
@@ -606,6 +606,89 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, | |||
606 | status->pause = 1; | 606 | status->pause = 1; |
607 | } | 607 | } |
608 | 608 | ||
609 | static int bcm_sf2_sw_suspend(struct dsa_switch *ds) | ||
610 | { | ||
611 | struct bcm_sf2_priv *priv = ds_to_priv(ds); | ||
612 | unsigned int port; | ||
613 | |||
614 | intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); | ||
615 | intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); | ||
616 | intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); | ||
617 | intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); | ||
618 | intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); | ||
619 | intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); | ||
620 | |||
621 | /* Disable all ports physically present including the IMP | ||
622 | * port, the other ones have already been disabled during | ||
623 | * bcm_sf2_sw_setup | ||
624 | */ | ||
625 | for (port = 0; port < DSA_MAX_PORTS; port++) { | ||
626 | if ((1 << port) & ds->phys_port_mask || | ||
627 | dsa_is_cpu_port(ds, port)) | ||
628 | bcm_sf2_port_disable(ds, port); | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv) | ||
635 | { | ||
636 | unsigned int timeout = 1000; | ||
637 | u32 reg; | ||
638 | |||
639 | reg = core_readl(priv, CORE_WATCHDOG_CTRL); | ||
640 | reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET; | ||
641 | core_writel(priv, reg, CORE_WATCHDOG_CTRL); | ||
642 | |||
643 | do { | ||
644 | reg = core_readl(priv, CORE_WATCHDOG_CTRL); | ||
645 | if (!(reg & SOFTWARE_RESET)) | ||
646 | break; | ||
647 | |||
648 | usleep_range(1000, 2000); | ||
649 | } while (timeout-- > 0); | ||
650 | |||
651 | if (timeout == 0) | ||
652 | return -ETIMEDOUT; | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | static int bcm_sf2_sw_resume(struct dsa_switch *ds) | ||
658 | { | ||
659 | struct bcm_sf2_priv *priv = ds_to_priv(ds); | ||
660 | unsigned int port; | ||
661 | u32 reg; | ||
662 | int ret; | ||
663 | |||
664 | ret = bcm_sf2_sw_rst(priv); | ||
665 | if (ret) { | ||
666 | pr_err("%s: failed to software reset switch\n", __func__); | ||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | /* Reinitialize the single GPHY */ | ||
671 | if (priv->hw_params.num_gphy == 1) { | ||
672 | reg = reg_readl(priv, REG_SPHY_CNTRL); | ||
673 | reg |= PHY_RESET; | ||
674 | reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS); | ||
675 | reg_writel(priv, reg, REG_SPHY_CNTRL); | ||
676 | udelay(21); | ||
677 | reg = reg_readl(priv, REG_SPHY_CNTRL); | ||
678 | reg &= ~PHY_RESET; | ||
679 | reg_writel(priv, reg, REG_SPHY_CNTRL); | ||
680 | } | ||
681 | |||
682 | for (port = 0; port < DSA_MAX_PORTS; port++) { | ||
683 | if ((1 << port) & ds->phys_port_mask) | ||
684 | bcm_sf2_port_setup(ds, port); | ||
685 | else if (dsa_is_cpu_port(ds, port)) | ||
686 | bcm_sf2_imp_setup(ds, port); | ||
687 | } | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
609 | static struct dsa_switch_driver bcm_sf2_switch_driver = { | 692 | static struct dsa_switch_driver bcm_sf2_switch_driver = { |
610 | .tag_protocol = DSA_TAG_PROTO_BRCM, | 693 | .tag_protocol = DSA_TAG_PROTO_BRCM, |
611 | .priv_size = sizeof(struct bcm_sf2_priv), | 694 | .priv_size = sizeof(struct bcm_sf2_priv), |
@@ -620,6 +703,8 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = { | |||
620 | .get_sset_count = bcm_sf2_sw_get_sset_count, | 703 | .get_sset_count = bcm_sf2_sw_get_sset_count, |
621 | .adjust_link = bcm_sf2_sw_adjust_link, | 704 | .adjust_link = bcm_sf2_sw_adjust_link, |
622 | .fixed_link_update = bcm_sf2_sw_fixed_link_update, | 705 | .fixed_link_update = bcm_sf2_sw_fixed_link_update, |
706 | .suspend = bcm_sf2_sw_suspend, | ||
707 | .resume = bcm_sf2_sw_resume, | ||
623 | }; | 708 | }; |
624 | 709 | ||
625 | static int __init bcm_sf2_init(void) | 710 | static int __init bcm_sf2_init(void) |