Linux Audio

Check our new training course

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, &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, &reg);
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, &reg);
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, &reg[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], &reg);
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}