Linux Audio

Check our new training course

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