10
10
#include <linux/mii.h>
11
11
#include <linux/ethtool.h>
12
12
#include <linux/phy.h>
13
+ #include <linux/bitfield.h>
13
14
14
15
/* Vitesse Extended Page Magic Register(s) */
16
+ #define MII_VSC73XX_EXT_PAGE_1E 0x01
15
17
#define MII_VSC82X4_EXT_PAGE_16E 0x10
16
18
#define MII_VSC82X4_EXT_PAGE_17E 0x11
17
19
#define MII_VSC82X4_EXT_PAGE_18E 0x12
60
62
/* Vitesse Extended Page Access Register */
61
63
#define MII_VSC82X4_EXT_PAGE_ACCESS 0x1f
62
64
65
+ /* Vitesse VSC73XX Extended Control Register */
66
+ #define MII_VSC73XX_PHY_CTRL_EXT3 0x14
67
+
68
+ #define MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_EN BIT(4)
69
+ #define MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_CNT GENMASK(3, 2)
70
+ #define MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_STA BIT(1)
71
+ #define MII_VSC73XX_DOWNSHIFT_MAX 5
72
+ #define MII_VSC73XX_DOWNSHIFT_INVAL 1
73
+
63
74
/* Vitesse VSC8601 Extended PHY Control Register 1 */
64
75
#define MII_VSC8601_EPHY_CTL 0x17
65
76
#define MII_VSC8601_EPHY_CTL_RGMII_SKEW (1 << 8)
@@ -128,6 +139,74 @@ static int vsc73xx_write_page(struct phy_device *phydev, int page)
128
139
return __phy_write (phydev , VSC73XX_EXT_PAGE_ACCESS , page );
129
140
}
130
141
142
+ static int vsc73xx_get_downshift (struct phy_device * phydev , u8 * data )
143
+ {
144
+ int val , enable , cnt ;
145
+
146
+ val = phy_read_paged (phydev , MII_VSC73XX_EXT_PAGE_1E ,
147
+ MII_VSC73XX_PHY_CTRL_EXT3 );
148
+ if (val < 0 )
149
+ return val ;
150
+
151
+ enable = FIELD_GET (MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_EN , val );
152
+ cnt = FIELD_GET (MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_CNT , val ) + 2 ;
153
+
154
+ * data = enable ? cnt : DOWNSHIFT_DEV_DISABLE ;
155
+
156
+ return 0 ;
157
+ }
158
+
159
+ static int vsc73xx_set_downshift (struct phy_device * phydev , u8 cnt )
160
+ {
161
+ u16 mask , val ;
162
+ int ret ;
163
+
164
+ if (cnt > MII_VSC73XX_DOWNSHIFT_MAX )
165
+ return - E2BIG ;
166
+ else if (cnt == MII_VSC73XX_DOWNSHIFT_INVAL )
167
+ return - EINVAL ;
168
+
169
+ mask = MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_EN ;
170
+
171
+ if (!cnt ) {
172
+ val = 0 ;
173
+ } else {
174
+ mask |= MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_CNT ;
175
+ val = MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_EN |
176
+ FIELD_PREP (MII_VSC73XX_PHY_CTRL_EXT3_DOWNSHIFT_CNT ,
177
+ cnt - 2 );
178
+ }
179
+
180
+ ret = phy_modify_paged (phydev , MII_VSC73XX_EXT_PAGE_1E ,
181
+ MII_VSC73XX_PHY_CTRL_EXT3 , mask , val );
182
+ if (ret < 0 )
183
+ return ret ;
184
+
185
+ return genphy_soft_reset (phydev );
186
+ }
187
+
188
+ static int vsc73xx_get_tunable (struct phy_device * phydev ,
189
+ struct ethtool_tunable * tuna , void * data )
190
+ {
191
+ switch (tuna -> id ) {
192
+ case ETHTOOL_PHY_DOWNSHIFT :
193
+ return vsc73xx_get_downshift (phydev , data );
194
+ default :
195
+ return - EOPNOTSUPP ;
196
+ }
197
+ }
198
+
199
+ static int vsc73xx_set_tunable (struct phy_device * phydev ,
200
+ struct ethtool_tunable * tuna , const void * data )
201
+ {
202
+ switch (tuna -> id ) {
203
+ case ETHTOOL_PHY_DOWNSHIFT :
204
+ return vsc73xx_set_downshift (phydev , * (const u8 * )data );
205
+ default :
206
+ return - EOPNOTSUPP ;
207
+ }
208
+ }
209
+
131
210
static void vsc73xx_config_init (struct phy_device * phydev )
132
211
{
133
212
/* Receiver init */
@@ -137,6 +216,9 @@ static void vsc73xx_config_init(struct phy_device *phydev)
137
216
138
217
/* Config LEDs 0x61 */
139
218
phy_modify (phydev , MII_TPISTATUS , 0xff00 , 0x0061 );
219
+
220
+ /* Enable downshift by default */
221
+ vsc73xx_set_downshift (phydev , MII_VSC73XX_DOWNSHIFT_MAX );
140
222
}
141
223
142
224
static int vsc738x_config_init (struct phy_device * phydev )
@@ -447,6 +529,8 @@ static struct phy_driver vsc82xx_driver[] = {
447
529
.config_aneg = vsc73xx_config_aneg ,
448
530
.read_page = vsc73xx_read_page ,
449
531
.write_page = vsc73xx_write_page ,
532
+ .get_tunable = vsc73xx_get_tunable ,
533
+ .set_tunable = vsc73xx_set_tunable ,
450
534
}, {
451
535
.phy_id = PHY_ID_VSC7388 ,
452
536
.name = "Vitesse VSC7388" ,
@@ -456,6 +540,8 @@ static struct phy_driver vsc82xx_driver[] = {
456
540
.config_aneg = vsc73xx_config_aneg ,
457
541
.read_page = vsc73xx_read_page ,
458
542
.write_page = vsc73xx_write_page ,
543
+ .get_tunable = vsc73xx_get_tunable ,
544
+ .set_tunable = vsc73xx_set_tunable ,
459
545
}, {
460
546
.phy_id = PHY_ID_VSC7395 ,
461
547
.name = "Vitesse VSC7395" ,
@@ -465,6 +551,8 @@ static struct phy_driver vsc82xx_driver[] = {
465
551
.config_aneg = vsc73xx_config_aneg ,
466
552
.read_page = vsc73xx_read_page ,
467
553
.write_page = vsc73xx_write_page ,
554
+ .get_tunable = vsc73xx_get_tunable ,
555
+ .set_tunable = vsc73xx_set_tunable ,
468
556
}, {
469
557
.phy_id = PHY_ID_VSC7398 ,
470
558
.name = "Vitesse VSC7398" ,
@@ -474,6 +562,8 @@ static struct phy_driver vsc82xx_driver[] = {
474
562
.config_aneg = vsc73xx_config_aneg ,
475
563
.read_page = vsc73xx_read_page ,
476
564
.write_page = vsc73xx_write_page ,
565
+ .get_tunable = vsc73xx_get_tunable ,
566
+ .set_tunable = vsc73xx_set_tunable ,
477
567
}, {
478
568
.phy_id = PHY_ID_VSC8662 ,
479
569
.name = "Vitesse VSC8662" ,
0 commit comments