Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
  4 * Synopsys DesignWare XPCS helpers
  5 *
  6 * Author: Jose Abreu <Jose.Abreu@synopsys.com>
  7 */
  8
  9#include <linux/delay.h>
 10#include <linux/mdio.h>
 11#include <linux/mdio-xpcs.h>
 12#include <linux/phylink.h>
 13#include <linux/workqueue.h>
 14
 15#define SYNOPSYS_XPCS_USXGMII_ID	0x7996ced0
 16#define SYNOPSYS_XPCS_10GKR_ID		0x7996ced0
 17#define SYNOPSYS_XPCS_XLGMII_ID		0x7996ced0
 18#define SYNOPSYS_XPCS_MASK		0xffffffff
 19
 20/* Vendor regs access */
 21#define DW_VENDOR			BIT(15)
 22
 23/* VR_XS_PCS */
 24#define DW_USXGMII_RST			BIT(10)
 25#define DW_USXGMII_EN			BIT(9)
 26#define DW_VR_XS_PCS_DIG_STS		0x0010
 27#define DW_RXFIFO_ERR			GENMASK(6, 5)
 28
 29/* SR_MII */
 30#define DW_USXGMII_FULL			BIT(8)
 31#define DW_USXGMII_SS_MASK		(BIT(13) | BIT(6) | BIT(5))
 32#define DW_USXGMII_10000		(BIT(13) | BIT(6))
 33#define DW_USXGMII_5000			(BIT(13) | BIT(5))
 34#define DW_USXGMII_2500			(BIT(5))
 35#define DW_USXGMII_1000			(BIT(6))
 36#define DW_USXGMII_100			(BIT(13))
 37#define DW_USXGMII_10			(0)
 38
 39/* SR_AN */
 40#define DW_SR_AN_ADV1			0x10
 41#define DW_SR_AN_ADV2			0x11
 42#define DW_SR_AN_ADV3			0x12
 43#define DW_SR_AN_LP_ABL1		0x13
 44#define DW_SR_AN_LP_ABL2		0x14
 45#define DW_SR_AN_LP_ABL3		0x15
 46
 47/* Clause 73 Defines */
 48/* AN_LP_ABL1 */
 49#define DW_C73_PAUSE			BIT(10)
 50#define DW_C73_ASYM_PAUSE		BIT(11)
 51#define DW_C73_AN_ADV_SF		0x1
 52/* AN_LP_ABL2 */
 53#define DW_C73_1000KX			BIT(5)
 54#define DW_C73_10000KX4			BIT(6)
 55#define DW_C73_10000KR			BIT(7)
 56/* AN_LP_ABL3 */
 57#define DW_C73_2500KX			BIT(0)
 58#define DW_C73_5000KR			BIT(1)
 59
 60static const int xpcs_usxgmii_features[] = {
 61	ETHTOOL_LINK_MODE_Pause_BIT,
 62	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
 63	ETHTOOL_LINK_MODE_Autoneg_BIT,
 64	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
 65	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
 66	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
 67	ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
 68	__ETHTOOL_LINK_MODE_MASK_NBITS,
 69};
 70
 71static const int xpcs_10gkr_features[] = {
 72	ETHTOOL_LINK_MODE_Pause_BIT,
 73	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
 74	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
 75	__ETHTOOL_LINK_MODE_MASK_NBITS,
 76};
 77
 78static const int xpcs_xlgmii_features[] = {
 79	ETHTOOL_LINK_MODE_Pause_BIT,
 80	ETHTOOL_LINK_MODE_Asym_Pause_BIT,
 81	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
 82	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
 83	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
 84	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
 85	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
 86	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
 87	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
 88	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
 89	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
 90	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
 91	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
 92	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
 93	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
 94	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
 95	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
 96	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
 97	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
 98	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
 99	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
100	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
101	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
102	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
103	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
104	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
105	__ETHTOOL_LINK_MODE_MASK_NBITS,
106};
107
108static const phy_interface_t xpcs_usxgmii_interfaces[] = {
109	PHY_INTERFACE_MODE_USXGMII,
110	PHY_INTERFACE_MODE_MAX,
111};
112
113static const phy_interface_t xpcs_10gkr_interfaces[] = {
114	PHY_INTERFACE_MODE_10GKR,
115	PHY_INTERFACE_MODE_MAX,
116};
117
118static const phy_interface_t xpcs_xlgmii_interfaces[] = {
119	PHY_INTERFACE_MODE_XLGMII,
120	PHY_INTERFACE_MODE_MAX,
121};
122
123static struct xpcs_id {
124	u32 id;
125	u32 mask;
126	const int *supported;
127	const phy_interface_t *interface;
128} xpcs_id_list[] = {
129	{
130		.id = SYNOPSYS_XPCS_USXGMII_ID,
131		.mask = SYNOPSYS_XPCS_MASK,
132		.supported = xpcs_usxgmii_features,
133		.interface = xpcs_usxgmii_interfaces,
134	}, {
135		.id = SYNOPSYS_XPCS_10GKR_ID,
136		.mask = SYNOPSYS_XPCS_MASK,
137		.supported = xpcs_10gkr_features,
138		.interface = xpcs_10gkr_interfaces,
139	}, {
140		.id = SYNOPSYS_XPCS_XLGMII_ID,
141		.mask = SYNOPSYS_XPCS_MASK,
142		.supported = xpcs_xlgmii_features,
143		.interface = xpcs_xlgmii_interfaces,
144	},
145};
146
147static int xpcs_read(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
148{
149	u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg;
150
151	return mdiobus_read(xpcs->bus, xpcs->addr, reg_addr);
152}
153
154static int xpcs_write(struct mdio_xpcs_args *xpcs, int dev, u32 reg, u16 val)
155{
156	u32 reg_addr = MII_ADDR_C45 | dev << 16 | reg;
157
158	return mdiobus_write(xpcs->bus, xpcs->addr, reg_addr, val);
159}
160
161static int xpcs_read_vendor(struct mdio_xpcs_args *xpcs, int dev, u32 reg)
162{
163	return xpcs_read(xpcs, dev, DW_VENDOR | reg);
164}
165
166static int xpcs_write_vendor(struct mdio_xpcs_args *xpcs, int dev, int reg,
167			     u16 val)
168{
169	return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
170}
171
172static int xpcs_read_vpcs(struct mdio_xpcs_args *xpcs, int reg)
173{
174	return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
175}
176
177static int xpcs_write_vpcs(struct mdio_xpcs_args *xpcs, int reg, u16 val)
178{
179	return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
180}
181
182static int xpcs_poll_reset(struct mdio_xpcs_args *xpcs, int dev)
183{
184	/* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
185	unsigned int retries = 12;
186	int ret;
187
188	do {
189		msleep(50);
190		ret = xpcs_read(xpcs, dev, MDIO_CTRL1);
191		if (ret < 0)
192			return ret;
193	} while (ret & MDIO_CTRL1_RESET && --retries);
194
195	return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
196}
197
198static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs, int dev)
199{
200	int ret;
201
202	ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET);
203	if (ret < 0)
204		return ret;
205
206	return xpcs_poll_reset(xpcs, dev);
207}
208
209#define xpcs_warn(__xpcs, __state, __args...) \
210({ \
211	if ((__state)->link) \
212		dev_warn(&(__xpcs)->bus->dev, ##__args); \
213})
214
215static int xpcs_read_fault(struct mdio_xpcs_args *xpcs,
216			   struct phylink_link_state *state)
217{
218	int ret;
219
220	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
221	if (ret < 0)
222		return ret;
223
224	if (ret & MDIO_STAT1_FAULT) {
225		xpcs_warn(xpcs, state, "Link fault condition detected!\n");
226		return -EFAULT;
227	}
228
229	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2);
230	if (ret < 0)
231		return ret;
232
233	if (ret & MDIO_STAT2_RXFAULT)
234		xpcs_warn(xpcs, state, "Receiver fault detected!\n");
235	if (ret & MDIO_STAT2_TXFAULT)
236		xpcs_warn(xpcs, state, "Transmitter fault detected!\n");
237
238	ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS);
239	if (ret < 0)
240		return ret;
241
242	if (ret & DW_RXFIFO_ERR) {
243		xpcs_warn(xpcs, state, "FIFO fault condition detected!\n");
244		return -EFAULT;
245	}
246
247	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
248	if (ret < 0)
249		return ret;
250
251	if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK))
252		xpcs_warn(xpcs, state, "Link is not locked!\n");
253
254	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2);
255	if (ret < 0)
256		return ret;
257
258	if (ret & MDIO_PCS_10GBRT_STAT2_ERR) {
259		xpcs_warn(xpcs, state, "Link has errors!\n");
260		return -EFAULT;
261	}
262
263	return 0;
264}
265
266static int xpcs_read_link(struct mdio_xpcs_args *xpcs, bool an)
267{
268	bool link = true;
269	int ret;
270
271	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
272	if (ret < 0)
273		return ret;
274
275	if (!(ret & MDIO_STAT1_LSTATUS))
276		link = false;
277
278	if (an) {
279		ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
280		if (ret < 0)
281			return ret;
282
283		if (!(ret & MDIO_STAT1_LSTATUS))
284			link = false;
285	}
286
287	return link;
288}
289
290static int xpcs_get_max_usxgmii_speed(const unsigned long *supported)
291{
292	int max = SPEED_UNKNOWN;
293
294	if (phylink_test(supported, 1000baseKX_Full))
295		max = SPEED_1000;
296	if (phylink_test(supported, 2500baseX_Full))
297		max = SPEED_2500;
298	if (phylink_test(supported, 10000baseKX4_Full))
299		max = SPEED_10000;
300	if (phylink_test(supported, 10000baseKR_Full))
301		max = SPEED_10000;
302
303	return max;
304}
305
306static int xpcs_config_usxgmii(struct mdio_xpcs_args *xpcs, int speed)
307{
308	int ret, speed_sel;
309
310	switch (speed) {
311	case SPEED_10:
312		speed_sel = DW_USXGMII_10;
313		break;
314	case SPEED_100:
315		speed_sel = DW_USXGMII_100;
316		break;
317	case SPEED_1000:
318		speed_sel = DW_USXGMII_1000;
319		break;
320	case SPEED_2500:
321		speed_sel = DW_USXGMII_2500;
322		break;
323	case SPEED_5000:
324		speed_sel = DW_USXGMII_5000;
325		break;
326	case SPEED_10000:
327		speed_sel = DW_USXGMII_10000;
328		break;
329	default:
330		/* Nothing to do here */
331		return -EINVAL;
332	}
333
334	ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
335	if (ret < 0)
336		return ret;
337
338	ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN);
339	if (ret < 0)
340		return ret;
341
342	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
343	if (ret < 0)
344		return ret;
345
346	ret &= ~DW_USXGMII_SS_MASK;
347	ret |= speed_sel | DW_USXGMII_FULL;
348
349	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
350	if (ret < 0)
351		return ret;
352
353	ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
354	if (ret < 0)
355		return ret;
356
357	return xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
358}
359
360static int xpcs_config_aneg_c73(struct mdio_xpcs_args *xpcs)
361{
362	int ret, adv;
363
364	/* By default, in USXGMII mode XPCS operates at 10G baud and
365	 * replicates data to achieve lower speeds. Hereby, in this
366	 * default configuration we need to advertise all supported
367	 * modes and not only the ones we want to use.
368	 */
369
370	/* SR_AN_ADV3 */
371	adv = 0;
372	if (phylink_test(xpcs->supported, 2500baseX_Full))
373		adv |= DW_C73_2500KX;
374
375	/* TODO: 5000baseKR */
376
377	ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
378	if (ret < 0)
379		return ret;
380
381	/* SR_AN_ADV2 */
382	adv = 0;
383	if (phylink_test(xpcs->supported, 1000baseKX_Full))
384		adv |= DW_C73_1000KX;
385	if (phylink_test(xpcs->supported, 10000baseKX4_Full))
386		adv |= DW_C73_10000KX4;
387	if (phylink_test(xpcs->supported, 10000baseKR_Full))
388		adv |= DW_C73_10000KR;
389
390	ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
391	if (ret < 0)
392		return ret;
393
394	/* SR_AN_ADV1 */
395	adv = DW_C73_AN_ADV_SF;
396	if (phylink_test(xpcs->supported, Pause))
397		adv |= DW_C73_PAUSE;
398	if (phylink_test(xpcs->supported, Asym_Pause))
399		adv |= DW_C73_ASYM_PAUSE;
400
401	return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
402}
403
404static int xpcs_config_aneg(struct mdio_xpcs_args *xpcs)
405{
406	int ret;
407
408	ret = xpcs_config_aneg_c73(xpcs);
409	if (ret < 0)
410		return ret;
411
412	ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1);
413	if (ret < 0)
414		return ret;
415
416	ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
417
418	return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
419}
420
421static int xpcs_aneg_done(struct mdio_xpcs_args *xpcs,
422			  struct phylink_link_state *state)
423{
424	int ret;
425
426	ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
427	if (ret < 0)
428		return ret;
429
430	if (ret & MDIO_AN_STAT1_COMPLETE) {
431		ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
432		if (ret < 0)
433			return ret;
434
435		/* Check if Aneg outcome is valid */
436		if (!(ret & DW_C73_AN_ADV_SF)) {
437			xpcs_config_aneg(xpcs);
438			return 0;
439		}
440
441		return 1;
442	}
443
444	return 0;
445}
446
447static int xpcs_read_lpa(struct mdio_xpcs_args *xpcs,
448			 struct phylink_link_state *state)
449{
450	int ret;
451
452	ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
453	if (ret < 0)
454		return ret;
455
456	if (!(ret & MDIO_AN_STAT1_LPABLE)) {
457		phylink_clear(state->lp_advertising, Autoneg);
458		return 0;
459	}
460
461	phylink_set(state->lp_advertising, Autoneg);
462
463	/* Clause 73 outcome */
464	ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3);
465	if (ret < 0)
466		return ret;
467
468	if (ret & DW_C73_2500KX)
469		phylink_set(state->lp_advertising, 2500baseX_Full);
470
471	ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2);
472	if (ret < 0)
473		return ret;
474
475	if (ret & DW_C73_1000KX)
476		phylink_set(state->lp_advertising, 1000baseKX_Full);
477	if (ret & DW_C73_10000KX4)
478		phylink_set(state->lp_advertising, 10000baseKX4_Full);
479	if (ret & DW_C73_10000KR)
480		phylink_set(state->lp_advertising, 10000baseKR_Full);
481
482	ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
483	if (ret < 0)
484		return ret;
485
486	if (ret & DW_C73_PAUSE)
487		phylink_set(state->lp_advertising, Pause);
488	if (ret & DW_C73_ASYM_PAUSE)
489		phylink_set(state->lp_advertising, Asym_Pause);
490
491	linkmode_and(state->lp_advertising, state->lp_advertising,
492		     state->advertising);
493	return 0;
494}
495
496static void xpcs_resolve_lpa(struct mdio_xpcs_args *xpcs,
497			     struct phylink_link_state *state)
498{
499	int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
500
501	state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
502	state->speed = max_speed;
503	state->duplex = DUPLEX_FULL;
504}
505
506static int xpcs_get_max_xlgmii_speed(struct mdio_xpcs_args *xpcs,
507				     struct phylink_link_state *state)
508{
509	unsigned long *adv = state->advertising;
510	int speed = SPEED_UNKNOWN;
511	int bit;
512
513	for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) {
514		int new_speed = SPEED_UNKNOWN;
515
516		switch (bit) {
517		case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
518		case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
519		case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
520			new_speed = SPEED_25000;
521			break;
522		case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
523		case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
524		case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
525		case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
526			new_speed = SPEED_40000;
527			break;
528		case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT:
529		case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT:
530		case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT:
531		case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
532		case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
533		case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
534		case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
535		case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT:
536			new_speed = SPEED_50000;
537			break;
538		case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
539		case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
540		case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
541		case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
542		case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT:
543		case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT:
544		case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT:
545		case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT:
546		case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT:
547			new_speed = SPEED_100000;
548			break;
549		default:
550			continue;
551		}
552
553		if (new_speed > speed)
554			speed = new_speed;
555	}
556
557	return speed;
558}
559
560static void xpcs_resolve_pma(struct mdio_xpcs_args *xpcs,
561			     struct phylink_link_state *state)
562{
563	state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
564	state->duplex = DUPLEX_FULL;
565
566	switch (state->interface) {
567	case PHY_INTERFACE_MODE_10GKR:
568		state->speed = SPEED_10000;
569		break;
570	case PHY_INTERFACE_MODE_XLGMII:
571		state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
572		break;
573	default:
574		state->speed = SPEED_UNKNOWN;
575		break;
576	}
577}
578
579static int xpcs_validate(struct mdio_xpcs_args *xpcs,
580			 unsigned long *supported,
581			 struct phylink_link_state *state)
582{
583	linkmode_and(supported, supported, xpcs->supported);
584	linkmode_and(state->advertising, state->advertising, xpcs->supported);
585	return 0;
586}
587
588static int xpcs_config(struct mdio_xpcs_args *xpcs,
589		       const struct phylink_link_state *state)
590{
591	int ret;
592
593	if (state->an_enabled) {
594		ret = xpcs_config_aneg(xpcs);
595		if (ret)
596			return ret;
597	}
598
599	return 0;
600}
601
602static int xpcs_get_state(struct mdio_xpcs_args *xpcs,
603			  struct phylink_link_state *state)
604{
605	int ret;
606
607	/* Link needs to be read first ... */
608	state->link = xpcs_read_link(xpcs, state->an_enabled) > 0 ? 1 : 0;
609
610	/* ... and then we check the faults. */
611	ret = xpcs_read_fault(xpcs, state);
612	if (ret) {
613		ret = xpcs_soft_reset(xpcs, MDIO_MMD_PCS);
614		if (ret)
615			return ret;
616
617		state->link = 0;
618
619		return xpcs_config(xpcs, state);
620	}
621
622	if (state->an_enabled && xpcs_aneg_done(xpcs, state)) {
623		state->an_complete = true;
624		xpcs_read_lpa(xpcs, state);
625		xpcs_resolve_lpa(xpcs, state);
626	} else if (state->an_enabled) {
627		state->link = 0;
628	} else if (state->link) {
629		xpcs_resolve_pma(xpcs, state);
630	}
631
632	return 0;
633}
634
635static int xpcs_link_up(struct mdio_xpcs_args *xpcs, int speed,
636			phy_interface_t interface)
637{
638	if (interface == PHY_INTERFACE_MODE_USXGMII)
639		return xpcs_config_usxgmii(xpcs, speed);
640
641	return 0;
642}
643
644static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
645{
646	int ret;
647	u32 id;
648
649	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
650	if (ret < 0)
651		return 0xffffffff;
652
653	id = ret << 16;
654
655	ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
656	if (ret < 0)
657		return 0xffffffff;
658
659	return id | ret;
660}
661
662static bool xpcs_check_features(struct mdio_xpcs_args *xpcs,
663				struct xpcs_id *match,
664				phy_interface_t interface)
665{
666	int i;
667
668	for (i = 0; match->interface[i] != PHY_INTERFACE_MODE_MAX; i++) {
669		if (match->interface[i] == interface)
670			break;
671	}
672
673	if (match->interface[i] == PHY_INTERFACE_MODE_MAX)
674		return false;
675
676	for (i = 0; match->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
677		set_bit(match->supported[i], xpcs->supported);
678
679	return true;
680}
681
682static int xpcs_probe(struct mdio_xpcs_args *xpcs, phy_interface_t interface)
683{
684	u32 xpcs_id = xpcs_get_id(xpcs);
685	struct xpcs_id *match = NULL;
686	int i;
687
688	for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
689		struct xpcs_id *entry = &xpcs_id_list[i];
690
691		if ((xpcs_id & entry->mask) == entry->id) {
692			match = entry;
693
694			if (xpcs_check_features(xpcs, match, interface))
695				return xpcs_soft_reset(xpcs, MDIO_MMD_PCS);
696		}
697	}
698
699	return -ENODEV;
700}
701
702static struct mdio_xpcs_ops xpcs_ops = {
703	.validate = xpcs_validate,
704	.config = xpcs_config,
705	.get_state = xpcs_get_state,
706	.link_up = xpcs_link_up,
707	.probe = xpcs_probe,
708};
709
710struct mdio_xpcs_ops *mdio_xpcs_get_ops(void)
711{
712	return &xpcs_ops;
713}
714EXPORT_SYMBOL_GPL(mdio_xpcs_get_ops);
715
716MODULE_LICENSE("GPL v2");