• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 #include "common.h"
33 #include "regs.h"
34 
35 enum {
36 	AEL100X_TX_CONFIG1 = 0xc002,
37 	AEL1002_PWR_DOWN_HI = 0xc011,
38 	AEL1002_PWR_DOWN_LO = 0xc012,
39 	AEL1002_XFI_EQL = 0xc015,
40 	AEL1002_LB_EN = 0xc017,
41 	AEL_OPT_SETTINGS = 0xc017,
42 	AEL_I2C_CTRL = 0xc30a,
43 	AEL_I2C_DATA = 0xc30b,
44 	AEL_I2C_STAT = 0xc30c,
45 	AEL2005_GPIO_CTRL = 0xc214,
46 	AEL2005_GPIO_STAT = 0xc215,
47 
48 	AEL2020_GPIO_INTR   = 0xc103,	/* Latch High (LH) */
49 	AEL2020_GPIO_CTRL   = 0xc108,	/* Store Clear (SC) */
50 	AEL2020_GPIO_STAT   = 0xc10c,	/* Read Only (RO) */
51 	AEL2020_GPIO_CFG    = 0xc110,	/* Read Write (RW) */
52 
53 	AEL2020_GPIO_SDA    = 0,	/* IN: i2c serial data */
54 	AEL2020_GPIO_MODDET = 1,	/* IN: Module Detect */
55 	AEL2020_GPIO_0      = 3,	/* IN: unassigned */
56 	AEL2020_GPIO_1      = 2,	/* OUT: unassigned */
57 	AEL2020_GPIO_LSTAT  = AEL2020_GPIO_1, /* wired to link status LED */
58 };
59 
60 enum { edc_none, edc_sr, edc_twinax };
61 
62 /* PHY module I2C device address */
63 enum {
64 	MODULE_DEV_ADDR	= 0xa0,
65 	SFF_DEV_ADDR	= 0xa2,
66 };
67 
68 /* PHY transceiver type */
69 enum {
70 	phy_transtype_unknown = 0,
71 	phy_transtype_sfp     = 3,
72 	phy_transtype_xfp     = 6,
73 };
74 
75 #define AEL2005_MODDET_IRQ 4
76 
77 struct reg_val {
78 	unsigned short mmd_addr;
79 	unsigned short reg_addr;
80 	unsigned short clear_bits;
81 	unsigned short set_bits;
82 };
83 
set_phy_regs(struct cphy * phy,const struct reg_val * rv)84 static int set_phy_regs(struct cphy *phy, const struct reg_val *rv)
85 {
86 	int err;
87 
88 	for (err = 0; rv->mmd_addr && !err; rv++) {
89 		if (rv->clear_bits == 0xffff)
90 			err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr,
91 					    rv->set_bits);
92 		else
93 			err = t3_mdio_change_bits(phy, rv->mmd_addr,
94 						  rv->reg_addr, rv->clear_bits,
95 						  rv->set_bits);
96 	}
97 	return err;
98 }
99 
ael100x_txon(struct cphy * phy)100 static void ael100x_txon(struct cphy *phy)
101 {
102 	int tx_on_gpio =
103 		phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
104 
105 	msleep(100);
106 	t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
107 	msleep(30);
108 }
109 
110 /*
111  * Read an 8-bit word from a device attached to the PHY's i2c bus.
112  */
ael_i2c_rd(struct cphy * phy,int dev_addr,int word_addr)113 static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
114 {
115 	int i, err;
116 	unsigned int stat, data;
117 
118 	err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
119 			    (dev_addr << 8) | (1 << 8) | word_addr);
120 	if (err)
121 		return err;
122 
123 	for (i = 0; i < 200; i++) {
124 		msleep(1);
125 		err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
126 		if (err)
127 			return err;
128 		if ((stat & 3) == 1) {
129 			err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
130 					   &data);
131 			if (err)
132 				return err;
133 			return data >> 8;
134 		}
135 	}
136 	CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n",
137 		phy->mdio.prtad, dev_addr, word_addr);
138 	return -ETIMEDOUT;
139 }
140 
ael1002_power_down(struct cphy * phy,int enable)141 static int ael1002_power_down(struct cphy *phy, int enable)
142 {
143 	int err;
144 
145 	err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable);
146 	if (!err)
147 		err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
148 				    MDIO_MMD_PMAPMD, MDIO_CTRL1,
149 				    MDIO_CTRL1_LPOWER, enable);
150 	return err;
151 }
152 
ael1002_reset(struct cphy * phy,int wait)153 static int ael1002_reset(struct cphy *phy, int wait)
154 {
155 	int err;
156 
157 	if ((err = ael1002_power_down(phy, 0)) ||
158 	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) ||
159 	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) ||
160 	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) ||
161 	    (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) ||
162 	    (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN,
163 				       0, 1 << 5)))
164 		return err;
165 	return 0;
166 }
167 
ael1002_intr_noop(struct cphy * phy)168 static int ael1002_intr_noop(struct cphy *phy)
169 {
170 	return 0;
171 }
172 
173 /*
174  * Get link status for a 10GBASE-R device.
175  */
get_link_status_r(struct cphy * phy,int * link_ok,int * speed,int * duplex,int * fc)176 static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed,
177 			     int *duplex, int *fc)
178 {
179 	if (link_ok) {
180 		unsigned int stat0, stat1, stat2;
181 		int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
182 				       MDIO_PMA_RXDET, &stat0);
183 
184 		if (!err)
185 			err = t3_mdio_read(phy, MDIO_MMD_PCS,
186 					   MDIO_PCS_10GBRT_STAT1, &stat1);
187 		if (!err)
188 			err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
189 					   MDIO_PHYXS_LNSTAT, &stat2);
190 		if (err)
191 			return err;
192 		*link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1;
193 	}
194 	if (speed)
195 		*speed = SPEED_10000;
196 	if (duplex)
197 		*duplex = DUPLEX_FULL;
198 	return 0;
199 }
200 
201 static const struct cphy_ops ael1002_ops = {
202 	.reset = ael1002_reset,
203 	.intr_enable = ael1002_intr_noop,
204 	.intr_disable = ael1002_intr_noop,
205 	.intr_clear = ael1002_intr_noop,
206 	.intr_handler = ael1002_intr_noop,
207 	.get_link_status = get_link_status_r,
208 	.power_down = ael1002_power_down,
209 	.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
210 };
211 
t3_ael1002_phy_prep(struct cphy * phy,struct adapter * adapter,int phy_addr,const struct mdio_ops * mdio_ops)212 int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
213 			int phy_addr, const struct mdio_ops *mdio_ops)
214 {
215 	cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops,
216 		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
217 		   "10GBASE-R");
218 	ael100x_txon(phy);
219 	return 0;
220 }
221 
ael1006_reset(struct cphy * phy,int wait)222 static int ael1006_reset(struct cphy *phy, int wait)
223 {
224 	return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
225 }
226 
227 static const struct cphy_ops ael1006_ops = {
228 	.reset = ael1006_reset,
229 	.intr_enable = t3_phy_lasi_intr_enable,
230 	.intr_disable = t3_phy_lasi_intr_disable,
231 	.intr_clear = t3_phy_lasi_intr_clear,
232 	.intr_handler = t3_phy_lasi_intr_handler,
233 	.get_link_status = get_link_status_r,
234 	.power_down = ael1002_power_down,
235 	.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
236 };
237 
t3_ael1006_phy_prep(struct cphy * phy,struct adapter * adapter,int phy_addr,const struct mdio_ops * mdio_ops)238 int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
239 			     int phy_addr, const struct mdio_ops *mdio_ops)
240 {
241 	cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops,
242 		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE,
243 		   "10GBASE-SR");
244 	ael100x_txon(phy);
245 	return 0;
246 }
247 
248 /*
249  * Decode our module type.
250  */
ael2xxx_get_module_type(struct cphy * phy,int delay_ms)251 static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms)
252 {
253 	int v;
254 
255 	if (delay_ms)
256 		msleep(delay_ms);
257 
258 	/* see SFF-8472 for below */
259 	v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3);
260 	if (v < 0)
261 		return v;
262 
263 	if (v == 0x10)
264 		return phy_modtype_sr;
265 	if (v == 0x20)
266 		return phy_modtype_lr;
267 	if (v == 0x40)
268 		return phy_modtype_lrm;
269 
270 	v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6);
271 	if (v < 0)
272 		return v;
273 	if (v != 4)
274 		goto unknown;
275 
276 	v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10);
277 	if (v < 0)
278 		return v;
279 
280 	if (v & 0x80) {
281 		v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
282 		if (v < 0)
283 			return v;
284 		return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
285 	}
286 unknown:
287 	return phy_modtype_unknown;
288 }
289 
290 /*
291  * Code to support the Aeluros/NetLogic 2005 10Gb PHY.
292  */
ael2005_setup_sr_edc(struct cphy * phy)293 static int ael2005_setup_sr_edc(struct cphy *phy)
294 {
295 	static const struct reg_val regs[] = {
296 		{ MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 },
297 		{ MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a },
298 		{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
299 		{ 0, 0, 0, 0 }
300 	};
301 
302 	int i, err;
303 
304 	err = set_phy_regs(phy, regs);
305 	if (err)
306 		return err;
307 
308 	msleep(50);
309 
310 	if (phy->priv != edc_sr)
311 		err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
312 				    EDC_OPT_AEL2005_SIZE);
313 	if (err)
314 		return err;
315 
316 	for (i = 0; i <  EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
317 		err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
318 				    phy->phy_cache[i],
319 				    phy->phy_cache[i + 1]);
320 	if (!err)
321 		phy->priv = edc_sr;
322 	return err;
323 }
324 
ael2005_setup_twinax_edc(struct cphy * phy,int modtype)325 static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
326 {
327 	static const struct reg_val regs[] = {
328 		{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 },
329 		{ 0, 0, 0, 0 }
330 	};
331 	static const struct reg_val preemphasis[] = {
332 		{ MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 },
333 		{ MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
334 		{ 0, 0, 0, 0 }
335 	};
336 	int i, err;
337 
338 	err = set_phy_regs(phy, regs);
339 	if (!err && modtype == phy_modtype_twinax_long)
340 		err = set_phy_regs(phy, preemphasis);
341 	if (err)
342 		return err;
343 
344 	msleep(50);
345 
346 	if (phy->priv != edc_twinax)
347 		err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
348 				    EDC_TWX_AEL2005_SIZE);
349 	if (err)
350 		return err;
351 
352 	for (i = 0; i <  EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
353 		err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
354 				    phy->phy_cache[i],
355 				    phy->phy_cache[i + 1]);
356 	if (!err)
357 		phy->priv = edc_twinax;
358 	return err;
359 }
360 
ael2005_get_module_type(struct cphy * phy,int delay_ms)361 static int ael2005_get_module_type(struct cphy *phy, int delay_ms)
362 {
363 	int v;
364 	unsigned int stat;
365 
366 	v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat);
367 	if (v)
368 		return v;
369 
370 	if (stat & (1 << 8))			/* module absent */
371 		return phy_modtype_none;
372 
373 	return ael2xxx_get_module_type(phy, delay_ms);
374 }
375 
ael2005_intr_enable(struct cphy * phy)376 static int ael2005_intr_enable(struct cphy *phy)
377 {
378 	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200);
379 	return err ? err : t3_phy_lasi_intr_enable(phy);
380 }
381 
ael2005_intr_disable(struct cphy * phy)382 static int ael2005_intr_disable(struct cphy *phy)
383 {
384 	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100);
385 	return err ? err : t3_phy_lasi_intr_disable(phy);
386 }
387 
ael2005_intr_clear(struct cphy * phy)388 static int ael2005_intr_clear(struct cphy *phy)
389 {
390 	int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00);
391 	return err ? err : t3_phy_lasi_intr_clear(phy);
392 }
393 
ael2005_reset(struct cphy * phy,int wait)394 static int ael2005_reset(struct cphy *phy, int wait)
395 {
396 	static const struct reg_val regs0[] = {
397 		{ MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 },
398 		{ MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 },
399 		{ MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 },
400 		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
401 		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 },
402 		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 },
403 		{ MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 },
404 		{ 0, 0, 0, 0 }
405 	};
406 	static const struct reg_val regs1[] = {
407 		{ MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 },
408 		{ MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 },
409 		{ 0, 0, 0, 0 }
410 	};
411 
412 	int err;
413 	unsigned int lasi_ctrl;
414 
415 	err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
416 			   &lasi_ctrl);
417 	if (err)
418 		return err;
419 
420 	err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0);
421 	if (err)
422 		return err;
423 
424 	msleep(125);
425 	phy->priv = edc_none;
426 	err = set_phy_regs(phy, regs0);
427 	if (err)
428 		return err;
429 
430 	msleep(50);
431 
432 	err = ael2005_get_module_type(phy, 0);
433 	if (err < 0)
434 		return err;
435 	phy->modtype = err;
436 
437 	if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
438 		err = ael2005_setup_twinax_edc(phy, err);
439 	else
440 		err = ael2005_setup_sr_edc(phy);
441 	if (err)
442 		return err;
443 
444 	err = set_phy_regs(phy, regs1);
445 	if (err)
446 		return err;
447 
448 	/* reset wipes out interrupts, reenable them if they were on */
449 	if (lasi_ctrl & 1)
450 		err = ael2005_intr_enable(phy);
451 	return err;
452 }
453 
ael2005_intr_handler(struct cphy * phy)454 static int ael2005_intr_handler(struct cphy *phy)
455 {
456 	unsigned int stat;
457 	int ret, edc_needed, cause = 0;
458 
459 	ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat);
460 	if (ret)
461 		return ret;
462 
463 	if (stat & AEL2005_MODDET_IRQ) {
464 		ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL,
465 				    0xd00);
466 		if (ret)
467 			return ret;
468 
469 		/* modules have max 300 ms init time after hot plug */
470 		ret = ael2005_get_module_type(phy, 300);
471 		if (ret < 0)
472 			return ret;
473 
474 		phy->modtype = ret;
475 		if (ret == phy_modtype_none)
476 			edc_needed = phy->priv;       /* on unplug retain EDC */
477 		else if (ret == phy_modtype_twinax ||
478 			 ret == phy_modtype_twinax_long)
479 			edc_needed = edc_twinax;
480 		else
481 			edc_needed = edc_sr;
482 
483 		if (edc_needed != phy->priv) {
484 			ret = ael2005_reset(phy, 0);
485 			return ret ? ret : cphy_cause_module_change;
486 		}
487 		cause = cphy_cause_module_change;
488 	}
489 
490 	ret = t3_phy_lasi_intr_handler(phy);
491 	if (ret < 0)
492 		return ret;
493 
494 	ret |= cause;
495 	return ret ? ret : cphy_cause_link_change;
496 }
497 
498 static const struct cphy_ops ael2005_ops = {
499 	.reset           = ael2005_reset,
500 	.intr_enable     = ael2005_intr_enable,
501 	.intr_disable    = ael2005_intr_disable,
502 	.intr_clear      = ael2005_intr_clear,
503 	.intr_handler    = ael2005_intr_handler,
504 	.get_link_status = get_link_status_r,
505 	.power_down      = ael1002_power_down,
506 	.mmds            = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
507 };
508 
t3_ael2005_phy_prep(struct cphy * phy,struct adapter * adapter,int phy_addr,const struct mdio_ops * mdio_ops)509 int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
510 			int phy_addr, const struct mdio_ops *mdio_ops)
511 {
512 	cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops,
513 		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
514 		  SUPPORTED_IRQ, "10GBASE-R");
515 	msleep(125);
516 	return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0,
517 				   1 << 5);
518 }
519 
520 /*
521  * Setup EDC and other parameters for operation with an optical module.
522  */
ael2020_setup_sr_edc(struct cphy * phy)523 static int ael2020_setup_sr_edc(struct cphy *phy)
524 {
525 	static const struct reg_val regs[] = {
526 		/* set CDR offset to 10 */
527 		{ MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a },
528 
529 		/* adjust 10G RX bias current */
530 		{ MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 },
531 		{ MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 },
532 		{ MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 },
533 
534 		/* end */
535 		{ 0, 0, 0, 0 }
536 	};
537 	int err;
538 
539 	err = set_phy_regs(phy, regs);
540 	msleep(50);
541 	if (err)
542 		return err;
543 
544 	phy->priv = edc_sr;
545 	return 0;
546 }
547 
548 /*
549  * Setup EDC and other parameters for operation with an TWINAX module.
550  */
ael2020_setup_twinax_edc(struct cphy * phy,int modtype)551 static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
552 {
553 	/* set uC to 40MHz */
554 	static const struct reg_val uCclock40MHz[] = {
555 		{ MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 },
556 		{ MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 },
557 		{ 0, 0, 0, 0 }
558 	};
559 
560 	/* activate uC clock */
561 	static const struct reg_val uCclockActivate[] = {
562 		{ MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 },
563 		{ 0, 0, 0, 0 }
564 	};
565 
566 	/* set PC to start of SRAM and activate uC */
567 	static const struct reg_val uCactivate[] = {
568 		{ MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 },
569 		{ MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
570 		{ 0, 0, 0, 0 }
571 	};
572 	int i, err;
573 
574 	/* set uC clock and activate it */
575 	err = set_phy_regs(phy, uCclock40MHz);
576 	msleep(500);
577 	if (err)
578 		return err;
579 	err = set_phy_regs(phy, uCclockActivate);
580 	msleep(500);
581 	if (err)
582 		return err;
583 
584 	if (phy->priv != edc_twinax)
585 		err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
586 				    EDC_TWX_AEL2020_SIZE);
587 	if (err)
588 		return err;
589 
590 	for (i = 0; i <  EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
591 		err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
592 				    phy->phy_cache[i],
593 				    phy->phy_cache[i + 1]);
594 	/* activate uC */
595 	err = set_phy_regs(phy, uCactivate);
596 	if (!err)
597 		phy->priv = edc_twinax;
598 	return err;
599 }
600 
601 /*
602  * Return Module Type.
603  */
ael2020_get_module_type(struct cphy * phy,int delay_ms)604 static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
605 {
606 	int v;
607 	unsigned int stat;
608 
609 	v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat);
610 	if (v)
611 		return v;
612 
613 	if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) {
614 		/* module absent */
615 		return phy_modtype_none;
616 	}
617 
618 	return ael2xxx_get_module_type(phy, delay_ms);
619 }
620 
621 /*
622  * Enable PHY interrupts.  We enable "Module Detection" interrupts (on any
623  * state transition) and then generic Link Alarm Status Interrupt (LASI).
624  */
ael2020_intr_enable(struct cphy * phy)625 static int ael2020_intr_enable(struct cphy *phy)
626 {
627 	static const struct reg_val regs[] = {
628 		/* output Module's Loss Of Signal (LOS) to LED */
629 		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
630 			0xffff, 0x4 },
631 		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
632 			0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
633 
634 		 /* enable module detect status change interrupts */
635 		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
636 			0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
637 
638 		/* end */
639 		{ 0, 0, 0, 0 }
640 	};
641 	int err, link_ok = 0;
642 
643 	/* set up "link status" LED and enable module change interrupts */
644 	err = set_phy_regs(phy, regs);
645 	if (err)
646 		return err;
647 
648 	err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
649 	if (err)
650 		return err;
651 	if (link_ok)
652 		t3_link_changed(phy->adapter,
653 				phy2portid(phy));
654 
655 	err = t3_phy_lasi_intr_enable(phy);
656 	if (err)
657 		return err;
658 
659 	return 0;
660 }
661 
662 /*
663  * Disable PHY interrupts.  The mirror of the above ...
664  */
ael2020_intr_disable(struct cphy * phy)665 static int ael2020_intr_disable(struct cphy *phy)
666 {
667 	static const struct reg_val regs[] = {
668 		/* reset "link status" LED to "off" */
669 		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
670 			0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
671 
672 		/* disable module detect status change interrupts */
673 		{ MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
674 			0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
675 
676 		/* end */
677 		{ 0, 0, 0, 0 }
678 	};
679 	int err;
680 
681 	/* turn off "link status" LED and disable module change interrupts */
682 	err = set_phy_regs(phy, regs);
683 	if (err)
684 		return err;
685 
686 	return t3_phy_lasi_intr_disable(phy);
687 }
688 
689 /*
690  * Clear PHY interrupt state.
691  */
ael2020_intr_clear(struct cphy * phy)692 static int ael2020_intr_clear(struct cphy *phy)
693 {
694 	/*
695 	 * The GPIO Interrupt register on the AEL2020 is a "Latching High"
696 	 * (LH) register which is cleared to the current state when it's read.
697 	 * Thus, we simply read the register and discard the result.
698 	 */
699 	unsigned int stat;
700 	int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
701 	return err ? err : t3_phy_lasi_intr_clear(phy);
702 }
703 
704 static const struct reg_val ael2020_reset_regs[] = {
705 	/* Erratum #2: CDRLOL asserted, causing PMA link down status */
706 	{ MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
707 
708 	/* force XAUI to send LF when RX_LOS is asserted */
709 	{ MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
710 
711 	/* allow writes to transceiver module EEPROM on i2c bus */
712 	{ MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
713 	{ MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
714 	{ MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
715 
716 	/* end */
717 	{ 0, 0, 0, 0 }
718 };
719 /*
720  * Reset the PHY and put it into a canonical operating state.
721  */
ael2020_reset(struct cphy * phy,int wait)722 static int ael2020_reset(struct cphy *phy, int wait)
723 {
724 	int err;
725 	unsigned int lasi_ctrl;
726 
727 	/* grab current interrupt state */
728 	err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
729 			   &lasi_ctrl);
730 	if (err)
731 		return err;
732 
733 	err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125);
734 	if (err)
735 		return err;
736 	msleep(100);
737 
738 	/* basic initialization for all module types */
739 	phy->priv = edc_none;
740 	err = set_phy_regs(phy, ael2020_reset_regs);
741 	if (err)
742 		return err;
743 
744 	/* determine module type and perform appropriate initialization */
745 	err = ael2020_get_module_type(phy, 0);
746 	if (err < 0)
747 		return err;
748 	phy->modtype = (u8)err;
749 	if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
750 		err = ael2020_setup_twinax_edc(phy, err);
751 	else
752 		err = ael2020_setup_sr_edc(phy);
753 	if (err)
754 		return err;
755 
756 	/* reset wipes out interrupts, reenable them if they were on */
757 	if (lasi_ctrl & 1)
758 		err = ael2005_intr_enable(phy);
759 	return err;
760 }
761 
762 /*
763  * Handle a PHY interrupt.
764  */
ael2020_intr_handler(struct cphy * phy)765 static int ael2020_intr_handler(struct cphy *phy)
766 {
767 	unsigned int stat;
768 	int ret, edc_needed, cause = 0;
769 
770 	ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
771 	if (ret)
772 		return ret;
773 
774 	if (stat & (0x1 << AEL2020_GPIO_MODDET)) {
775 		/* modules have max 300 ms init time after hot plug */
776 		ret = ael2020_get_module_type(phy, 300);
777 		if (ret < 0)
778 			return ret;
779 
780 		phy->modtype = (u8)ret;
781 		if (ret == phy_modtype_none)
782 			edc_needed = phy->priv;       /* on unplug retain EDC */
783 		else if (ret == phy_modtype_twinax ||
784 			 ret == phy_modtype_twinax_long)
785 			edc_needed = edc_twinax;
786 		else
787 			edc_needed = edc_sr;
788 
789 		if (edc_needed != phy->priv) {
790 			ret = ael2020_reset(phy, 0);
791 			return ret ? ret : cphy_cause_module_change;
792 		}
793 		cause = cphy_cause_module_change;
794 	}
795 
796 	ret = t3_phy_lasi_intr_handler(phy);
797 	if (ret < 0)
798 		return ret;
799 
800 	ret |= cause;
801 	return ret ? ret : cphy_cause_link_change;
802 }
803 
804 static const struct cphy_ops ael2020_ops = {
805 	.reset           = ael2020_reset,
806 	.intr_enable     = ael2020_intr_enable,
807 	.intr_disable    = ael2020_intr_disable,
808 	.intr_clear      = ael2020_intr_clear,
809 	.intr_handler    = ael2020_intr_handler,
810 	.get_link_status = get_link_status_r,
811 	.power_down      = ael1002_power_down,
812 	.mmds		 = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
813 };
814 
t3_ael2020_phy_prep(struct cphy * phy,struct adapter * adapter,int phy_addr,const struct mdio_ops * mdio_ops)815 int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
816 			const struct mdio_ops *mdio_ops)
817 {
818 	cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
819 		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
820 		  SUPPORTED_IRQ, "10GBASE-R");
821 	msleep(125);
822 
823 	return set_phy_regs(phy, ael2020_reset_regs);
824 }
825 
826 /*
827  * Get link status for a 10GBASE-X device.
828  */
get_link_status_x(struct cphy * phy,int * link_ok,int * speed,int * duplex,int * fc)829 static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
830 			     int *duplex, int *fc)
831 {
832 	if (link_ok) {
833 		unsigned int stat0, stat1, stat2;
834 		int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD,
835 				       MDIO_PMA_RXDET, &stat0);
836 
837 		if (!err)
838 			err = t3_mdio_read(phy, MDIO_MMD_PCS,
839 					   MDIO_PCS_10GBX_STAT1, &stat1);
840 		if (!err)
841 			err = t3_mdio_read(phy, MDIO_MMD_PHYXS,
842 					   MDIO_PHYXS_LNSTAT, &stat2);
843 		if (err)
844 			return err;
845 		*link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1;
846 	}
847 	if (speed)
848 		*speed = SPEED_10000;
849 	if (duplex)
850 		*duplex = DUPLEX_FULL;
851 	return 0;
852 }
853 
854 static const struct cphy_ops qt2045_ops = {
855 	.reset = ael1006_reset,
856 	.intr_enable = t3_phy_lasi_intr_enable,
857 	.intr_disable = t3_phy_lasi_intr_disable,
858 	.intr_clear = t3_phy_lasi_intr_clear,
859 	.intr_handler = t3_phy_lasi_intr_handler,
860 	.get_link_status = get_link_status_x,
861 	.power_down = ael1002_power_down,
862 	.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
863 };
864 
t3_qt2045_phy_prep(struct cphy * phy,struct adapter * adapter,int phy_addr,const struct mdio_ops * mdio_ops)865 int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
866 		       int phy_addr, const struct mdio_ops *mdio_ops)
867 {
868 	unsigned int stat;
869 
870 	cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops,
871 		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
872 		  "10GBASE-CX4");
873 
874 	/*
875 	 * Some cards where the PHY is supposed to be at address 0 actually
876 	 * have it at 1.
877 	 */
878 	if (!phy_addr &&
879 	    !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) &&
880 	    stat == 0xffff)
881 		phy->mdio.prtad = 1;
882 	return 0;
883 }
884 
xaui_direct_reset(struct cphy * phy,int wait)885 static int xaui_direct_reset(struct cphy *phy, int wait)
886 {
887 	return 0;
888 }
889 
xaui_direct_get_link_status(struct cphy * phy,int * link_ok,int * speed,int * duplex,int * fc)890 static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
891 				       int *speed, int *duplex, int *fc)
892 {
893 	if (link_ok) {
894 		unsigned int status;
895 		int prtad = phy->mdio.prtad;
896 
897 		status = t3_read_reg(phy->adapter,
898 				     XGM_REG(A_XGM_SERDES_STAT0, prtad)) |
899 		    t3_read_reg(phy->adapter,
900 				    XGM_REG(A_XGM_SERDES_STAT1, prtad)) |
901 		    t3_read_reg(phy->adapter,
902 				XGM_REG(A_XGM_SERDES_STAT2, prtad)) |
903 		    t3_read_reg(phy->adapter,
904 				XGM_REG(A_XGM_SERDES_STAT3, prtad));
905 		*link_ok = !(status & F_LOWSIG0);
906 	}
907 	if (speed)
908 		*speed = SPEED_10000;
909 	if (duplex)
910 		*duplex = DUPLEX_FULL;
911 	return 0;
912 }
913 
xaui_direct_power_down(struct cphy * phy,int enable)914 static int xaui_direct_power_down(struct cphy *phy, int enable)
915 {
916 	return 0;
917 }
918 
919 static const struct cphy_ops xaui_direct_ops = {
920 	.reset = xaui_direct_reset,
921 	.intr_enable = ael1002_intr_noop,
922 	.intr_disable = ael1002_intr_noop,
923 	.intr_clear = ael1002_intr_noop,
924 	.intr_handler = ael1002_intr_noop,
925 	.get_link_status = xaui_direct_get_link_status,
926 	.power_down = xaui_direct_power_down,
927 };
928 
t3_xaui_direct_phy_prep(struct cphy * phy,struct adapter * adapter,int phy_addr,const struct mdio_ops * mdio_ops)929 int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
930 			    int phy_addr, const struct mdio_ops *mdio_ops)
931 {
932 	cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops,
933 		  SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP,
934 		  "10GBASE-CX4");
935 	return 0;
936 }
937