Add support for the latest 1G/10G Chelsio adapter, T3.
[safe/jmp/linux-2.6] / drivers / net / cxgb3 / vsc8211.c
1 /*
2  * This file is part of the Chelsio T3 Ethernet driver.
3  *
4  * Copyright (C) 2005-2006 Chelsio Communications.  All rights reserved.
5  *
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.
10  */
11
12 #include "common.h"
13
14 /* VSC8211 PHY specific registers. */
15 enum {
16         VSC8211_INTR_ENABLE = 25,
17         VSC8211_INTR_STATUS = 26,
18         VSC8211_AUX_CTRL_STAT = 28,
19 };
20
21 enum {
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 */
35 };
36
37 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
38                            VSC_INTR_NEG_DONE)
39 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
40                    VSC_INTR_ENABLE)
41
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)
46
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)
50
51 #define S_ACSR_DUPLEX 5
52 #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
53
54 #define S_ACSR_ACTIPHY 6
55 #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
56
57 /*
58  * Reset the PHY.  This PHY completes reset immediately so we never wait.
59  */
60 static int vsc8211_reset(struct cphy *cphy, int wait)
61 {
62         return t3_phy_reset(cphy, 0, 0);
63 }
64
65 static int vsc8211_intr_enable(struct cphy *cphy)
66 {
67         return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
68 }
69
70 static int vsc8211_intr_disable(struct cphy *cphy)
71 {
72         return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
73 }
74
75 static int vsc8211_intr_clear(struct cphy *cphy)
76 {
77         u32 val;
78
79         /* Clear PHY interrupts by reading the register. */
80         return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
81 }
82
83 static int vsc8211_autoneg_enable(struct cphy *cphy)
84 {
85         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
86                                    BMCR_ANENABLE | BMCR_ANRESTART);
87 }
88
89 static int vsc8211_autoneg_restart(struct cphy *cphy)
90 {
91         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
92                                    BMCR_ANRESTART);
93 }
94
95 static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
96                                    int *speed, int *duplex, int *fc)
97 {
98         unsigned int bmcr, status, lpa, adv;
99         int err, sp = -1, dplx = -1, pause = 0;
100
101         err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
102         if (!err)
103                 err = mdio_read(cphy, 0, MII_BMSR, &status);
104         if (err)
105                 return err;
106
107         if (link_ok) {
108                 /*
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.
111                  */
112                 if (!(status & BMSR_LSTATUS))
113                         err = mdio_read(cphy, 0, MII_BMSR, &status);
114                 if (err)
115                         return err;
116                 *link_ok = (status & BMSR_LSTATUS) != 0;
117         }
118         if (!(bmcr & BMCR_ANENABLE)) {
119                 dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
120                 if (bmcr & BMCR_SPEED1000)
121                         sp = SPEED_1000;
122                 else if (bmcr & BMCR_SPEED100)
123                         sp = SPEED_100;
124                 else
125                         sp = SPEED_10;
126         } else if (status & BMSR_ANEGCOMPLETE) {
127                 err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
128                 if (err)
129                         return err;
130
131                 dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
132                 sp = G_ACSR_SPEED(status);
133                 if (sp == 0)
134                         sp = SPEED_10;
135                 else if (sp == 1)
136                         sp = SPEED_100;
137                 else
138                         sp = SPEED_1000;
139
140                 if (fc && dplx == DUPLEX_FULL) {
141                         err = mdio_read(cphy, 0, MII_LPA, &lpa);
142                         if (!err)
143                                 err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
144                         if (err)
145                                 return err;
146
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))
152                                 pause = PAUSE_TX;
153                         else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
154                                  (adv & ADVERTISE_PAUSE_CAP))
155                                 pause = PAUSE_RX;
156                 }
157         }
158         if (speed)
159                 *speed = sp;
160         if (duplex)
161                 *duplex = dplx;
162         if (fc)
163                 *fc = pause;
164         return 0;
165 }
166
167 static int vsc8211_power_down(struct cphy *cphy, int enable)
168 {
169         return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
170                                    enable ? BMCR_PDOWN : 0);
171 }
172
173 static int vsc8211_intr_handler(struct cphy *cphy)
174 {
175         unsigned int cause;
176         int err, cphy_cause = 0;
177
178         err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
179         if (err)
180                 return err;
181
182         cause &= INTR_MASK;
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;
187         return cphy_cause;
188 }
189
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,
202 };
203
204 void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
205                          int phy_addr, const struct mdio_ops *mdio_ops)
206 {
207         cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
208 }