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}
v5.9
   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	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
  40
  41	return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
  42}
  43
  44static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
  45				  int lane, int device, int reg, u16 val)
  46{
  47	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
  48
  49	return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
  50}
  51
  52static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
  53					  u16 status, u16 lpa,
  54					  struct phylink_link_state *state)
  55{
  56	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
  57		state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
  58		state->duplex = status &
  59				MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
  60			                         DUPLEX_FULL : DUPLEX_HALF;
  61
  62		if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE)
  63			state->pause |= MLO_PAUSE_TX;
  64		if (status & MV88E6390_SGMII_PHY_STATUS_RX_PAUSE)
  65			state->pause |= MLO_PAUSE_RX;
  66
  67		switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
  68		case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
  69			if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
  70				state->speed = SPEED_2500;
  71			else
  72				state->speed = SPEED_1000;
  73			break;
  74		case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
  75			state->speed = SPEED_100;
  76			break;
  77		case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
  78			state->speed = SPEED_10;
  79			break;
  80		default:
  81			dev_err(chip->dev, "invalid PHY speed\n");
  82			return -EINVAL;
  83		}
  84	} else {
  85		state->link = false;
  86	}
  87
  88	if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
  89		mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
  90				       ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
  91	else if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
  92		mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
  93				       ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
  94
  95	return 0;
  96}
  97
  98int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
  99			   bool up)
 100{
 101	u16 val, new_val;
 102	int err;
 103
 104	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
 105	if (err)
 106		return err;
 107
 108	if (up)
 109		new_val = val & ~BMCR_PDOWN;
 110	else
 111		new_val = val | BMCR_PDOWN;
 112
 113	if (val != new_val)
 114		err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
 115
 116	return err;
 117}
 118
 119int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
 120				u8 lane, unsigned int mode,
 121				phy_interface_t interface,
 122				const unsigned long *advertise)
 123{
 124	u16 adv, bmcr, val;
 125	bool changed;
 126	int err;
 127
 128	switch (interface) {
 129	case PHY_INTERFACE_MODE_SGMII:
 130		adv = 0x0001;
 131		break;
 132
 133	case PHY_INTERFACE_MODE_1000BASEX:
 134		adv = linkmode_adv_to_mii_adv_x(advertise,
 135					ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
 136		break;
 137
 138	default:
 139		return 0;
 140	}
 141
 142	err = mv88e6352_serdes_read(chip, MII_ADVERTISE, &val);
 143	if (err)
 144		return err;
 145
 146	changed = val != adv;
 147	if (changed) {
 148		err = mv88e6352_serdes_write(chip, MII_ADVERTISE, adv);
 149		if (err)
 150			return err;
 151	}
 152
 153	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
 154	if (err)
 155		return err;
 156
 157	if (phylink_autoneg_inband(mode))
 158		bmcr = val | BMCR_ANENABLE;
 159	else
 160		bmcr = val & ~BMCR_ANENABLE;
 161
 162	if (bmcr == val)
 163		return changed;
 164
 165	return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
 166}
 167
 168int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
 169				   u8 lane, struct phylink_link_state *state)
 170{
 171	u16 lpa, status;
 172	int err;
 173
 174	err = mv88e6352_serdes_read(chip, 0x11, &status);
 175	if (err) {
 176		dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
 177		return err;
 178	}
 179
 180	err = mv88e6352_serdes_read(chip, MII_LPA, &lpa);
 181	if (err) {
 182		dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err);
 183		return err;
 184	}
 185
 186	return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
 187}
 188
 189int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
 190				    u8 lane)
 191{
 192	u16 bmcr;
 193	int err;
 194
 195	err = mv88e6352_serdes_read(chip, MII_BMCR, &bmcr);
 196	if (err)
 197		return err;
 198
 199	return mv88e6352_serdes_write(chip, MII_BMCR, bmcr | BMCR_ANRESTART);
 200}
 201
 202int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
 203				 u8 lane, int speed, int duplex)
 204{
 205	u16 val, bmcr;
 206	int err;
 207
 208	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
 209	if (err)
 210		return err;
 211
 212	bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000);
 213	switch (speed) {
 214	case SPEED_1000:
 215		bmcr |= BMCR_SPEED1000;
 216		break;
 217	case SPEED_100:
 218		bmcr |= BMCR_SPEED100;
 219		break;
 220	case SPEED_10:
 221		break;
 222	}
 223
 224	if (duplex == DUPLEX_FULL)
 225		bmcr |= BMCR_FULLDPLX;
 226
 227	if (bmcr == val)
 228		return 0;
 229
 230	return mv88e6352_serdes_write(chip, MII_BMCR, bmcr);
 231}
 232
 233u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
 234{
 235	u8 cmode = chip->ports[port].cmode;
 236	u8 lane = 0;
 237
 238	if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
 239	    (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
 240	    (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
 241		lane = 0xff; /* Unused */
 242
 243	return lane;
 244}
 245
 246static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
 247{
 248	if (mv88e6xxx_serdes_get_lane(chip, port))
 249		return true;
 250
 251	return false;
 252}
 253
 254struct mv88e6352_serdes_hw_stat {
 255	char string[ETH_GSTRING_LEN];
 256	int sizeof_stat;
 257	int reg;
 258};
 259
 260static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
 261	{ "serdes_fibre_rx_error", 16, 21 },
 262	{ "serdes_PRBS_error", 32, 24 },
 263};
 264
 265int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
 266{
 267	if (mv88e6352_port_has_serdes(chip, port))
 268		return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
 269
 270	return 0;
 271}
 272
 273int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
 274				 int port, uint8_t *data)
 275{
 276	struct mv88e6352_serdes_hw_stat *stat;
 277	int i;
 278
 279	if (!mv88e6352_port_has_serdes(chip, port))
 280		return 0;
 281
 282	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
 283		stat = &mv88e6352_serdes_hw_stats[i];
 284		memcpy(data + i * ETH_GSTRING_LEN, stat->string,
 285		       ETH_GSTRING_LEN);
 286	}
 287	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
 288}
 289
 290static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
 291					  struct mv88e6352_serdes_hw_stat *stat)
 292{
 293	u64 val = 0;
 294	u16 reg;
 295	int err;
 296
 297	err = mv88e6352_serdes_read(chip, stat->reg, &reg);
 298	if (err) {
 299		dev_err(chip->dev, "failed to read statistic\n");
 300		return 0;
 301	}
 302
 303	val = reg;
 304
 305	if (stat->sizeof_stat == 32) {
 306		err = mv88e6352_serdes_read(chip, stat->reg + 1, &reg);
 307		if (err) {
 308			dev_err(chip->dev, "failed to read statistic\n");
 309			return 0;
 310		}
 311		val = val << 16 | reg;
 312	}
 313
 314	return val;
 315}
 316
 317int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
 318			       uint64_t *data)
 319{
 320	struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
 321	struct mv88e6352_serdes_hw_stat *stat;
 322	u64 value;
 323	int i;
 324
 325	if (!mv88e6352_port_has_serdes(chip, port))
 326		return 0;
 327
 328	BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
 329		     ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
 330
 331	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
 332		stat = &mv88e6352_serdes_hw_stats[i];
 333		value = mv88e6352_serdes_get_stat(chip, stat);
 334		mv88e6xxx_port->serdes_stats[i] += value;
 335		data[i] = mv88e6xxx_port->serdes_stats[i];
 336	}
 337
 338	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
 339}
 340
 341static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
 342{
 343	u16 bmsr;
 344	int err;
 345
 346	/* If the link has dropped, we want to know about it. */
 347	err = mv88e6352_serdes_read(chip, MII_BMSR, &bmsr);
 348	if (err) {
 349		dev_err(chip->dev, "can't read Serdes BMSR: %d\n", err);
 350		return;
 351	}
 352
 353	dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS));
 354}
 355
 356irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
 357					u8 lane)
 358{
 359	irqreturn_t ret = IRQ_NONE;
 360	u16 status;
 361	int err;
 362
 363	err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
 364	if (err)
 365		return ret;
 366
 367	if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
 368		ret = IRQ_HANDLED;
 369		mv88e6352_serdes_irq_link(chip, port);
 370	}
 371
 372	return ret;
 373}
 374
 375int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
 376				bool enable)
 377{
 378	u16 val = 0;
 379
 380	if (enable)
 381		val |= MV88E6352_SERDES_INT_LINK_CHANGE;
 382
 383	return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val);
 384}
 385
 386unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
 387{
 388	return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
 389}
 390
 391int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
 392{
 393	if (!mv88e6352_port_has_serdes(chip, port))
 394		return 0;
 395
 396	return 32 * sizeof(u16);
 397}
 398
 399void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
 400{
 401	u16 *p = _p;
 402	u16 reg;
 403	int i;
 404
 405	if (!mv88e6352_port_has_serdes(chip, port))
 406		return;
 407
 408	for (i = 0 ; i < 32; i++) {
 409		mv88e6352_serdes_read(chip, i, &reg);
 410		p[i] = reg;
 411	}
 412}
 413
 414u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
 415{
 416	u8 cmode = chip->ports[port].cmode;
 417	u8 lane = 0;
 418
 419	switch (port) {
 420	case 5:
 421		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 422		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 423		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
 424			lane = MV88E6341_PORT5_LANE;
 425		break;
 426	}
 427
 428	return lane;
 429}
 430
 431u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
 432{
 433	u8 cmode = chip->ports[port].cmode;
 434	u8 lane = 0;
 435
 436	switch (port) {
 437	case 9:
 438		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 439		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 440		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
 441			lane = MV88E6390_PORT9_LANE0;
 442		break;
 443	case 10:
 444		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 445		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 446		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
 447			lane = MV88E6390_PORT10_LANE0;
 448		break;
 449	}
 450
 451	return lane;
 452}
 453
 454u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
 455{
 456	u8 cmode_port = chip->ports[port].cmode;
 457	u8 cmode_port10 = chip->ports[10].cmode;
 458	u8 cmode_port9 = chip->ports[9].cmode;
 459	u8 lane = 0;
 460
 461	switch (port) {
 462	case 2:
 463		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 464		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 465		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
 466			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
 467				lane = MV88E6390_PORT9_LANE1;
 468		break;
 469	case 3:
 470		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 471		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 472		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
 473		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
 474			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
 475				lane = MV88E6390_PORT9_LANE2;
 476		break;
 477	case 4:
 478		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 479		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 480		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
 481		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
 482			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
 483				lane = MV88E6390_PORT9_LANE3;
 484		break;
 485	case 5:
 486		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 487		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 488		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
 489			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
 490				lane = MV88E6390_PORT10_LANE1;
 491		break;
 492	case 6:
 493		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 494		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 495		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
 496		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
 497			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
 498				lane = MV88E6390_PORT10_LANE2;
 499		break;
 500	case 7:
 501		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 502		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 503		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
 504		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
 505			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
 506				lane = MV88E6390_PORT10_LANE3;
 507		break;
 508	case 9:
 509		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 510		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 511		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
 512		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
 513		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
 514			lane = MV88E6390_PORT9_LANE0;
 515		break;
 516	case 10:
 517		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
 518		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
 519		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
 520		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
 521		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
 522			lane = MV88E6390_PORT10_LANE0;
 523		break;
 524	}
 525
 526	return lane;
 527}
 528
 529/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
 530static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
 531				      bool up)
 532{
 533	u16 val, new_val;
 
 534	int err;
 535
 536	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 537				    MV88E6390_10G_CTRL1, &val);
 538
 539	if (err)
 540		return err;
 541
 542	if (up)
 543		new_val = val & ~(MDIO_CTRL1_RESET |
 544				  MDIO_PCS_CTRL1_LOOPBACK |
 545				  MDIO_CTRL1_LPOWER);
 546	else
 547		new_val = val | MDIO_CTRL1_LPOWER;
 548
 549	if (val != new_val)
 550		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 551					     MV88E6390_10G_CTRL1, new_val);
 552
 553	return err;
 554}
 555
 556/* Set power up/down for SGMII and 1000Base-X */
 557static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
 558					bool up)
 559{
 560	u16 val, new_val;
 
 561	int err;
 562
 563	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 564				    MV88E6390_SGMII_BMCR, &val);
 
 565	if (err)
 566		return err;
 567
 568	if (up)
 569		new_val = val & ~(BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN);
 
 
 570	else
 571		new_val = val | BMCR_PDOWN;
 572
 573	if (val != new_val)
 574		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 575					     MV88E6390_SGMII_BMCR, new_val);
 576
 577	return err;
 578}
 579
 580struct mv88e6390_serdes_hw_stat {
 581	char string[ETH_GSTRING_LEN];
 582	int reg;
 583};
 584
 585static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {
 586	{ "serdes_rx_pkts", 0xf021 },
 587	{ "serdes_rx_bytes", 0xf024 },
 588	{ "serdes_rx_pkts_error", 0xf027 },
 589};
 590
 591int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
 592{
 593	if (mv88e6390_serdes_get_lane(chip, port) == 0)
 594		return 0;
 595
 596	return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
 597}
 598
 599int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
 600				 int port, uint8_t *data)
 601{
 602	struct mv88e6390_serdes_hw_stat *stat;
 603	int i;
 604
 605	if (mv88e6390_serdes_get_lane(chip, port) == 0)
 606		return 0;
 607
 608	for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
 609		stat = &mv88e6390_serdes_hw_stats[i];
 610		memcpy(data + i * ETH_GSTRING_LEN, stat->string,
 611		       ETH_GSTRING_LEN);
 612	}
 613	return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
 614}
 615
 616static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane,
 617					  struct mv88e6390_serdes_hw_stat *stat)
 618{
 619	u16 reg[3];
 620	int err, i;
 621
 622	for (i = 0; i < 3; i++) {
 623		err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 624					    stat->reg + i, &reg[i]);
 625		if (err) {
 626			dev_err(chip->dev, "failed to read statistic\n");
 627			return 0;
 628		}
 629	}
 630
 631	return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32);
 632}
 633
 634int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
 635			       uint64_t *data)
 636{
 637	struct mv88e6390_serdes_hw_stat *stat;
 638	int lane;
 639	int i;
 640
 641	lane = mv88e6390_serdes_get_lane(chip, port);
 642	if (lane == 0)
 643		return 0;
 644
 645	for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
 646		stat = &mv88e6390_serdes_hw_stats[i];
 647		data[i] = mv88e6390_serdes_get_stat(chip, lane, stat);
 648	}
 649
 650	return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
 651}
 652
 653static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
 654{
 655	u16 reg;
 656	int err;
 
 657
 658	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 659				    MV88E6390_PG_CONTROL, &reg);
 660	if (err)
 661		return err;
 662
 663	reg |= MV88E6390_PG_CONTROL_ENABLE_PC;
 664	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 665				      MV88E6390_PG_CONTROL, reg);
 
 
 
 
 
 
 
 
 
 
 666}
 667
 668int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
 669			   bool up)
 670{
 671	u8 cmode = chip->ports[port].cmode;
 672	int err = 0;
 673
 674	switch (cmode) {
 
 675	case MV88E6XXX_PORT_STS_CMODE_SGMII:
 676	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 677	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 678		err = mv88e6390_serdes_power_sgmii(chip, lane, up);
 679		break;
 680	case MV88E6XXX_PORT_STS_CMODE_XAUI:
 681	case MV88E6XXX_PORT_STS_CMODE_RXAUI:
 682		err = mv88e6390_serdes_power_10g(chip, lane, up);
 683		break;
 684	}
 685
 686	if (!err && up)
 687		err = mv88e6390_serdes_enable_checker(chip, lane);
 688
 689	return err;
 690}
 691
 692int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
 693				u8 lane, unsigned int mode,
 694				phy_interface_t interface,
 695				const unsigned long *advertise)
 696{
 697	u16 val, bmcr, adv;
 698	bool changed;
 699	int err;
 700
 701	switch (interface) {
 702	case PHY_INTERFACE_MODE_SGMII:
 703		adv = 0x0001;
 704		break;
 705
 706	case PHY_INTERFACE_MODE_1000BASEX:
 707		adv = linkmode_adv_to_mii_adv_x(advertise,
 708					ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
 709		break;
 710
 711	case PHY_INTERFACE_MODE_2500BASEX:
 712		adv = linkmode_adv_to_mii_adv_x(advertise,
 713					ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
 714		break;
 715
 716	default:
 717		return 0;
 718	}
 719
 720	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 721				    MV88E6390_SGMII_ADVERTISE, &val);
 722	if (err)
 723		return err;
 724
 725	changed = val != adv;
 726	if (changed) {
 727		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 728					     MV88E6390_SGMII_ADVERTISE, adv);
 729		if (err)
 730			return err;
 731	}
 732
 733	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 734				    MV88E6390_SGMII_BMCR, &val);
 735	if (err)
 736		return err;
 737
 738	if (phylink_autoneg_inband(mode))
 739		bmcr = val | BMCR_ANENABLE;
 740	else
 741		bmcr = val & ~BMCR_ANENABLE;
 742
 743	/* setting ANENABLE triggers a restart of negotiation */
 744	if (bmcr == val)
 745		return changed;
 746
 747	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 748				      MV88E6390_SGMII_BMCR, bmcr);
 749}
 750
 751static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
 752	int port, u8 lane, struct phylink_link_state *state)
 753{
 754	u16 lpa, status;
 755	int err;
 756
 757	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 758				    MV88E6390_SGMII_PHY_STATUS, &status);
 759	if (err) {
 760		dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
 761		return err;
 762	}
 763
 764	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 765				    MV88E6390_SGMII_LPA, &lpa);
 766	if (err) {
 767		dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err);
 768		return err;
 769	}
 770
 771	return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
 772}
 773
 774static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
 775	int port, u8 lane, struct phylink_link_state *state)
 776{
 777	u16 status;
 778	int err;
 779
 780	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 781				    MV88E6390_10G_STAT1, &status);
 782	if (err)
 783		return err;
 784
 785	state->link = !!(status & MDIO_STAT1_LSTATUS);
 786	if (state->link) {
 787		state->speed = SPEED_10000;
 788		state->duplex = DUPLEX_FULL;
 789	}
 790
 791	return 0;
 792}
 793
 794int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
 795				   u8 lane, struct phylink_link_state *state)
 796{
 797	switch (state->interface) {
 798	case PHY_INTERFACE_MODE_SGMII:
 799	case PHY_INTERFACE_MODE_1000BASEX:
 800	case PHY_INTERFACE_MODE_2500BASEX:
 801		return mv88e6390_serdes_pcs_get_state_sgmii(chip, port, lane,
 802							    state);
 803	case PHY_INTERFACE_MODE_XAUI:
 804	case PHY_INTERFACE_MODE_RXAUI:
 805		return mv88e6390_serdes_pcs_get_state_10g(chip, port, lane,
 806							  state);
 807
 808	default:
 809		return -EOPNOTSUPP;
 810	}
 811}
 812
 813int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
 814				    u8 lane)
 815{
 816	u16 bmcr;
 817	int err;
 818
 819	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 820				    MV88E6390_SGMII_BMCR, &bmcr);
 821	if (err)
 822		return err;
 823
 824	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 825				      MV88E6390_SGMII_BMCR,
 826				      bmcr | BMCR_ANRESTART);
 827}
 828
 829int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port,
 830				 u8 lane, int speed, int duplex)
 831{
 832	u16 val, bmcr;
 833	int err;
 834
 835	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 836				    MV88E6390_SGMII_BMCR, &val);
 837	if (err)
 838		return err;
 839
 840	bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000);
 841	switch (speed) {
 842	case SPEED_2500:
 843	case SPEED_1000:
 844		bmcr |= BMCR_SPEED1000;
 845		break;
 846	case SPEED_100:
 847		bmcr |= BMCR_SPEED100;
 848		break;
 849	case SPEED_10:
 850		break;
 851	}
 852
 853	if (duplex == DUPLEX_FULL)
 854		bmcr |= BMCR_FULLDPLX;
 855
 856	if (bmcr == val)
 857		return 0;
 858
 859	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 860				      MV88E6390_SGMII_BMCR, bmcr);
 861}
 862
 863static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
 864					    int port, u8 lane)
 865{
 866	u16 bmsr;
 867	int err;
 868
 869	/* If the link has dropped, we want to know about it. */
 870	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 871				    MV88E6390_SGMII_BMSR, &bmsr);
 872	if (err) {
 873		dev_err(chip->dev, "can't read Serdes BMSR: %d\n", err);
 874		return;
 875	}
 876
 877	dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS));
 878}
 879
 880static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
 881					     u8 lane, bool enable)
 882{
 883	u16 val = 0;
 884
 885	if (enable)
 886		val |= MV88E6390_SGMII_INT_LINK_DOWN |
 887			MV88E6390_SGMII_INT_LINK_UP;
 888
 889	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
 890				      MV88E6390_SGMII_INT_ENABLE, val);
 891}
 892
 893int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
 894				bool enable)
 895{
 896	u8 cmode = chip->ports[port].cmode;
 897
 898	switch (cmode) {
 899	case MV88E6XXX_PORT_STS_CMODE_SGMII:
 900	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 
 
 
 901	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 902		return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
 903	}
 904
 905	return 0;
 906}
 907
 908static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
 909					     u8 lane, u16 *status)
 910{
 
 911	int err;
 912
 913	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 914				    MV88E6390_SGMII_INT_STATUS, status);
 
 915
 916	return err;
 917}
 918
 919irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
 920					u8 lane)
 921{
 922	u8 cmode = chip->ports[port].cmode;
 923	irqreturn_t ret = IRQ_NONE;
 924	u16 status;
 925	int err;
 926
 927	switch (cmode) {
 928	case MV88E6XXX_PORT_STS_CMODE_SGMII:
 929	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
 930	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
 931		err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
 932		if (err)
 933			return ret;
 934		if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
 935			      MV88E6390_SGMII_INT_LINK_UP)) {
 936			ret = IRQ_HANDLED;
 937			mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
 938		}
 
 
 
 
 
 
 939	}
 940
 941	return ret;
 942}
 943
 944unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
 945{
 946	return irq_find_mapping(chip->g2_irq.domain, port);
 947}
 948
 949static const u16 mv88e6390_serdes_regs[] = {
 950	/* SERDES common registers */
 951	0xf00a, 0xf00b, 0xf00c,
 952	0xf010, 0xf011, 0xf012, 0xf013,
 953	0xf016, 0xf017, 0xf018,
 954	0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
 955	0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
 956	0xf028, 0xf029,
 957	0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
 958	0xf038, 0xf039,
 959	/* SGMII */
 960	0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
 961	0x2008,
 962	0x200f,
 963	0xa000, 0xa001, 0xa002, 0xa003,
 964	/* 10Gbase-X */
 965	0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
 966	0x1008,
 967	0x100e, 0x100f,
 968	0x1018, 0x1019,
 969	0x9000, 0x9001, 0x9002, 0x9003, 0x9004,
 970	0x9006,
 971	0x9010, 0x9011, 0x9012, 0x9013, 0x9014, 0x9015, 0x9016,
 972	/* 10Gbase-R */
 973	0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
 974	0x1028, 0x1029, 0x102a, 0x102b,
 975};
 976
 977int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port)
 978{
 979	if (mv88e6xxx_serdes_get_lane(chip, port) == 0)
 980		return 0;
 981
 982	return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16);
 983}
 984
 985void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
 986{
 987	u16 *p = _p;
 988	int lane;
 989	u16 reg;
 990	int i;
 991
 992	lane = mv88e6xxx_serdes_get_lane(chip, port);
 993	if (lane == 0)
 994		return;
 995
 996	for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) {
 997		mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
 998				      mv88e6390_serdes_regs[i], &reg);
 999		p[i] = reg;
1000	}
1001}