xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/serdes.c (revision 6600d8e5)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Marvell 88E6xxx SERDES manipulation, via SMI bus
4  *
5  * Copyright (c) 2008 Marvell Semiconductor
6  *
7  * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
8  */
9 
10 #include <linux/interrupt.h>
11 #include <linux/irqdomain.h>
12 #include <linux/mii.h>
13 
14 #include "chip.h"
15 #include "global2.h"
16 #include "phy.h"
17 #include "port.h"
18 #include "serdes.h"
19 
20 static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
21 				 u16 *val)
22 {
23 	return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
24 				       MV88E6352_SERDES_PAGE_FIBER,
25 				       reg, val);
26 }
27 
28 static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
29 				  u16 val)
30 {
31 	return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
32 					MV88E6352_SERDES_PAGE_FIBER,
33 					reg, val);
34 }
35 
36 static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
37 				 int lane, int device, int reg, u16 *val)
38 {
39 	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
40 
41 	return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
42 }
43 
44 static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
45 				  int lane, int device, int reg, u16 val)
46 {
47 	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
48 
49 	return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
50 }
51 
52 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
53 {
54 	u16 val, new_val;
55 	int err;
56 
57 	if (!mv88e6xxx_serdes_get_lane(chip, port))
58 		return 0;
59 
60 	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
61 	if (err)
62 		return err;
63 
64 	if (on)
65 		new_val = val & ~BMCR_PDOWN;
66 	else
67 		new_val = val | BMCR_PDOWN;
68 
69 	if (val != new_val)
70 		err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
71 
72 	return err;
73 }
74 
75 u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
76 {
77 	u8 cmode = chip->ports[port].cmode;
78 	u8 lane = 0;
79 
80 	if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
81 	    (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
82 	    (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
83 		lane = 0xff; /* Unused */
84 
85 	return lane;
86 }
87 
88 static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
89 {
90 	if (mv88e6xxx_serdes_get_lane(chip, port))
91 		return true;
92 
93 	return false;
94 }
95 
96 struct mv88e6352_serdes_hw_stat {
97 	char string[ETH_GSTRING_LEN];
98 	int sizeof_stat;
99 	int reg;
100 };
101 
102 static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
103 	{ "serdes_fibre_rx_error", 16, 21 },
104 	{ "serdes_PRBS_error", 32, 24 },
105 };
106 
107 int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
108 {
109 	if (mv88e6352_port_has_serdes(chip, port))
110 		return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
111 
112 	return 0;
113 }
114 
115 int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
116 				 int port, uint8_t *data)
117 {
118 	struct mv88e6352_serdes_hw_stat *stat;
119 	int i;
120 
121 	if (!mv88e6352_port_has_serdes(chip, port))
122 		return 0;
123 
124 	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
125 		stat = &mv88e6352_serdes_hw_stats[i];
126 		memcpy(data + i * ETH_GSTRING_LEN, stat->string,
127 		       ETH_GSTRING_LEN);
128 	}
129 	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
130 }
131 
132 static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
133 					  struct mv88e6352_serdes_hw_stat *stat)
134 {
135 	u64 val = 0;
136 	u16 reg;
137 	int err;
138 
139 	err = mv88e6352_serdes_read(chip, stat->reg, &reg);
140 	if (err) {
141 		dev_err(chip->dev, "failed to read statistic\n");
142 		return 0;
143 	}
144 
145 	val = reg;
146 
147 	if (stat->sizeof_stat == 32) {
148 		err = mv88e6352_serdes_read(chip, stat->reg + 1, &reg);
149 		if (err) {
150 			dev_err(chip->dev, "failed to read statistic\n");
151 			return 0;
152 		}
153 		val = val << 16 | reg;
154 	}
155 
156 	return val;
157 }
158 
159 int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
160 			       uint64_t *data)
161 {
162 	struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
163 	struct mv88e6352_serdes_hw_stat *stat;
164 	u64 value;
165 	int i;
166 
167 	if (!mv88e6352_port_has_serdes(chip, port))
168 		return 0;
169 
170 	BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
171 		     ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
172 
173 	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
174 		stat = &mv88e6352_serdes_hw_stats[i];
175 		value = mv88e6352_serdes_get_stat(chip, stat);
176 		mv88e6xxx_port->serdes_stats[i] += value;
177 		data[i] = mv88e6xxx_port->serdes_stats[i];
178 	}
179 
180 	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
181 }
182 
183 static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
184 {
185 	struct dsa_switch *ds = chip->ds;
186 	u16 status;
187 	bool up;
188 	int err;
189 
190 	err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
191 	if (err)
192 		return;
193 
194 	/* Status must be read twice in order to give the current link
195 	 * status. Otherwise the change in link status since the last
196 	 * read of the register is returned.
197 	 */
198 	err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
199 	if (err)
200 		return;
201 
202 	up = status & BMSR_LSTATUS;
203 
204 	dsa_port_phylink_mac_change(ds, port, up);
205 }
206 
207 static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
208 {
209 	struct mv88e6xxx_port *port = dev_id;
210 	struct mv88e6xxx_chip *chip = port->chip;
211 	irqreturn_t ret = IRQ_NONE;
212 	u16 status;
213 	int err;
214 
215 	mv88e6xxx_reg_lock(chip);
216 
217 	err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
218 	if (err)
219 		goto out;
220 
221 	if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
222 		ret = IRQ_HANDLED;
223 		mv88e6352_serdes_irq_link(chip, port->port);
224 	}
225 out:
226 	mv88e6xxx_reg_unlock(chip);
227 
228 	return ret;
229 }
230 
231 static int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip)
232 {
233 	return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE,
234 				      MV88E6352_SERDES_INT_LINK_CHANGE);
235 }
236 
237 static int mv88e6352_serdes_irq_disable(struct mv88e6xxx_chip *chip)
238 {
239 	return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, 0);
240 }
241 
242 unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
243 {
244 	return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
245 }
246 
247 int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
248 {
249 	unsigned int irq;
250 	int err;
251 
252 	if (!mv88e6352_port_has_serdes(chip, port))
253 		return 0;
254 
255 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
256 	if (!irq)
257 		return 0;
258 
259 	chip->ports[port].serdes_irq = irq;
260 
261 	/* Requesting the IRQ will trigger irq callbacks. So we cannot
262 	 * hold the reg_lock.
263 	 */
264 	mv88e6xxx_reg_unlock(chip);
265 	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
266 				   mv88e6352_serdes_thread_fn,
267 				   IRQF_ONESHOT, "mv88e6xxx-serdes",
268 				   &chip->ports[port]);
269 	mv88e6xxx_reg_lock(chip);
270 
271 	if (err) {
272 		dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
273 			err);
274 		return err;
275 	}
276 
277 	return mv88e6352_serdes_irq_enable(chip);
278 }
279 
280 void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
281 {
282 	if (!mv88e6352_port_has_serdes(chip, port))
283 		return;
284 
285 	mv88e6352_serdes_irq_disable(chip);
286 
287 	/* Freeing the IRQ will trigger irq callbacks. So we cannot
288 	 * hold the reg_lock.
289 	 */
290 	mv88e6xxx_reg_unlock(chip);
291 	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
292 	mv88e6xxx_reg_lock(chip);
293 
294 	chip->ports[port].serdes_irq = 0;
295 }
296 
297 u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
298 {
299 	u8 cmode = chip->ports[port].cmode;
300 	u8 lane = 0;
301 
302 	switch (port) {
303 	case 5:
304 		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
305 		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
306 		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
307 			lane = MV88E6341_PORT5_LANE;
308 		break;
309 	}
310 
311 	return lane;
312 }
313 
314 u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
315 {
316 	u8 cmode = chip->ports[port].cmode;
317 	u8 lane = 0;
318 
319 	switch (port) {
320 	case 9:
321 		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
322 		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
323 		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
324 			lane = MV88E6390_PORT9_LANE0;
325 		break;
326 	case 10:
327 		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
328 		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
329 		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
330 			lane = MV88E6390_PORT10_LANE0;
331 		break;
332 	}
333 
334 	return lane;
335 }
336 
337 u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
338 {
339 	u8 cmode_port = chip->ports[port].cmode;
340 	u8 cmode_port10 = chip->ports[10].cmode;
341 	u8 cmode_port9 = chip->ports[9].cmode;
342 	u8 lane = 0;
343 
344 	switch (port) {
345 	case 2:
346 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
347 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
348 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
349 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
350 				lane = MV88E6390_PORT9_LANE1;
351 		break;
352 	case 3:
353 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
354 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
355 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
356 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
357 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
358 				lane = MV88E6390_PORT9_LANE2;
359 		break;
360 	case 4:
361 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
362 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
363 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
364 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
365 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
366 				lane = MV88E6390_PORT9_LANE3;
367 		break;
368 	case 5:
369 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
370 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
371 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
372 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
373 				lane = MV88E6390_PORT10_LANE1;
374 		break;
375 	case 6:
376 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
377 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
378 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
379 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
380 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
381 				lane = MV88E6390_PORT10_LANE2;
382 		break;
383 	case 7:
384 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
385 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
386 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
387 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
388 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
389 				lane = MV88E6390_PORT10_LANE3;
390 		break;
391 	case 9:
392 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
393 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
394 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
395 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
396 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
397 			lane = MV88E6390_PORT9_LANE0;
398 		break;
399 	case 10:
400 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
401 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
402 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
403 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
404 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
405 			lane = MV88E6390_PORT10_LANE0;
406 		break;
407 	}
408 
409 	return lane;
410 }
411 
412 /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
413 static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
414 				      bool on)
415 {
416 	u16 val, new_val;
417 	int err;
418 
419 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
420 				    MV88E6390_PCS_CONTROL_1, &val);
421 
422 	if (err)
423 		return err;
424 
425 	if (on)
426 		new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
427 				  MV88E6390_PCS_CONTROL_1_LOOPBACK |
428 				  MV88E6390_PCS_CONTROL_1_PDOWN);
429 	else
430 		new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
431 
432 	if (val != new_val)
433 		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
434 					     MV88E6390_PCS_CONTROL_1, new_val);
435 
436 	return err;
437 }
438 
439 /* Set the power on/off for SGMII and 1000Base-X */
440 static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
441 					bool on)
442 {
443 	u16 val, new_val;
444 	int err;
445 
446 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
447 				    MV88E6390_SGMII_CONTROL, &val);
448 	if (err)
449 		return err;
450 
451 	if (on)
452 		new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
453 				  MV88E6390_SGMII_CONTROL_LOOPBACK |
454 				  MV88E6390_SGMII_CONTROL_PDOWN);
455 	else
456 		new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
457 
458 	if (val != new_val)
459 		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
460 					     MV88E6390_SGMII_CONTROL, new_val);
461 
462 	return err;
463 }
464 
465 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
466 {
467 	u8 cmode = chip->ports[port].cmode;
468 	u8 lane;
469 
470 	lane = mv88e6xxx_serdes_get_lane(chip, port);
471 	if (!lane)
472 		return 0;
473 
474 	switch (cmode) {
475 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
476 	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
477 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
478 		return mv88e6390_serdes_power_sgmii(chip, lane, on);
479 	case MV88E6XXX_PORT_STS_CMODE_XAUI:
480 	case MV88E6XXX_PORT_STS_CMODE_RXAUI:
481 		return mv88e6390_serdes_power_10g(chip, lane, on);
482 	}
483 
484 	return 0;
485 }
486 
487 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
488 					    int port, u8 lane)
489 {
490 	u8 cmode = chip->ports[port].cmode;
491 	struct dsa_switch *ds = chip->ds;
492 	int duplex = DUPLEX_UNKNOWN;
493 	int speed = SPEED_UNKNOWN;
494 	phy_interface_t mode;
495 	int link, err;
496 	u16 status;
497 
498 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
499 				    MV88E6390_SGMII_PHY_STATUS, &status);
500 	if (err) {
501 		dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err);
502 		return;
503 	}
504 
505 	link = status & MV88E6390_SGMII_PHY_STATUS_LINK ?
506 	       LINK_FORCED_UP : LINK_FORCED_DOWN;
507 
508 	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
509 		duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
510 			 DUPLEX_FULL : DUPLEX_HALF;
511 
512 		switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
513 		case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
514 			if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
515 				speed = SPEED_2500;
516 			else
517 				speed = SPEED_1000;
518 			break;
519 		case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
520 			speed = SPEED_100;
521 			break;
522 		case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
523 			speed = SPEED_10;
524 			break;
525 		default:
526 			dev_err(chip->dev, "invalid PHY speed\n");
527 			return;
528 		}
529 	}
530 
531 	switch (cmode) {
532 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
533 		mode = PHY_INTERFACE_MODE_SGMII;
534 		break;
535 	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
536 		mode = PHY_INTERFACE_MODE_1000BASEX;
537 		break;
538 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
539 		mode = PHY_INTERFACE_MODE_2500BASEX;
540 		break;
541 	default:
542 		mode = PHY_INTERFACE_MODE_NA;
543 	}
544 
545 	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
546 				       PAUSE_OFF, mode);
547 	if (err)
548 		dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
549 			err);
550 	else
551 		dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP);
552 }
553 
554 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
555 					     u8 lane)
556 {
557 	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
558 				      MV88E6390_SGMII_INT_ENABLE,
559 				      MV88E6390_SGMII_INT_LINK_DOWN |
560 				      MV88E6390_SGMII_INT_LINK_UP);
561 }
562 
563 static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
564 					      u8 lane)
565 {
566 	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
567 				      MV88E6390_SGMII_INT_ENABLE, 0);
568 }
569 
570 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
571 				u8 lane)
572 {
573 	u8 cmode = chip->ports[port].cmode;
574 	int err = 0;
575 
576 	switch (cmode) {
577 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
578 	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
579 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
580 		err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
581 	}
582 
583 	return err;
584 }
585 
586 int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
587 				 u8 lane)
588 {
589 	u8 cmode = chip->ports[port].cmode;
590 	int err = 0;
591 
592 	switch (cmode) {
593 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
594 	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
595 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
596 		err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
597 	}
598 
599 	return err;
600 }
601 
602 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
603 					     u8 lane, u16 *status)
604 {
605 	int err;
606 
607 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
608 				    MV88E6390_SGMII_INT_STATUS, status);
609 
610 	return err;
611 }
612 
613 static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
614 {
615 	struct mv88e6xxx_port *port = dev_id;
616 	struct mv88e6xxx_chip *chip = port->chip;
617 	irqreturn_t ret = IRQ_NONE;
618 	u8 cmode = port->cmode;
619 	u16 status;
620 	int err;
621 	u8 lane;
622 
623 	mv88e6xxx_reg_lock(chip);
624 
625 	lane = mv88e6xxx_serdes_get_lane(chip, port->port);
626 	if (!lane)
627 		goto out;
628 
629 	switch (cmode) {
630 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
631 	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
632 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
633 		err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
634 		if (err)
635 			goto out;
636 		if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
637 			      MV88E6390_SGMII_INT_LINK_UP)) {
638 			ret = IRQ_HANDLED;
639 			mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane);
640 		}
641 	}
642 out:
643 	mv88e6xxx_reg_unlock(chip);
644 
645 	return ret;
646 }
647 
648 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
649 {
650 	return irq_find_mapping(chip->g2_irq.domain, port);
651 }
652 
653 int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
654 {
655 	unsigned int irq;
656 	int err;
657 	u8 lane;
658 
659 	lane = mv88e6xxx_serdes_get_lane(chip, port);
660 	if (!lane)
661 		return 0;
662 
663 	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
664 	if (!irq)
665 		return 0;
666 
667 	chip->ports[port].serdes_irq = irq;
668 
669 	/* Requesting the IRQ will trigger irq callbacks. So we cannot
670 	 * hold the reg_lock.
671 	 */
672 	mv88e6xxx_reg_unlock(chip);
673 	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
674 				   mv88e6390_serdes_thread_fn,
675 				   IRQF_ONESHOT, "mv88e6xxx-serdes",
676 				   &chip->ports[port]);
677 	mv88e6xxx_reg_lock(chip);
678 
679 	if (err) {
680 		dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
681 			err);
682 		return err;
683 	}
684 
685 	return mv88e6390_serdes_irq_enable(chip, port, lane);
686 }
687 
688 void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
689 {
690 	u8 lane;
691 
692 	lane = mv88e6xxx_serdes_get_lane(chip, port);
693 	if (!lane)
694 		return;
695 
696 	mv88e6390_serdes_irq_disable(chip, port, lane);
697 
698 	/* Freeing the IRQ will trigger irq callbacks. So we cannot
699 	 * hold the reg_lock.
700 	 */
701 	mv88e6xxx_reg_unlock(chip);
702 	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
703 	mv88e6xxx_reg_lock(chip);
704 
705 	chip->ports[port].serdes_irq = 0;
706 }
707