Skip to content

Commit ac4c593

Browse files
CHKDSK88davem330
authored andcommitted
net: phy: vitesse: implement downshift in vsc73xx phys
This commit implements downshift feature in vsc73xx family phys. By default downshift was enabled with maximum tries. Reviewed-by: Russell King (Oracle) <[email protected]> Signed-off-by: Pawel Dembicki <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c89cca3 commit ac4c593

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

drivers/net/phy/vitesse.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
#include <linux/mii.h>
1111
#include <linux/ethtool.h>
1212
#include <linux/phy.h>
13+
#include <linux/bitfield.h>
1314

1415
/* Vitesse Extended Page Magic Register(s) */
16+
#define MII_VSC73XX_EXT_PAGE_1E 0x01
1517
#define MII_VSC82X4_EXT_PAGE_16E 0x10
1618
#define MII_VSC82X4_EXT_PAGE_17E 0x11
1719
#define MII_VSC82X4_EXT_PAGE_18E 0x12
@@ -60,6 +62,15 @@
6062
/* Vitesse Extended Page Access Register */
6163
#define MII_VSC82X4_EXT_PAGE_ACCESS 0x1f
6264

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+
6374
/* Vitesse VSC8601 Extended PHY Control Register 1 */
6475
#define MII_VSC8601_EPHY_CTL 0x17
6576
#define MII_VSC8601_EPHY_CTL_RGMII_SKEW (1 << 8)
@@ -128,6 +139,74 @@ static int vsc73xx_write_page(struct phy_device *phydev, int page)
128139
return __phy_write(phydev, VSC73XX_EXT_PAGE_ACCESS, page);
129140
}
130141

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+
131210
static void vsc73xx_config_init(struct phy_device *phydev)
132211
{
133212
/* Receiver init */
@@ -137,6 +216,9 @@ static void vsc73xx_config_init(struct phy_device *phydev)
137216

138217
/* Config LEDs 0x61 */
139218
phy_modify(phydev, MII_TPISTATUS, 0xff00, 0x0061);
219+
220+
/* Enable downshift by default */
221+
vsc73xx_set_downshift(phydev, MII_VSC73XX_DOWNSHIFT_MAX);
140222
}
141223

142224
static int vsc738x_config_init(struct phy_device *phydev)
@@ -447,6 +529,8 @@ static struct phy_driver vsc82xx_driver[] = {
447529
.config_aneg = vsc73xx_config_aneg,
448530
.read_page = vsc73xx_read_page,
449531
.write_page = vsc73xx_write_page,
532+
.get_tunable = vsc73xx_get_tunable,
533+
.set_tunable = vsc73xx_set_tunable,
450534
}, {
451535
.phy_id = PHY_ID_VSC7388,
452536
.name = "Vitesse VSC7388",
@@ -456,6 +540,8 @@ static struct phy_driver vsc82xx_driver[] = {
456540
.config_aneg = vsc73xx_config_aneg,
457541
.read_page = vsc73xx_read_page,
458542
.write_page = vsc73xx_write_page,
543+
.get_tunable = vsc73xx_get_tunable,
544+
.set_tunable = vsc73xx_set_tunable,
459545
}, {
460546
.phy_id = PHY_ID_VSC7395,
461547
.name = "Vitesse VSC7395",
@@ -465,6 +551,8 @@ static struct phy_driver vsc82xx_driver[] = {
465551
.config_aneg = vsc73xx_config_aneg,
466552
.read_page = vsc73xx_read_page,
467553
.write_page = vsc73xx_write_page,
554+
.get_tunable = vsc73xx_get_tunable,
555+
.set_tunable = vsc73xx_set_tunable,
468556
}, {
469557
.phy_id = PHY_ID_VSC7398,
470558
.name = "Vitesse VSC7398",
@@ -474,6 +562,8 @@ static struct phy_driver vsc82xx_driver[] = {
474562
.config_aneg = vsc73xx_config_aneg,
475563
.read_page = vsc73xx_read_page,
476564
.write_page = vsc73xx_write_page,
565+
.get_tunable = vsc73xx_get_tunable,
566+
.set_tunable = vsc73xx_set_tunable,
477567
}, {
478568
.phy_id = PHY_ID_VSC8662,
479569
.name = "Vitesse VSC8662",

0 commit comments

Comments
 (0)