aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2018-08-09 09:38:40 -0400
committerDavid S. Miller <davem@davemloft.net>2018-08-09 14:08:20 -0400
commita8c01c0d941d2f220a5a31ded77a67d89ddec3b0 (patch)
tree6efc4de4686199e6a701ee4a0819f6b8c68eae44
parent6c422e34b1b6533af5730280835365d4b50786d3 (diff)
net: dsa: mv88e6xxx: Refactor SERDES lane code
The 6390 family has 8 SERDES lanes. What ports use these lanes depends on how ports 9 and 10 are configured. If 9 and 10 does not make use of a line, one of the lower ports can use it. Add a function to return the lane a port is using, if any, and simplify the code to power up/down the lane. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c195
1 files changed, 114 insertions, 81 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 880b2cf0a530..a218870971fe 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -174,8 +174,97 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
174 return ARRAY_SIZE(mv88e6352_serdes_hw_stats); 174 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
175} 175}
176 176
177/* Return the SERDES lane address a port is using. Ports 9 and 10 can
178 * use multiple lanes. If so, return the first lane the port uses.
179 * Returns -ENODEV if a port does not have a lane.
180 */
181static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
182{
183 u8 cmode_port9, cmode_port10, cmode_port;
184 int err;
185
186 err = mv88e6xxx_port_get_cmode(chip, 9, &cmode_port9);
187 if (err)
188 return err;
189
190 err = mv88e6xxx_port_get_cmode(chip, 10, &cmode_port10);
191 if (err)
192 return err;
193
194 err = mv88e6xxx_port_get_cmode(chip, port, &cmode_port);
195 if (err)
196 return err;
197
198 switch (port) {
199 case 2:
200 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
201 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
202 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
203 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
204 return MV88E6390_PORT9_LANE1;
205 return -ENODEV;
206 case 3:
207 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
208 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
209 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
210 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
211 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
212 return MV88E6390_PORT9_LANE2;
213 return -ENODEV;
214 case 4:
215 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
216 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
217 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
218 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
219 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
220 return MV88E6390_PORT9_LANE3;
221 return -ENODEV;
222 case 5:
223 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
224 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
225 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
226 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
227 return MV88E6390_PORT10_LANE1;
228 return -ENODEV;
229 case 6:
230 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
231 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
232 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
233 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
234 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
235 return MV88E6390_PORT10_LANE2;
236 return -ENODEV;
237 case 7:
238 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
239 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
240 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
241 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
242 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
243 return MV88E6390_PORT10_LANE3;
244 return -ENODEV;
245 case 9:
246 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
247 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
248 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
249 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
250 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
251 return MV88E6390_PORT9_LANE0;
252 return -ENODEV;
253 case 10:
254 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
255 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
256 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
257 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
258 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
259 return MV88E6390_PORT10_LANE0;
260 return -ENODEV;
261 default:
262 return -ENODEV;
263 }
264}
265
177/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ 266/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
178static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on) 267static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int lane, bool on)
179{ 268{
180 u16 val, new_val; 269 u16 val, new_val;
181 int reg_c45; 270 int reg_c45;
@@ -183,7 +272,7 @@ static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on)
183 272
184 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | 273 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
185 MV88E6390_PCS_CONTROL_1; 274 MV88E6390_PCS_CONTROL_1;
186 err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val); 275 err = mv88e6xxx_phy_read(chip, lane, reg_c45, &val);
187 if (err) 276 if (err)
188 return err; 277 return err;
189 278
@@ -195,13 +284,13 @@ static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on)
195 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN; 284 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
196 285
197 if (val != new_val) 286 if (val != new_val)
198 err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val); 287 err = mv88e6xxx_phy_write(chip, lane, reg_c45, new_val);
199 288
200 return err; 289 return err;
201} 290}
202 291
203/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ 292/* Set the power on/off for SGMII and 1000Base-X */
204static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr, 293static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int lane,
205 bool on) 294 bool on)
206{ 295{
207 u16 val, new_val; 296 u16 val, new_val;
@@ -210,7 +299,7 @@ static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr,
210 299
211 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE | 300 reg_c45 = MII_ADDR_C45 | MV88E6390_SERDES_DEVICE |
212 MV88E6390_SGMII_CONTROL; 301 MV88E6390_SGMII_CONTROL;
213 err = mv88e6xxx_phy_read(chip, addr, reg_c45, &val); 302 err = mv88e6xxx_phy_read(chip, lane, reg_c45, &val);
214 if (err) 303 if (err)
215 return err; 304 return err;
216 305
@@ -222,63 +311,29 @@ static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr,
222 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN; 311 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
223 312
224 if (val != new_val) 313 if (val != new_val)
225 err = mv88e6xxx_phy_write(chip, addr, reg_c45, new_val); 314 err = mv88e6xxx_phy_write(chip, lane, reg_c45, new_val);
226 315
227 return err; 316 return err;
228} 317}
229 318
230static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode, 319static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
231 int port_donor, int lane, bool rxaui, bool on) 320 int lane, bool on)
232{ 321{
322 u8 cmode;
233 int err; 323 int err;
234 u8 cmode_donor;
235 324
236 err = mv88e6xxx_port_get_cmode(chip, port_donor, &cmode_donor); 325 err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
237 if (err) 326 if (err)
238 return err; 327 return err;
239 328
240 switch (cmode_donor) {
241 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
242 if (!rxaui)
243 break;
244 /* Fall through */
245 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
246 case MV88E6XXX_PORT_STS_CMODE_SGMII:
247 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
248 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
249 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)
250 return mv88e6390_serdes_sgmii(chip, lane, on);
251 }
252 return 0;
253}
254
255static int mv88e6390_serdes_port9(struct mv88e6xxx_chip *chip, u8 cmode,
256 bool on)
257{
258 switch (cmode) { 329 switch (cmode) {
259 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
260 case MV88E6XXX_PORT_STS_CMODE_SGMII: 330 case MV88E6XXX_PORT_STS_CMODE_SGMII:
261 return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT9_LANE0, on); 331 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
332 return mv88e6390_serdes_sgmii(chip, lane, on);
262 case MV88E6XXX_PORT_STS_CMODE_XAUI: 333 case MV88E6XXX_PORT_STS_CMODE_XAUI:
263 case MV88E6XXX_PORT_STS_CMODE_RXAUI: 334 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
264 case MV88E6XXX_PORT_STS_CMODE_2500BASEX: 335 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
265 return mv88e6390_serdes_10g(chip, MV88E6390_PORT9_LANE0, on); 336 return mv88e6390_serdes_10g(chip, lane, on);
266 }
267
268 return 0;
269}
270
271static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode,
272 bool on)
273{
274 switch (cmode) {
275 case MV88E6XXX_PORT_STS_CMODE_SGMII:
276 return mv88e6390_serdes_sgmii(chip, MV88E6390_PORT10_LANE0, on);
277 case MV88E6XXX_PORT_STS_CMODE_XAUI:
278 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
279 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
280 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
281 return mv88e6390_serdes_10g(chip, MV88E6390_PORT10_LANE0, on);
282 } 337 }
283 338
284 return 0; 339 return 0;
@@ -286,42 +341,20 @@ static int mv88e6390_serdes_port10(struct mv88e6xxx_chip *chip, u8 cmode,
286 341
287int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) 342int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
288{ 343{
289 u8 cmode; 344 int lane;
290 int err;
291 345
292 err = mv88e6xxx_port_get_cmode(chip, port, &cmode); 346 lane = mv88e6390_serdes_get_lane(chip, port);
293 if (err) 347 if (lane == -ENODEV)
294 return err; 348 return 0;
349
350 if (lane < 0)
351 return lane;
295 352
296 switch (port) { 353 switch (port) {
297 case 2: 354 case 2 ... 4:
298 return mv88e6390_serdes_lower(chip, cmode, 9, 355 case 5 ... 7:
299 MV88E6390_PORT9_LANE1, 356 case 9 ... 10:
300 false, on); 357 return mv88e6390_serdes_power_lane(chip, port, lane, on);
301 case 3:
302 return mv88e6390_serdes_lower(chip, cmode, 9,
303 MV88E6390_PORT9_LANE2,
304 true, on);
305 case 4:
306 return mv88e6390_serdes_lower(chip, cmode, 9,
307 MV88E6390_PORT9_LANE3,
308 true, on);
309 case 5:
310 return mv88e6390_serdes_lower(chip, cmode, 10,
311 MV88E6390_PORT10_LANE1,
312 false, on);
313 case 6:
314 return mv88e6390_serdes_lower(chip, cmode, 10,
315 MV88E6390_PORT10_LANE2,
316 true, on);
317 case 7:
318 return mv88e6390_serdes_lower(chip, cmode, 10,
319 MV88E6390_PORT10_LANE3,
320 true, on);
321 case 9:
322 return mv88e6390_serdes_port9(chip, cmode, on);
323 case 10:
324 return mv88e6390_serdes_port10(chip, cmode, on);
325 } 358 }
326 359
327 return 0; 360 return 0;