2 * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
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,
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) */
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 */
60 enum { edc_none
, edc_sr
, edc_twinax
};
62 /* PHY module I2C device address */
64 MODULE_DEV_ADDR
= 0xa0,
68 /* PHY transceiver type */
70 phy_transtype_unknown
= 0,
71 phy_transtype_sfp
= 3,
72 phy_transtype_xfp
= 6,
75 #define AEL2005_MODDET_IRQ 4
78 unsigned short mmd_addr
;
79 unsigned short reg_addr
;
80 unsigned short clear_bits
;
81 unsigned short set_bits
;
84 static int set_phy_regs(struct cphy
*phy
, const struct reg_val
*rv
)
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
,
93 err
= t3_mdio_change_bits(phy
, rv
->mmd_addr
,
94 rv
->reg_addr
, rv
->clear_bits
,
100 static void ael100x_txon(struct cphy
*phy
)
103 phy
->mdio
.prtad
== 0 ? F_GPIO7_OUT_VAL
: F_GPIO2_OUT_VAL
;
106 t3_set_reg_field(phy
->adapter
, A_T3DBG_GPIO_EN
, 0, tx_on_gpio
);
111 * Read an 8-bit word from a device attached to the PHY's i2c bus.
113 static int ael_i2c_rd(struct cphy
*phy
, int dev_addr
, int word_addr
)
116 unsigned int stat
, data
;
118 err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
, AEL_I2C_CTRL
,
119 (dev_addr
<< 8) | (1 << 8) | word_addr
);
123 for (i
= 0; i
< 200; i
++) {
125 err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL_I2C_STAT
, &stat
);
128 if ((stat
& 3) == 1) {
129 err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL_I2C_DATA
,
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
);
141 static int ael1002_power_down(struct cphy
*phy
, int enable
)
145 err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
, MDIO_PMA_TXDIS
, !!enable
);
147 err
= mdio_set_flag(&phy
->mdio
, phy
->mdio
.prtad
,
148 MDIO_MMD_PMAPMD
, MDIO_CTRL1
,
149 MDIO_CTRL1_LPOWER
, enable
);
153 static int ael1002_reset(struct cphy
*phy
, int wait
)
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
,
168 static int ael1002_intr_noop(struct cphy
*phy
)
174 * Get link status for a 10GBASE-R device.
176 static int get_link_status_r(struct cphy
*phy
, int *link_ok
, int *speed
,
177 int *duplex
, int *fc
)
180 unsigned int stat0
, stat1
, stat2
;
181 int err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
,
182 MDIO_PMA_RXDET
, &stat0
);
185 err
= t3_mdio_read(phy
, MDIO_MMD_PCS
,
186 MDIO_PCS_10GBRT_STAT1
, &stat1
);
188 err
= t3_mdio_read(phy
, MDIO_MMD_PHYXS
,
189 MDIO_PHYXS_LNSTAT
, &stat2
);
192 *link_ok
= (stat0
& stat1
& (stat2
>> 12)) & 1;
195 *speed
= SPEED_10000
;
197 *duplex
= DUPLEX_FULL
;
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
,
212 int t3_ael1002_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
213 int phy_addr
, const struct mdio_ops
*mdio_ops
)
215 cphy_init(phy
, adapter
, phy_addr
, &ael1002_ops
, mdio_ops
,
216 SUPPORTED_10000baseT_Full
| SUPPORTED_AUI
| SUPPORTED_FIBRE
,
222 static int ael1006_reset(struct cphy
*phy
, int wait
)
224 return t3_phy_reset(phy
, MDIO_MMD_PMAPMD
, wait
);
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
,
238 int t3_ael1006_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
239 int phy_addr
, const struct mdio_ops
*mdio_ops
)
241 cphy_init(phy
, adapter
, phy_addr
, &ael1006_ops
, mdio_ops
,
242 SUPPORTED_10000baseT_Full
| SUPPORTED_AUI
| SUPPORTED_FIBRE
,
249 * Decode our module type.
251 static int ael2xxx_get_module_type(struct cphy
*phy
, int delay_ms
)
258 /* see SFF-8472 for below */
259 v
= ael_i2c_rd(phy
, MODULE_DEV_ADDR
, 3);
264 return phy_modtype_sr
;
266 return phy_modtype_lr
;
268 return phy_modtype_lrm
;
270 v
= ael_i2c_rd(phy
, MODULE_DEV_ADDR
, 6);
276 v
= ael_i2c_rd(phy
, MODULE_DEV_ADDR
, 10);
281 v
= ael_i2c_rd(phy
, MODULE_DEV_ADDR
, 0x12);
284 return v
> 10 ? phy_modtype_twinax_long
: phy_modtype_twinax
;
287 return phy_modtype_unknown
;
291 * Code to support the Aeluros/NetLogic 2005 10Gb PHY.
293 static int ael2005_setup_sr_edc(struct cphy
*phy
)
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 },
304 err
= set_phy_regs(phy
, regs
);
310 if (phy
->priv
!= edc_sr
)
311 err
= t3_get_edc_fw(phy
, EDC_OPT_AEL2005
,
312 EDC_OPT_AEL2005_SIZE
);
316 for (i
= 0; i
< EDC_OPT_AEL2005_SIZE
/ sizeof(u16
) && !err
; i
+= 2)
317 err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
,
319 phy
->phy_cache
[i
+ 1]);
325 static int ael2005_setup_twinax_edc(struct cphy
*phy
, int modtype
)
327 static const struct reg_val regs
[] = {
328 { MDIO_MMD_PMAPMD
, 0xc04a, 0xffff, 0x5a00 },
331 static const struct reg_val preemphasis
[] = {
332 { MDIO_MMD_PMAPMD
, 0xc014, 0xffff, 0xfe16 },
333 { MDIO_MMD_PMAPMD
, 0xc015, 0xffff, 0xa000 },
338 err
= set_phy_regs(phy
, regs
);
339 if (!err
&& modtype
== phy_modtype_twinax_long
)
340 err
= set_phy_regs(phy
, preemphasis
);
346 if (phy
->priv
!= edc_twinax
)
347 err
= t3_get_edc_fw(phy
, EDC_TWX_AEL2005
,
348 EDC_TWX_AEL2005_SIZE
);
352 for (i
= 0; i
< EDC_TWX_AEL2005_SIZE
/ sizeof(u16
) && !err
; i
+= 2)
353 err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
,
355 phy
->phy_cache
[i
+ 1]);
357 phy
->priv
= edc_twinax
;
361 static int ael2005_get_module_type(struct cphy
*phy
, int delay_ms
)
366 v
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL2005_GPIO_CTRL
, &stat
);
370 if (stat
& (1 << 8)) /* module absent */
371 return phy_modtype_none
;
373 return ael2xxx_get_module_type(phy
, delay_ms
);
376 static int ael2005_intr_enable(struct cphy
*phy
)
378 int err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
, AEL2005_GPIO_CTRL
, 0x200);
379 return err
? err
: t3_phy_lasi_intr_enable(phy
);
382 static int ael2005_intr_disable(struct cphy
*phy
)
384 int err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
, AEL2005_GPIO_CTRL
, 0x100);
385 return err
? err
: t3_phy_lasi_intr_disable(phy
);
388 static int ael2005_intr_clear(struct cphy
*phy
)
390 int err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
, AEL2005_GPIO_CTRL
, 0xd00);
391 return err
? err
: t3_phy_lasi_intr_clear(phy
);
394 static int ael2005_reset(struct cphy
*phy
, int wait
)
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 },
406 static const struct reg_val regs1
[] = {
407 { MDIO_MMD_PMAPMD
, 0xca00, 0xffff, 0x0080 },
408 { MDIO_MMD_PMAPMD
, 0xca12, 0xffff, 0 },
413 unsigned int lasi_ctrl
;
415 err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_CTRL
,
420 err
= t3_phy_reset(phy
, MDIO_MMD_PMAPMD
, 0);
425 phy
->priv
= edc_none
;
426 err
= set_phy_regs(phy
, regs0
);
432 err
= ael2005_get_module_type(phy
, 0);
437 if (err
== phy_modtype_twinax
|| err
== phy_modtype_twinax_long
)
438 err
= ael2005_setup_twinax_edc(phy
, err
);
440 err
= ael2005_setup_sr_edc(phy
);
444 err
= set_phy_regs(phy
, regs1
);
448 /* reset wipes out interrupts, reenable them if they were on */
450 err
= ael2005_intr_enable(phy
);
454 static int ael2005_intr_handler(struct cphy
*phy
)
457 int ret
, edc_needed
, cause
= 0;
459 ret
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL2005_GPIO_STAT
, &stat
);
463 if (stat
& AEL2005_MODDET_IRQ
) {
464 ret
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
, AEL2005_GPIO_CTRL
,
469 /* modules have max 300 ms init time after hot plug */
470 ret
= ael2005_get_module_type(phy
, 300);
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
;
483 if (edc_needed
!= phy
->priv
) {
484 ret
= ael2005_reset(phy
, 0);
485 return ret
? ret
: cphy_cause_module_change
;
487 cause
= cphy_cause_module_change
;
490 ret
= t3_phy_lasi_intr_handler(phy
);
495 return ret
? ret
: cphy_cause_link_change
;
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
,
509 int t3_ael2005_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
510 int phy_addr
, const struct mdio_ops
*mdio_ops
)
512 cphy_init(phy
, adapter
, phy_addr
, &ael2005_ops
, mdio_ops
,
513 SUPPORTED_10000baseT_Full
| SUPPORTED_AUI
| SUPPORTED_FIBRE
|
514 SUPPORTED_IRQ
, "10GBASE-R");
516 return t3_mdio_change_bits(phy
, MDIO_MMD_PMAPMD
, AEL_OPT_SETTINGS
, 0,
521 * Setup EDC and other parameters for operation with an optical module.
523 static int ael2020_setup_sr_edc(struct cphy
*phy
)
525 static const struct reg_val regs
[] = {
526 /* set CDR offset to 10 */
527 { MDIO_MMD_PMAPMD
, 0xcc01, 0xffff, 0x488a },
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 },
539 err
= set_phy_regs(phy
, regs
);
549 * Setup EDC and other parameters for operation with an TWINAX module.
551 static int ael2020_setup_twinax_edc(struct cphy
*phy
, int modtype
)
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 },
560 /* activate uC clock */
561 static const struct reg_val uCclockActivate
[] = {
562 { MDIO_MMD_PMAPMD
, 0xd000, 0xffff, 0x5200 },
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 },
574 /* set uC clock and activate it */
575 err
= set_phy_regs(phy
, uCclock40MHz
);
579 err
= set_phy_regs(phy
, uCclockActivate
);
584 if (phy
->priv
!= edc_twinax
)
585 err
= t3_get_edc_fw(phy
, EDC_TWX_AEL2020
,
586 EDC_TWX_AEL2020_SIZE
);
590 for (i
= 0; i
< EDC_TWX_AEL2020_SIZE
/ sizeof(u16
) && !err
; i
+= 2)
591 err
= t3_mdio_write(phy
, MDIO_MMD_PMAPMD
,
593 phy
->phy_cache
[i
+ 1]);
595 err
= set_phy_regs(phy
, uCactivate
);
597 phy
->priv
= edc_twinax
;
602 * Return Module Type.
604 static int ael2020_get_module_type(struct cphy
*phy
, int delay_ms
)
609 v
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL2020_GPIO_STAT
, &stat
);
613 if (stat
& (0x1 << (AEL2020_GPIO_MODDET
*4))) {
615 return phy_modtype_none
;
618 return ael2xxx_get_module_type(phy
, delay_ms
);
622 * Enable PHY interrupts. We enable "Module Detection" interrupts (on any
623 * state transition) and then generic Link Alarm Status Interrupt (LASI).
625 static int ael2020_intr_enable(struct cphy
*phy
)
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
,
631 { MDIO_MMD_PMAPMD
, AEL2020_GPIO_CTRL
,
632 0xffff, 0x8 << (AEL2020_GPIO_LSTAT
*4) },
634 /* enable module detect status change interrupts */
635 { MDIO_MMD_PMAPMD
, AEL2020_GPIO_CTRL
,
636 0xffff, 0x2 << (AEL2020_GPIO_MODDET
*4) },
641 int err
, link_ok
= 0;
643 /* set up "link status" LED and enable module change interrupts */
644 err
= set_phy_regs(phy
, regs
);
648 err
= get_link_status_r(phy
, &link_ok
, NULL
, NULL
, NULL
);
652 t3_link_changed(phy
->adapter
,
655 err
= t3_phy_lasi_intr_enable(phy
);
663 * Disable PHY interrupts. The mirror of the above ...
665 static int ael2020_intr_disable(struct cphy
*phy
)
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) },
672 /* disable module detect status change interrupts */
673 { MDIO_MMD_PMAPMD
, AEL2020_GPIO_CTRL
,
674 0xffff, 0x1 << (AEL2020_GPIO_MODDET
*4) },
681 /* turn off "link status" LED and disable module change interrupts */
682 err
= set_phy_regs(phy
, regs
);
686 return t3_phy_lasi_intr_disable(phy
);
690 * Clear PHY interrupt state.
692 static int ael2020_intr_clear(struct cphy
*phy
)
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.
700 int err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL2020_GPIO_INTR
, &stat
);
701 return err
? err
: t3_phy_lasi_intr_clear(phy
);
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 },
708 /* force XAUI to send LF when RX_LOS is asserted */
709 { MDIO_MMD_PMAPMD
, 0xcd40, 0xffff, 0x0001 },
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 },
720 * Reset the PHY and put it into a canonical operating state.
722 static int ael2020_reset(struct cphy
*phy
, int wait
)
725 unsigned int lasi_ctrl
;
727 /* grab current interrupt state */
728 err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_CTRL
,
733 err
= t3_phy_reset(phy
, MDIO_MMD_PMAPMD
, 125);
738 /* basic initialization for all module types */
739 phy
->priv
= edc_none
;
740 err
= set_phy_regs(phy
, ael2020_reset_regs
);
744 /* determine module type and perform appropriate initialization */
745 err
= ael2020_get_module_type(phy
, 0);
748 phy
->modtype
= (u8
)err
;
749 if (err
== phy_modtype_twinax
|| err
== phy_modtype_twinax_long
)
750 err
= ael2020_setup_twinax_edc(phy
, err
);
752 err
= ael2020_setup_sr_edc(phy
);
756 /* reset wipes out interrupts, reenable them if they were on */
758 err
= ael2005_intr_enable(phy
);
763 * Handle a PHY interrupt.
765 static int ael2020_intr_handler(struct cphy
*phy
)
768 int ret
, edc_needed
, cause
= 0;
770 ret
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, AEL2020_GPIO_INTR
, &stat
);
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);
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
;
789 if (edc_needed
!= phy
->priv
) {
790 ret
= ael2020_reset(phy
, 0);
791 return ret
? ret
: cphy_cause_module_change
;
793 cause
= cphy_cause_module_change
;
796 ret
= t3_phy_lasi_intr_handler(phy
);
801 return ret
? ret
: cphy_cause_link_change
;
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
,
815 int t3_ael2020_phy_prep(struct cphy
*phy
, struct adapter
*adapter
, int phy_addr
,
816 const struct mdio_ops
*mdio_ops
)
820 cphy_init(phy
, adapter
, phy_addr
, &ael2020_ops
, mdio_ops
,
821 SUPPORTED_10000baseT_Full
| SUPPORTED_AUI
| SUPPORTED_FIBRE
|
822 SUPPORTED_IRQ
, "10GBASE-R");
825 err
= set_phy_regs(phy
, ael2020_reset_regs
);
832 * Get link status for a 10GBASE-X device.
834 static int get_link_status_x(struct cphy
*phy
, int *link_ok
, int *speed
,
835 int *duplex
, int *fc
)
838 unsigned int stat0
, stat1
, stat2
;
839 int err
= t3_mdio_read(phy
, MDIO_MMD_PMAPMD
,
840 MDIO_PMA_RXDET
, &stat0
);
843 err
= t3_mdio_read(phy
, MDIO_MMD_PCS
,
844 MDIO_PCS_10GBX_STAT1
, &stat1
);
846 err
= t3_mdio_read(phy
, MDIO_MMD_PHYXS
,
847 MDIO_PHYXS_LNSTAT
, &stat2
);
850 *link_ok
= (stat0
& (stat1
>> 12) & (stat2
>> 12)) & 1;
853 *speed
= SPEED_10000
;
855 *duplex
= DUPLEX_FULL
;
859 static const struct cphy_ops qt2045_ops
= {
860 .reset
= ael1006_reset
,
861 .intr_enable
= t3_phy_lasi_intr_enable
,
862 .intr_disable
= t3_phy_lasi_intr_disable
,
863 .intr_clear
= t3_phy_lasi_intr_clear
,
864 .intr_handler
= t3_phy_lasi_intr_handler
,
865 .get_link_status
= get_link_status_x
,
866 .power_down
= ael1002_power_down
,
867 .mmds
= MDIO_DEVS_PMAPMD
| MDIO_DEVS_PCS
| MDIO_DEVS_PHYXS
,
870 int t3_qt2045_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
871 int phy_addr
, const struct mdio_ops
*mdio_ops
)
875 cphy_init(phy
, adapter
, phy_addr
, &qt2045_ops
, mdio_ops
,
876 SUPPORTED_10000baseT_Full
| SUPPORTED_AUI
| SUPPORTED_TP
,
880 * Some cards where the PHY is supposed to be at address 0 actually
884 !t3_mdio_read(phy
, MDIO_MMD_PMAPMD
, MDIO_STAT1
, &stat
) &&
890 static int xaui_direct_reset(struct cphy
*phy
, int wait
)
895 static int xaui_direct_get_link_status(struct cphy
*phy
, int *link_ok
,
896 int *speed
, int *duplex
, int *fc
)
900 int prtad
= phy
->mdio
.prtad
;
902 status
= t3_read_reg(phy
->adapter
,
903 XGM_REG(A_XGM_SERDES_STAT0
, prtad
)) |
904 t3_read_reg(phy
->adapter
,
905 XGM_REG(A_XGM_SERDES_STAT1
, prtad
)) |
906 t3_read_reg(phy
->adapter
,
907 XGM_REG(A_XGM_SERDES_STAT2
, prtad
)) |
908 t3_read_reg(phy
->adapter
,
909 XGM_REG(A_XGM_SERDES_STAT3
, prtad
));
910 *link_ok
= !(status
& F_LOWSIG0
);
913 *speed
= SPEED_10000
;
915 *duplex
= DUPLEX_FULL
;
919 static int xaui_direct_power_down(struct cphy
*phy
, int enable
)
924 static const struct cphy_ops xaui_direct_ops
= {
925 .reset
= xaui_direct_reset
,
926 .intr_enable
= ael1002_intr_noop
,
927 .intr_disable
= ael1002_intr_noop
,
928 .intr_clear
= ael1002_intr_noop
,
929 .intr_handler
= ael1002_intr_noop
,
930 .get_link_status
= xaui_direct_get_link_status
,
931 .power_down
= xaui_direct_power_down
,
934 int t3_xaui_direct_phy_prep(struct cphy
*phy
, struct adapter
*adapter
,
935 int phy_addr
, const struct mdio_ops
*mdio_ops
)
937 cphy_init(phy
, adapter
, phy_addr
, &xaui_direct_ops
, mdio_ops
,
938 SUPPORTED_10000baseT_Full
| SUPPORTED_AUI
| SUPPORTED_TP
,