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
35enum {
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
60enum { edc_none, edc_sr, edc_twinax };
61
62/* PHY module I2C device address */
63enum {
64	MODULE_DEV_ADDR	= 0xa0,
65	SFF_DEV_ADDR	= 0xa2,
66};
67
68/* PHY transceiver type */
69enum {
70	phy_transtype_unknown = 0,
71	phy_transtype_sfp     = 3,
72	phy_transtype_xfp     = 6,
73};
74
75#define AEL2005_MODDET_IRQ 4
76
77struct reg_val {
78	unsigned short mmd_addr;
79	unsigned short reg_addr;
80	unsigned short clear_bits;
81	unsigned short set_bits;
82};
83
84static 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
100static 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 */
113static 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
141static 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
153static 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
168static int ael1002_intr_noop(struct cphy *phy)
169{
170	return 0;
171}
172
173/*
174 * Get link status for a 10GBASE-R device.
175 */
176static 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
201static 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
212int 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
222static int ael1006_reset(struct cphy *phy, int wait)
223{
224	return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
225}
226
227static 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
238int 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 */
251static 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	}
286unknown:
287	return phy_modtype_unknown;
288}
289
290/*
291 * Code to support the Aeluros/NetLogic 2005 10Gb PHY.
292 */
293static 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
325static 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
361static 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
376static 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
382static 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
388static 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
394static 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
454static 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
498static 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
509int 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 */
523static 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 */
551static 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 */
604static 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 */
625static 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 */
665static 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 */
692static 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
704static 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 */
722static 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 */
765static 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
804static 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
815int 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 */
829static 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
854static 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
865int 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
885static int xaui_direct_reset(struct cphy *phy, int wait)
886{
887	return 0;
888}
889
890static 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
914static int xaui_direct_power_down(struct cphy *phy, int enable)
915{
916	return 0;
917}
918
919static 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
929int 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