2 * Marvell 88E6xxx SERDES manipulation, via SMI bus
4 * Copyright (c) 2008 Marvell Semiconductor
6 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
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.
14 #include <linux/mii.h>
22 static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
25 return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
26 MV88E6352_SERDES_PAGE_FIBER,
30 static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
33 return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
34 MV88E6352_SERDES_PAGE_FIBER,
38 static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
43 err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
48 new_val = val & ~BMCR_PDOWN;
50 new_val = val | BMCR_PDOWN;
53 err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
58 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
63 err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
67 if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) ||
68 (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) ||
69 (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) {
70 err = mv88e6352_serdes_power_set(chip, on);
78 /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
79 static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on)
85 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
86 MV88E6390_PCS_CONTROL_1;
87 err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val);
92 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
93 MV88E6390_PCS_CONTROL_1_LOOPBACK |
94 MV88E6390_PCS_CONTROL_1_PDOWN);
96 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
99 err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val);
104 /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
105 static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr,
112 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
113 MV88E6390_SGMII_CONTROL;
114 err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val);
119 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
120 MV88E6390_SGMII_CONTROL_LOOPBACK |
121 MV88E6390_SGMII_CONTROL_PDOWN);
123 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
126 err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val);
131 static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode,
132 int port_donor, int lane, bool rxaui, bool on)
137 err = mv88e6xxx_port_get_cmode(chip, port_donor, &cmode_donor);
141 switch (cmode_donor) {
142 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
146 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
147 case MV88E6XXX_PORT_STS_CMODE_SGMII:
148 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
149 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
150 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)
151 return mv88e6390_serdes_sgmii(chip, lane, on);
156 static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode,
160 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
161 case MV88E6XXX_PORT_STS_CMODE_SGMII:
162 return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT9_LANE0, on);
163 case MV88E6XXX_PORT_STS_CMODE_XAUI:
164 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
165 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
166 return mv88e6390_serdes_10g(chip, MV88E6390_PORT9_LANE0, on);
172 static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode,
176 case MV88E6XXX_PORT_STS_CMODE_SGMII:
177 return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT10_LANE0, on);
178 case MV88E6XXX_PORT_STS_CMODE_XAUI:
179 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
180 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
181 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
182 return mv88e6390_serdes_10g(chip, MV88E6390_PORT10_LANE0, on);
188 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
193 err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
199 return mv88e6390_serdes_lower(chip, cmode, 9,
200 MV88E6390_PORT9_LANE1,
203 return mv88e6390_serdes_lower(chip, cmode, 9,
204 MV88E6390_PORT9_LANE2,
207 return mv88e6390_serdes_lower(chip, cmode, 9,
208 MV88E6390_PORT9_LANE3,
211 return mv88e6390_serdes_lower(chip, cmode, 10,
212 MV88E6390_PORT10_LANE1,
215 return mv88e6390_serdes_lower(chip, cmode, 10,
216 MV88E6390_PORT10_LANE2,
219 return mv88e6390_serdes_lower(chip, cmode, 10,
220 MV88E6390_PORT10_LANE3,
223 return mv88e6390_serdes_port9(chip, cmode, on);
225 return mv88e6390_serdes_port10(chip, cmode, on);