Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / net / ethernet / chelsio / cxgb3 / vsc8211.c
1 /*
2  * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 #include "common.h"
33
34 /* VSC8211 PHY specific registers. */
35 enum {
36         VSC8211_SIGDET_CTRL = 19,
37         VSC8211_EXT_CTRL = 23,
38         VSC8211_INTR_ENABLE = 25,
39         VSC8211_INTR_STATUS = 26,
40         VSC8211_LED_CTRL = 27,
41         VSC8211_AUX_CTRL_STAT = 28,
42         VSC8211_EXT_PAGE_AXS = 31,
43 };
44
45 enum {
46         VSC_INTR_RX_ERR = 1 << 0,
47         VSC_INTR_MS_ERR = 1 << 1,  /* master/slave resolution error */
48         VSC_INTR_CABLE = 1 << 2,  /* cable impairment */
49         VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
50         VSC_INTR_MEDIA_CHG = 1 << 4,  /* AMS media change */
51         VSC_INTR_RX_FIFO = 1 << 5,  /* Rx FIFO over/underflow */
52         VSC_INTR_TX_FIFO = 1 << 6,  /* Tx FIFO over/underflow */
53         VSC_INTR_DESCRAMBL = 1 << 7,  /* descrambler lock-lost */
54         VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
55         VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
56         VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
57         VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */
58         VSC_INTR_LINK_CHG = 1 << 13, /* link change */
59         VSC_INTR_SPD_CHG = 1 << 14, /* speed change */
60         VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
61 };
62
63 enum {
64         VSC_CTRL_CLAUSE37_VIEW = 1 << 4,   /* Switch to Clause 37 view */
65         VSC_CTRL_MEDIA_MODE_HI = 0xf000    /* High part of media mode select */
66 };
67
68 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
69                            VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \
70                            VSC_INTR_NEG_DONE)
71 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
72                    VSC_INTR_ENABLE)
73
74 /* PHY specific auxiliary control & status register fields */
75 #define S_ACSR_ACTIPHY_TMR    0
76 #define M_ACSR_ACTIPHY_TMR    0x3
77 #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
78
79 #define S_ACSR_SPEED    3
80 #define M_ACSR_SPEED    0x3
81 #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
82
83 #define S_ACSR_DUPLEX 5
84 #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
85
86 #define S_ACSR_ACTIPHY 6
87 #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
88
89 /*
90  * Reset the PHY.  This PHY completes reset immediately so we never wait.
91  */
92 static int vsc8211_reset(struct cphy *cphy, int wait)
93 {
94         return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0);
95 }
96
97 static int vsc8211_intr_enable(struct cphy *cphy)
98 {
99         return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE,
100                              INTR_MASK);
101 }
102
103 static int vsc8211_intr_disable(struct cphy *cphy)
104 {
105         return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0);
106 }
107
108 static int vsc8211_intr_clear(struct cphy *cphy)
109 {
110         u32 val;
111
112         /* Clear PHY interrupts by reading the register. */
113         return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val);
114 }
115
116 static int vsc8211_autoneg_enable(struct cphy *cphy)
117 {
118         return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR,
119                                    BMCR_PDOWN | BMCR_ISOLATE,
120                                    BMCR_ANENABLE | BMCR_ANRESTART);
121 }
122
123 static int vsc8211_autoneg_restart(struct cphy *cphy)
124 {
125         return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR,
126                                    BMCR_PDOWN | BMCR_ISOLATE,
127                                    BMCR_ANRESTART);
128 }
129
130 static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
131                                    int *speed, int *duplex, int *fc)
132 {
133         unsigned int bmcr, status, lpa, adv;
134         int err, sp = -1, dplx = -1, pause = 0;
135
136         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr);
137         if (!err)
138                 err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status);
139         if (err)
140                 return err;
141
142         if (link_ok) {
143                 /*
144                  * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
145                  * once more to get the current link state.
146                  */
147                 if (!(status & BMSR_LSTATUS))
148                         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR,
149                                            &status);
150                 if (err)
151                         return err;
152                 *link_ok = (status & BMSR_LSTATUS) != 0;
153         }
154         if (!(bmcr & BMCR_ANENABLE)) {
155                 dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
156                 if (bmcr & BMCR_SPEED1000)
157                         sp = SPEED_1000;
158                 else if (bmcr & BMCR_SPEED100)
159                         sp = SPEED_100;
160                 else
161                         sp = SPEED_10;
162         } else if (status & BMSR_ANEGCOMPLETE) {
163                 err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT,
164                                    &status);
165                 if (err)
166                         return err;
167
168                 dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
169                 sp = G_ACSR_SPEED(status);
170                 if (sp == 0)
171                         sp = SPEED_10;
172                 else if (sp == 1)
173                         sp = SPEED_100;
174                 else
175                         sp = SPEED_1000;
176
177                 if (fc && dplx == DUPLEX_FULL) {
178                         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA,
179                                            &lpa);
180                         if (!err)
181                                 err = t3_mdio_read(cphy, MDIO_DEVAD_NONE,
182                                                    MII_ADVERTISE, &adv);
183                         if (err)
184                                 return err;
185
186                         if (lpa & adv & ADVERTISE_PAUSE_CAP)
187                                 pause = PAUSE_RX | PAUSE_TX;
188                         else if ((lpa & ADVERTISE_PAUSE_CAP) &&
189                                  (lpa & ADVERTISE_PAUSE_ASYM) &&
190                                  (adv & ADVERTISE_PAUSE_ASYM))
191                                 pause = PAUSE_TX;
192                         else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
193                                  (adv & ADVERTISE_PAUSE_CAP))
194                                 pause = PAUSE_RX;
195                 }
196         }
197         if (speed)
198                 *speed = sp;
199         if (duplex)
200                 *duplex = dplx;
201         if (fc)
202                 *fc = pause;
203         return 0;
204 }
205
206 static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok,
207                                          int *speed, int *duplex, int *fc)
208 {
209         unsigned int bmcr, status, lpa, adv;
210         int err, sp = -1, dplx = -1, pause = 0;
211
212         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr);
213         if (!err)
214                 err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status);
215         if (err)
216                 return err;
217
218         if (link_ok) {
219                 /*
220                  * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
221                  * once more to get the current link state.
222                  */
223                 if (!(status & BMSR_LSTATUS))
224                         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR,
225                                            &status);
226                 if (err)
227                         return err;
228                 *link_ok = (status & BMSR_LSTATUS) != 0;
229         }
230         if (!(bmcr & BMCR_ANENABLE)) {
231                 dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
232                 if (bmcr & BMCR_SPEED1000)
233                         sp = SPEED_1000;
234                 else if (bmcr & BMCR_SPEED100)
235                         sp = SPEED_100;
236                 else
237                         sp = SPEED_10;
238         } else if (status & BMSR_ANEGCOMPLETE) {
239                 err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa);
240                 if (!err)
241                         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE,
242                                            &adv);
243                 if (err)
244                         return err;
245
246                 if (adv & lpa & ADVERTISE_1000XFULL) {
247                         dplx = DUPLEX_FULL;
248                         sp = SPEED_1000;
249                 } else if (adv & lpa & ADVERTISE_1000XHALF) {
250                         dplx = DUPLEX_HALF;
251                         sp = SPEED_1000;
252                 }
253
254                 if (fc && dplx == DUPLEX_FULL) {
255                         if (lpa & adv & ADVERTISE_1000XPAUSE)
256                                 pause = PAUSE_RX | PAUSE_TX;
257                         else if ((lpa & ADVERTISE_1000XPAUSE) &&
258                                  (adv & lpa & ADVERTISE_1000XPSE_ASYM))
259                                 pause = PAUSE_TX;
260                         else if ((lpa & ADVERTISE_1000XPSE_ASYM) &&
261                                  (adv & ADVERTISE_1000XPAUSE))
262                                 pause = PAUSE_RX;
263                 }
264         }
265         if (speed)
266                 *speed = sp;
267         if (duplex)
268                 *duplex = dplx;
269         if (fc)
270                 *fc = pause;
271         return 0;
272 }
273
274 #ifdef UNUSED
275 /*
276  * Enable/disable auto MDI/MDI-X in forced link speed mode.
277  */
278 static int vsc8211_set_automdi(struct cphy *phy, int enable)
279 {
280         int err;
281
282         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5);
283         if (err)
284                 return err;
285
286         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12);
287         if (err)
288                 return err;
289
290         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003);
291         if (err)
292                 return err;
293
294         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa);
295         if (err)
296                 return err;
297
298         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0);
299         if (err)
300                 return err;
301
302         return 0;
303 }
304
305 int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex)
306 {
307         int err;
308
309         err = t3_set_phy_speed_duplex(phy, speed, duplex);
310         if (!err)
311                 err = vsc8211_set_automdi(phy, 1);
312         return err;
313 }
314 #endif /* UNUSED */
315
316 static int vsc8211_power_down(struct cphy *cphy, int enable)
317 {
318         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
319                                    enable ? BMCR_PDOWN : 0);
320 }
321
322 static int vsc8211_intr_handler(struct cphy *cphy)
323 {
324         unsigned int cause;
325         int err, cphy_cause = 0;
326
327         err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause);
328         if (err)
329                 return err;
330
331         cause &= INTR_MASK;
332         if (cause & CFG_CHG_INTR_MASK)
333                 cphy_cause |= cphy_cause_link_change;
334         if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
335                 cphy_cause |= cphy_cause_fifo_error;
336         return cphy_cause;
337 }
338
339 static const struct cphy_ops vsc8211_ops = {
340         .reset = vsc8211_reset,
341         .intr_enable = vsc8211_intr_enable,
342         .intr_disable = vsc8211_intr_disable,
343         .intr_clear = vsc8211_intr_clear,
344         .intr_handler = vsc8211_intr_handler,
345         .autoneg_enable = vsc8211_autoneg_enable,
346         .autoneg_restart = vsc8211_autoneg_restart,
347         .advertise = t3_phy_advertise,
348         .set_speed_duplex = t3_set_phy_speed_duplex,
349         .get_link_status = vsc8211_get_link_status,
350         .power_down = vsc8211_power_down,
351 };
352
353 static const struct cphy_ops vsc8211_fiber_ops = {
354         .reset = vsc8211_reset,
355         .intr_enable = vsc8211_intr_enable,
356         .intr_disable = vsc8211_intr_disable,
357         .intr_clear = vsc8211_intr_clear,
358         .intr_handler = vsc8211_intr_handler,
359         .autoneg_enable = vsc8211_autoneg_enable,
360         .autoneg_restart = vsc8211_autoneg_restart,
361         .advertise = t3_phy_advertise_fiber,
362         .set_speed_duplex = t3_set_phy_speed_duplex,
363         .get_link_status = vsc8211_get_link_status_fiber,
364         .power_down = vsc8211_power_down,
365 };
366
367 int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
368                         int phy_addr, const struct mdio_ops *mdio_ops)
369 {
370         int err;
371         unsigned int val;
372
373         cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops,
374                   SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
375                   SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
376                   SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
377         msleep(20);       /* PHY needs ~10ms to start responding to MDIO */
378
379         err = t3_mdio_read(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, &val);
380         if (err)
381                 return err;
382         if (val & VSC_CTRL_MEDIA_MODE_HI) {
383                 /* copper interface, just need to configure the LEDs */
384                 return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL,
385                                      0x100);
386         }
387
388         phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
389                     SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ;
390         phy->desc = "1000BASE-X";
391         phy->ops = &vsc8211_fiber_ops;
392
393         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1);
394         if (err)
395                 return err;
396
397         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1);
398         if (err)
399                 return err;
400
401         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0);
402         if (err)
403                 return err;
404
405         err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL,
406                             val | VSC_CTRL_CLAUSE37_VIEW);
407         if (err)
408                 return err;
409
410         err = vsc8211_reset(phy, 0);
411         if (err)
412                 return err;
413
414         udelay(5); /* delay after reset before next SMI */
415         return 0;
416 }