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. 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.
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.
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.
32 ***************************************************************************/
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <dev/cxgb/common/cxgb_common.h>
38 #include <dev/cxgb/common/cxgb_regs.h>
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,
52 static void ael100x_txon(struct cphy *phy)
54 int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
57 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
61 static int ael1002_power_down(struct cphy *phy, int enable)
65 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
67 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
68 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
72 static int ael1002_reset(struct cphy *phy, int wait)
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,
87 static int ael1002_intr_noop(struct cphy *phy)
92 static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
93 int *speed, int *duplex, int *fc)
97 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
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.
103 if (!err && !(status & BMSR_LSTATUS))
104 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
108 *link_ok = !!(status & BMSR_LSTATUS);
111 *speed = SPEED_10000;
113 *duplex = DUPLEX_FULL;
117 #ifdef C99_NOT_SUPPORTED
118 static struct cphy_ops ael1002_ops = {
130 ael100x_get_link_status,
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,
145 void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
146 const struct mdio_ops *mdio_ops)
148 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
152 static int ael1006_reset(struct cphy *phy, int wait)
154 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
157 static int ael1006_intr_enable(struct cphy *phy)
159 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
162 static int ael1006_intr_disable(struct cphy *phy)
164 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
167 static int ael1006_intr_clear(struct cphy *phy)
171 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
174 static int ael1006_intr_handler(struct cphy *phy)
177 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
181 return (status & 1) ? cphy_cause_link_change : 0;
184 static int ael1006_power_down(struct cphy *phy, int enable)
186 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
187 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
190 #ifdef C99_NOT_SUPPORTED
191 static struct cphy_ops ael1006_ops = {
195 ael1006_intr_disable,
197 ael1006_intr_handler,
203 ael100x_get_link_status,
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,
218 void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
219 const struct mdio_ops *mdio_ops)
221 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
225 #ifdef C99_NOT_SUPPORTED
226 static struct cphy_ops qt2045_ops = {
230 ael1006_intr_disable,
232 ael1006_intr_handler,
238 ael100x_get_link_status,
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,
253 void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
254 const struct mdio_ops *mdio_ops)
258 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
261 * Some cards where the PHY is supposed to be at address 0 actually
264 if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
269 static int xaui_direct_reset(struct cphy *phy, int wait)
274 static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
275 int *speed, int *duplex, int *fc)
280 status = t3_read_reg(phy->adapter,
281 XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
282 *link_ok = !(status & F_LOWSIG0);
285 *speed = SPEED_10000;
287 *duplex = DUPLEX_FULL;
291 static int xaui_direct_power_down(struct cphy *phy, int enable)
296 #ifdef C99_NOT_SUPPORTED
297 static struct cphy_ops xaui_direct_ops = {
309 xaui_direct_get_link_status,
310 xaui_direct_power_down,
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,
324 void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
325 const struct mdio_ops *mdio_ops)
327 cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);