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 */
71static 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
85static 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
113static 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
123static 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. */
146static 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
158static 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
171static 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
214static 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
269static 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
296U_BOOT_PHY_DRIVER(vsc8211) = {
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
306U_BOOT_PHY_DRIVER(vsc8221) = {
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
316U_BOOT_PHY_DRIVER(vsc8244) = {
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
326U_BOOT_PHY_DRIVER(vsc8234) = {
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
336U_BOOT_PHY_DRIVER(vsc8574) = {
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
346U_BOOT_PHY_DRIVER(vsc8514) = {
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
356U_BOOT_PHY_DRIVER(vsc8584) = {
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
366U_BOOT_PHY_DRIVER(vsc8601) = {
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
376U_BOOT_PHY_DRIVER(vsc8641) = {
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
386U_BOOT_PHY_DRIVER(vsc8662) = {
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
396U_BOOT_PHY_DRIVER(vsc8664) = {
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 */
407U_BOOT_PHY_DRIVER(cis8201) = {
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
417U_BOOT_PHY_DRIVER(cis8204) = {
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