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. 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.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26POSSIBILITY OF SUCH DAMAGE.
27
28***************************************************************************/
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_ael1002.c 170076 2007-05-28 22:57:27Z kmacy $");
32
33#ifdef CONFIG_DEFINED
34#include <cxgb_include.h>
35#else
36#include <dev/cxgb/cxgb_include.h>
37#endif
38
39enum {
40 AEL100X_TX_DISABLE = 9,
41 AEL100X_TX_CONFIG1 = 0xc002,
42 AEL1002_PWR_DOWN_HI = 0xc011,
43 AEL1002_PWR_DOWN_LO = 0xc012,
44 AEL1002_XFI_EQL = 0xc015,
45 AEL1002_LB_EN = 0xc017,
46
47 LASI_CTRL = 0x9002,
48 LASI_STAT = 0x9005
49};
50
51static void ael100x_txon(struct cphy *phy)
52{
53 int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
54
55 t3_os_sleep(100);
56 t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
57 t3_os_sleep(30);
58}
59
60static int ael1002_power_down(struct cphy *phy, int enable)
61{
62 int err;
63
64 err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
65 if (!err)
66 err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
67 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
68 return err;
69}
70
71static int ael1002_reset(struct cphy *phy, int wait)
72{
73 int err;
74
75 if ((err = ael1002_power_down(phy, 0)) ||
76 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
77 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
78 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
79 (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
80 (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
81 0, 1 << 5)))
82 return err;
83 return 0;
84}
85
86static int ael1002_intr_noop(struct cphy *phy)
87{
88 return 0;
89}
90
91static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
92 int *speed, int *duplex, int *fc)
93{
94 if (link_ok) {
95 unsigned int status;
96 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
97
98 /*
99 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
100 * once more to get the current link state.
101 */
102 if (!err && !(status & BMSR_LSTATUS))
103 err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
104 &status);
105 if (err)
106 return err;
107 *link_ok = !!(status & BMSR_LSTATUS);
108 }
109 if (speed)
110 *speed = SPEED_10000;
111 if (duplex)
112 *duplex = DUPLEX_FULL;
113 return 0;
114}
115
116#ifdef C99_NOT_SUPPORTED
117static struct cphy_ops ael1002_ops = {
118 NULL,
119 ael1002_reset,
120 ael1002_intr_noop,
121 ael1002_intr_noop,
122 ael1002_intr_noop,
123 ael1002_intr_noop,
124 NULL,
125 NULL,
126 NULL,
127 NULL,
128 NULL,
129 ael100x_get_link_status,
130 ael1002_power_down,
131};
132#else
133static struct cphy_ops ael1002_ops = {
134 .reset = ael1002_reset,
135 .intr_enable = ael1002_intr_noop,
136 .intr_disable = ael1002_intr_noop,
137 .intr_clear = ael1002_intr_noop,
138 .intr_handler = ael1002_intr_noop,
139 .get_link_status = ael100x_get_link_status,
140 .power_down = ael1002_power_down,
141};
142#endif
143
144void t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
145 const struct mdio_ops *mdio_ops)
146{
147 cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
148 ael100x_txon(phy);
149}
150
151static int ael1006_reset(struct cphy *phy, int wait)
152{
153 return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
154}
155
156static int ael1006_intr_enable(struct cphy *phy)
157{
158 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
159}
160
161static int ael1006_intr_disable(struct cphy *phy)
162{
163 return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
164}
165
166static int ael1006_intr_clear(struct cphy *phy)
167{
168 u32 val;
169
170 return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
171}
172
173static int ael1006_intr_handler(struct cphy *phy)
174{
175 unsigned int status;
176 int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
177
178 if (err)
179 return err;
180 return (status & 1) ? cphy_cause_link_change : 0;
181}
182
183static int ael1006_power_down(struct cphy *phy, int enable)
184{
185 return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
186 BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
187}
188
189#ifdef C99_NOT_SUPPORTED
190static struct cphy_ops ael1006_ops = {
191 NULL,
192 ael1006_reset,
193 ael1006_intr_enable,
194 ael1006_intr_disable,
195 ael1006_intr_clear,
196 ael1006_intr_handler,
197 NULL,
198 NULL,
199 NULL,
200 NULL,
201 NULL,
202 ael100x_get_link_status,
203 ael1006_power_down,
204};
205#else
206static struct cphy_ops ael1006_ops = {
207 .reset = ael1006_reset,
208 .intr_enable = ael1006_intr_enable,
209 .intr_disable = ael1006_intr_disable,
210 .intr_clear = ael1006_intr_clear,
211 .intr_handler = ael1006_intr_handler,
212 .get_link_status = ael100x_get_link_status,
213 .power_down = ael1006_power_down,
214};
215#endif
216
217void t3_ael1006_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
218 const struct mdio_ops *mdio_ops)
219{
220 cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
221 ael100x_txon(phy);
222}
223
224#ifdef C99_NOT_SUPPORTED
225static struct cphy_ops qt2045_ops = {
226 NULL,
227 ael1006_reset,
228 ael1006_intr_enable,
229 ael1006_intr_disable,
230 ael1006_intr_clear,
231 ael1006_intr_handler,
232 NULL,
233 NULL,
234 NULL,
235 NULL,
236 NULL,
237 ael100x_get_link_status,
238 ael1006_power_down,
239};
240#else
241static struct cphy_ops qt2045_ops = {
242 .reset = ael1006_reset,
243 .intr_enable = ael1006_intr_enable,
244 .intr_disable = ael1006_intr_disable,
245 .intr_clear = ael1006_intr_clear,
246 .intr_handler = ael1006_intr_handler,
247 .get_link_status = ael100x_get_link_status,
248 .power_down = ael1006_power_down,
249};
250#endif
251
252void t3_qt2045_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
253 const struct mdio_ops *mdio_ops)
254{
255 unsigned int stat;
256
257 cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
258
259 /*
260 * Some cards where the PHY is supposed to be at address 0 actually
261 * have it at 1.
262 */
263 if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
264 stat == 0xffff)
265 phy->addr = 1;
266}
267
268static int xaui_direct_reset(struct cphy *phy, int wait)
269{
270 return 0;
271}
272
273static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
274 int *speed, int *duplex, int *fc)
275{
276 if (link_ok) {
277 unsigned int status;
278
279 status = t3_read_reg(phy->adapter,
280 XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
281 *link_ok = !(status & F_LOWSIG0);
282 }
283 if (speed)
284 *speed = SPEED_10000;
285 if (duplex)
286 *duplex = DUPLEX_FULL;
287 return 0;
288}
289
290static int xaui_direct_power_down(struct cphy *phy, int enable)
291{
292 return 0;
293}
294
295#ifdef C99_NOT_SUPPORTED
296static struct cphy_ops xaui_direct_ops = {
297 NULL,
298 xaui_direct_reset,
299 ael1002_intr_noop,
300 ael1002_intr_noop,
301 ael1002_intr_noop,
302 ael1002_intr_noop,
303 NULL,
304 NULL,
305 NULL,
306 NULL,
307 NULL,
308 xaui_direct_get_link_status,
309 xaui_direct_power_down,
310};
311#else
312static struct cphy_ops xaui_direct_ops = {
313 .reset = xaui_direct_reset,
314 .intr_enable = ael1002_intr_noop,
315 .intr_disable = ael1002_intr_noop,
316 .intr_clear = ael1002_intr_noop,
317 .intr_handler = ael1002_intr_noop,
318 .get_link_status = xaui_direct_get_link_status,
319 .power_down = xaui_direct_power_down,
320};
321#endif
322
323void t3_xaui_direct_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr,
324 const struct mdio_ops *mdio_ops)
325{
326 cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
327}