1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Vitesse PHY drivers
4  *
5  * Copyright 2010-2014 Freescale Semiconductor, Inc.
6  * Original Author: Andy Fleming
7  * Add vsc8662 phy support - Priyanka Jain
8  */
9 #include <common.h>
10 #include <miiphy.h>
11 
12 /* Cicada Auxiliary Control/Status Register */
13 #define MIIM_CIS82xx_AUX_CONSTAT	0x1c
14 #define MIIM_CIS82xx_AUXCONSTAT_INIT	0x0004
15 #define MIIM_CIS82xx_AUXCONSTAT_DUPLEX	0x0020
16 #define MIIM_CIS82xx_AUXCONSTAT_SPEED	0x0018
17 #define MIIM_CIS82xx_AUXCONSTAT_GBIT	0x0010
18 #define MIIM_CIS82xx_AUXCONSTAT_100	0x0008
19 
20 /* Cicada Extended Control Register 1 */
21 #define MIIM_CIS82xx_EXT_CON1		0x17
22 #define MIIM_CIS8201_EXTCON1_INIT	0x0000
23 
24 /* Cicada 8204 Extended PHY Control Register 1 */
25 #define MIIM_CIS8204_EPHY_CON		0x17
26 #define MIIM_CIS8204_EPHYCON_INIT	0x0006
27 #define MIIM_CIS8204_EPHYCON_RGMII	0x1100
28 
29 /* Cicada 8204 Serial LED Control Register */
30 #define MIIM_CIS8204_SLED_CON		0x1b
31 #define MIIM_CIS8204_SLEDCON_INIT	0x1115
32 
33 /* Vitesse VSC8601 Extended PHY Control Register 1 */
34 #define MII_VSC8601_EPHY_CTL		0x17
35 #define MII_VSC8601_EPHY_CTL_RGMII_SKEW	(1 << 8)
36 
37 #define PHY_EXT_PAGE_ACCESS    0x1f
38 #define PHY_EXT_PAGE_ACCESS_GENERAL	0x10
39 #define PHY_EXT_PAGE_ACCESS_EXTENDED3	0x3
40 
41 /* Vitesse VSC8574 control register */
42 #define MIIM_VSC8574_MAC_SERDES_CON	0x10
43 #define MIIM_VSC8574_MAC_SERDES_ANEG	0x80
44 #define MIIM_VSC8574_GENERAL18		0x12
45 #define MIIM_VSC8574_GENERAL19		0x13
46 
47 /* Vitesse VSC8574 gerenal purpose register 18 */
48 #define MIIM_VSC8574_18G_SGMII		0x80f0
49 #define MIIM_VSC8574_18G_QSGMII		0x80e0
50 #define MIIM_VSC8574_18G_CMDSTAT	0x8000
51 
52 /* Vitesse VSC8514 control register */
53 #define MIIM_VSC8514_MAC_SERDES_CON     0x10
54 #define MIIM_VSC8514_GENERAL18		0x12
55 #define MIIM_VSC8514_GENERAL19		0x13
56 #define MIIM_VSC8514_GENERAL23		0x17
57 
58 /* Vitesse VSC8514 gerenal purpose register 18 */
59 #define MIIM_VSC8514_18G_QSGMII		0x80e0
60 #define MIIM_VSC8514_18G_CMDSTAT	0x8000
61 
62 /* Vitesse VSC8664 Control/Status Register */
63 #define MIIM_VSC8664_SERDES_AND_SIGDET	0x13
64 #define MIIM_VSC8664_ADDITIONAL_DEV	0x16
65 #define MIIM_VSC8664_EPHY_CON		0x17
66 #define MIIM_VSC8664_LED_CON		0x1E
67 
68 #define PHY_EXT_PAGE_ACCESS_EXTENDED	0x0001
69 
70 /* CIS8201 */
vitesse_config(struct phy_device * phydev)71 static int vitesse_config(struct phy_device *phydev)
72 {
73 	/* Override PHY config settings */
74 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
75 			MIIM_CIS82xx_AUXCONSTAT_INIT);
76 	/* Set up the interface mode */
77 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1,
78 			MIIM_CIS8201_EXTCON1_INIT);
79 
80 	genphy_config_aneg(phydev);
81 
82 	return 0;
83 }
84 
vitesse_parse_status(struct phy_device * phydev)85 static int vitesse_parse_status(struct phy_device *phydev)
86 {
87 	int speed;
88 	int mii_reg;
89 
90 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT);
91 
92 	if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX)
93 		phydev->duplex = DUPLEX_FULL;
94 	else
95 		phydev->duplex = DUPLEX_HALF;
96 
97 	speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED;
98 	switch (speed) {
99 	case MIIM_CIS82xx_AUXCONSTAT_GBIT:
100 		phydev->speed = SPEED_1000;
101 		break;
102 	case MIIM_CIS82xx_AUXCONSTAT_100:
103 		phydev->speed = SPEED_100;
104 		break;
105 	default:
106 		phydev->speed = SPEED_10;
107 		break;
108 	}
109 
110 	return 0;
111 }
112 
vitesse_startup(struct phy_device * phydev)113 static int vitesse_startup(struct phy_device *phydev)
114 {
115 	int ret;
116 
117 	ret = genphy_update_link(phydev);
118 	if (ret)
119 		return ret;
120 	return vitesse_parse_status(phydev);
121 }
122 
cis8204_config(struct phy_device * phydev)123 static int cis8204_config(struct phy_device *phydev)
124 {
125 	/* Override PHY config settings */
126 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
127 			MIIM_CIS82xx_AUXCONSTAT_INIT);
128 
129 	genphy_config_aneg(phydev);
130 
131 	if (phy_interface_is_rgmii(phydev))
132 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
133 				MIIM_CIS8204_EPHYCON_INIT |
134 				MIIM_CIS8204_EPHYCON_RGMII);
135 	else
136 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
137 				MIIM_CIS8204_EPHYCON_INIT);
138 
139 	return 0;
140 }
141 
142 /* Vitesse VSC8601 */
143 /* This adds a skew for both TX and RX clocks, so the skew should only be
144  * applied to "rgmii-id" interfaces. It may not work as expected
145  * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */
vsc8601_add_skew(struct phy_device * phydev)146 static int vsc8601_add_skew(struct phy_device *phydev)
147 {
148 	int ret;
149 
150 	ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL);
151 	if (ret < 0)
152 		return ret;
153 
154 	ret |= MII_VSC8601_EPHY_CTL_RGMII_SKEW;
155 	return phy_write(phydev, MDIO_DEVAD_NONE, MII_VSC8601_EPHY_CTL, ret);
156 }
157 
vsc8601_config(struct phy_device * phydev)158 static int vsc8601_config(struct phy_device *phydev)
159 {
160 	int ret = 0;
161 
162 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
163 		ret = vsc8601_add_skew(phydev);
164 
165 	if (ret < 0)
166 		return ret;
167 
168 	return genphy_config_aneg(phydev);
169 }
170 
vsc8574_config(struct phy_device * phydev)171 static int vsc8574_config(struct phy_device *phydev)
172 {
173 	u32 val;
174 	/* configure register 19G for MAC */
175 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
176 		  PHY_EXT_PAGE_ACCESS_GENERAL);
177 
178 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19);
179 	if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
180 		/* set bit 15:14 to '01' for QSGMII mode */
181 		val = (val & 0x3fff) | (1 << 14);
182 		phy_write(phydev, MDIO_DEVAD_NONE,
183 			  MIIM_VSC8574_GENERAL19, val);
184 		/* Enable 4 ports MAC QSGMII */
185 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
186 			  MIIM_VSC8574_18G_QSGMII);
187 	} else {
188 		/* set bit 15:14 to '00' for SGMII mode */
189 		val = val & 0x3fff;
190 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val);
191 		/* Enable 4 ports MAC SGMII */
192 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
193 			  MIIM_VSC8574_18G_SGMII);
194 	}
195 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
196 	/* When bit 15 is cleared the command has completed */
197 	while (val & MIIM_VSC8574_18G_CMDSTAT)
198 		val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
199 
200 	/* Enable Serdes Auto-negotiation */
201 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
202 		  PHY_EXT_PAGE_ACCESS_EXTENDED3);
203 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON);
204 	val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
205 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val);
206 
207 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
208 
209 	genphy_config_aneg(phydev);
210 
211 	return 0;
212 }
213 
vsc8514_config(struct phy_device * phydev)214 static int vsc8514_config(struct phy_device *phydev)
215 {
216 	u32 val;
217 	int timeout = 1000000;
218 
219 	/* configure register to access 19G */
220 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
221 		  PHY_EXT_PAGE_ACCESS_GENERAL);
222 
223 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL19);
224 	if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
225 		/* set bit 15:14 to '01' for QSGMII mode */
226 		val = (val & 0x3fff) | (1 << 14);
227 		phy_write(phydev, MDIO_DEVAD_NONE,
228 			  MIIM_VSC8514_GENERAL19, val);
229 		/* Enable 4 ports MAC QSGMII */
230 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18,
231 			  MIIM_VSC8514_18G_QSGMII);
232 	} else {
233 		/*TODO Add SGMII functionality once spec sheet
234 		 * for VSC8514 defines complete functionality
235 		 */
236 	}
237 
238 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
239 	/* When bit 15 is cleared the command has completed */
240 	while ((val & MIIM_VSC8514_18G_CMDSTAT) && timeout--)
241 		val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL18);
242 
243 	if (0 == timeout) {
244 		printf("PHY 8514 config failed\n");
245 		return -1;
246 	}
247 
248 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
249 
250 	/* configure register to access 23 */
251 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23);
252 	/* set bits 10:8 to '000' */
253 	val = (val & 0xf8ff);
254 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val);
255 
256 	/* Enable Serdes Auto-negotiation */
257 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
258 		  PHY_EXT_PAGE_ACCESS_EXTENDED3);
259 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON);
260 	val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
261 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val);
262 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
263 
264 	genphy_config_aneg(phydev);
265 
266 	return 0;
267 }
268 
vsc8664_config(struct phy_device * phydev)269 static int vsc8664_config(struct phy_device *phydev)
270 {
271 	u32 val;
272 
273 	/* Enable MAC interface auto-negotiation */
274 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
275 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON);
276 	val |= (1 << 13);
277 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val);
278 
279 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
280 		  PHY_EXT_PAGE_ACCESS_EXTENDED);
281 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET);
282 	val |= (1 << 11);
283 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val);
284 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
285 
286 	/* Enable LED blink */
287 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON);
288 	val &= ~(1 << 2);
289 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val);
290 
291 	genphy_config_aneg(phydev);
292 
293 	return 0;
294 }
295 
296 static struct phy_driver VSC8211_driver = {
297 	.name	= "Vitesse VSC8211",
298 	.uid	= 0xfc4b0,
299 	.mask	= 0xffff0,
300 	.features = PHY_GBIT_FEATURES,
301 	.config = &vitesse_config,
302 	.startup = &vitesse_startup,
303 	.shutdown = &genphy_shutdown,
304 };
305 
306 static struct phy_driver VSC8221_driver = {
307 	.name = "Vitesse VSC8221",
308 	.uid = 0xfc550,
309 	.mask = 0xffff0,
310 	.features = PHY_GBIT_FEATURES,
311 	.config = &genphy_config_aneg,
312 	.startup = &vitesse_startup,
313 	.shutdown = &genphy_shutdown,
314 };
315 
316 static struct phy_driver VSC8244_driver = {
317 	.name = "Vitesse VSC8244",
318 	.uid = 0xfc6c0,
319 	.mask = 0xffff0,
320 	.features = PHY_GBIT_FEATURES,
321 	.config = &genphy_config_aneg,
322 	.startup = &vitesse_startup,
323 	.shutdown = &genphy_shutdown,
324 };
325 
326 static struct phy_driver VSC8234_driver = {
327 	.name = "Vitesse VSC8234",
328 	.uid = 0xfc620,
329 	.mask = 0xffff0,
330 	.features = PHY_GBIT_FEATURES,
331 	.config = &genphy_config_aneg,
332 	.startup = &vitesse_startup,
333 	.shutdown = &genphy_shutdown,
334 };
335 
336 static struct phy_driver VSC8574_driver = {
337 	.name = "Vitesse VSC8574",
338 	.uid = 0x704a0,
339 	.mask = 0xffff0,
340 	.features = PHY_GBIT_FEATURES,
341 	.config = &vsc8574_config,
342 	.startup = &vitesse_startup,
343 	.shutdown = &genphy_shutdown,
344 };
345 
346 static struct phy_driver VSC8514_driver = {
347 	.name = "Vitesse VSC8514",
348 	.uid = 0x70670,
349 	.mask = 0xffff0,
350 	.features = PHY_GBIT_FEATURES,
351 	.config = &vsc8514_config,
352 	.startup = &vitesse_startup,
353 	.shutdown = &genphy_shutdown,
354 };
355 
356 static struct phy_driver VSC8584_driver = {
357 	.name = "Vitesse VSC8584",
358 	.uid = 0x707c0,
359 	.mask = 0xffff0,
360 	.features = PHY_GBIT_FEATURES,
361 	.config = &vsc8574_config,
362 	.startup = &vitesse_startup,
363 	.shutdown = &genphy_shutdown,
364 };
365 
366 static struct phy_driver VSC8601_driver = {
367 	.name = "Vitesse VSC8601",
368 	.uid = 0x70420,
369 	.mask = 0xffff0,
370 	.features = PHY_GBIT_FEATURES,
371 	.config = &vsc8601_config,
372 	.startup = &vitesse_startup,
373 	.shutdown = &genphy_shutdown,
374 };
375 
376 static struct phy_driver VSC8641_driver = {
377 	.name = "Vitesse VSC8641",
378 	.uid = 0x70430,
379 	.mask = 0xffff0,
380 	.features = PHY_GBIT_FEATURES,
381 	.config = &genphy_config_aneg,
382 	.startup = &vitesse_startup,
383 	.shutdown = &genphy_shutdown,
384 };
385 
386 static struct phy_driver VSC8662_driver = {
387 	.name = "Vitesse VSC8662",
388 	.uid = 0x70660,
389 	.mask = 0xffff0,
390 	.features = PHY_GBIT_FEATURES,
391 	.config = &genphy_config_aneg,
392 	.startup = &vitesse_startup,
393 	.shutdown = &genphy_shutdown,
394 };
395 
396 static struct phy_driver VSC8664_driver = {
397 	.name = "Vitesse VSC8664",
398 	.uid = 0x70660,
399 	.mask = 0xffff0,
400 	.features = PHY_GBIT_FEATURES,
401 	.config = &vsc8664_config,
402 	.startup = &vitesse_startup,
403 	.shutdown = &genphy_shutdown,
404 };
405 
406 /* Vitesse bought Cicada, so we'll put these here */
407 static struct phy_driver cis8201_driver = {
408 	.name = "CIS8201",
409 	.uid = 0xfc410,
410 	.mask = 0xffff0,
411 	.features = PHY_GBIT_FEATURES,
412 	.config = &vitesse_config,
413 	.startup = &vitesse_startup,
414 	.shutdown = &genphy_shutdown,
415 };
416 
417 static struct phy_driver cis8204_driver = {
418 	.name = "Cicada Cis8204",
419 	.uid = 0xfc440,
420 	.mask = 0xffff0,
421 	.features = PHY_GBIT_FEATURES,
422 	.config = &cis8204_config,
423 	.startup = &vitesse_startup,
424 	.shutdown = &genphy_shutdown,
425 };
426 
phy_vitesse_init(void)427 int phy_vitesse_init(void)
428 {
429 	phy_register(&VSC8641_driver);
430 	phy_register(&VSC8601_driver);
431 	phy_register(&VSC8234_driver);
432 	phy_register(&VSC8244_driver);
433 	phy_register(&VSC8211_driver);
434 	phy_register(&VSC8221_driver);
435 	phy_register(&VSC8574_driver);
436 	phy_register(&VSC8584_driver);
437 	phy_register(&VSC8514_driver);
438 	phy_register(&VSC8662_driver);
439 	phy_register(&VSC8664_driver);
440 	phy_register(&cis8201_driver);
441 	phy_register(&cis8204_driver);
442 
443 	return 0;
444 }
445