|
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 |
|
|
21 | 23 | #define MII_DP83867_PHYCTRL 0x10 |
22 | 24 | #define MII_DP83867_MICR 0x12 |
23 | 25 | #define MII_DP83867_ISR 0x13 |
24 | | -#define DP83867_CTRL 0x1f |
| 26 | +#define DP83867_CFG2 0x14 |
25 | 27 | #define DP83867_CFG3 0x1e |
| 28 | +#define DP83867_CTRL 0x1f |
26 | 29 |
|
27 | 30 | /* Extended Registers */ |
28 | 31 | #define DP83867_CFG4 0x0031 |
|
36 | 39 | #define DP83867_STRAP_STS1 0x006E |
37 | 40 | #define DP83867_STRAP_STS2 0x006f |
38 | 41 | #define DP83867_RGMIIDCTL 0x0086 |
| 42 | +#define DP83867_RXFCFG 0x0134 |
| 43 | +#define DP83867_RXFPMD1 0x0136 |
| 44 | +#define DP83867_RXFPMD2 0x0137 |
| 45 | +#define DP83867_RXFPMD3 0x0138 |
| 46 | +#define DP83867_RXFSOP1 0x0139 |
| 47 | +#define DP83867_RXFSOP2 0x013A |
| 48 | +#define DP83867_RXFSOP3 0x013B |
39 | 49 | #define DP83867_IO_MUX_CFG 0x0170 |
40 | 50 | #define DP83867_SGMIICTL 0x00D3 |
41 | 51 | #define DP83867_10M_SGMII_CFG 0x016F |
|
65 | 75 | /* SGMIICTL bits */ |
66 | 76 | #define DP83867_SGMII_TYPE BIT(14) |
67 | 77 |
|
| 78 | +/* RXFCFG bits*/ |
| 79 | +#define DP83867_WOL_MAGIC_EN BIT(0) |
| 80 | +#define DP83867_WOL_BCAST_EN BIT(2) |
| 81 | +#define DP83867_WOL_UCAST_EN BIT(4) |
| 82 | +#define DP83867_WOL_SEC_EN BIT(5) |
| 83 | +#define DP83867_WOL_ENH_MAC BIT(7) |
| 84 | + |
68 | 85 | /* STRAP_STS1 bits */ |
69 | 86 | #define DP83867_STRAP_STS1_RESERVED BIT(11) |
70 | 87 |
|
@@ -130,6 +147,115 @@ static int dp83867_ack_interrupt(struct phy_device *phydev) |
130 | 147 | return 0; |
131 | 148 | } |
132 | 149 |
|
| 150 | +static int dp83867_set_wol(struct phy_device *phydev, |
| 151 | + struct ethtool_wolinfo *wol) |
| 152 | +{ |
| 153 | + struct net_device *ndev = phydev->attached_dev; |
| 154 | + u16 val_rxcfg, val_micr; |
| 155 | + u8 *mac; |
| 156 | + |
| 157 | + val_rxcfg = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG); |
| 158 | + val_micr = phy_read(phydev, MII_DP83867_MICR); |
| 159 | + |
| 160 | + if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_UCAST | |
| 161 | + WAKE_BCAST)) { |
| 162 | + val_rxcfg |= DP83867_WOL_ENH_MAC; |
| 163 | + val_micr |= MII_DP83867_MICR_WOL_INT_EN; |
| 164 | + |
| 165 | + if (wol->wolopts & WAKE_MAGIC) { |
| 166 | + mac = (u8 *)ndev->dev_addr; |
| 167 | + |
| 168 | + if (!is_valid_ether_addr(mac)) |
| 169 | + return -EINVAL; |
| 170 | + |
| 171 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD1, |
| 172 | + (mac[1] << 8 | mac[0])); |
| 173 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD2, |
| 174 | + (mac[3] << 8 | mac[2])); |
| 175 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD3, |
| 176 | + (mac[5] << 8 | mac[4])); |
| 177 | + |
| 178 | + val_rxcfg |= DP83867_WOL_MAGIC_EN; |
| 179 | + } else { |
| 180 | + val_rxcfg &= ~DP83867_WOL_MAGIC_EN; |
| 181 | + } |
| 182 | + |
| 183 | + if (wol->wolopts & WAKE_MAGICSECURE) { |
| 184 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, |
| 185 | + (wol->sopass[1] << 8) | wol->sopass[0]); |
| 186 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, |
| 187 | + (wol->sopass[3] << 8) | wol->sopass[2]); |
| 188 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, |
| 189 | + (wol->sopass[5] << 8) | wol->sopass[4]); |
| 190 | + |
| 191 | + val_rxcfg |= DP83867_WOL_SEC_EN; |
| 192 | + } else { |
| 193 | + val_rxcfg &= ~DP83867_WOL_SEC_EN; |
| 194 | + } |
| 195 | + |
| 196 | + if (wol->wolopts & WAKE_UCAST) |
| 197 | + val_rxcfg |= DP83867_WOL_UCAST_EN; |
| 198 | + else |
| 199 | + val_rxcfg &= ~DP83867_WOL_UCAST_EN; |
| 200 | + |
| 201 | + if (wol->wolopts & WAKE_BCAST) |
| 202 | + val_rxcfg |= DP83867_WOL_BCAST_EN; |
| 203 | + else |
| 204 | + val_rxcfg &= ~DP83867_WOL_BCAST_EN; |
| 205 | + } else { |
| 206 | + val_rxcfg &= ~DP83867_WOL_ENH_MAC; |
| 207 | + val_micr &= ~MII_DP83867_MICR_WOL_INT_EN; |
| 208 | + } |
| 209 | + |
| 210 | + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG, val_rxcfg); |
| 211 | + phy_write(phydev, MII_DP83867_MICR, val_micr); |
| 212 | + |
| 213 | + return 0; |
| 214 | +} |
| 215 | + |
| 216 | +static void dp83867_get_wol(struct phy_device *phydev, |
| 217 | + struct ethtool_wolinfo *wol) |
| 218 | +{ |
| 219 | + u16 value, sopass_val; |
| 220 | + |
| 221 | + wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC | |
| 222 | + WAKE_MAGICSECURE); |
| 223 | + wol->wolopts = 0; |
| 224 | + |
| 225 | + value = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG); |
| 226 | + |
| 227 | + if (value & DP83867_WOL_UCAST_EN) |
| 228 | + wol->wolopts |= WAKE_UCAST; |
| 229 | + |
| 230 | + if (value & DP83867_WOL_BCAST_EN) |
| 231 | + wol->wolopts |= WAKE_BCAST; |
| 232 | + |
| 233 | + if (value & DP83867_WOL_MAGIC_EN) |
| 234 | + wol->wolopts |= WAKE_MAGIC; |
| 235 | + |
| 236 | + if (value & DP83867_WOL_SEC_EN) { |
| 237 | + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, |
| 238 | + DP83867_RXFSOP1); |
| 239 | + wol->sopass[0] = (sopass_val & 0xff); |
| 240 | + wol->sopass[1] = (sopass_val >> 8); |
| 241 | + |
| 242 | + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, |
| 243 | + DP83867_RXFSOP2); |
| 244 | + wol->sopass[2] = (sopass_val & 0xff); |
| 245 | + wol->sopass[3] = (sopass_val >> 8); |
| 246 | + |
| 247 | + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, |
| 248 | + DP83867_RXFSOP3); |
| 249 | + wol->sopass[4] = (sopass_val & 0xff); |
| 250 | + wol->sopass[5] = (sopass_val >> 8); |
| 251 | + |
| 252 | + wol->wolopts |= WAKE_MAGICSECURE; |
| 253 | + } |
| 254 | + |
| 255 | + if (!(value & DP83867_WOL_ENH_MAC)) |
| 256 | + wol->wolopts = 0; |
| 257 | +} |
| 258 | + |
133 | 259 | static int dp83867_config_intr(struct phy_device *phydev) |
134 | 260 | { |
135 | 261 | int micr_status; |
@@ -464,6 +590,9 @@ static struct phy_driver dp83867_driver[] = { |
464 | 590 | .config_init = dp83867_config_init, |
465 | 591 | .soft_reset = dp83867_phy_reset, |
466 | 592 |
|
| 593 | + .get_wol = dp83867_get_wol, |
| 594 | + .set_wol = dp83867_set_wol, |
| 595 | + |
467 | 596 | /* IRQ related */ |
468 | 597 | .ack_interrupt = dp83867_ack_interrupt, |
469 | 598 | .config_intr = dp83867_config_intr, |
|
0 commit comments