Skip to content

Commit 975ae7c

Browse files
linuswdavem330
authored andcommitted
net: phy: vitesse: Add support for VSC73xx
The VSC7385, VSC7388, VSC7395 and VSC7398 are integrated switch/router chips for 5+1 or 8-port switches/routers. When managed directly by Linux using DSA we need to do a special set-up "dance" on the PHY. Unfortunately these sequences switches the PHY to undocumented pages named 2a30 and 52b6 and does undocumented things. It is described by these opaque sequences also in the reference manual. This is a best effort to integrate it anyways. Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 1decd2e commit 975ae7c

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

drivers/net/phy/vitesse.c

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
#define PHY_ID_VSC8572 0x000704d0
7373
#define PHY_ID_VSC8574 0x000704a0
7474
#define PHY_ID_VSC8601 0x00070420
75+
#define PHY_ID_VSC7385 0x00070450
76+
#define PHY_ID_VSC7388 0x00070480
77+
#define PHY_ID_VSC7395 0x00070550
78+
#define PHY_ID_VSC7398 0x00070580
7579
#define PHY_ID_VSC8662 0x00070660
7680
#define PHY_ID_VSC8221 0x000fc550
7781
#define PHY_ID_VSC8211 0x000fc4b0
@@ -116,6 +120,137 @@ static int vsc824x_config_init(struct phy_device *phydev)
116120
return err;
117121
}
118122

