xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/serdes.c (revision 6d91782f)
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/mii.h>
15 
16 #include "mv88e6xxx.h"
17 #include "phy.h"
18 #include "port.h"
19 #include "serdes.h"
20 
21 static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
22 				 u16 *val)
23 {
24 	return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
25 				       MV88E6352_SERDES_PAGE_FIBER,
26 				       reg, val);
27 }
28 
29 static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
30 				  u16 val)
31 {
32 	return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
33 					MV88E6352_SERDES_PAGE_FIBER,
34 					reg, val);
35 }
36 
37 static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
38 {
39 	u16 val, new_val;
40 	int err;
41 
42 	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
43 	if (err)
44 		return err;
45 
46 	if (on)
47 		new_val = val & ~BMCR_PDOWN;
48 	else
49 		new_val = val | BMCR_PDOWN;
50 
51 	if (val != new_val)
52 		err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
53 
54 	return err;
55 }
56 
57 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
58 {
59 	int err;
60 	u8 cmode;
61 
62 	err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
63 	if (err)
64 		return err;
65 
66 	if ((cmode == PORT_STATUS_CMODE_100BASE_X) ||
67 	    (cmode == PORT_STATUS_CMODE_1000BASE_X) ||
68 	    (cmode == PORT_STATUS_CMODE_SGMII)) {
69 		err = mv88e6352_serdes_power_set(chip, on);
70 		if (err < 0)
71 			return err;
72 	}
73 
74 	return 0;
75 }
76