Skip to content

Commit caabee5

Browse files
Thomas Haemmerledavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 76d7774 commit caabee5

File tree

1 file changed

+130
-1
lines changed

1 file changed

+130
-1
lines changed

drivers/net/phy/dp83867.c

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <linux/of.h>
1313
#include <linux/phy.h>
1414
#include <linux/delay.h>
15+
#include <linux/netdevice.h>
16+
#include <linux/etherdevice.h>
1517

1618
#include <dt-bindings/net/ti-dp83867.h>
1719

@@ -21,8 +23,9 @@
2123
#define MII_DP83867_PHYCTRL 0x10
2224
#define MII_DP83867_MICR 0x12
2325
#define MII_DP83867_ISR 0x13
24-
#define DP83867_CTRL 0x1f
26+
#define DP83867_CFG2 0x14
2527
#define DP83867_CFG3 0x1e
28+
#define DP83867_CTRL 0x1f
2629

2730
/* Extended Registers */
2831
#define DP83867_CFG4 0x0031
@@ -36,6 +39,13 @@
3639
#define DP83867_STRAP_STS1 0x006E
3740
#define DP83867_STRAP_STS2 0x006f
3841
#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
3949
#define DP83867_IO_MUX_CFG 0x0170
4050
#define DP83867_SGMIICTL 0x00D3
4151
#define DP83867_10M_SGMII_CFG 0x016F
@@ -65,6 +75,13 @@
6575
/* SGMIICTL bits */
6676
#define DP83867_SGMII_TYPE BIT(14)
6777

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+
6885
/* STRAP_STS1 bits */
6986
#define DP83867_STRAP_STS1_RESERVED BIT(11)
7087

@@ -130,6 +147,115 @@ static int dp83867_ack_interrupt(struct phy_device *phydev)
130147
return 0;
131148
}
132149

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+
133259
static int dp83867_config_intr(struct phy_device *phydev)
134260
{
135261
int micr_status;
@@ -464,6 +590,9 @@ static struct phy_driver dp83867_driver[] = {
464590
.config_init = dp83867_config_init,
465591
.soft_reset = dp83867_phy_reset,
466592

593+
.get_wol = dp83867_get_wol,
594+
.set_wol = dp83867_set_wol,
595+
467596
/* IRQ related */
468597
.ack_interrupt = dp83867_ack_interrupt,
469598
.config_intr = dp83867_config_intr,

0 commit comments

Comments
 (0)