aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb3/ael1002.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/cxgb3/ael1002.c')
-rw-r--r--drivers/net/cxgb3/ael1002.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
new file mode 100644
index 000000000000..93a90d825d85
--- /dev/null
+++ b/drivers/net/cxgb3/ael1002.c
@@ -0,0 +1,231 @@
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#include "regs.h"
14
15enum {
16 AEL100X_TX_DISABLE = 9,
17 AEL100X_TX_CONFIG1 = 0xc002,
18 AEL1002_PWR_DOWN_HI = 0xc011,
19 AEL1002_PWR_DOWN_LO = 0xc012,
20 AEL1002_XFI_EQL = 0xc015,
21 AEL1002_LB_EN = 0xc017,
22
23 LASI_CTRL = 0x9002,
24 LASI_STAT = 0x9005
25};
26
27static void ael100x_txon(struct cphy *phy)
28{
29 int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
30
31 msleep(100);
32 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
33 msleep(30);
34}
35
36static int ael1002_power_down(struct cphy *phy, int enable)
37{
38 int err;
39
40 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
41 if (!err)
42 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
43 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
44 return err;
45}
46
47static int ael1002_reset(struct cphy *phy, int wait)
48{
49 int err;
50
51 if ((err = ael1002_power_down(phy, 0)) ||
52 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
53 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
54 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
55 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
56 (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
57 0, 1 << 5)))
58 return err;
59 return 0;
60}
61
62static int ael1002_intr_noop(struct cphy *phy)
63{
64 return 0;
65}
66
67static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
68 int *speed, int *duplex, int *fc)
69{
70 if (link_ok) {
71 unsigned int status;
72 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
73
74 /*
75 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
76 * once more to get the current link state.
77 */
78 if (!err && !(status & BMSR_LSTATUS))
79 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
80 &status);
81 if (err)
82 return err;
83 *link_ok = !!(status & BMSR_LSTATUS);
84 }
85 if (speed)
86 *speed = SPEED_10000;
87 if (duplex)
88 *duplex = DUPLEX_FULL;
89 return 0;
90}
91
92static struct cphy_ops ael1002_ops = {
93 .reset = ael1002_reset,
94 .intr_enable = ael1002_intr_noop,
95 .intr_disable = ael1002_intr_noop,
96 .intr_clear = ael1002_intr_noop,
97 .intr_handler = ael1002_intr_noop,
98 .get_link_status = ael100x_get_link_status,
99 .power_down = ael1002_power_down,
100};
101
102void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
103 int phy_addr, const struct mdio_ops *mdio_ops)
104{
105 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
106 ael100x_txon(phy);
107}
108
109static int ael1006_reset(struct cphy *phy, int wait)
110{
111 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
112}
113
114static int ael1006_intr_enable(struct cphy *phy)
115{
116 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
117}
118
119static int ael1006_intr_disable(struct cphy *phy)
120{
121 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
122}
123
124static int ael1006_intr_clear(struct cphy *phy)
125{
126 u32 val;
127
128 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
129}
130
131static int ael1006_intr_handler(struct cphy *phy)
132{
133 unsigned int status;
134 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
135
136 if (err)
137 return err;
138 return (status & 1) ? cphy_cause_link_change : 0;
139}
140
141static int ael1006_power_down(struct cphy *phy, int enable)
142{
143 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
144 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
145}
146
147static struct cphy_ops ael1006_ops = {
148 .reset = ael1006_reset,
149 .intr_enable = ael1006_intr_enable,
150 .intr_disable = ael1006_intr_disable,
151 .intr_clear = ael1006_intr_clear,
152 .intr_handler = ael1006_intr_handler,
153 .get_link_status = ael100x_get_link_status,
154 .power_down = ael1006_power_down,
155};
156
157void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
158 int phy_addr, const struct mdio_ops *mdio_ops)
159{
160 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
161 ael100x_txon(phy);
162}
163
164static struct cphy_ops qt2045_ops = {
165 .reset = ael1006_reset,
166 .intr_enable = ael1006_intr_enable,
167 .intr_disable = ael1006_intr_disable,
168 .intr_clear = ael1006_intr_clear,
169 .intr_handler = ael1006_intr_handler,
170 .get_link_status = ael100x_get_link_status,
171 .power_down = ael1006_power_down,
172};
173
174void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
175 int phy_addr, const struct mdio_ops *mdio_ops)
176{
177 unsigned int stat;
178
179 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
180
181 /*
182 * Some cards where the PHY is supposed to be at address 0 actually
183 * have it at 1.
184 */
185 if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
186 stat == 0xffff)
187 phy->addr = 1;
188}
189
190static int xaui_direct_reset(struct cphy *phy, int wait)
191{
192 return 0;
193}
194
195static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
196 int *speed, int *duplex, int *fc)
197{
198 if (link_ok) {
199 unsigned int status;
200
201 status = t3_read_reg(phy->adapter,
202 XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
203 *link_ok = !(status & F_LOWSIG0);
204 }
205 if (speed)
206 *speed = SPEED_10000;
207 if (duplex)
208 *duplex = DUPLEX_FULL;
209 return 0;
210}
211
212static int xaui_direct_power_down(struct cphy *phy, int enable)
213{
214 return 0;
215}
216
217static struct cphy_ops xaui_direct_ops = {
218 .reset = xaui_direct_reset,
219 .intr_enable = ael1002_intr_noop,
220 .intr_disable = ael1002_intr_noop,
221 .intr_clear = ael1002_intr_noop,
222 .intr_handler = ael1002_intr_noop,
223 .get_link_status = xaui_direct_get_link_status,
224 .power_down = xaui_direct_power_down,
225};
226
227void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
228 int phy_addr, const struct mdio_ops *mdio_ops)
229{
230 cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
231}