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