2 * This file is part of the Chelsio T3 Ethernet driver.
4 * Copyright (C) 2005-2006 Chelsio Communications. All rights reserved.
6 * This program is distributed in the hope that it will be useful, but WITHOUT
7 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8 * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
9 * release for licensing terms and conditions.
14 /* VSC8211 PHY specific registers. */
16 VSC8211_INTR_ENABLE
= 25,
17 VSC8211_INTR_STATUS
= 26,
18 VSC8211_AUX_CTRL_STAT
= 28,
22 VSC_INTR_RX_ERR
= 1 << 0,
23 VSC_INTR_MS_ERR
= 1 << 1, /* master/slave resolution error */
24 VSC_INTR_CABLE
= 1 << 2, /* cable impairment */
25 VSC_INTR_FALSE_CARR
= 1 << 3, /* false carrier */
26 VSC_INTR_MEDIA_CHG
= 1 << 4, /* AMS media change */
27 VSC_INTR_RX_FIFO
= 1 << 5, /* Rx FIFO over/underflow */
28 VSC_INTR_TX_FIFO
= 1 << 6, /* Tx FIFO over/underflow */
29 VSC_INTR_DESCRAMBL
= 1 << 7, /* descrambler lock-lost */
30 VSC_INTR_SYMBOL_ERR
= 1 << 8, /* symbol error */
31 VSC_INTR_NEG_DONE
= 1 << 10, /* autoneg done */
32 VSC_INTR_NEG_ERR
= 1 << 11, /* autoneg error */
33 VSC_INTR_LINK_CHG
= 1 << 13, /* link change */
34 VSC_INTR_ENABLE
= 1 << 15, /* interrupt enable */
37 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
39 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
42 /* PHY specific auxiliary control & status register fields */
43 #define S_ACSR_ACTIPHY_TMR 0
44 #define M_ACSR_ACTIPHY_TMR 0x3
45 #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
47 #define S_ACSR_SPEED 3
48 #define M_ACSR_SPEED 0x3
49 #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
51 #define S_ACSR_DUPLEX 5
52 #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
54 #define S_ACSR_ACTIPHY 6
55 #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
58 * Reset the PHY. This PHY completes reset immediately so we never wait.
60 static int vsc8211_reset(struct cphy
*cphy
, int wait
)
62 return t3_phy_reset(cphy
, 0, 0);
65 static int vsc8211_intr_enable(struct cphy
*cphy
)
67 return mdio_write(cphy
, 0, VSC8211_INTR_ENABLE
, INTR_MASK
);
70 static int vsc8211_intr_disable(struct cphy
*cphy
)
72 return mdio_write(cphy
, 0, VSC8211_INTR_ENABLE
, 0);
75 static int vsc8211_intr_clear(struct cphy
*cphy
)
79 /* Clear PHY interrupts by reading the register. */
80 return mdio_read(cphy
, 0, VSC8211_INTR_STATUS
, &val
);
83 static int vsc8211_autoneg_enable(struct cphy
*cphy
)
85 return t3_mdio_change_bits(cphy
, 0, MII_BMCR
, BMCR_PDOWN
| BMCR_ISOLATE
,
86 BMCR_ANENABLE
| BMCR_ANRESTART
);
89 static int vsc8211_autoneg_restart(struct cphy
*cphy
)
91 return t3_mdio_change_bits(cphy
, 0, MII_BMCR
, BMCR_PDOWN
| BMCR_ISOLATE
,
95 static int vsc8211_get_link_status(struct cphy
*cphy
, int *link_ok
,
96 int *speed
, int *duplex
, int *fc
)
98 unsigned int bmcr
, status
, lpa
, adv
;
99 int err
, sp
= -1, dplx
= -1, pause
= 0;
101 err
= mdio_read(cphy
, 0, MII_BMCR
, &bmcr
);
103 err
= mdio_read(cphy
, 0, MII_BMSR
, &status
);
109 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
110 * once more to get the current link state.
112 if (!(status
& BMSR_LSTATUS
))
113 err
= mdio_read(cphy
, 0, MII_BMSR
, &status
);
116 *link_ok
= (status
& BMSR_LSTATUS
) != 0;
118 if (!(bmcr
& BMCR_ANENABLE
)) {
119 dplx
= (bmcr
& BMCR_FULLDPLX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
120 if (bmcr
& BMCR_SPEED1000
)
122 else if (bmcr
& BMCR_SPEED100
)
126 } else if (status
& BMSR_ANEGCOMPLETE
) {
127 err
= mdio_read(cphy
, 0, VSC8211_AUX_CTRL_STAT
, &status
);
131 dplx
= (status
& F_ACSR_DUPLEX
) ? DUPLEX_FULL
: DUPLEX_HALF
;
132 sp
= G_ACSR_SPEED(status
);
140 if (fc
&& dplx
== DUPLEX_FULL
) {
141 err
= mdio_read(cphy
, 0, MII_LPA
, &lpa
);
143 err
= mdio_read(cphy
, 0, MII_ADVERTISE
, &adv
);
147 if (lpa
& adv
& ADVERTISE_PAUSE_CAP
)
148 pause
= PAUSE_RX
| PAUSE_TX
;
149 else if ((lpa
& ADVERTISE_PAUSE_CAP
) &&
150 (lpa
& ADVERTISE_PAUSE_ASYM
) &&
151 (adv
& ADVERTISE_PAUSE_ASYM
))
153 else if ((lpa
& ADVERTISE_PAUSE_ASYM
) &&
154 (adv
& ADVERTISE_PAUSE_CAP
))
167 static int vsc8211_power_down(struct cphy
*cphy
, int enable
)
169 return t3_mdio_change_bits(cphy
, 0, MII_BMCR
, BMCR_PDOWN
,
170 enable
? BMCR_PDOWN
: 0);
173 static int vsc8211_intr_handler(struct cphy
*cphy
)
176 int err
, cphy_cause
= 0;
178 err
= mdio_read(cphy
, 0, VSC8211_INTR_STATUS
, &cause
);
183 if (cause
& CFG_CHG_INTR_MASK
)
184 cphy_cause
|= cphy_cause_link_change
;
185 if (cause
& (VSC_INTR_RX_FIFO
| VSC_INTR_TX_FIFO
))
186 cphy_cause
|= cphy_cause_fifo_error
;
190 static struct cphy_ops vsc8211_ops
= {
191 .reset
= vsc8211_reset
,
192 .intr_enable
= vsc8211_intr_enable
,
193 .intr_disable
= vsc8211_intr_disable
,
194 .intr_clear
= vsc8211_intr_clear
,
195 .intr_handler
= vsc8211_intr_handler
,
196 .autoneg_enable
= vsc8211_autoneg_enable
,
197 .autoneg_restart
= vsc8211_autoneg_restart
,
198 .advertise
= t3_phy_advertise
,
199 .set_speed_duplex
= t3_set_phy_speed_duplex
,
200 .get_link_status
= vsc8211_get_link_status
,
201 .power_down
= vsc8211_power_down
,
204 void t3_vsc8211_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
205 int phy_addr
, const struct mdio_ops
*mdio_ops
)
207 cphy_init(phy
, adapter
, phy_addr
, &vsc8211_ops
, mdio_ops
);