Deleted Added
sdiff udiff text old ( 167514 ) new ( 170076 )
full compact
1/**************************************************************************
2
3Copyright (c) 2007, Chelsio Inc.
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, 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
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30POSSIBILITY OF SUCH DAMAGE.
31
32***************************************************************************/
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_ael1002.c 167514 2007-03-14 02:37:44Z kmacy $");
36
37#include <dev/cxgb/common/cxgb_common.h>
38#include <dev/cxgb/common/cxgb_regs.h>
39
40enum {
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
52static 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
61static 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
72static 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
87static int ael1002_intr_noop(struct cphy *phy)
88{
89 return 0;
90}
91
92static 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
118static 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
134static 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
145void 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
152static int ael1006_reset(struct cphy *phy, int wait)
153{
154 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
155}
156
157static int ael1006_intr_enable(struct cphy *phy)
158{
159 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
160}
161
162static int ael1006_intr_disable(struct cphy *phy)
163{
164 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
165}
166
167static 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
174static 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
184static 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
191static 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
207static 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
218void 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
226static 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
242static 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
253void 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
269static int xaui_direct_reset(struct cphy *phy, int wait)
270{
271 return 0;
272}
273
274static 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
291static int xaui_direct_power_down(struct cphy *phy, int enable)
292{
293 return 0;
294}
295
296#ifdef C99_NOT_SUPPORTED
297static 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
313static 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
324void 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}