]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgb/common/cxgb_ael1002.c
This commit was generated by cvs2svn to compensate for changes in r169962,
[FreeBSD/FreeBSD.git] / sys / dev / cxgb / common / cxgb_ael1002.c
1 /**************************************************************************
2
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in the
14     documentation and/or other materials provided with the distribution.
15
16  3. Neither the name of the Chelsio Corporation nor the names of its
17     contributors may be used to endorse or promote products derived from
18     this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31
32 ***************************************************************************/
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <dev/cxgb/common/cxgb_common.h>
38 #include <dev/cxgb/common/cxgb_regs.h>
39
40 enum {
41         AEL100X_TX_DISABLE  = 9,
42         AEL100X_TX_CONFIG1  = 0xc002,
43         AEL1002_PWR_DOWN_HI = 0xc011,
44         AEL1002_PWR_DOWN_LO = 0xc012,
45         AEL1002_XFI_EQL     = 0xc015,
46         AEL1002_LB_EN       = 0xc017,
47
48         LASI_CTRL   = 0x9002,
49         LASI_STAT   = 0x9005
50 };
51
52 static void ael100x_txon(struct cphy *phy)
53 {
54         int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
55
56         t3_os_sleep(100);
57         t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
58         t3_os_sleep(30);
59 }
60
61 static int ael1002_power_down(struct cphy *phy, int enable)
62 {
63         int err;
64
65         err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
66         if (!err)
67                 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
68                                           BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
69         return err;
70 }
71
72 static int ael1002_reset(struct cphy *phy, int wait)
73 {
74         int err;
75
76         if ((err = ael1002_power_down(phy, 0)) ||
77             (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
78             (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
79             (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
80             (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
81             (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
82                                        0, 1 << 5)))
83                 return err;
84         return 0;
85 }
86
87 static int ael1002_intr_noop(struct cphy *phy)
88 {
89         return 0;
90 }
91
92 static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
93                                    int *speed, int *duplex, int *fc)
94 {
95         if (link_ok) {
96                 unsigned int status;
97                 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
98
99                 /*
100                  * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
101                  * once more to get the current link state.
102                  */
103                 if (!err && !(status & BMSR_LSTATUS))
104                         err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
105                                         &status);
106                 if (err)
107                         return err;
108                 *link_ok = !!(status & BMSR_LSTATUS);
109         }
110         if (speed)
111                 *speed = SPEED_10000;
112         if (duplex)
113                 *duplex = DUPLEX_FULL;
114         return 0;
115 }
116
117 #ifdef C99_NOT_SUPPORTED
118 static struct cphy_ops ael1002_ops = {
119         NULL,
120         ael1002_reset,
121         ael1002_intr_noop,
122         ael1002_intr_noop,
123         ael1002_intr_noop,
124         ael1002_intr_noop,
125         NULL,
126         NULL,
127         NULL,
128         NULL,
129         NULL,
130         ael100x_get_link_status,
131         ael1002_power_down,
132 };
133 #else
134 static struct cphy_ops ael1002_ops = {
135         .reset           = ael1002_reset,
136         .intr_enable     = ael1002_intr_noop,
137         .intr_disable    = ael1002_intr_noop,
138         .intr_clear      = ael1002_intr_noop,
139         .intr_handler    = ael1002_intr_noop,
140         .get_link_status = ael100x_get_link_status,
141         .power_down      = ael1002_power_down,
142 };
143 #endif
144
145 void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
146                          const struct mdio_ops *mdio_ops)
147 {
148         cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
149         ael100x_txon(phy);
150 }
151
152 static int ael1006_reset(struct cphy *phy, int wait)
153 {
154         return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
155 }
156
157 static int ael1006_intr_enable(struct cphy *phy)
158 {
159         return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
160 }
161
162 static int ael1006_intr_disable(struct cphy *phy)
163 {
164         return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
165 }
166
167 static int ael1006_intr_clear(struct cphy *phy)
168 {
169         u32 val;
170
171         return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
172 }
173
174 static int ael1006_intr_handler(struct cphy *phy)
175 {
176         unsigned int status;
177         int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
178
179         if (err)
180                 return err;
181         return (status & 1) ?  cphy_cause_link_change : 0;
182 }
183
184 static int ael1006_power_down(struct cphy *phy, int enable)
185 {
186         return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
187                                    BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
188 }
189
190 #ifdef C99_NOT_SUPPORTED
191 static struct cphy_ops ael1006_ops = {
192         NULL,
193         ael1006_reset,
194         ael1006_intr_enable,
195         ael1006_intr_disable,
196         ael1006_intr_clear,
197         ael1006_intr_handler,
198         NULL,
199         NULL,
200         NULL,
201         NULL,
202         NULL,
203         ael100x_get_link_status,
204         ael1006_power_down,
205 };
206 #else
207 static struct cphy_ops ael1006_ops = {
208         .reset           = ael1006_reset,
209         .intr_enable     = ael1006_intr_enable,
210         .intr_disable    = ael1006_intr_disable,
211         .intr_clear      = ael1006_intr_clear,
212         .intr_handler    = ael1006_intr_handler,
213         .get_link_status = ael100x_get_link_status,
214         .power_down      = ael1006_power_down,
215 };
216 #endif
217
218 void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
219                          const struct mdio_ops *mdio_ops)
220 {
221         cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
222         ael100x_txon(phy);
223 }
224
225 #ifdef C99_NOT_SUPPORTED
226 static struct cphy_ops qt2045_ops = {
227         NULL,
228         ael1006_reset,
229         ael1006_intr_enable,
230         ael1006_intr_disable,
231         ael1006_intr_clear,
232         ael1006_intr_handler,
233         NULL,
234         NULL,
235         NULL,
236         NULL,
237         NULL,
238         ael100x_get_link_status,
239         ael1006_power_down,
240 };
241 #else
242 static struct cphy_ops qt2045_ops = {
243         .reset           = ael1006_reset,
244         .intr_enable     = ael1006_intr_enable,
245         .intr_disable    = ael1006_intr_disable,
246         .intr_clear      = ael1006_intr_clear,
247         .intr_handler    = ael1006_intr_handler,
248         .get_link_status = ael100x_get_link_status,
249         .power_down      = ael1006_power_down,
250 };
251 #endif
252
253 void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
254                         const struct mdio_ops *mdio_ops)
255 {
256         unsigned int stat;
257
258         cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
259
260         /*
261          * Some cards where the PHY is supposed to be at address 0 actually
262          * have it at 1.
263          */
264         if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
265             stat == 0xffff)
266                 phy->addr = 1;
267 }
268
269 static int xaui_direct_reset(struct cphy *phy, int wait)
270 {
271         return 0;
272 }
273
274 static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
275                                        int *speed, int *duplex, int *fc)
276 {
277         if (link_ok) {
278                 unsigned int status;
279                 
280                 status = t3_read_reg(phy->adapter,
281                                      XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
282                 *link_ok = !(status & F_LOWSIG0);
283         }
284         if (speed)
285                 *speed = SPEED_10000;
286         if (duplex)
287                 *duplex = DUPLEX_FULL;
288         return 0;
289 }
290
291 static int xaui_direct_power_down(struct cphy *phy, int enable)
292 {
293         return 0;
294 }
295
296 #ifdef C99_NOT_SUPPORTED
297 static struct cphy_ops xaui_direct_ops = {
298         NULL,
299         xaui_direct_reset,
300         ael1002_intr_noop,
301         ael1002_intr_noop,
302         ael1002_intr_noop,
303         ael1002_intr_noop,
304         NULL,
305         NULL,
306         NULL,
307         NULL,
308         NULL,
309         xaui_direct_get_link_status,
310         xaui_direct_power_down,
311 };
312 #else
313 static struct cphy_ops xaui_direct_ops = {
314         .reset           = xaui_direct_reset,
315         .intr_enable     = ael1002_intr_noop,
316         .intr_disable    = ael1002_intr_noop,
317         .intr_clear      = ael1002_intr_noop,
318         .intr_handler    = ael1002_intr_noop,
319         .get_link_status = xaui_direct_get_link_status,
320         .power_down      = xaui_direct_power_down,
321 };
322 #endif
323
324 void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
325                              const struct mdio_ops *mdio_ops)
326 {
327         cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
328 }