1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/mii.h>
15
16#include "chip.h"
17#include "global2.h"
18#include "phy.h"
19#include "port.h"
20#include "serdes.h"
21
22static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
23 u16 *val)
24{
25 return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
26 MV88E6352_SERDES_PAGE_FIBER,
27 reg, val);
28}
29
30static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
31 u16 val)
32{
33 return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
34 MV88E6352_SERDES_PAGE_FIBER,
35 reg, val);
36}
37
38static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
39{
40 u16 val, new_val;
41 int err;
42
43 err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
44 if (err)
45 return err;
46
47 if (on)
48 new_val = val & ~BMCR_PDOWN;
49 else
50 new_val = val | BMCR_PDOWN;
51
52 if (val != new_val)
53 err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
54
55 return err;
56}
57
58int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
59{
60 int err;
61 u8 cmode;
62
63 err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
64 if (err)
65 return err;
66
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);
71 if (err < 0)
72 return err;
73 }
74
75 return 0;
76}
77
78
79static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on)
80{
81 u16 val, new_val;
82 int reg_c45;
83 int err;
84
85 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
86 MV88E6390_PCS_CONTROL_1;
87 err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val);
88 if (err)
89 return err;
90
91 if (on)
92 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
93 MV88E6390_PCS_CONTROL_1_LOOPBACK |
94 MV88E6390_PCS_CONTROL_1_PDOWN);
95 else
96 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
97
98 if (val != new_val)
99 err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val);
100
101 return err;
102}
103
104
105static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr,
106 bool on)
107{
108 u16 val, new_val;
109 int reg_c45;
110 int err;
111
112 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
113 MV88E6390_SGMII_CONTROL;
114 err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val);
115 if (err)
116 return err;
117
118 if (on)
119 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
120 MV88E6390_SGMII_CONTROL_LOOPBACK |
121 MV88E6390_SGMII_CONTROL_PDOWN);
122 else
123 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
124
125 if (val != new_val)
126 err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val);
127
128 return err;
129}
130
131static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode,
132 int port_donor, int lane, bool rxaui, bool on)
133{
134 int err;
135 u8 cmode_donor;
136
137 err = mv88e6xxx_port_get_cmode(chip, port_donor, &cmode_donor);
138 if (err)
139 return err;
140
141 switch (cmode_donor) {
142 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
143 if (!rxaui)
144 break;
145
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);
152 }
153 return 0;
154}
155
156static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode,
157 bool on)
158{
159 switch (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);
167 }
168
169 return 0;
170}
171
172static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode,
173 bool on)
174{
175 switch (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);
183 }
184
185 return 0;
186}
187
188int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
189{
190 u8 cmode;
191 int err;
192
193 err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
194 if (err)
195 return err;
196
197 switch (port) {
198 case 2:
199 return mv88e6390_serdes_lower(chip, cmode, 9,
200 MV88E6390_PORT9_LANE1,
201 false, on);
202 case 3:
203 return mv88e6390_serdes_lower(chip, cmode, 9,
204 MV88E6390_PORT9_LANE2,
205 true, on);
206 case 4:
207 return mv88e6390_serdes_lower(chip, cmode, 9,
208 MV88E6390_PORT9_LANE3,
209 true, on);
210 case 5:
211 return mv88e6390_serdes_lower(chip, cmode, 10,
212 MV88E6390_PORT10_LANE1,
213 false, on);
214 case 6:
215 return mv88e6390_serdes_lower(chip, cmode, 10,
216 MV88E6390_PORT10_LANE2,
217 true, on);
218 case 7:
219 return mv88e6390_serdes_lower(chip, cmode, 10,
220 MV88E6390_PORT10_LANE3,
221 true, on);
222 case 9:
223 return mv88e6390_serdes_port9(chip, cmode, on);
224 case 10:
225 return mv88e6390_serdes_port10(chip, cmode, on);
226 }
227
228 return 0;
229}
230