Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: David S. Miller <davem@davemloft.net>

+56 -12
+52 -12
drivers/net/dsa/bcm_sf2.c
··· 233 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 265 static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, 237 266 struct phy_device *phy) 238 267 { ··· 276 247 277 248 /* Clear the Rx and Tx disable bits and set to no spanning tree */ 278 249 core_writel(priv, 0, CORE_G_PCTL_PORT(port)); 250 + 251 + /* Re-enable the GPHY and re-apply workarounds */ 252 + if (port == 0 && priv->hw_params.num_gphy == 1) { 253 + bcm_sf2_gphy_enable_set(ds, true); 254 + if (phy) { 255 + /* if phy_stop() has been called before, phy 256 + * will be in halted state, and phy_start() 257 + * will call resume. 258 + * 259 + * the resume path does not configure back 260 + * autoneg settings, and since we hard reset 261 + * the phy manually here, we need to reset the 262 + * state machine also. 263 + */ 264 + phy->state = PHY_READY; 265 + phy_init_hw(phy); 266 + } 267 + } 279 268 280 269 /* Enable port 7 interrupts to get notified */ 281 270 if (port == 7) ··· 327 280 intrl2_1_mask_set(priv, P_IRQ_MASK(P7_IRQ_OFF)); 328 281 intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR); 329 282 } 283 + 284 + if (port == 0 && priv->hw_params.num_gphy == 1) 285 + bcm_sf2_gphy_enable_set(ds, false); 330 286 331 287 if (dsa_is_cpu_port(ds, port)) 332 288 off = CORE_IMP_CTL; ··· 821 771 { 822 772 struct bcm_sf2_priv *priv = ds_to_priv(ds); 823 773 unsigned int port; 824 - u32 reg; 825 774 int ret; 826 775 827 776 ret = bcm_sf2_sw_rst(priv); ··· 829 780 return ret; 830 781 } 831 782 832 - /* Reinitialize the single GPHY */ 833 - if (priv->hw_params.num_gphy == 1) { 834 - reg = reg_readl(priv, REG_SPHY_CNTRL); 835 - reg |= PHY_RESET; 836 - reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS); 837 - reg_writel(priv, reg, REG_SPHY_CNTRL); 838 - udelay(21); 839 - reg = reg_readl(priv, REG_SPHY_CNTRL); 840 - reg &= ~PHY_RESET; 841 - reg_writel(priv, reg, REG_SPHY_CNTRL); 842 - } 783 + if (priv->hw_params.num_gphy == 1) 784 + bcm_sf2_gphy_enable_set(ds, true); 843 785 844 786 for (port = 0; port < DSA_MAX_PORTS; port++) { 845 787 if ((1 << port) & ds->phys_port_mask)
+4
drivers/net/dsa/bcm_sf2_regs.h
··· 61 61 #define LPI_COUNT_SHIFT 9 62 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 68 /* Register set relative to 'INTRL2_0' and 'INTRL2_1' */ 65 69 #define INTRL2_CPU_STATUS 0x00 66 70 #define INTRL2_CPU_SET 0x04