2 * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
34 /* VSC8211 PHY specific registers. */
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,
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 */
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 */
68 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
69 VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \
71 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
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)
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)
83 #define S_ACSR_DUPLEX 5
84 #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
86 #define S_ACSR_ACTIPHY 6
87 #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
90 * Reset the PHY. This PHY completes reset immediately so we never wait.
92 static int vsc8211_reset(struct cphy
*cphy
, int wait
)
94 return t3_phy_reset(cphy
, MDIO_DEVAD_NONE
, 0);
97 static int vsc8211_intr_enable(struct cphy
*cphy
)
99 return t3_mdio_write(cphy
, MDIO_DEVAD_NONE
, VSC8211_INTR_ENABLE
,
103 static int vsc8211_intr_disable(struct cphy
*cphy
)
105 return t3_mdio_write(cphy
, MDIO_DEVAD_NONE
, VSC8211_INTR_ENABLE
, 0);
108 static int vsc8211_intr_clear(struct cphy
*cphy
)
112 /* Clear PHY interrupts by reading the register. */
113 return t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, VSC8211_INTR_STATUS
, &val
);
116 static int vsc8211_autoneg_enable(struct cphy
*cphy
)
118 return t3_mdio_change_bits(cphy
, MDIO_DEVAD_NONE
, MII_BMCR
,
119 BMCR_PDOWN
| BMCR_ISOLATE
,
120 BMCR_ANENABLE
| BMCR_ANRESTART
);
123 static int vsc8211_autoneg_restart(struct cphy
*cphy
)
125 return t3_mdio_change_bits(cphy
, MDIO_DEVAD_NONE
, MII_BMCR
,
126 BMCR_PDOWN
| BMCR_ISOLATE
,
130 static int vsc8211_get_link_status(struct cphy
*cphy
, int *link_ok
,
131 int *speed
, int *duplex
, int *fc
)
133 unsigned int bmcr
, status
, lpa
, adv
;
134 int err
, sp
= -1, dplx
= -1, pause
= 0;
136 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_BMCR
, &bmcr
);
138 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_BMSR
, &status
);
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.
147 if (!(status
& BMSR_LSTATUS
))
148 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_BMSR
,
152 *link_ok
= (status
& BMSR_LSTATUS
) != 0;
154 if (!(bmcr
& BMCR_ANENABLE
)) {
155 dplx
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
156 if (bmcr
& BMCR_SPEED1000
)
158 else if (bmcr
& BMCR_SPEED100
)
162 } else if (status
& BMSR_ANEGCOMPLETE
) {
163 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, VSC8211_AUX_CTRL_STAT
,
168 dplx
= (status
& F_ACSR_DUPLEX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
169 sp
= G_ACSR_SPEED(status
);
177 if (fc
&& dplx
== DUPLEX_FULL
) {
178 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_LPA
,
181 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
,
182 MII_ADVERTISE
, &adv
);
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
))
192 else if ((lpa
& ADVERTISE_PAUSE_ASYM
) &&
193 (adv
& ADVERTISE_PAUSE_CAP
))
206 static int vsc8211_get_link_status_fiber(struct cphy
*cphy
, int *link_ok
,
207 int *speed
, int *duplex
, int *fc
)
209 unsigned int bmcr
, status
, lpa
, adv
;
210 int err
, sp
= -1, dplx
= -1, pause
= 0;
212 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_BMCR
, &bmcr
);
214 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_BMSR
, &status
);
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.
223 if (!(status
& BMSR_LSTATUS
))
224 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_BMSR
,
228 *link_ok
= (status
& BMSR_LSTATUS
) != 0;
230 if (!(bmcr
& BMCR_ANENABLE
)) {
231 dplx
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
232 if (bmcr
& BMCR_SPEED1000
)
234 else if (bmcr
& BMCR_SPEED100
)
238 } else if (status
& BMSR_ANEGCOMPLETE
) {
239 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_LPA
, &lpa
);
241 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, MII_ADVERTISE
,
246 if (adv
& lpa
& ADVERTISE_1000XFULL
) {
249 } else if (adv
& lpa
& ADVERTISE_1000XHALF
) {
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
))
260 else if ((lpa
& ADVERTISE_1000XPSE_ASYM
) &&
261 (adv
& ADVERTISE_1000XPAUSE
))
276 * Enable/disable auto MDI/MDI-X in forced link speed mode.
278 static int vsc8211_set_automdi(struct cphy
*phy
, int enable
)
282 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, VSC8211_EXT_PAGE_AXS
, 0x52b5);
286 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, 18, 0x12);
290 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, 17, enable
? 0x2803 : 0x3003);
294 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, 16, 0x87fa);
298 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, VSC8211_EXT_PAGE_AXS
, 0);
305 int vsc8211_set_speed_duplex(struct cphy
*phy
, int speed
, int duplex
)
309 err
= t3_set_phy_speed_duplex(phy
, speed
, duplex
);
311 err
= vsc8211_set_automdi(phy
, 1);
316 static int vsc8211_power_down(struct cphy
*cphy
, int enable
)
318 return t3_mdio_change_bits(cphy
, 0, MII_BMCR
, BMCR_PDOWN
,
319 enable
? BMCR_PDOWN
: 0);
322 static int vsc8211_intr_handler(struct cphy
*cphy
)
325 int err
, cphy_cause
= 0;
327 err
= t3_mdio_read(cphy
, MDIO_DEVAD_NONE
, VSC8211_INTR_STATUS
, &cause
);
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
;
339 static 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
,
353 static 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
,
367 int t3_vsc8211_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
368 int phy_addr
, const struct mdio_ops
*mdio_ops
)
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 */
379 err
= t3_mdio_read(phy
, MDIO_DEVAD_NONE
, VSC8211_EXT_CTRL
, &val
);
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
,
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
;
393 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, VSC8211_EXT_PAGE_AXS
, 1);
397 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, VSC8211_SIGDET_CTRL
, 1);
401 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, VSC8211_EXT_PAGE_AXS
, 0);
405 err
= t3_mdio_write(phy
, MDIO_DEVAD_NONE
, VSC8211_EXT_CTRL
,
406 val
| VSC_CTRL_CLAUSE37_VIEW
);
410 err
= vsc8211_reset(phy
, 0);
414 udelay(5); /* delay after reset before next SMI */