2 * Copyright (c) 2005-2007 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
36 AEL100X_TX_DISABLE
= 9,
37 AEL100X_TX_CONFIG1
= 0xc002,
38 AEL1002_PWR_DOWN_HI
= 0xc011,
39 AEL1002_PWR_DOWN_LO
= 0xc012,
40 AEL1002_XFI_EQL
= 0xc015,
41 AEL1002_LB_EN
= 0xc017,
47 static void ael100x_txon(struct cphy
*phy
)
49 int tx_on_gpio
= phy
->addr
== 0 ? F_GPIO7_OUT_VAL
: F_GPIO2_OUT_VAL
;
52 t3_set_reg_field(phy
->adapter
, A_T3DBG_GPIO_EN
, 0, tx_on_gpio
);
56 static int ael1002_power_down(struct cphy
*phy
, int enable
)
60 err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL100X_TX_DISABLE
, !!enable
);
62 err
= t3_mdio_change_bits(phy
, MDIO_DEV_PMA_PMD
, MII_BMCR
,
63 BMCR_PDOWN
, enable
? BMCR_PDOWN
: 0);
67 static int ael1002_reset(struct cphy
*phy
, int wait
)
71 if ((err
= ael1002_power_down(phy
, 0)) ||
72 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL100X_TX_CONFIG1
, 1)) ||
73 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL1002_PWR_DOWN_HI
, 0)) ||
74 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL1002_PWR_DOWN_LO
, 0)) ||
75 (err
= mdio_write(phy
, MDIO_DEV_PMA_PMD
, AEL1002_XFI_EQL
, 0x18)) ||
76 (err
= t3_mdio_change_bits(phy
, MDIO_DEV_PMA_PMD
, AEL1002_LB_EN
,
82 static int ael1002_intr_noop(struct cphy
*phy
)
87 static int ael100x_get_link_status(struct cphy
*phy
, int *link_ok
,
88 int *speed
, int *duplex
, int *fc
)
92 int err
= mdio_read(phy
, MDIO_DEV_PMA_PMD
, MII_BMSR
, &status
);
95 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
96 * once more to get the current link state.
98 if (!err
&& !(status
& BMSR_LSTATUS
))
99 err
= mdio_read(phy
, MDIO_DEV_PMA_PMD
, MII_BMSR
,
103 *link_ok
= !!(status
& BMSR_LSTATUS
);
106 *speed
= SPEED_10000
;
108 *duplex
= DUPLEX_FULL
;
112 static struct cphy_ops ael1002_ops
= {
113 .reset
= ael1002_reset
,
114 .intr_enable
= ael1002_intr_noop
,
115 .intr_disable
= ael1002_intr_noop
,
116 .intr_clear
= ael1002_intr_noop
,
117 .intr_handler
= ael1002_intr_noop
,
118 .get_link_status
= ael100x_get_link_status
,
119 .power_down
= ael1002_power_down
,
122 void t3_ael1002_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
123 int phy_addr
, const struct mdio_ops
*mdio_ops
)
125 cphy_init(phy
, adapter
, phy_addr
, &ael1002_ops
, mdio_ops
);
129 static int ael1006_reset(struct cphy
*phy
, int wait
)
131 return t3_phy_reset(phy
, MDIO_DEV_PMA_PMD
, wait
);
134 static int ael1006_intr_enable(struct cphy
*phy
)
136 return mdio_write(phy
, MDIO_DEV_PMA_PMD
, LASI_CTRL
, 1);
139 static int ael1006_intr_disable(struct cphy
*phy
)
141 return mdio_write(phy
, MDIO_DEV_PMA_PMD
, LASI_CTRL
, 0);
144 static int ael1006_intr_clear(struct cphy
*phy
)
148 return mdio_read(phy
, MDIO_DEV_PMA_PMD
, LASI_STAT
, &val
);
151 static int ael1006_intr_handler(struct cphy
*phy
)
154 int err
= mdio_read(phy
, MDIO_DEV_PMA_PMD
, LASI_STAT
, &status
);
158 return (status
& 1) ? cphy_cause_link_change
: 0;
161 static int ael1006_power_down(struct cphy
*phy
, int enable
)
163 return t3_mdio_change_bits(phy
, MDIO_DEV_PMA_PMD
, MII_BMCR
,
164 BMCR_PDOWN
, enable
? BMCR_PDOWN
: 0);
167 static struct cphy_ops ael1006_ops
= {
168 .reset
= ael1006_reset
,
169 .intr_enable
= ael1006_intr_enable
,
170 .intr_disable
= ael1006_intr_disable
,
171 .intr_clear
= ael1006_intr_clear
,
172 .intr_handler
= ael1006_intr_handler
,
173 .get_link_status
= ael100x_get_link_status
,
174 .power_down
= ael1006_power_down
,
177 void t3_ael1006_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
178 int phy_addr
, const struct mdio_ops
*mdio_ops
)
180 cphy_init(phy
, adapter
, phy_addr
, &ael1006_ops
, mdio_ops
);
184 static struct cphy_ops qt2045_ops
= {
185 .reset
= ael1006_reset
,
186 .intr_enable
= ael1006_intr_enable
,
187 .intr_disable
= ael1006_intr_disable
,
188 .intr_clear
= ael1006_intr_clear
,
189 .intr_handler
= ael1006_intr_handler
,
190 .get_link_status
= ael100x_get_link_status
,
191 .power_down
= ael1006_power_down
,
194 void t3_qt2045_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
195 int phy_addr
, const struct mdio_ops
*mdio_ops
)
199 cphy_init(phy
, adapter
, phy_addr
, &qt2045_ops
, mdio_ops
);
202 * Some cards where the PHY is supposed to be at address 0 actually
205 if (!phy_addr
&& !mdio_read(phy
, MDIO_DEV_PMA_PMD
, MII_BMSR
, &stat
) &&
210 static int xaui_direct_reset(struct cphy
*phy
, int wait
)
215 static int xaui_direct_get_link_status(struct cphy
*phy
, int *link_ok
,
216 int *speed
, int *duplex
, int *fc
)
221 status
= t3_read_reg(phy
->adapter
,
222 XGM_REG(A_XGM_SERDES_STAT0
, phy
->addr
)) |
223 t3_read_reg(phy
->adapter
,
224 XGM_REG(A_XGM_SERDES_STAT1
, phy
->addr
)) |
225 t3_read_reg(phy
->adapter
,
226 XGM_REG(A_XGM_SERDES_STAT2
, phy
->addr
)) |
227 t3_read_reg(phy
->adapter
,
228 XGM_REG(A_XGM_SERDES_STAT3
, phy
->addr
));
229 *link_ok
= !(status
& F_LOWSIG0
);
232 *speed
= SPEED_10000
;
234 *duplex
= DUPLEX_FULL
;
238 static int xaui_direct_power_down(struct cphy
*phy
, int enable
)
243 static struct cphy_ops xaui_direct_ops
= {
244 .reset
= xaui_direct_reset
,
245 .intr_enable
= ael1002_intr_noop
,
246 .intr_disable
= ael1002_intr_noop
,
247 .intr_clear
= ael1002_intr_noop
,
248 .intr_handler
= ael1002_intr_noop
,
249 .get_link_status
= xaui_direct_get_link_status
,
250 .power_down
= xaui_direct_power_down
,
253 void t3_xaui_direct_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
254 int phy_addr
, const struct mdio_ops
*mdio_ops
)
256 cphy_init(phy
, adapter
, phy_addr
, &xaui_direct_ops
, mdio_ops
);