1 // SPDX-License-Identifier: GPL-2.0-only
2 /*****************************************************************************
6 * $Date: 2005/04/15 19:27:14 $ *
8 * Marvell PHY (mv88x201x) functionality. *
9 * part of the Chelsio 10Gb Ethernet Driver. *
12 * http://www.chelsio.com *
14 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *
15 * All rights reserved. *
17 * Maintainers: maintainers@chelsio.com *
19 * Authors: Dimitrios Michailidis <dm@chelsio.com> *
20 * Tina Yang <tainay@chelsio.com> *
21 * Felix Marti <felix@chelsio.com> *
22 * Scott Bardone <sbardone@chelsio.com> *
23 * Kurt Ottaway <kottaway@chelsio.com> *
24 * Frank DiMambro <frank@chelsio.com> *
28 ****************************************************************************/
34 * The 88x2010 Rev C. requires some link status registers * to be read
35 * twice in order to get the right values. Future * revisions will fix
36 * this problem and then this macro * can disappear.
38 #define MV88x2010_LINK_STATUS_BUGS 1
40 static int led_init(struct cphy
*cphy
)
42 /* Setup the LED registers so we can turn on/off.
43 * Writing these bits maps control to another
44 * register. mmd(0x1) addr(0x7)
46 cphy_mdio_write(cphy
, MDIO_MMD_PCS
, 0x8304, 0xdddd);
50 static int led_link(struct cphy
*cphy
, u32 do_enable
)
53 #define LINK_ENABLE_BIT 0x1
55 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_CTRL2
, &led
);
57 if (do_enable
& LINK_ENABLE_BIT
) {
58 led
|= LINK_ENABLE_BIT
;
59 cphy_mdio_write(cphy
, MDIO_MMD_PMAPMD
, MDIO_CTRL2
, led
);
61 led
&= ~LINK_ENABLE_BIT
;
62 cphy_mdio_write(cphy
, MDIO_MMD_PMAPMD
, MDIO_CTRL2
, led
);
68 static int mv88x201x_reset(struct cphy
*cphy
, int wait
)
70 /* This can be done through registers. It is not required since
71 * a full chip reset is used.
76 static int mv88x201x_interrupt_enable(struct cphy
*cphy
)
78 /* Enable PHY LASI interrupts. */
79 cphy_mdio_write(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_CTRL
,
80 MDIO_PMA_LASI_LSALARM
);
82 /* Enable Marvell interrupts through Elmer0. */
83 if (t1_is_asic(cphy
->adapter
)) {
86 t1_tpi_read(cphy
->adapter
, A_ELMER0_INT_ENABLE
, &elmer
);
87 elmer
|= ELMER0_GP_BIT6
;
88 t1_tpi_write(cphy
->adapter
, A_ELMER0_INT_ENABLE
, elmer
);
93 static int mv88x201x_interrupt_disable(struct cphy
*cphy
)
95 /* Disable PHY LASI interrupts. */
96 cphy_mdio_write(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_CTRL
, 0x0);
98 /* Disable Marvell interrupts through Elmer0. */
99 if (t1_is_asic(cphy
->adapter
)) {
102 t1_tpi_read(cphy
->adapter
, A_ELMER0_INT_ENABLE
, &elmer
);
103 elmer
&= ~ELMER0_GP_BIT6
;
104 t1_tpi_write(cphy
->adapter
, A_ELMER0_INT_ENABLE
, elmer
);
109 static int mv88x201x_interrupt_clear(struct cphy
*cphy
)
114 #ifdef MV88x2010_LINK_STATUS_BUGS
115 /* Required to read twice before clear takes affect. */
116 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_RXSTAT
, &val
);
117 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_TXSTAT
, &val
);
118 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_STAT
, &val
);
120 /* Read this register after the others above it else
121 * the register doesn't clear correctly.
123 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_STAT1
, &val
);
126 /* Clear link status. */
127 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_STAT1
, &val
);
128 /* Clear PHY LASI interrupts. */
129 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_STAT
, &val
);
131 #ifdef MV88x2010_LINK_STATUS_BUGS
133 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_RXSTAT
, &val
);
134 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_PMA_LASI_TXSTAT
, &val
);
137 /* Clear Marvell interrupts through Elmer0. */
138 if (t1_is_asic(cphy
->adapter
)) {
139 t1_tpi_read(cphy
->adapter
, A_ELMER0_INT_CAUSE
, &elmer
);
140 elmer
|= ELMER0_GP_BIT6
;
141 t1_tpi_write(cphy
->adapter
, A_ELMER0_INT_CAUSE
, elmer
);
146 static int mv88x201x_interrupt_handler(struct cphy
*cphy
)
148 /* Clear interrupts */
149 mv88x201x_interrupt_clear(cphy
);
151 /* We have only enabled link change interrupts and so
152 * cphy_cause must be a link change interrupt.
154 return cphy_cause_link_change
;
157 static int mv88x201x_set_loopback(struct cphy
*cphy
, int on
)
162 static int mv88x201x_get_link_status(struct cphy
*cphy
, int *link_ok
,
163 int *speed
, int *duplex
, int *fc
)
168 /* Read link status. */
169 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_STAT1
, &val
);
170 val
&= MDIO_STAT1_LSTATUS
;
171 *link_ok
= (val
== MDIO_STAT1_LSTATUS
);
172 /* Turn on/off Link LED */
173 led_link(cphy
, *link_ok
);
176 *speed
= SPEED_10000
;
178 *duplex
= DUPLEX_FULL
;
180 *fc
= PAUSE_RX
| PAUSE_TX
;
184 static void mv88x201x_destroy(struct cphy
*cphy
)
189 static const struct cphy_ops mv88x201x_ops
= {
190 .destroy
= mv88x201x_destroy
,
191 .reset
= mv88x201x_reset
,
192 .interrupt_enable
= mv88x201x_interrupt_enable
,
193 .interrupt_disable
= mv88x201x_interrupt_disable
,
194 .interrupt_clear
= mv88x201x_interrupt_clear
,
195 .interrupt_handler
= mv88x201x_interrupt_handler
,
196 .get_link_status
= mv88x201x_get_link_status
,
197 .set_loopback
= mv88x201x_set_loopback
,
198 .mmds
= (MDIO_DEVS_PMAPMD
| MDIO_DEVS_PCS
|
199 MDIO_DEVS_PHYXS
| MDIO_DEVS_WIS
),
202 static struct cphy
*mv88x201x_phy_create(struct net_device
*dev
, int phy_addr
,
203 const struct mdio_ops
*mdio_ops
)
206 struct cphy
*cphy
= kzalloc(sizeof(*cphy
), GFP_KERNEL
);
211 cphy_init(cphy
, dev
, phy_addr
, &mv88x201x_ops
, mdio_ops
);
213 /* Commands the PHY to enable XFP's clock. */
214 cphy_mdio_read(cphy
, MDIO_MMD_PCS
, 0x8300, &val
);
215 cphy_mdio_write(cphy
, MDIO_MMD_PCS
, 0x8300, val
| 1);
217 /* Clear link status. Required because of a bug in the PHY. */
218 cphy_mdio_read(cphy
, MDIO_MMD_PMAPMD
, MDIO_STAT2
, &val
);
219 cphy_mdio_read(cphy
, MDIO_MMD_PCS
, MDIO_STAT2
, &val
);
221 /* Allows for Link,Ack LED turn on/off */
227 static int mv88x201x_phy_reset(adapter_t
*adapter
)
231 t1_tpi_read(adapter
, A_ELMER0_GPO
, &val
);
233 t1_tpi_write(adapter
, A_ELMER0_GPO
, val
);
236 t1_tpi_write(adapter
, A_ELMER0_GPO
, val
| 4);
239 /* Now lets enable the Laser. Delay 100us */
240 t1_tpi_read(adapter
, A_ELMER0_GPO
, &val
);
242 t1_tpi_write(adapter
, A_ELMER0_GPO
, val
);
247 const struct gphy t1_mv88x201x_ops
= {
248 .create
= mv88x201x_phy_create
,
249 .reset
= mv88x201x_phy_reset