xref: /openbmc/u-boot/drivers/net/phy/vitesse.c (revision 198a40b9)
1 /*
2  * Vitesse PHY drivers
3  *
4  * Copyright 2010-2012 Freescale Semiconductor, Inc.
5  * Author: Andy Fleming
6  * Add vsc8662 phy support - Priyanka Jain
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 #include <miiphy.h>
23 
24 /* Cicada Auxiliary Control/Status Register */
25 #define MIIM_CIS82xx_AUX_CONSTAT	0x1c
26 #define MIIM_CIS82xx_AUXCONSTAT_INIT	0x0004
27 #define MIIM_CIS82xx_AUXCONSTAT_DUPLEX	0x0020
28 #define MIIM_CIS82xx_AUXCONSTAT_SPEED	0x0018
29 #define MIIM_CIS82xx_AUXCONSTAT_GBIT	0x0010
30 #define MIIM_CIS82xx_AUXCONSTAT_100	0x0008
31 
32 /* Cicada Extended Control Register 1 */
33 #define MIIM_CIS82xx_EXT_CON1		0x17
34 #define MIIM_CIS8201_EXTCON1_INIT	0x0000
35 
36 /* Cicada 8204 Extended PHY Control Register 1 */
37 #define MIIM_CIS8204_EPHY_CON		0x17
38 #define MIIM_CIS8204_EPHYCON_INIT	0x0006
39 #define MIIM_CIS8204_EPHYCON_RGMII	0x1100
40 
41 /* Cicada 8204 Serial LED Control Register */
42 #define MIIM_CIS8204_SLED_CON		0x1b
43 #define MIIM_CIS8204_SLEDCON_INIT	0x1115
44 
45 /* Vitesse VSC8601 Extended PHY Control Register 1 */
46 #define MIIM_VSC8601_EPHY_CON		0x17
47 #define MIIM_VSC8601_EPHY_CON_INIT_SKEW	0x1120
48 #define MIIM_VSC8601_SKEW_CTRL		0x1c
49 
50 #define PHY_EXT_PAGE_ACCESS    0x1f
51 #define PHY_EXT_PAGE_ACCESS_GENERAL	0x10
52 #define PHY_EXT_PAGE_ACCESS_EXTENDED3	0x3
53 
54 /* Vitesse VSC8574 control register */
55 #define MIIM_VSC8574_MAC_SERDES_CON	0x10
56 #define MIIM_VSC8574_MAC_SERDES_ANEG	0x80
57 #define MIIM_VSC8574_GENERAL18		0x12
58 #define MIIM_VSC8574_GENERAL19		0x13
59 
60 /* Vitesse VSC8574 gerenal purpose register 18 */
61 #define MIIM_VSC8574_18G_SGMII		0x80f0
62 #define MIIM_VSC8574_18G_QSGMII		0x80e0
63 #define MIIM_VSC8574_18G_CMDSTAT	0x8000
64 
65 /* CIS8201 */
66 static int vitesse_config(struct phy_device *phydev)
67 {
68 	/* Override PHY config settings */
69 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
70 			MIIM_CIS82xx_AUXCONSTAT_INIT);
71 	/* Set up the interface mode */
72 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1,
73 			MIIM_CIS8201_EXTCON1_INIT);
74 
75 	genphy_config_aneg(phydev);
76 
77 	return 0;
78 }
79 
80 static int vitesse_parse_status(struct phy_device *phydev)
81 {
82 	int speed;
83 	int mii_reg;
84 
85 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT);
86 
87 	if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX)
88 		phydev->duplex = DUPLEX_FULL;
89 	else
90 		phydev->duplex = DUPLEX_HALF;
91 
92 	speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED;
93 	switch (speed) {
94 	case MIIM_CIS82xx_AUXCONSTAT_GBIT:
95 		phydev->speed = SPEED_1000;
96 		break;
97 	case MIIM_CIS82xx_AUXCONSTAT_100:
98 		phydev->speed = SPEED_100;
99 		break;
100 	default:
101 		phydev->speed = SPEED_10;
102 		break;
103 	}
104 
105 	return 0;
106 }
107 
108 static int vitesse_startup(struct phy_device *phydev)
109 {
110 	genphy_update_link(phydev);
111 	vitesse_parse_status(phydev);
112 
113 	return 0;
114 }
115 
116 static int cis8204_config(struct phy_device *phydev)
117 {
118 	/* Override PHY config settings */
119 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT,
120 			MIIM_CIS82xx_AUXCONSTAT_INIT);
121 
122 	genphy_config_aneg(phydev);
123 
124 	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
125 			(phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
126 			(phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
127 			(phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID))
128 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
129 				MIIM_CIS8204_EPHYCON_INIT |
130 				MIIM_CIS8204_EPHYCON_RGMII);
131 	else
132 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON,
133 				MIIM_CIS8204_EPHYCON_INIT);
134 
135 	return 0;
136 }
137 
138 /* Vitesse VSC8601 */
139 static int vsc8601_config(struct phy_device *phydev)
140 {
141 	/* Configure some basic stuff */
142 #ifdef CONFIG_SYS_VSC8601_SKEWFIX
143 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON,
144 			MIIM_VSC8601_EPHY_CON_INIT_SKEW);
145 #if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
146 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1);
147 #define VSC8101_SKEW \
148 	((CONFIG_SYS_VSC8601_SKEW_TX << 14) \
149 	| (CONFIG_SYS_VSC8601_SKEW_RX << 12))
150 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL,
151 			VSC8101_SKEW);
152 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
153 #endif
154 #endif
155 
156 	genphy_config_aneg(phydev);
157 
158 	return 0;
159 }
160 
161 static int vsc8574_config(struct phy_device *phydev)
162 {
163 	u32 val;
164 	/* configure regiser 19G for MAC */
165 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
166 		  PHY_EXT_PAGE_ACCESS_GENERAL);
167 
168 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19);
169 	if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
170 		/* set bit 15:14 to '01' for QSGMII mode */
171 		val = (val & 0x3fff) | (1 << 14);
172 		phy_write(phydev, MDIO_DEVAD_NONE,
173 			  MIIM_VSC8574_GENERAL19, val);
174 		/* Enable 4 ports MAC QSGMII */
175 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
176 			  MIIM_VSC8574_18G_QSGMII);
177 	} else {
178 		/* set bit 15:14 to '00' for SGMII mode */
179 		val = val & 0x3fff;
180 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val);
181 		/* Enable 4 ports MAC SGMII */
182 		phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
183 			  MIIM_VSC8574_18G_SGMII);
184 	}
185 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
186 	/* When bit 15 is cleared the command has completed */
187 	while (val & MIIM_VSC8574_18G_CMDSTAT)
188 		val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
189 
190 	/* Enable Serdes Auto-negotiation */
191 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
192 		  PHY_EXT_PAGE_ACCESS_EXTENDED3);
193 	val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON);
194 	val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
195 	phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val);
196 
197 	phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
198 
199 	genphy_config_aneg(phydev);
200 
201 	return 0;
202 }
203 
204 static struct phy_driver VSC8211_driver = {
205 	.name	= "Vitesse VSC8211",
206 	.uid	= 0xfc4b0,
207 	.mask	= 0xffff0,
208 	.features = PHY_GBIT_FEATURES,
209 	.config = &vitesse_config,
210 	.startup = &vitesse_startup,
211 	.shutdown = &genphy_shutdown,
212 };
213 
214 static struct phy_driver VSC8221_driver = {
215 	.name = "Vitesse VSC8221",
216 	.uid = 0xfc550,
217 	.mask = 0xffff0,
218 	.features = PHY_GBIT_FEATURES,
219 	.config = &genphy_config_aneg,
220 	.startup = &vitesse_startup,
221 	.shutdown = &genphy_shutdown,
222 };
223 
224 static struct phy_driver VSC8244_driver = {
225 	.name = "Vitesse VSC8244",
226 	.uid = 0xfc6c0,
227 	.mask = 0xffff0,
228 	.features = PHY_GBIT_FEATURES,
229 	.config = &genphy_config_aneg,
230 	.startup = &vitesse_startup,
231 	.shutdown = &genphy_shutdown,
232 };
233 
234 static struct phy_driver VSC8234_driver = {
235 	.name = "Vitesse VSC8234",
236 	.uid = 0xfc620,
237 	.mask = 0xffff0,
238 	.features = PHY_GBIT_FEATURES,
239 	.config = &genphy_config_aneg,
240 	.startup = &vitesse_startup,
241 	.shutdown = &genphy_shutdown,
242 };
243 
244 static struct phy_driver VSC8574_driver = {
245 	.name = "Vitesse VSC8574",
246 	.uid = 0x704a0,
247 	.mask = 0xffff0,
248 	.features = PHY_GBIT_FEATURES,
249 	.config = &vsc8574_config,
250 	.startup = &vitesse_startup,
251 	.shutdown = &genphy_shutdown,
252 };
253 
254 static struct phy_driver VSC8601_driver = {
255 	.name = "Vitesse VSC8601",
256 	.uid = 0x70420,
257 	.mask = 0xffff0,
258 	.features = PHY_GBIT_FEATURES,
259 	.config = &vsc8601_config,
260 	.startup = &vitesse_startup,
261 	.shutdown = &genphy_shutdown,
262 };
263 
264 static struct phy_driver VSC8641_driver = {
265 	.name = "Vitesse VSC8641",
266 	.uid = 0x70430,
267 	.mask = 0xffff0,
268 	.features = PHY_GBIT_FEATURES,
269 	.config = &genphy_config_aneg,
270 	.startup = &vitesse_startup,
271 	.shutdown = &genphy_shutdown,
272 };
273 
274 static struct phy_driver VSC8662_driver = {
275 	.name = "Vitesse VSC8662",
276 	.uid = 0x70660,
277 	.mask = 0xffff0,
278 	.features = PHY_GBIT_FEATURES,
279 	.config = &genphy_config_aneg,
280 	.startup = &vitesse_startup,
281 	.shutdown = &genphy_shutdown,
282 };
283 
284 /* Vitesse bought Cicada, so we'll put these here */
285 static struct phy_driver cis8201_driver = {
286 	.name = "CIS8201",
287 	.uid = 0xfc410,
288 	.mask = 0xffff0,
289 	.features = PHY_GBIT_FEATURES,
290 	.config = &vitesse_config,
291 	.startup = &vitesse_startup,
292 	.shutdown = &genphy_shutdown,
293 };
294 
295 static struct phy_driver cis8204_driver = {
296 	.name = "Cicada Cis8204",
297 	.uid = 0xfc440,
298 	.mask = 0xffff0,
299 	.features = PHY_GBIT_FEATURES,
300 	.config = &cis8204_config,
301 	.startup = &vitesse_startup,
302 	.shutdown = &genphy_shutdown,
303 };
304 
305 int phy_vitesse_init(void)
306 {
307 	phy_register(&VSC8641_driver);
308 	phy_register(&VSC8601_driver);
309 	phy_register(&VSC8234_driver);
310 	phy_register(&VSC8244_driver);
311 	phy_register(&VSC8211_driver);
312 	phy_register(&VSC8221_driver);
313 	phy_register(&VSC8574_driver);
314 	phy_register(&VSC8662_driver);
315 	phy_register(&cis8201_driver);
316 	phy_register(&cis8204_driver);
317 
318 	return 0;
319 }
320