File Index
Files and directories
Sign in
FILE

serdes.c

File preview with syntax highlighting.

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