1 /**************************************************************************
3 Copyright (c) 2007, Chelsio Inc.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Neither the name of the Chelsio Corporation nor the names of its
13 contributors may be used to endorse or promote products derived from
14 this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
28 ***************************************************************************/
30 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: cxgb_ael1002.c,v 1.2 2007/12/11 11:25:46 lukem Exp $");
35 __FBSDID("$FreeBSD: src/sys/dev/cxgb/common/cxgb_ael1002.c,v 1.3 2007/06/13 05:36:00 kmacy Exp $");
39 #include <cxgb_include.h>
42 #include <dev/cxgb/cxgb_include.h>
45 #include <dev/pci/cxgb_include.h>
50 AEL100X_TX_DISABLE
= 9,
51 AEL100X_TX_CONFIG1
= 0xc002,
52 AEL1002_PWR_DOWN_HI
= 0xc011,
53 AEL1002_PWR_DOWN_LO
= 0xc012,
54 AEL1002_XFI_EQL
= 0xc015,
55 AEL1002_LB_EN
= 0xc017,
61 static void ael100x_txon(struct cphy
*phy
)
63 int tx_on_gpio
= phy
->addr
== 0 ? F_GPIO7_OUT_VAL
: F_GPIO2_OUT_VAL
;
66 t3_set_reg_field(phy
->adapter
, A_T3DBG_GPIO_EN
, 0, tx_on_gpio
);
70 static int ael1002_power_down(struct cphy
*phy
, int enable
)
74 err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL100X_TX_DISABLE
, !!enable
);
76 err
= t3_mdio_change_bits(phy
, MDIO_DEV_PMA_PMD
, MII_BMCR
,
77 BMCR_PDOWN
, enable
? BMCR_PDOWN
: 0);
81 static int ael1002_reset(struct cphy
*phy
, int wait
)
85 if ((err
= ael1002_power_down(phy
, 0)) ||
86 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL100X_TX_CONFIG1
, 1)) ||
87 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL1002_PWR_DOWN_HI
, 0)) ||
88 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL1002_PWR_DOWN_LO
, 0)) ||
89 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL1002_XFI_EQL
, 0x18)) ||
90 (err
= t3_mdio_change_bits(phy
, MDIO_DEV_PMA_PMD
, AEL1002_LB_EN
,
96 static int ael1002_intr_noop(struct cphy
*phy
)
101 static int ael100x_get_link_status(struct cphy
*phy
, int *link_ok
,
102 int *speed
, int *duplex
, int *fc
)
106 int err
= mdio_read(phy
, MDIO_DEV_PMA_PMD
, 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 (!err
&& !(status
& BMSR_LSTATUS
))
113 err
= mdio_read(phy
, MDIO_DEV_PMA_PMD
, MII_BMSR
,
117 *link_ok
= !!(status
& BMSR_LSTATUS
);
120 *speed
= SPEED_10000
;
122 *duplex
= DUPLEX_FULL
;
126 #ifdef C99_NOT_SUPPORTED
127 static struct cphy_ops ael1002_ops
= {
139 ael100x_get_link_status
,
143 static struct cphy_ops ael1002_ops
= {
144 .reset
= ael1002_reset
,
145 .intr_enable
= ael1002_intr_noop
,
146 .intr_disable
= ael1002_intr_noop
,
147 .intr_clear
= ael1002_intr_noop
,
148 .intr_handler
= ael1002_intr_noop
,
149 .get_link_status
= ael100x_get_link_status
,
150 .power_down
= ael1002_power_down
,
154 void t3_ael1002_phy_prep(struct cphy
*phy
, adapter_t
*adapter
, int phy_addr
,
155 const struct mdio_ops
*mdio_ops
)
157 cphy_init(phy
, adapter
, phy_addr
, &ael1002_ops
, mdio_ops
);
161 static int ael1006_reset(struct cphy
*phy
, int wait
)
163 return t3_phy_reset(phy
, MDIO_DEV_PMA_PMD
, wait
);
166 static int ael1006_intr_enable(struct cphy
*phy
)
168 return mdio_write(phy
, MDIO_DEV_PMA_PMD
, LASI_CTRL
, 1);
171 static int ael1006_intr_disable(struct cphy
*phy
)
173 return mdio_write(phy
, MDIO_DEV_PMA_PMD
, LASI_CTRL
, 0);
176 static int ael1006_intr_clear(struct cphy
*phy
)
180 return mdio_read(phy
, MDIO_DEV_PMA_PMD
, LASI_STAT
, &val
);
183 static int ael1006_intr_handler(struct cphy
*phy
)
186 int err
= mdio_read(phy
, MDIO_DEV_PMA_PMD
, LASI_STAT
, &status
);
190 return (status
& 1) ? cphy_cause_link_change
: 0;
193 static int ael1006_power_down(struct cphy
*phy
, int enable
)
195 return t3_mdio_change_bits(phy
, MDIO_DEV_PMA_PMD
, MII_BMCR
,
196 BMCR_PDOWN
, enable
? BMCR_PDOWN
: 0);
199 #ifdef C99_NOT_SUPPORTED
200 static struct cphy_ops ael1006_ops
= {
204 ael1006_intr_disable
,
206 ael1006_intr_handler
,
212 ael100x_get_link_status
,
216 static struct cphy_ops ael1006_ops
= {
217 .reset
= ael1006_reset
,
218 .intr_enable
= ael1006_intr_enable
,
219 .intr_disable
= ael1006_intr_disable
,
220 .intr_clear
= ael1006_intr_clear
,
221 .intr_handler
= ael1006_intr_handler
,
222 .get_link_status
= ael100x_get_link_status
,
223 .power_down
= ael1006_power_down
,
227 void t3_ael1006_phy_prep(struct cphy
*phy
, adapter_t
*adapter
, int phy_addr
,
228 const struct mdio_ops
*mdio_ops
)
230 cphy_init(phy
, adapter
, phy_addr
, &ael1006_ops
, mdio_ops
);
234 #ifdef C99_NOT_SUPPORTED
235 static struct cphy_ops qt2045_ops
= {
239 ael1006_intr_disable
,
241 ael1006_intr_handler
,
247 ael100x_get_link_status
,
251 static struct cphy_ops qt2045_ops
= {
252 .reset
= ael1006_reset
,
253 .intr_enable
= ael1006_intr_enable
,
254 .intr_disable
= ael1006_intr_disable
,
255 .intr_clear
= ael1006_intr_clear
,
256 .intr_handler
= ael1006_intr_handler
,
257 .get_link_status
= ael100x_get_link_status
,
258 .power_down
= ael1006_power_down
,
262 void t3_qt2045_phy_prep(struct cphy
*phy
, adapter_t
*adapter
, int phy_addr
,
263 const struct mdio_ops
*mdio_ops
)
267 cphy_init(phy
, adapter
, phy_addr
, &qt2045_ops
, mdio_ops
);
270 * Some cards where the PHY is supposed to be at address 0 actually
273 if (!phy_addr
&& !mdio_read(phy
, MDIO_DEV_PMA_PMD
, MII_BMSR
, &stat
) &&
278 static int xaui_direct_reset(struct cphy
*phy
, int wait
)
283 static int xaui_direct_get_link_status(struct cphy
*phy
, int *link_ok
,
284 int *speed
, int *duplex
, int *fc
)
289 status
= t3_read_reg(phy
->adapter
,
290 XGM_REG(A_XGM_SERDES_STAT0
, phy
->addr
)) |
291 t3_read_reg(phy
->adapter
,
292 XGM_REG(A_XGM_SERDES_STAT1
, phy
->addr
)) |
293 t3_read_reg(phy
->adapter
,
294 XGM_REG(A_XGM_SERDES_STAT2
, phy
->addr
)) |
295 t3_read_reg(phy
->adapter
,
296 XGM_REG(A_XGM_SERDES_STAT3
, phy
->addr
));
297 *link_ok
= !(status
& F_LOWSIG0
);
300 *speed
= SPEED_10000
;
302 *duplex
= DUPLEX_FULL
;
306 static int xaui_direct_power_down(struct cphy
*phy
, int enable
)
311 #ifdef C99_NOT_SUPPORTED
312 static struct cphy_ops xaui_direct_ops
= {
324 xaui_direct_get_link_status
,
325 xaui_direct_power_down
,
328 static struct cphy_ops xaui_direct_ops
= {
329 .reset
= xaui_direct_reset
,
330 .intr_enable
= ael1002_intr_noop
,
331 .intr_disable
= ael1002_intr_noop
,
332 .intr_clear
= ael1002_intr_noop
,
333 .intr_handler
= ael1002_intr_noop
,
334 .get_link_status
= xaui_direct_get_link_status
,
335 .power_down
= xaui_direct_power_down
,
339 void t3_xaui_direct_phy_prep(struct cphy
*phy
, adapter_t
*adapter
, int phy_addr
,
340 const struct mdio_ops
*mdio_ops
)
342 cphy_init(phy
, adapter
, phy_addr
, &xaui_direct_ops
, mdio_ops
);