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

net: phy: dp83867: support Wake on LAN

This adds WoL support on TI DP83867 for magic, magic secure, unicast and
broadcast.

Signed-off-by: Thomas Haemmerle <thomas.haemmerle@wolfvision.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Thomas Haemmerle and committed by
David S. Miller
caabee5b 76d7774e

+130 -1
+130 -1
drivers/net/phy/dp83867.c
··· 12 12 #include <linux/of.h> 13 13 #include <linux/phy.h> 14 14 #include <linux/delay.h> 15 + #include <linux/netdevice.h> 16 + #include <linux/etherdevice.h> 15 17 16 18 #include <dt-bindings/net/ti-dp83867.h> 17 19 ··· 23 21 #define MII_DP83867_PHYCTRL 0x10 24 22 #define MII_DP83867_MICR 0x12 25 23 #define MII_DP83867_ISR 0x13 26 - #define DP83867_CTRL 0x1f 24 + #define DP83867_CFG2 0x14 27 25 #define DP83867_CFG3 0x1e 26 + #define DP83867_CTRL 0x1f 28 27 29 28 /* Extended Registers */ 30 29 #define DP83867_CFG4 0x0031 ··· 39 36 #define DP83867_STRAP_STS1 0x006E 40 37 #define DP83867_STRAP_STS2 0x006f 41 38 #define DP83867_RGMIIDCTL 0x0086 39 + #define DP83867_RXFCFG 0x0134 40 + #define DP83867_RXFPMD1 0x0136 41 + #define DP83867_RXFPMD2 0x0137 42 + #define DP83867_RXFPMD3 0x0138 43 + #define DP83867_RXFSOP1 0x0139 44 + #define DP83867_RXFSOP2 0x013A 45 + #define DP83867_RXFSOP3 0x013B 42 46 #define DP83867_IO_MUX_CFG 0x0170 43 47 #define DP83867_SGMIICTL 0x00D3 44 48 #define DP83867_10M_SGMII_CFG 0x016F ··· 74 64 75 65 /* SGMIICTL bits */ 76 66 #define DP83867_SGMII_TYPE BIT(14) 67 + 68 + /* RXFCFG bits*/ 69 + #define DP83867_WOL_MAGIC_EN BIT(0) 70 + #define DP83867_WOL_BCAST_EN BIT(2) 71 + #define DP83867_WOL_UCAST_EN BIT(4) 72 + #define DP83867_WOL_SEC_EN BIT(5) 73 + #define DP83867_WOL_ENH_MAC BIT(7) 77 74 78 75 /* STRAP_STS1 bits */ 79 76 #define DP83867_STRAP_STS1_RESERVED BIT(11) ··· 145 128 return err; 146 129 147 130 return 0; 131 + } 132 + 133 + static int dp83867_set_wol(struct phy_device *phydev, 134 + struct ethtool_wolinfo *wol) 135 + { 136 + struct net_device *ndev = phydev->attached_dev; 137 + u16 val_rxcfg, val_micr; 138 + u8 *mac; 139 + 140 + val_rxcfg = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG); 141 + val_micr = phy_read(phydev, MII_DP83867_MICR); 142 + 143 + if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_UCAST | 144 + WAKE_BCAST)) { 145 + val_rxcfg |= DP83867_WOL_ENH_MAC; 146 + val_micr |= MII_DP83867_MICR_WOL_INT_EN; 147 + 148 + if (wol->wolopts & WAKE_MAGIC) { 149 + mac = (u8 *)ndev->dev_addr; 150 + 151 + if (!is_valid_ether_addr(mac)) 152 + return -EINVAL; 153 + 154 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD1, 155 + (mac[1] << 8 | mac[0])); 156 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD2, 157 + (mac[3] << 8 | mac[2])); 158 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD3, 159 + (mac[5] << 8 | mac[4])); 160 + 161 + val_rxcfg |= DP83867_WOL_MAGIC_EN; 162 + } else { 163 + val_rxcfg &= ~DP83867_WOL_MAGIC_EN; 164 + } 165 + 166 + if (wol->wolopts & WAKE_MAGICSECURE) { 167 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, 168 + (wol->sopass[1] << 8) | wol->sopass[0]); 169 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, 170 + (wol->sopass[3] << 8) | wol->sopass[2]); 171 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, 172 + (wol->sopass[5] << 8) | wol->sopass[4]); 173 + 174 + val_rxcfg |= DP83867_WOL_SEC_EN; 175 + } else { 176 + val_rxcfg &= ~DP83867_WOL_SEC_EN; 177 + } 178 + 179 + if (wol->wolopts & WAKE_UCAST) 180 + val_rxcfg |= DP83867_WOL_UCAST_EN; 181 + else 182 + val_rxcfg &= ~DP83867_WOL_UCAST_EN; 183 + 184 + if (wol->wolopts & WAKE_BCAST) 185 + val_rxcfg |= DP83867_WOL_BCAST_EN; 186 + else 187 + val_rxcfg &= ~DP83867_WOL_BCAST_EN; 188 + } else { 189 + val_rxcfg &= ~DP83867_WOL_ENH_MAC; 190 + val_micr &= ~MII_DP83867_MICR_WOL_INT_EN; 191 + } 192 + 193 + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG, val_rxcfg); 194 + phy_write(phydev, MII_DP83867_MICR, val_micr); 195 + 196 + return 0; 197 + } 198 + 199 + static void dp83867_get_wol(struct phy_device *phydev, 200 + struct ethtool_wolinfo *wol) 201 + { 202 + u16 value, sopass_val; 203 + 204 + wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC | 205 + WAKE_MAGICSECURE); 206 + wol->wolopts = 0; 207 + 208 + value = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG); 209 + 210 + if (value & DP83867_WOL_UCAST_EN) 211 + wol->wolopts |= WAKE_UCAST; 212 + 213 + if (value & DP83867_WOL_BCAST_EN) 214 + wol->wolopts |= WAKE_BCAST; 215 + 216 + if (value & DP83867_WOL_MAGIC_EN) 217 + wol->wolopts |= WAKE_MAGIC; 218 + 219 + if (value & DP83867_WOL_SEC_EN) { 220 + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, 221 + DP83867_RXFSOP1); 222 + wol->sopass[0] = (sopass_val & 0xff); 223 + wol->sopass[1] = (sopass_val >> 8); 224 + 225 + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, 226 + DP83867_RXFSOP2); 227 + wol->sopass[2] = (sopass_val & 0xff); 228 + wol->sopass[3] = (sopass_val >> 8); 229 + 230 + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, 231 + DP83867_RXFSOP3); 232 + wol->sopass[4] = (sopass_val & 0xff); 233 + wol->sopass[5] = (sopass_val >> 8); 234 + 235 + wol->wolopts |= WAKE_MAGICSECURE; 236 + } 237 + 238 + if (!(value & DP83867_WOL_ENH_MAC)) 239 + wol->wolopts = 0; 148 240 } 149 241 150 242 static int dp83867_config_intr(struct phy_device *phydev) ··· 589 463 .probe = dp83867_probe, 590 464 .config_init = dp83867_config_init, 591 465 .soft_reset = dp83867_phy_reset, 466 + 467 + .get_wol = dp83867_get_wol, 468 + .set_wol = dp83867_set_wol, 592 469 593 470 /* IRQ related */ 594 471 .ack_interrupt = dp83867_ack_interrupt,