13
13
#include <linux/phy.h>
14
14
#include <linux/of.h>
15
15
#include <dt-bindings/net/mscc-phy-vsc8531.h>
16
+ #include <linux/netdevice.h>
16
17
17
18
enum rgmii_rx_clock_delay {
18
19
RGMII_RX_CLK_DELAY_0_2_NS = 0 ,
@@ -37,6 +38,7 @@ enum rgmii_rx_clock_delay {
37
38
38
39
#define MII_VSC85XX_INT_MASK 25
39
40
#define MII_VSC85XX_INT_MASK_MASK 0xa000
41
+ #define MII_VSC85XX_INT_MASK_WOL 0x0040
40
42
#define MII_VSC85XX_INT_STATUS 26
41
43
42
44
#define MSCC_PHY_WOL_MAC_CONTROL 27
@@ -52,6 +54,17 @@ enum rgmii_rx_clock_delay {
52
54
#define RGMII_RX_CLK_DELAY_MASK 0x0070
53
55
#define RGMII_RX_CLK_DELAY_POS 4
54
56
57
+ #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
58
+ #define MSCC_PHY_WOL_MID_MAC_ADDR 22
59
+ #define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
60
+ #define MSCC_PHY_WOL_LOWER_PASSWD 24
61
+ #define MSCC_PHY_WOL_MID_PASSWD 25
62
+ #define MSCC_PHY_WOL_UPPER_PASSWD 26
63
+
64
+ #define MSCC_PHY_WOL_MAC_CONTROL 27
65
+ #define SECURE_ON_ENABLE 0x8000
66
+ #define SECURE_ON_PASSWD_LEN_4 0x4000
67
+
55
68
/* Microsemi PHY ID's */
56
69
#define PHY_ID_VSC8531 0x00070570
57
70
#define PHY_ID_VSC8541 0x00070770
@@ -81,6 +94,117 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
81
94
return rc ;
82
95
}
83
96
97
+ static int vsc85xx_wol_set (struct phy_device * phydev ,
98
+ struct ethtool_wolinfo * wol )
99
+ {
100
+ int rc ;
101
+ u16 reg_val ;
102
+ u8 i ;
103
+ u16 pwd [3 ] = {0 , 0 , 0 };
104
+ struct ethtool_wolinfo * wol_conf = wol ;
105
+ u8 * mac_addr = phydev -> attached_dev -> dev_addr ;
106
+
107
+ mutex_lock (& phydev -> lock );
108
+ rc = vsc85xx_phy_page_set (phydev , MSCC_PHY_PAGE_EXTENDED_2 );
109
+ if (rc != 0 )
110
+ goto out_unlock ;
111
+
112
+ if (wol -> wolopts & WAKE_MAGIC ) {
113
+ /* Store the device address for the magic packet */
114
+ for (i = 0 ; i < ARRAY_SIZE (pwd ); i ++ )
115
+ pwd [i ] = mac_addr [5 - (i * 2 + 1 )] << 8 |
116
+ mac_addr [5 - i * 2 ];
117
+ phy_write (phydev , MSCC_PHY_WOL_LOWER_MAC_ADDR , pwd [0 ]);
118
+ phy_write (phydev , MSCC_PHY_WOL_MID_MAC_ADDR , pwd [1 ]);
119
+ phy_write (phydev , MSCC_PHY_WOL_UPPER_MAC_ADDR , pwd [2 ]);
120
+ } else {
121
+ phy_write (phydev , MSCC_PHY_WOL_LOWER_MAC_ADDR , 0 );
122
+ phy_write (phydev , MSCC_PHY_WOL_MID_MAC_ADDR , 0 );
123
+ phy_write (phydev , MSCC_PHY_WOL_UPPER_MAC_ADDR , 0 );
124
+ }
125
+
126
+ if (wol_conf -> wolopts & WAKE_MAGICSECURE ) {
127
+ for (i = 0 ; i < ARRAY_SIZE (pwd ); i ++ )
128
+ pwd [i ] = wol_conf -> sopass [5 - (i * 2 + 1 )] << 8 |
129
+ wol_conf -> sopass [5 - i * 2 ];
130
+ phy_write (phydev , MSCC_PHY_WOL_LOWER_PASSWD , pwd [0 ]);
131
+ phy_write (phydev , MSCC_PHY_WOL_MID_PASSWD , pwd [1 ]);
132
+ phy_write (phydev , MSCC_PHY_WOL_UPPER_PASSWD , pwd [2 ]);
133
+ } else {
134
+ phy_write (phydev , MSCC_PHY_WOL_LOWER_PASSWD , 0 );
135
+ phy_write (phydev , MSCC_PHY_WOL_MID_PASSWD , 0 );
136
+ phy_write (phydev , MSCC_PHY_WOL_UPPER_PASSWD , 0 );
137
+ }
138
+
139
+ reg_val = phy_read (phydev , MSCC_PHY_WOL_MAC_CONTROL );
140
+ if (wol_conf -> wolopts & WAKE_MAGICSECURE )
141
+ reg_val |= SECURE_ON_ENABLE ;
142
+ else
143
+ reg_val &= ~SECURE_ON_ENABLE ;
144
+ phy_write (phydev , MSCC_PHY_WOL_MAC_CONTROL , reg_val );
145
+
146
+ rc = vsc85xx_phy_page_set (phydev , MSCC_PHY_PAGE_STANDARD );
147
+ if (rc != 0 )
148
+ goto out_unlock ;
149
+
150
+ if (wol -> wolopts & WAKE_MAGIC ) {
151
+ /* Enable the WOL interrupt */
152
+ reg_val = phy_read (phydev , MII_VSC85XX_INT_MASK );
153
+ reg_val |= MII_VSC85XX_INT_MASK_WOL ;
154
+ rc = phy_write (phydev , MII_VSC85XX_INT_MASK , reg_val );
155
+ if (rc != 0 )
156
+ goto out_unlock ;
157
+ } else {
158
+ /* Disable the WOL interrupt */
159
+ reg_val = phy_read (phydev , MII_VSC85XX_INT_MASK );
160
+ reg_val &= (~MII_VSC85XX_INT_MASK_WOL );
161
+ rc = phy_write (phydev , MII_VSC85XX_INT_MASK , reg_val );
162
+ if (rc != 0 )
163
+ goto out_unlock ;
164
+ }
165
+ /* Clear WOL iterrupt status */
166
+ reg_val = phy_read (phydev , MII_VSC85XX_INT_STATUS );
167
+
168
+ out_unlock :
169
+ mutex_unlock (& phydev -> lock );
170
+
171
+ return rc ;
172
+ }
173
+
174
+ static void vsc85xx_wol_get (struct phy_device * phydev ,
175
+ struct ethtool_wolinfo * wol )
176
+ {
177
+ int rc ;
178
+ u16 reg_val ;
179
+ u8 i ;
180
+ u16 pwd [3 ] = {0 , 0 , 0 };
181
+ struct ethtool_wolinfo * wol_conf = wol ;
182
+
183
+ mutex_lock (& phydev -> lock );
184
+ rc = vsc85xx_phy_page_set (phydev , MSCC_PHY_PAGE_EXTENDED_2 );
185
+ if (rc != 0 )
186
+ goto out_unlock ;
187
+
188
+ reg_val = phy_read (phydev , MSCC_PHY_WOL_MAC_CONTROL );
189
+ if (reg_val & SECURE_ON_ENABLE )
190
+ wol_conf -> wolopts |= WAKE_MAGICSECURE ;
191
+ if (wol_conf -> wolopts & WAKE_MAGICSECURE ) {
192
+ pwd [0 ] = phy_read (phydev , MSCC_PHY_WOL_LOWER_PASSWD );
193
+ pwd [1 ] = phy_read (phydev , MSCC_PHY_WOL_MID_PASSWD );
194
+ pwd [2 ] = phy_read (phydev , MSCC_PHY_WOL_UPPER_PASSWD );
195
+ for (i = 0 ; i < ARRAY_SIZE (pwd ); i ++ ) {
196
+ wol_conf -> sopass [5 - i * 2 ] = pwd [i ] & 0x00ff ;
197
+ wol_conf -> sopass [5 - (i * 2 + 1 )] = (pwd [i ] & 0xff00 )
198
+ >> 8 ;
199
+ }
200
+ }
201
+
202
+ rc = vsc85xx_phy_page_set (phydev , MSCC_PHY_PAGE_STANDARD );
203
+
204
+ out_unlock :
205
+ mutex_unlock (& phydev -> lock );
206
+ }
207
+
84
208
static u8 edge_rate_magic_get (u16 vddmac ,
85
209
int slowdown )
86
210
{
@@ -301,6 +425,8 @@ static struct phy_driver vsc85xx_driver[] = {
301
425
.suspend = & genphy_suspend ,
302
426
.resume = & genphy_resume ,
303
427
.probe = & vsc85xx_probe ,
428
+ .set_wol = & vsc85xx_wol_set ,
429
+ .get_wol = & vsc85xx_wol_get ,
304
430
},
305
431
{
306
432
.phy_id = PHY_ID_VSC8541 ,
@@ -318,6 +444,8 @@ static struct phy_driver vsc85xx_driver[] = {
318
444
.suspend = & genphy_suspend ,
319
445
.resume = & genphy_resume ,
320
446
.probe = & vsc85xx_probe ,
447
+ .set_wol = & vsc85xx_wol_set ,
448
+ .get_wol = & vsc85xx_wol_get ,
321
449
}
322
450
323
451
};
0 commit comments