1// SPDX-License-Identifier: GPL-2.0+
2/* Copyright (c) 2021-2022 NXP. */
3
4#include <linux/module.h>
5#include <linux/of.h>
6#include <linux/phy.h>
7#include <linux/phy/phy.h>
8#include <linux/platform_device.h>
9#include <linux/workqueue.h>
10
11#define LYNX_28G_NUM_LANE			8
12#define LYNX_28G_NUM_PLL			2
13
14/* General registers per SerDes block */
15#define LYNX_28G_PCC8				0x10a0
16#define LYNX_28G_PCC8_SGMII			0x1
17#define LYNX_28G_PCC8_SGMII_DIS			0x0
18
19#define LYNX_28G_PCCC				0x10b0
20#define LYNX_28G_PCCC_10GBASER			0x9
21#define LYNX_28G_PCCC_USXGMII			0x1
22#define LYNX_28G_PCCC_SXGMII_DIS		0x0
23
24#define LYNX_28G_LNa_PCC_OFFSET(lane)		(4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
25
26/* Per PLL registers */
27#define LYNX_28G_PLLnRSTCTL(pll)		(0x400 + (pll) * 0x100 + 0x0)
28#define LYNX_28G_PLLnRSTCTL_DIS(rstctl)		(((rstctl) & BIT(24)) >> 24)
29#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl)	(((rstctl) & BIT(23)) >> 23)
30
31#define LYNX_28G_PLLnCR0(pll)			(0x400 + (pll) * 0x100 + 0x4)
32#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0)	(((cr0) & GENMASK(20, 16)))
33#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ	0x0
34#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ	0x10000
35#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ	0x20000
36#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ	0x30000
37#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ	0x40000
38
39#define LYNX_28G_PLLnCR1(pll)			(0x400 + (pll) * 0x100 + 0x8)
40#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1)		(((cr1) & GENMASK(28, 24)))
41#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO	0x0
42#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO	0x10000000
43#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO	0x6000000
44
45/* Per SerDes lane registers */
46/* Lane a General Control Register */
47#define LYNX_28G_LNaGCR0(lane)			(0x800 + (lane) * 0x100 + 0x0)
48#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK		GENMASK(7, 3)
49#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII	0x8
50#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI		0x50
51#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK		GENMASK(2, 0)
52#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT	0x0
53#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT	0x2
54
55/* Lane a Tx Reset Control Register */
56#define LYNX_28G_LNaTRSTCTL(lane)		(0x800 + (lane) * 0x100 + 0x20)
57#define LYNX_28G_LNaTRSTCTL_HLT_REQ		BIT(27)
58#define LYNX_28G_LNaTRSTCTL_RST_DONE		BIT(30)
59#define LYNX_28G_LNaTRSTCTL_RST_REQ		BIT(31)
60
61/* Lane a Tx General Control Register */
62#define LYNX_28G_LNaTGCR0(lane)			(0x800 + (lane) * 0x100 + 0x24)
63#define LYNX_28G_LNaTGCR0_USE_PLLF		0x0
64#define LYNX_28G_LNaTGCR0_USE_PLLS		BIT(28)
65#define LYNX_28G_LNaTGCR0_USE_PLL_MSK		BIT(28)
66#define LYNX_28G_LNaTGCR0_N_RATE_FULL		0x0
67#define LYNX_28G_LNaTGCR0_N_RATE_HALF		0x1000000
68#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER	0x2000000
69#define LYNX_28G_LNaTGCR0_N_RATE_MSK		GENMASK(26, 24)
70
71#define LYNX_28G_LNaTECR0(lane)			(0x800 + (lane) * 0x100 + 0x30)
72
73/* Lane a Rx Reset Control Register */
74#define LYNX_28G_LNaRRSTCTL(lane)		(0x800 + (lane) * 0x100 + 0x40)
75#define LYNX_28G_LNaRRSTCTL_HLT_REQ		BIT(27)
76#define LYNX_28G_LNaRRSTCTL_RST_DONE		BIT(30)
77#define LYNX_28G_LNaRRSTCTL_RST_REQ		BIT(31)
78#define LYNX_28G_LNaRRSTCTL_CDR_LOCK		BIT(12)
79
80/* Lane a Rx General Control Register */
81#define LYNX_28G_LNaRGCR0(lane)			(0x800 + (lane) * 0x100 + 0x44)
82#define LYNX_28G_LNaRGCR0_USE_PLLF		0x0
83#define LYNX_28G_LNaRGCR0_USE_PLLS		BIT(28)
84#define LYNX_28G_LNaRGCR0_USE_PLL_MSK		BIT(28)
85#define LYNX_28G_LNaRGCR0_N_RATE_MSK		GENMASK(26, 24)
86#define LYNX_28G_LNaRGCR0_N_RATE_FULL		0x0
87#define LYNX_28G_LNaRGCR0_N_RATE_HALF		0x1000000
88#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER	0x2000000
89#define LYNX_28G_LNaRGCR0_N_RATE_MSK		GENMASK(26, 24)
90
91#define LYNX_28G_LNaRGCR1(lane)			(0x800 + (lane) * 0x100 + 0x48)
92
93#define LYNX_28G_LNaRECR0(lane)			(0x800 + (lane) * 0x100 + 0x50)
94#define LYNX_28G_LNaRECR1(lane)			(0x800 + (lane) * 0x100 + 0x54)
95#define LYNX_28G_LNaRECR2(lane)			(0x800 + (lane) * 0x100 + 0x58)
96
97#define LYNX_28G_LNaRSCCR0(lane)		(0x800 + (lane) * 0x100 + 0x74)
98
99#define LYNX_28G_LNaPSS(lane)			(0x1000 + (lane) * 0x4)
100#define LYNX_28G_LNaPSS_TYPE(pss)		(((pss) & GENMASK(30, 24)) >> 24)
101#define LYNX_28G_LNaPSS_TYPE_SGMII		0x4
102#define LYNX_28G_LNaPSS_TYPE_XFI		0x28
103
104#define LYNX_28G_SGMIIaCR1(lane)		(0x1804 + (lane) * 0x10)
105#define LYNX_28G_SGMIIaCR1_SGPCS_EN		BIT(11)
106#define LYNX_28G_SGMIIaCR1_SGPCS_DIS		0x0
107#define LYNX_28G_SGMIIaCR1_SGPCS_MSK		BIT(11)
108
109struct lynx_28g_priv;
110
111struct lynx_28g_pll {
112	struct lynx_28g_priv *priv;
113	u32 rstctl, cr0, cr1;
114	int id;
115	DECLARE_PHY_INTERFACE_MASK(supported);
116};
117
118struct lynx_28g_lane {
119	struct lynx_28g_priv *priv;
120	struct phy *phy;
121	bool powered_up;
122	bool init;
123	unsigned int id;
124	phy_interface_t interface;
125};
126
127struct lynx_28g_priv {
128	void __iomem *base;
129	struct device *dev;
130	/* Serialize concurrent access to registers shared between lanes,
131	 * like PCCn
132	 */
133	spinlock_t pcc_lock;
134	struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
135	struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
136
137	struct delayed_work cdr_check;
138};
139
140static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
141			 u32 val, u32 mask)
142{
143	void __iomem *reg = priv->base + off;
144	u32 orig, tmp;
145
146	orig = ioread32(reg);
147	tmp = orig & ~mask;
148	tmp |= val;
149	iowrite32(tmp, reg);
150}
151
152#define lynx_28g_lane_rmw(lane, reg, val, mask)	\
153	lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
154		     LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
155#define lynx_28g_lane_read(lane, reg)			\
156	ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
157#define lynx_28g_pll_read(pll, reg)			\
158	ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
159
160static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
161{
162	int i;
163
164	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
165		if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
166			continue;
167
168		if (test_bit(intf, priv->pll[i].supported))
169			return true;
170	}
171
172	return false;
173}
174
175static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
176					     phy_interface_t intf)
177{
178	struct lynx_28g_pll *pll;
179	int i;
180
181	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
182		pll = &priv->pll[i];
183
184		if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
185			continue;
186
187		if (test_bit(intf, pll->supported))
188			return pll;
189	}
190
191	return NULL;
192}
193
194static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
195				    struct lynx_28g_pll *pll,
196				    phy_interface_t intf)
197{
198	switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
199	case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
200	case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
201		switch (intf) {
202		case PHY_INTERFACE_MODE_SGMII:
203		case PHY_INTERFACE_MODE_1000BASEX:
204			lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
205			lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
206			break;
207		default:
208			break;
209		}
210		break;
211	case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
212		switch (intf) {
213		case PHY_INTERFACE_MODE_10GBASER:
214		case PHY_INTERFACE_MODE_USXGMII:
215			lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
216			lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
217			break;
218		default:
219			break;
220		}
221		break;
222	default:
223		break;
224	}
225}
226
227static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
228				  struct lynx_28g_pll *pll)
229{
230	if (pll->id == 0) {
231		lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
232		lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
233	} else {
234		lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
235		lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
236	}
237}
238
239static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
240{
241	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
242	struct lynx_28g_priv *priv = lane->priv;
243
244	/* Cleanup the protocol configuration registers of the current protocol */
245	switch (lane->interface) {
246	case PHY_INTERFACE_MODE_10GBASER:
247		lynx_28g_rmw(priv, LYNX_28G_PCCC,
248			     LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
249			     GENMASK(3, 0) << lane_offset);
250		break;
251	case PHY_INTERFACE_MODE_SGMII:
252	case PHY_INTERFACE_MODE_1000BASEX:
253		lynx_28g_rmw(priv, LYNX_28G_PCC8,
254			     LYNX_28G_PCC8_SGMII_DIS << lane_offset,
255			     GENMASK(3, 0) << lane_offset);
256		break;
257	default:
258		break;
259	}
260}
261
262static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
263{
264	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
265	struct lynx_28g_priv *priv = lane->priv;
266	struct lynx_28g_pll *pll;
267
268	lynx_28g_cleanup_lane(lane);
269
270	/* Setup the lane to run in SGMII */
271	lynx_28g_rmw(priv, LYNX_28G_PCC8,
272		     LYNX_28G_PCC8_SGMII << lane_offset,
273		     GENMASK(3, 0) << lane_offset);
274
275	/* Setup the protocol select and SerDes parallel interface width */
276	lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
277	lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
278
279	/* Switch to the PLL that works with this interface type */
280	pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
281	lynx_28g_lane_set_pll(lane, pll);
282
283	/* Choose the portion of clock net to be used on this lane */
284	lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
285
286	/* Enable the SGMII PCS */
287	lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
288
289	/* Configure the appropriate equalization parameters for the protocol */
290	iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
291	iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
292	iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
293	iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
294	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
295	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
296}
297
298static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
299{
300	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
301	struct lynx_28g_priv *priv = lane->priv;
302	struct lynx_28g_pll *pll;
303
304	lynx_28g_cleanup_lane(lane);
305
306	/* Enable the SXGMII lane */
307	lynx_28g_rmw(priv, LYNX_28G_PCCC,
308		     LYNX_28G_PCCC_10GBASER << lane_offset,
309		     GENMASK(3, 0) << lane_offset);
310
311	/* Setup the protocol select and SerDes parallel interface width */
312	lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
313	lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
314
315	/* Switch to the PLL that works with this interface type */
316	pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
317	lynx_28g_lane_set_pll(lane, pll);
318
319	/* Choose the portion of clock net to be used on this lane */
320	lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
321
322	/* Disable the SGMII PCS */
323	lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
324
325	/* Configure the appropriate equalization parameters for the protocol */
326	iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
327	iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
328	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
329	iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
330	iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
331	iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
332}
333
334static int lynx_28g_power_off(struct phy *phy)
335{
336	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
337	u32 trstctl, rrstctl;
338
339	if (!lane->powered_up)
340		return 0;
341
342	/* Issue a halt request */
343	lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
344	lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
345
346	/* Wait until the halting process is complete */
347	do {
348		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
349		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
350	} while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
351		 (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
352
353	lane->powered_up = false;
354
355	return 0;
356}
357
358static int lynx_28g_power_on(struct phy *phy)
359{
360	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
361	u32 trstctl, rrstctl;
362
363	if (lane->powered_up)
364		return 0;
365
366	/* Issue a reset request on the lane */
367	lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
368	lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
369
370	/* Wait until the reset sequence is completed */
371	do {
372		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
373		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
374	} while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
375		 !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
376
377	lane->powered_up = true;
378
379	return 0;
380}
381
382static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
383{
384	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
385	struct lynx_28g_priv *priv = lane->priv;
386	int powered_up = lane->powered_up;
387	int err = 0;
388
389	if (mode != PHY_MODE_ETHERNET)
390		return -EOPNOTSUPP;
391
392	if (lane->interface == PHY_INTERFACE_MODE_NA)
393		return -EOPNOTSUPP;
394
395	if (!lynx_28g_supports_interface(priv, submode))
396		return -EOPNOTSUPP;
397
398	/* If the lane is powered up, put the lane into the halt state while
399	 * the reconfiguration is being done.
400	 */
401	if (powered_up)
402		lynx_28g_power_off(phy);
403
404	spin_lock(&priv->pcc_lock);
405
406	switch (submode) {
407	case PHY_INTERFACE_MODE_SGMII:
408	case PHY_INTERFACE_MODE_1000BASEX:
409		lynx_28g_lane_set_sgmii(lane);
410		break;
411	case PHY_INTERFACE_MODE_10GBASER:
412		lynx_28g_lane_set_10gbaser(lane);
413		break;
414	default:
415		err = -EOPNOTSUPP;
416		goto out;
417	}
418
419	lane->interface = submode;
420
421out:
422	spin_unlock(&priv->pcc_lock);
423
424	/* Power up the lane if necessary */
425	if (powered_up)
426		lynx_28g_power_on(phy);
427
428	return err;
429}
430
431static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
432			     union phy_configure_opts *opts __always_unused)
433{
434	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
435	struct lynx_28g_priv *priv = lane->priv;
436
437	if (mode != PHY_MODE_ETHERNET)
438		return -EOPNOTSUPP;
439
440	if (!lynx_28g_supports_interface(priv, submode))
441		return -EOPNOTSUPP;
442
443	return 0;
444}
445
446static int lynx_28g_init(struct phy *phy)
447{
448	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
449
450	/* Mark the fact that the lane was init */
451	lane->init = true;
452
453	/* SerDes lanes are powered on at boot time.  Any lane that is managed
454	 * by this driver will get powered down at init time aka at dpaa2-eth
455	 * probe time.
456	 */
457	lane->powered_up = true;
458	lynx_28g_power_off(phy);
459
460	return 0;
461}
462
463static const struct phy_ops lynx_28g_ops = {
464	.init		= lynx_28g_init,
465	.power_on	= lynx_28g_power_on,
466	.power_off	= lynx_28g_power_off,
467	.set_mode	= lynx_28g_set_mode,
468	.validate	= lynx_28g_validate,
469	.owner		= THIS_MODULE,
470};
471
472static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
473{
474	struct lynx_28g_pll *pll;
475	int i;
476
477	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
478		pll = &priv->pll[i];
479		pll->priv = priv;
480		pll->id = i;
481
482		pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
483		pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
484		pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
485
486		if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
487			continue;
488
489		switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
490		case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
491		case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
492			/* 5GHz clock net */
493			__set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
494			__set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
495			break;
496		case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
497			/* 10.3125GHz clock net */
498			__set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
499			break;
500		default:
501			/* 6GHz, 12.890625GHz, 8GHz */
502			break;
503		}
504	}
505}
506
507#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)
508
509static void lynx_28g_cdr_lock_check(struct work_struct *work)
510{
511	struct lynx_28g_priv *priv = work_to_lynx(work);
512	struct lynx_28g_lane *lane;
513	u32 rrstctl;
514	int i;
515
516	for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
517		lane = &priv->lane[i];
518
519		mutex_lock(&lane->phy->mutex);
520
521		if (!lane->init || !lane->powered_up) {
522			mutex_unlock(&lane->phy->mutex);
523			continue;
524		}
525
526		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
527		if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
528			lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
529			do {
530				rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
531			} while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
532		}
533
534		mutex_unlock(&lane->phy->mutex);
535	}
536	queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
537			   msecs_to_jiffies(1000));
538}
539
540static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
541{
542	u32 pss, protocol;
543
544	pss = lynx_28g_lane_read(lane, LNaPSS);
545	protocol = LYNX_28G_LNaPSS_TYPE(pss);
546	switch (protocol) {
547	case LYNX_28G_LNaPSS_TYPE_SGMII:
548		lane->interface = PHY_INTERFACE_MODE_SGMII;
549		break;
550	case LYNX_28G_LNaPSS_TYPE_XFI:
551		lane->interface = PHY_INTERFACE_MODE_10GBASER;
552		break;
553	default:
554		lane->interface = PHY_INTERFACE_MODE_NA;
555	}
556}
557
558static struct phy *lynx_28g_xlate(struct device *dev,
559				  const struct of_phandle_args *args)
560{
561	struct lynx_28g_priv *priv = dev_get_drvdata(dev);
562	int idx = args->args[0];
563
564	if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
565		return ERR_PTR(-EINVAL);
566
567	return priv->lane[idx].phy;
568}
569
570static int lynx_28g_probe(struct platform_device *pdev)
571{
572	struct device *dev = &pdev->dev;
573	struct phy_provider *provider;
574	struct lynx_28g_priv *priv;
575	int i;
576
577	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
578	if (!priv)
579		return -ENOMEM;
580	priv->dev = &pdev->dev;
581
582	priv->base = devm_platform_ioremap_resource(pdev, 0);
583	if (IS_ERR(priv->base))
584		return PTR_ERR(priv->base);
585
586	lynx_28g_pll_read_configuration(priv);
587
588	for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
589		struct lynx_28g_lane *lane = &priv->lane[i];
590		struct phy *phy;
591
592		memset(lane, 0, sizeof(*lane));
593
594		phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
595		if (IS_ERR(phy))
596			return PTR_ERR(phy);
597
598		lane->priv = priv;
599		lane->phy = phy;
600		lane->id = i;
601		phy_set_drvdata(phy, lane);
602		lynx_28g_lane_read_configuration(lane);
603	}
604
605	dev_set_drvdata(dev, priv);
606
607	spin_lock_init(&priv->pcc_lock);
608	INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
609
610	queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
611			   msecs_to_jiffies(1000));
612
613	dev_set_drvdata(&pdev->dev, priv);
614	provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
615
616	return PTR_ERR_OR_ZERO(provider);
617}
618
619static void lynx_28g_remove(struct platform_device *pdev)
620{
621	struct device *dev = &pdev->dev;
622	struct lynx_28g_priv *priv = dev_get_drvdata(dev);
623
624	cancel_delayed_work_sync(&priv->cdr_check);
625}
626
627static const struct of_device_id lynx_28g_of_match_table[] = {
628	{ .compatible = "fsl,lynx-28g" },
629	{ },
630};
631MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
632
633static struct platform_driver lynx_28g_driver = {
634	.probe	= lynx_28g_probe,
635	.remove_new = lynx_28g_remove,
636	.driver	= {
637		.name = "lynx-28g",
638		.of_match_table = lynx_28g_of_match_table,
639	},
640};
641module_platform_driver(lynx_28g_driver);
642
643MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
644MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
645MODULE_LICENSE("GPL v2");
646