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