123+
#define VSC73XX_EXT_PAGE_ACCESS 0x1f
124+
125+
static int vsc73xx_read_page(struct phy_device *phydev)
126+
{
127+
return __phy_read(phydev, VSC73XX_EXT_PAGE_ACCESS);
128+
}
129+
130+
static int vsc73xx_write_page(struct phy_device *phydev, int page)
131+
{
132+
return __phy_write(phydev, VSC73XX_EXT_PAGE_ACCESS, page);
133+
}
134+
135+
static void vsc73xx_config_init(struct phy_device *phydev)
136+
{
137+
/* Receiver init */
138+
phy_write(phydev, 0x1f, 0x2a30);
139+
phy_modify(phydev, 0x0c, 0x0300, 0x0200);
140+
phy_write(phydev, 0x1f, 0x0000);
141+
142+
/* Config LEDs 0x61 */
143+
phy_modify(phydev, MII_TPISTATUS, 0xff00, 0x0061);
144+
}
145+
146+
static int vsc738x_config_init(struct phy_device *phydev)
147+
{
148+
u16 rev;
149+
/* This magic sequence appear in the application note
150+
* "VSC7385/7388 PHY Configuration".
151+
*
152+
* Maybe one day we will get to know what it all means.
153+
*/
154+
phy_write(phydev, 0x1f, 0x2a30);
155+
phy_modify(phydev, 0x08, 0x0200, 0x0200);
156+
phy_write(phydev, 0x1f, 0x52b5);
157+
phy_write(phydev, 0x10, 0xb68a);
158+
phy_modify(phydev, 0x12, 0xff07, 0x0003);
159+
phy_modify(phydev, 0x11, 0x00ff, 0x00a2);
160+
phy_write(phydev, 0x10, 0x968a);
161+
phy_write(phydev, 0x1f, 0x2a30);
162+
phy_modify(phydev, 0x08, 0x0200, 0x0000);
163+
phy_write(phydev, 0x1f, 0x0000);
164+
165+
/* Read revision */
166+
rev = phy_read(phydev, MII_PHYSID2);
167+
rev &= 0x0f;
168+
169+
/* Special quirk for revision 0 */
170+
if (rev == 0) {
171+
phy_write(phydev, 0x1f, 0x2a30);
172+
phy_modify(phydev, 0x08, 0x0200, 0x0200);
173+
phy_write(phydev, 0x1f, 0x52b5);
174+
phy_write(phydev, 0x12, 0x0000);
175+
phy_write(phydev, 0x11, 0x0689);
176+
phy_write(phydev, 0x10, 0x8f92);
177+
phy_write(phydev, 0x1f, 0x52b5);
178+
phy_write(phydev, 0x12, 0x0000);
179+
phy_write(phydev, 0x11, 0x0e35);
180+
phy_write(phydev, 0x10, 0x9786);
181+
phy_write(phydev, 0x1f, 0x2a30);
182+
phy_modify(phydev, 0x08, 0x0200, 0x0000);
183+
phy_write(phydev, 0x17, 0xff80);
184+
phy_write(phydev, 0x17, 0x0000);
185+
}
186+
187+
phy_write(phydev, 0x1f, 0x0000);
188+
phy_write(phydev, 0x12, 0x0048);
189+
190+
if (rev == 0) {
191+
phy_write(phydev, 0x1f, 0x2a30);
192+
phy_write(phydev, 0x14, 0x6600);
193+
phy_write(phydev, 0x1f, 0x0000);
194+
phy_write(phydev, 0x18, 0xa24e);
195+
} else {
196+
phy_write(phydev, 0x1f, 0x2a30);
197+
phy_modify(phydev, 0x16, 0x0fc0, 0x0240);
198+
phy_modify(phydev, 0x14, 0x6000, 0x4000);
199+
/* bits 14-15 in extended register 0x14 controls DACG amplitude
200+
* 6 = -8%, 2 is hardware default
201+
*/
202+
phy_write(phydev, 0x1f, 0x0001);
203+
phy_modify(phydev, 0x14, 0xe000, 0x6000);
204+
phy_write(phydev, 0x1f, 0x0000);
205+
}
206+
207+
vsc73xx_config_init(phydev);
208+
209+
return genphy_config_init(phydev);
210+
}
211+
212+
static int vsc739x_config_init(struct phy_device *phydev)
213+
{
214+
/* This magic sequence appears in the VSC7395 SparX-G5e application
215+
* note "VSC7395/VSC7398 PHY Configuration"
216+
*
217+
* Maybe one day we will get to know what it all means.
218+
*/
219+
phy_write(phydev, 0x1f, 0x2a30);
220+
phy_modify(phydev, 0x08, 0x0200, 0x0200);
221+
phy_write(phydev, 0x1f, 0x52b5);
222+
phy_write(phydev, 0x10, 0xb68a);
223+
phy_modify(phydev, 0x12, 0xff07, 0x0003);
224+
phy_modify(phydev, 0x11, 0x00ff, 0x00a2);
225+
phy_write(phydev, 0x10, 0x968a);
226+
phy_write(phydev, 0x1f, 0x2a30);
227+
phy_modify(phydev, 0x08, 0x0200, 0x0000);
228+
phy_write(phydev, 0x1f, 0x0000);
229+
230+
phy_write(phydev, 0x1f, 0x0000);
231+
phy_write(phydev, 0x12, 0x0048);
232+
phy_write(phydev, 0x1f, 0x2a30);
233+
phy_modify(phydev, 0x16, 0x0fc0, 0x0240);
234+
phy_modify(phydev, 0x14, 0x6000, 0x4000);
235+
phy_write(phydev, 0x1f, 0x0001);
236+
phy_modify(phydev, 0x14, 0xe000, 0x6000);
237+
phy_write(phydev, 0x1f, 0x0000);
238+
239+
vsc73xx_config_init(phydev);
240+
241+
return genphy_config_init(phydev);
242+
}
243+
244+
static int vsc73xx_config_aneg(struct phy_device *phydev)
245+
{
246+
/* The VSC73xx switches does not like to be instructed to
247+
* do autonegotiation in any way, it prefers that you just go
248+
* with the power-on/reset defaults. Writing some registers will
249+
* just make autonegotiation permanently fail.
250+
*/
251+
return 0;
252+
}
253+
119254
/* This adds a skew for both TX and RX clocks, so the skew should only be
120255
* applied to "rgmii-id" interfaces. It may not work as expected
121256
* on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */
@@ -318,6 +453,42 @@ static struct phy_driver vsc82xx_driver[] = {
318453
.config_init = &vsc8601_config_init,
319454
.ack_interrupt = &vsc824x_ack_interrupt,
320455
.config_intr = &vsc82xx_config_intr,
456+
}, {
457+
.phy_id = PHY_ID_VSC7385,
458+
.name = "Vitesse VSC7385",
459+
.phy_id_mask = 0x000ffff0,
460+
.features = PHY_GBIT_FEATURES,
461+
.config_init = vsc738x_config_init,
462+
.config_aneg = vsc73xx_config_aneg,
463+
.read_page = vsc73xx_read_page,
464+
.write_page = vsc73xx_write_page,
465+
}, {
466+
.phy_id = PHY_ID_VSC7388,
467+
.name = "Vitesse VSC7388",
468+
.phy_id_mask = 0x000ffff0,
469+
.features = PHY_GBIT_FEATURES,
470+
.config_init = vsc738x_config_init,
471+
.config_aneg = vsc73xx_config_aneg,
472+
.read_page = vsc73xx_read_page,
473+
.write_page = vsc73xx_write_page,
474+
}, {
475+
.phy_id = PHY_ID_VSC7395,
476+
.name = "Vitesse VSC7395",
477+
.phy_id_mask = 0x000ffff0,
478+
.features = PHY_GBIT_FEATURES,
479+
.config_init = vsc739x_config_init,
480+
.config_aneg = vsc73xx_config_aneg,
481+
.read_page = vsc73xx_read_page,
482+
.write_page = vsc73xx_write_page,
483+
}, {
484+
.phy_id = PHY_ID_VSC7398,
485+
.name = "Vitesse VSC7398",
486+
.phy_id_mask = 0x000ffff0,
487+
.features = PHY_GBIT_FEATURES,
488+
.config_init = vsc739x_config_init,
489+
.config_aneg = vsc73xx_config_aneg,
490+
.read_page = vsc73xx_read_page,
491+
.write_page = vsc73xx_write_page,
321492
}, {
322493
.phy_id = PHY_ID_VSC8662,
323494
.name = "Vitesse VSC8662",
@@ -358,6 +529,10 @@ static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
358529
{ PHY_ID_VSC8514, 0x000ffff0 },
359530
{ PHY_ID_VSC8572, 0x000ffff0 },
360531
{ PHY_ID_VSC8574, 0x000ffff0 },
532+
{ PHY_ID_VSC7385, 0x000ffff0 },
533+
{ PHY_ID_VSC7388, 0x000ffff0 },
534+
{ PHY_ID_VSC7395, 0x000ffff0 },
535+
{ PHY_ID_VSC7398, 0x000ffff0 },
361536
{ PHY_ID_VSC8662, 0x000ffff0 },
362537
{ PHY_ID_VSC8221, 0x000ffff0 },
363538
{ PHY_ID_VSC8211, 0x000ffff0 },

0 commit comments

Comments
 (0)