Loading...
Note: File does not exist in v3.15.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Marvell 88E6xxx SERDES manipulation, via SMI bus
4 *
5 * Copyright (c) 2008 Marvell Semiconductor
6 *
7 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
8 */
9
10#include <linux/interrupt.h>
11#include <linux/irqdomain.h>
12#include <linux/mii.h>
13
14#include "chip.h"
15#include "global2.h"
16#include "phy.h"
17#include "port.h"
18#include "serdes.h"
19
20static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
21 u16 *val)
22{
23 return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
24 MV88E6352_SERDES_PAGE_FIBER,
25 reg, val);
26}
27
28static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
29 u16 val)
30{
31 return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
32 MV88E6352_SERDES_PAGE_FIBER,
33 reg, val);
34}
35
36static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
37 int lane, int device, int reg, u16 *val)
38{
39 return mv88e6xxx_phy_read_c45(chip, lane, device, reg, val);
40}
41
42int mv88e6xxx_pcs_decode_state(struct device *dev, u16 bmsr, u16 lpa,
43 u16 status, struct phylink_link_state *state)
44{
45 state->link = false;
46
47 /* If the BMSR reports that the link had failed, report this to
48 * phylink.
49 */
50 if (!(bmsr & BMSR_LSTATUS))
51 return 0;
52
53 state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
54 state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
55
56 if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
57 /* The Spped and Duplex Resolved register is 1 if AN is enabled
58 * and complete, or if AN is disabled. So with disabled AN we
59 * still get here on link up.
60 */
61 state->duplex = status &
62 MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
63 DUPLEX_FULL : DUPLEX_HALF;
64
65 if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE)
66 state->pause |= MLO_PAUSE_TX;
67 if (status & MV88E6390_SGMII_PHY_STATUS_RX_PAUSE)
68 state->pause |= MLO_PAUSE_RX;
69
70 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
71 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
72 if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
73 state->speed = SPEED_2500;
74 else
75 state->speed = SPEED_1000;
76 break;
77 case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
78 state->speed = SPEED_100;
79 break;
80 case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
81 state->speed = SPEED_10;
82 break;
83 default:
84 dev_err(dev, "invalid PHY speed\n");
85 return -EINVAL;
86 }
87 } else if (state->link &&
88 state->interface != PHY_INTERFACE_MODE_SGMII) {
89 /* If Speed and Duplex Resolved register is 0 and link is up, it
90 * means that AN was enabled, but link partner had it disabled
91 * and the PHY invoked the Auto-Negotiation Bypass feature and
92 * linked anyway.
93 */
94 state->duplex = DUPLEX_FULL;
95 if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
96 state->speed = SPEED_2500;
97 else
98 state->speed = SPEED_1000;
99 } else {
100 state->link = false;
101 }
102
103 if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
104 mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
105 ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
106 else if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
107 mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
108 ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
109
110 return 0;
111}
112
113struct mv88e6352_serdes_hw_stat {
114 char string[ETH_GSTRING_LEN];
115 int sizeof_stat;
116 int reg;
117};
118
119static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
120 { "serdes_fibre_rx_error", 16, 21 },
121 { "serdes_PRBS_error", 32, 24 },
122};
123
124int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
125{
126 int err;
127
128 err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
129 if (err <= 0)
130 return err;
131
132 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
133}
134
135int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port,
136 uint8_t **data)
137{
138 struct mv88e6352_serdes_hw_stat *stat;
139 int err, i;
140
141 err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
142 if (err <= 0)
143 return err;
144
145 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
146 stat = &mv88e6352_serdes_hw_stats[i];
147 ethtool_puts(data, stat->string);
148 }
149 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
150}
151
152static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
153 struct mv88e6352_serdes_hw_stat *stat)
154{
155 u64 val = 0;
156 u16 reg;
157 int err;
158
159 err = mv88e6352_serdes_read(chip, stat->reg, ®);
160 if (err) {
161 dev_err(chip->dev, "failed to read statistic\n");
162 return 0;
163 }
164
165 val = reg;
166
167 if (stat->sizeof_stat == 32) {
168 err = mv88e6352_serdes_read(chip, stat->reg + 1, ®);
169 if (err) {
170 dev_err(chip->dev, "failed to read statistic\n");
171 return 0;
172 }
173 val = val << 16 | reg;
174 }
175
176 return val;
177}
178
179size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
180 uint64_t *data)
181{
182 struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
183 struct mv88e6352_serdes_hw_stat *stat;
184 int i, err;
185 u64 value;
186
187 err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
188 if (err <= 0)
189 return 0;
190
191 BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
192 ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
193
194 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
195 stat = &mv88e6352_serdes_hw_stats[i];
196 value = mv88e6352_serdes_get_stat(chip, stat);
197 mv88e6xxx_port->serdes_stats[i] += value;
198 data[i] = mv88e6xxx_port->serdes_stats[i];
199 }
200
201 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
202}
203
204unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
205{
206 return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
207}
208
209int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
210{
211 int err;
212
213 mv88e6xxx_reg_lock(chip);
214 err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
215 mv88e6xxx_reg_unlock(chip);
216 if (err <= 0)
217 return err;
218
219 return 32 * sizeof(u16);
220}
221
222void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
223{
224 u16 *p = _p;
225 u16 reg;
226 int err;
227 int i;
228
229 err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
230 if (err <= 0)
231 return;
232
233 for (i = 0 ; i < 32; i++) {
234 err = mv88e6352_serdes_read(chip, i, ®);
235 if (!err)
236 p[i] = reg;
237 }
238}
239
240int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
241{
242 u8 cmode = chip->ports[port].cmode;
243 int lane = -ENODEV;
244
245 switch (port) {
246 case 5:
247 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
248 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
249 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
250 lane = MV88E6341_PORT5_LANE;
251 break;
252 }
253
254 return lane;
255}
256
257int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
258{
259 u8 cmode = chip->ports[port].cmode;
260 int lane = -ENODEV;
261
262 switch (port) {
263 case 9:
264 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
265 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
266 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
267 lane = MV88E6390_PORT9_LANE0;
268 break;
269 case 10:
270 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
271 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
272 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
273 lane = MV88E6390_PORT10_LANE0;
274 break;
275 }
276
277 return lane;
278}
279
280int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
281{
282 u8 cmode_port = chip->ports[port].cmode;
283 u8 cmode_port10 = chip->ports[10].cmode;
284 u8 cmode_port9 = chip->ports[9].cmode;
285 int lane = -ENODEV;
286
287 switch (port) {
288 case 2:
289 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
290 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
291 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
292 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
293 lane = MV88E6390_PORT9_LANE1;
294 break;
295 case 3:
296 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
297 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
298 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
299 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
300 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
301 lane = MV88E6390_PORT9_LANE2;
302 break;
303 case 4:
304 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
305 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
306 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
307 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
308 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
309 lane = MV88E6390_PORT9_LANE3;
310 break;
311 case 5:
312 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
313 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
314 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
315 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
316 lane = MV88E6390_PORT10_LANE1;
317 break;
318 case 6:
319 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
320 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
321 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
322 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
323 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
324 lane = MV88E6390_PORT10_LANE2;
325 break;
326 case 7:
327 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
328 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
329 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
330 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
331 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
332 lane = MV88E6390_PORT10_LANE3;
333 break;
334 case 9:
335 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
336 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
337 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
338 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
339 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
340 lane = MV88E6390_PORT9_LANE0;
341 break;
342 case 10:
343 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
344 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
345 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
346 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
347 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
348 lane = MV88E6390_PORT10_LANE0;
349 break;
350 }
351
352 return lane;
353}
354
355/* Only Ports 0, 9 and 10 have SERDES lanes. Return the SERDES lane address
356 * a port is using else Returns -ENODEV.
357 */
358int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
359{
360 u8 cmode = chip->ports[port].cmode;
361 int lane = -ENODEV;
362
363 if (port != 0 && port != 9 && port != 10)
364 return -EOPNOTSUPP;
365
366 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
367 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
368 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
369 cmode == MV88E6393X_PORT_STS_CMODE_5GBASER ||
370 cmode == MV88E6393X_PORT_STS_CMODE_10GBASER ||
371 cmode == MV88E6393X_PORT_STS_CMODE_USXGMII)
372 lane = port;
373
374 return lane;
375}
376
377struct mv88e6390_serdes_hw_stat {
378 char string[ETH_GSTRING_LEN];
379 int reg;
380};
381
382static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {
383 { "serdes_rx_pkts", 0xf021 },
384 { "serdes_rx_bytes", 0xf024 },
385 { "serdes_rx_pkts_error", 0xf027 },
386};
387
388int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
389{
390 if (mv88e6xxx_serdes_get_lane(chip, port) < 0)
391 return 0;
392
393 return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
394}
395
396int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port,
397 uint8_t **data)
398{
399 struct mv88e6390_serdes_hw_stat *stat;
400 int i;
401
402 if (mv88e6xxx_serdes_get_lane(chip, port) < 0)
403 return 0;
404
405 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
406 stat = &mv88e6390_serdes_hw_stats[i];
407 ethtool_puts(data, stat->string);
408 }
409 return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
410}
411
412static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane,
413 struct mv88e6390_serdes_hw_stat *stat)
414{
415 u16 reg[3];
416 int err, i;
417
418 for (i = 0; i < 3; i++) {
419 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
420 stat->reg + i, ®[i]);
421 if (err) {
422 dev_err(chip->dev, "failed to read statistic\n");
423 return 0;
424 }
425 }
426
427 return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32);
428}
429
430size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
431 uint64_t *data)
432{
433 struct mv88e6390_serdes_hw_stat *stat;
434 int lane;
435 int i;
436
437 lane = mv88e6xxx_serdes_get_lane(chip, port);
438 if (lane < 0)
439 return 0;
440
441 for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
442 stat = &mv88e6390_serdes_hw_stats[i];
443 data[i] = mv88e6390_serdes_get_stat(chip, lane, stat);
444 }
445
446 return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
447}
448
449unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
450{
451 return irq_find_mapping(chip->g2_irq.domain, port);
452}
453
454static const u16 mv88e6390_serdes_regs[] = {
455 /* SERDES common registers */
456 0xf00a, 0xf00b, 0xf00c,
457 0xf010, 0xf011, 0xf012, 0xf013,
458 0xf016, 0xf017, 0xf018,
459 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
460 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
461 0xf028, 0xf029,
462 0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
463 0xf038, 0xf039,
464 /* SGMII */
465 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
466 0x2008,
467 0x200f,
468 0xa000, 0xa001, 0xa002, 0xa003,
469 /* 10Gbase-X */
470 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
471 0x1008,
472 0x100e, 0x100f,
473 0x1018, 0x1019,
474 0x9000, 0x9001, 0x9002, 0x9003, 0x9004,
475 0x9006,
476 0x9010, 0x9011, 0x9012, 0x9013, 0x9014, 0x9015, 0x9016,
477 /* 10Gbase-R */
478 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
479 0x1028, 0x1029, 0x102a, 0x102b,
480};
481
482int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
483{
484 if (mv88e6xxx_serdes_get_lane(chip, port) < 0)
485 return 0;
486
487 return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
488}
489
490void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
491{
492 u16 *p = _p;
493 int lane;
494 u16 reg;
495 int err;
496 int i;
497
498 lane = mv88e6xxx_serdes_get_lane(chip, port);
499 if (lane < 0)
500 return;
501
502 for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
503 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
504 mv88e6390_serdes_regs[i], ®);
505 if (!err)
506 p[i] = reg;
507 }
508}
509
510static const int mv88e6352_serdes_p2p_to_reg[] = {
511 /* Index of value in microvolts corresponds to the register value */
512 14000, 112000, 210000, 308000, 406000, 504000, 602000, 700000,
513};
514
515int mv88e6352_serdes_set_tx_amplitude(struct mv88e6xxx_chip *chip, int port,
516 int val)
517{
518 bool found = false;
519 u16 ctrl, reg;
520 int err;
521 int i;
522
523 err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
524 if (err <= 0)
525 return err;
526
527 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_p2p_to_reg); ++i) {
528 if (mv88e6352_serdes_p2p_to_reg[i] == val) {
529 reg = i;
530 found = true;
531 break;
532 }
533 }
534
535 if (!found)
536 return -EINVAL;
537
538 err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_SPEC_CTRL2, &ctrl);
539 if (err)
540 return err;
541
542 ctrl &= ~MV88E6352_SERDES_OUT_AMP_MASK;
543 ctrl |= reg;
544
545 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_SPEC_CTRL2, ctrl);
546}