xref: /linux/drivers/net/dsa/mv88e6xxx/serdes.c (revision e9f0878c4b2004ac19581274c1ae4c61ae3ca70e)
1 /*
2  * Marvell 88E6xxx SERDES manipulation, via SMI bus
3  *
4  * Copyright (c) 2008 Marvell Semiconductor
5  *
6  * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include <linux/interrupt.h>
15 #include <linux/irqdomain.h>
16 #include <linux/mii.h>
17 
18 #include "chip.h"
19 #include "global2.h"
20 #include "phy.h"
21 #include "port.h"
22 #include "serdes.h"
23 
24 static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
25 				 u16 *val)
26 {
27 	return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
28 				       MV88E6352_SERDES_PAGE_FIBER,
29 				       reg, val);
30 }
31 
32 static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
33 				  u16 val)
34 {
35 	return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
36 					MV88E6352_SERDES_PAGE_FIBER,
37 					reg, val);
38 }
39 
40 static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
41 				 int lane, int device, int reg, u16 *val)
42 {
43 	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
44 
45 	return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
46 }
47 
48 static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
49 				  int lane, int device, int reg, u16 val)
50 {
51 	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
52 
53 	return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
54 }
55 
56 static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
57 {
58 	u16 val, new_val;
59 	int err;
60 
61 	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
62 	if (err)
63 		return err;
64 
65 	if (on)
66 		new_val = val & ~BMCR_PDOWN;
67 	else
68 		new_val = val | BMCR_PDOWN;
69 
70 	if (val != new_val)
71 		err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
72 
73 	return err;
74 }
75 
76 static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
77 {
78 	u8 cmode = chip->ports[port].cmode;
79 
80 	if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) ||
81 	    (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) ||
82 	    (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
83 		return true;
84 
85 	return false;
86 }
87 
88 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
89 {
90 	int err;
91 
92 	if (mv88e6352_port_has_serdes(chip, port)) {
93 		err = mv88e6352_serdes_power_set(chip, on);
94 		if (err < 0)
95 			return err;
96 	}
97 
98 	return 0;
99 }
100 
101 struct mv88e6352_serdes_hw_stat {
102 	char string[ETH_GSTRING_LEN];
103 	int sizeof_stat;
104 	int reg;
105 };
106 
107 static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
108 	{ "serdes_fibre_rx_error", 16, 21 },
109 	{ "serdes_PRBS_error", 32, 24 },
110 };
111 
112 int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
113 {
114 	if (mv88e6352_port_has_serdes(chip, port))
115 		return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
116 
117 	return 0;
118 }
119 
120 int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
121 				 int port, uint8_t *data)
122 {
123 	struct mv88e6352_serdes_hw_stat *stat;
124 	int i;
125 
126 	if (!mv88e6352_port_has_serdes(chip, port))
127 		return 0;
128 
129 	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
130 		stat = &mv88e6352_serdes_hw_stats[i];
131 		memcpy(data + i * ETH_GSTRING_LEN, stat->string,
132 		       ETH_GSTRING_LEN);
133 	}
134 	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
135 }
136 
137 static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
138 					  struct mv88e6352_serdes_hw_stat *stat)
139 {
140 	u64 val = 0;
141 	u16 reg;
142 	int err;
143 
144 	err = mv88e6352_serdes_read(chip, stat->reg, &reg);
145 	if (err) {
146 		dev_err(chip->dev, "failed to read statistic\n");
147 		return 0;
148 	}
149 
150 	val = reg;
151 
152 	if (stat->sizeof_stat == 32) {
153 		err = mv88e6352_serdes_read(chip, stat->reg + 1, &reg);
154 		if (err) {
155 			dev_err(chip->dev, "failed to read statistic\n");
156 			return 0;
157 		}
158 		val = val << 16 | reg;
159 	}
160 
161 	return val;
162 }
163 
164 int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
165 			       uint64_t *data)
166 {
167 	struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
168 	struct mv88e6352_serdes_hw_stat *stat;
169 	u64 value;
170 	int i;
171 
172 	if (!mv88e6352_port_has_serdes(chip, port))
173 		return 0;
174 
175 	BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
176 		     ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
177 
178 	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
179 		stat = &mv88e6352_serdes_hw_stats[i];
180 		value = mv88e6352_serdes_get_stat(chip, stat);
181 		mv88e6xxx_port->serdes_stats[i] += value;
182 		data[i] = mv88e6xxx_port->serdes_stats[i];
183 	}
184 
185 	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
186 }
187 
188 /* Return the SERDES lane address a port is using. Only Ports 9 and 10
189  * have SERDES lanes. Returns -ENODEV if a port does not have a lane.
190  */
191 static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
192 {
193 	u8 cmode = chip->ports[port].cmode;
194 
195 	switch (port) {
196 	case 9:
197 		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
198 		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
199 		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
200 			return MV88E6390_PORT9_LANE0;
201 		return -ENODEV;
202 	case 10:
203 		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
204 		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
205 		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
206 			return MV88E6390_PORT10_LANE0;
207 		return -ENODEV;
208 	default:
209 		return -ENODEV;
210 	}
211 }
212 
213 /* Return the SERDES lane address a port is using. Ports 9 and 10 can
214  * use multiple lanes. If so, return the first lane the port uses.
215  * Returns -ENODEV if a port does not have a lane.
216  */
217 int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
218 {
219 	u8 cmode_port9, cmode_port10, cmode_port;
220 
221 	cmode_port9 = chip->ports[9].cmode;
222 	cmode_port10 = chip->ports[10].cmode;
223 	cmode_port = chip->ports[port].cmode;
224 
225 	switch (port) {
226 	case 2:
227 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
228 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
229 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
230 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
231 				return MV88E6390_PORT9_LANE1;
232 		return -ENODEV;
233 	case 3:
234 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
235 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
236 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
237 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
238 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
239 				return MV88E6390_PORT9_LANE2;
240 		return -ENODEV;
241 	case 4:
242 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
243 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
244 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
245 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
246 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
247 				return MV88E6390_PORT9_LANE3;
248 		return -ENODEV;
249 	case 5:
250 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
251 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
252 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
253 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
254 				return MV88E6390_PORT10_LANE1;
255 		return -ENODEV;
256 	case 6:
257 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
258 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
259 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
260 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
261 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
262 				return MV88E6390_PORT10_LANE2;
263 		return -ENODEV;
264 	case 7:
265 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
266 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
267 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
268 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
269 			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
270 				return MV88E6390_PORT10_LANE3;
271 		return -ENODEV;
272 	case 9:
273 		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
274 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
275 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
276 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
277 		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
278 			return MV88E6390_PORT9_LANE0;
279 		return -ENODEV;
280 	case 10:
281 		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
282 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
283 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
284 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
285 		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
286 			return MV88E6390_PORT10_LANE0;
287 		return -ENODEV;
288 	default:
289 		return -ENODEV;
290 	}
291 }
292 
293 /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
294 static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
295 				      bool on)
296 {
297 	u16 val, new_val;
298 	int err;
299 
300 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
301 				    MV88E6390_PCS_CONTROL_1, &val);
302 
303 	if (err)
304 		return err;
305 
306 	if (on)
307 		new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
308 				  MV88E6390_PCS_CONTROL_1_LOOPBACK |
309 				  MV88E6390_PCS_CONTROL_1_PDOWN);
310 	else
311 		new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
312 
313 	if (val != new_val)
314 		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
315 					     MV88E6390_PCS_CONTROL_1, new_val);
316 
317 	return err;
318 }
319 
320 /* Set the power on/off for SGMII and 1000Base-X */
321 static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
322 					bool on)
323 {
324 	u16 val, new_val;
325 	int err;
326 
327 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
328 				    MV88E6390_SGMII_CONTROL, &val);
329 	if (err)
330 		return err;
331 
332 	if (on)
333 		new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
334 				  MV88E6390_SGMII_CONTROL_LOOPBACK |
335 				  MV88E6390_SGMII_CONTROL_PDOWN);
336 	else
337 		new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
338 
339 	if (val != new_val)
340 		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
341 					     MV88E6390_SGMII_CONTROL, new_val);
342 
343 	return err;
344 }
345 
346 static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
347 				       int lane, bool on)
348 {
349 	u8 cmode = chip->ports[port].cmode;
350 
351 	switch (cmode) {
352 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
353 	case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
354 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
355 		return mv88e6390_serdes_power_sgmii(chip, lane, on);
356 	case MV88E6XXX_PORT_STS_CMODE_XAUI:
357 	case MV88E6XXX_PORT_STS_CMODE_RXAUI:
358 		return mv88e6390_serdes_power_10g(chip, lane, on);
359 	}
360 
361 	return 0;
362 }
363 
364 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
365 {
366 	int lane;
367 
368 	lane = mv88e6390_serdes_get_lane(chip, port);
369 	if (lane == -ENODEV)
370 		return 0;
371 
372 	if (lane < 0)
373 		return lane;
374 
375 	switch (port) {
376 	case 9 ... 10:
377 		return mv88e6390_serdes_power_lane(chip, port, lane, on);
378 	}
379 
380 	return 0;
381 }
382 
383 int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
384 {
385 	int lane;
386 
387 	lane = mv88e6390x_serdes_get_lane(chip, port);
388 	if (lane == -ENODEV)
389 		return 0;
390 
391 	if (lane < 0)
392 		return lane;
393 
394 	switch (port) {
395 	case 2 ... 4:
396 	case 5 ... 7:
397 	case 9 ... 10:
398 		return mv88e6390_serdes_power_lane(chip, port, lane, on);
399 	}
400 
401 	return 0;
402 }
403 
404 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
405 					    int port, int lane)
406 {
407 	struct dsa_switch *ds = chip->ds;
408 	u16 status;
409 	bool up;
410 
411 	mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
412 			      MV88E6390_SGMII_STATUS, &status);
413 
414 	/* Status must be read twice in order to give the current link
415 	 * status. Otherwise the change in link status since the last
416 	 * read of the register is returned.
417 	 */
418 	mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
419 			      MV88E6390_SGMII_STATUS, &status);
420 	up = status & MV88E6390_SGMII_STATUS_LINK;
421 
422 	dsa_port_phylink_mac_change(ds, port, up);
423 }
424 
425 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
426 					     int lane)
427 {
428 	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
429 				      MV88E6390_SGMII_INT_ENABLE,
430 				      MV88E6390_SGMII_INT_LINK_DOWN |
431 				      MV88E6390_SGMII_INT_LINK_UP);
432 }
433 
434 static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
435 					      int lane)
436 {
437 	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
438 				      MV88E6390_SGMII_INT_ENABLE, 0);
439 }
440 
441 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
442 				int lane)
443 {
444 	u8 cmode = chip->ports[port].cmode;
445 	int err = 0;
446 
447 	switch (cmode) {
448 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
449 	case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
450 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
451 		err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
452 	}
453 
454 	return err;
455 }
456 
457 int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
458 				 int lane)
459 {
460 	u8 cmode = chip->ports[port].cmode;
461 	int err = 0;
462 
463 	switch (cmode) {
464 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
465 	case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
466 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
467 		err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
468 	}
469 
470 	return err;
471 }
472 
473 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
474 					     int lane, u16 *status)
475 {
476 	int err;
477 
478 	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
479 				    MV88E6390_SGMII_INT_STATUS, status);
480 
481 	return err;
482 }
483 
484 static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
485 {
486 	struct mv88e6xxx_port *port = dev_id;
487 	struct mv88e6xxx_chip *chip = port->chip;
488 	irqreturn_t ret = IRQ_NONE;
489 	u8 cmode = port->cmode;
490 	u16 status;
491 	int lane;
492 	int err;
493 
494 	lane = mv88e6390x_serdes_get_lane(chip, port->port);
495 
496 	mutex_lock(&chip->reg_lock);
497 
498 	switch (cmode) {
499 	case MV88E6XXX_PORT_STS_CMODE_SGMII:
500 	case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
501 	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
502 		err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
503 		if (err)
504 			goto out;
505 		if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
506 			      MV88E6390_SGMII_INT_LINK_UP)) {
507 			ret = IRQ_HANDLED;
508 			mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane);
509 		}
510 	}
511 out:
512 	mutex_unlock(&chip->reg_lock);
513 
514 	return ret;
515 }
516 
517 int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
518 {
519 	int lane;
520 	int err;
521 
522 	/* Only support ports 9 and 10 at the moment */
523 	if (port < 9)
524 		return 0;
525 
526 	lane = mv88e6390x_serdes_get_lane(chip, port);
527 
528 	if (lane == -ENODEV)
529 		return 0;
530 
531 	if (lane < 0)
532 		return lane;
533 
534 	chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
535 							port);
536 	if (chip->ports[port].serdes_irq < 0) {
537 		dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
538 			chip->ports[port].serdes_irq);
539 		return chip->ports[port].serdes_irq;
540 	}
541 
542 	/* Requesting the IRQ will trigger irq callbacks. So we cannot
543 	 * hold the reg_lock.
544 	 */
545 	mutex_unlock(&chip->reg_lock);
546 	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
547 				   mv88e6390_serdes_thread_fn,
548 				   IRQF_ONESHOT, "mv88e6xxx-serdes",
549 				   &chip->ports[port]);
550 	mutex_lock(&chip->reg_lock);
551 
552 	if (err) {
553 		dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
554 			err);
555 		return err;
556 	}
557 
558 	return mv88e6390_serdes_irq_enable(chip, port, lane);
559 }
560 
561 void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
562 {
563 	int lane = mv88e6390x_serdes_get_lane(chip, port);
564 
565 	if (port < 9)
566 		return;
567 
568 	if (lane < 0)
569 		return;
570 
571 	mv88e6390_serdes_irq_disable(chip, port, lane);
572 
573 	/* Freeing the IRQ will trigger irq callbacks. So we cannot
574 	 * hold the reg_lock.
575 	 */
576 	mutex_unlock(&chip->reg_lock);
577 	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
578 	mutex_lock(&chip->reg_lock);
579 
580 	chip->ports[port].serdes_irq = 0;
581 }
582 
583 int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
584 {
585 	u8 cmode = chip->ports[port].cmode;
586 
587 	if (port != 5)
588 		return 0;
589 
590 	if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
591 	    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
592 	    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
593 		return mv88e6390_serdes_power_sgmii(chip, MV88E6341_ADDR_SERDES,
594 						    on);
595 
596 	return 0;
597 }
598