diff options
author | Andrew Lunn <andrew@lunn.ch> | 2018-08-09 09:38:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-08-09 14:08:20 -0400 |
commit | a8c01c0d941d2f220a5a31ded77a67d89ddec3b0 (patch) | |
tree | 6efc4de4686199e6a701ee4a0819f6b8c68eae44 | |
parent | 6c422e34b1b6533af5730280835365d4b50786d3 (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.c | 195 |
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 | */ | ||
181 | static 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 */ |
178 | static int mv88e6390_serdes_10g(struct mv88e6xxx_chip *chip, int addr, bool on) | 267 | static 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 */ |
204 | static int mv88e6390_serdes_sgmii(struct mv88e6xxx_chip *chip, int addr, | 293 | static 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 | ||
230 | static int mv88e6390_serdes_lower(struct mv88e6xxx_chip *chip, u8 cmode, | 319 | static 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 | |||
255 | static 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 | |||
271 | static 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 | ||
287 | int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on) | 342 | int 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; |