diff options
| -rw-r--r-- | drivers/net/dsa/bcm_sf2.c | 64 | ||||
| -rw-r--r-- | drivers/net/dsa/bcm_sf2_regs.h | 4 |
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 | ||
| 236 | static 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 | |||
| 236 | static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, | 265 | static 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 |
