File Index
Files and directories
Sign in
FILE

phy-fsl-lynx-28g.c

File preview with syntax highlighting.

linux-6.19.14/drivers/phy/freescale/phy-fsl-lynx-28g.c C
  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	/* no pll supports requested mode, either caller forgot to check
192	 * lynx_28g_supports_lane_mode, or this is a bug.
193	 */
194	dev_WARN_ONCE(priv->dev, 1, "no pll for interface %s\n", phy_modes(intf));
195	return NULL;
196}
197
198static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
199				    struct lynx_28g_pll *pll,
200				    phy_interface_t intf)
201{
202	switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
203	case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
204	case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
205		switch (intf) {
206		case PHY_INTERFACE_MODE_SGMII:
207		case PHY_INTERFACE_MODE_1000BASEX:
208			lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
209			lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
210			break;
211		default:
212			break;
213		}
214		break;
215	case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
216		switch (intf) {
217		case PHY_INTERFACE_MODE_10GBASER:
218		case PHY_INTERFACE_MODE_USXGMII:
219			lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
220			lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
221			break;
222		default:
223			break;
224		}
225		break;
226	default:
227		break;
228	}
229}
230
231static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
232				  struct lynx_28g_pll *pll)
233{
234	if (pll->id == 0) {
235		lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
236		lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
237	} else {
238		lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
239		lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
240	}
241}
242
243static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
244{
245	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
246	struct lynx_28g_priv *priv = lane->priv;
247
248	/* Cleanup the protocol configuration registers of the current protocol */
249	switch (lane->interface) {
250	case PHY_INTERFACE_MODE_10GBASER:
251		lynx_28g_rmw(priv, LYNX_28G_PCCC,
252			     LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
253			     GENMASK(3, 0) << lane_offset);
254		break;
255	case PHY_INTERFACE_MODE_SGMII:
256	case PHY_INTERFACE_MODE_1000BASEX:
257		lynx_28g_rmw(priv, LYNX_28G_PCC8,
258			     LYNX_28G_PCC8_SGMII_DIS << lane_offset,
259			     GENMASK(3, 0) << lane_offset);
260		break;
261	default:
262		break;
263	}
264}
265
266static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
267{
268	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
269	struct lynx_28g_priv *priv = lane->priv;
270	struct lynx_28g_pll *pll;
271
272	lynx_28g_cleanup_lane(lane);
273
274	/* Setup the lane to run in SGMII */
275	lynx_28g_rmw(priv, LYNX_28G_PCC8,
276		     LYNX_28G_PCC8_SGMII << lane_offset,
277		     GENMASK(3, 0) << lane_offset);
278
279	/* Setup the protocol select and SerDes parallel interface width */
280	lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
281	lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
282
283	/* Find the PLL that works with this interface type */
284	pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
285	if (unlikely(pll == NULL))
286		return;
287
288	/* Switch to the PLL that works with this interface type */
289	lynx_28g_lane_set_pll(lane, pll);
290
291	/* Choose the portion of clock net to be used on this lane */
292	lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
293
294	/* Enable the SGMII PCS */
295	lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
296
297	/* Configure the appropriate equalization parameters for the protocol */
298	iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
299	iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
300	iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
301	iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
302	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
303	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
304}
305
306static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
307{
308	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
309	struct lynx_28g_priv *priv = lane->priv;
310	struct lynx_28g_pll *pll;
311
312	lynx_28g_cleanup_lane(lane);
313
314	/* Enable the SXGMII lane */
315	lynx_28g_rmw(priv, LYNX_28G_PCCC,
316		     LYNX_28G_PCCC_10GBASER << lane_offset,
317		     GENMASK(3, 0) << lane_offset);
318
319	/* Setup the protocol select and SerDes parallel interface width */
320	lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
321	lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
322
323	/* Find the PLL that works with this interface type */
324	pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
325	if (unlikely(pll == NULL))
326		return;
327
328	/* Switch to the PLL that works with this interface type */
329	lynx_28g_lane_set_pll(lane, pll);
330
331	/* Choose the portion of clock net to be used on this lane */
332	lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
333
334	/* Disable the SGMII PCS */
335	lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
336
337	/* Configure the appropriate equalization parameters for the protocol */
338	iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
339	iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
340	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
341	iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
342	iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
343	iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
344}
345
346static int lynx_28g_power_off(struct phy *phy)
347{
348	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
349	u32 trstctl, rrstctl;
350
351	if (!lane->powered_up)
352		return 0;
353
354	/* Issue a halt request */
355	lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
356	lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
357
358	/* Wait until the halting process is complete */
359	do {
360		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
361		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
362	} while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
363		 (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
364
365	lane->powered_up = false;
366
367	return 0;
368}
369
370static int lynx_28g_power_on(struct phy *phy)
371{
372	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
373	u32 trstctl, rrstctl;
374
375	if (lane->powered_up)
376		return 0;
377
378	/* Issue a reset request on the lane */
379	lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
380	lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
381
382	/* Wait until the reset sequence is completed */
383	do {
384		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
385		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
386	} while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
387		 !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
388
389	lane->powered_up = true;
390
391	return 0;
392}
393
394static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
395{
396	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
397	struct lynx_28g_priv *priv = lane->priv;
398	int powered_up = lane->powered_up;
399	int err = 0;
400
401	if (mode != PHY_MODE_ETHERNET)
402		return -EOPNOTSUPP;
403
404	if (lane->interface == PHY_INTERFACE_MODE_NA)
405		return -EOPNOTSUPP;
406
407	if (!lynx_28g_supports_interface(priv, submode))
408		return -EOPNOTSUPP;
409
410	/* If the lane is powered up, put the lane into the halt state while
411	 * the reconfiguration is being done.
412	 */
413	if (powered_up)
414		lynx_28g_power_off(phy);
415
416	spin_lock(&priv->pcc_lock);
417
418	switch (submode) {
419	case PHY_INTERFACE_MODE_SGMII:
420	case PHY_INTERFACE_MODE_1000BASEX:
421		lynx_28g_lane_set_sgmii(lane);
422		break;
423	case PHY_INTERFACE_MODE_10GBASER:
424		lynx_28g_lane_set_10gbaser(lane);
425		break;
426	default:
427		err = -EOPNOTSUPP;
428		goto out;
429	}
430
431	lane->interface = submode;
432
433out:
434	spin_unlock(&priv->pcc_lock);
435
436	/* Power up the lane if necessary */
437	if (powered_up)
438		lynx_28g_power_on(phy);
439
440	return err;
441}
442
443static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
444			     union phy_configure_opts *opts __always_unused)
445{
446	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
447	struct lynx_28g_priv *priv = lane->priv;
448
449	if (mode != PHY_MODE_ETHERNET)
450		return -EOPNOTSUPP;
451
452	if (!lynx_28g_supports_interface(priv, submode))
453		return -EOPNOTSUPP;
454
455	return 0;
456}
457
458static int lynx_28g_init(struct phy *phy)
459{
460	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
461
462	/* Mark the fact that the lane was init */
463	lane->init = true;
464
465	/* SerDes lanes are powered on at boot time.  Any lane that is managed
466	 * by this driver will get powered down at init time aka at dpaa2-eth
467	 * probe time.
468	 */
469	lane->powered_up = true;
470	lynx_28g_power_off(phy);
471
472	return 0;
473}
474
475static const struct phy_ops lynx_28g_ops = {
476	.init		= lynx_28g_init,
477	.power_on	= lynx_28g_power_on,
478	.power_off	= lynx_28g_power_off,
479	.set_mode	= lynx_28g_set_mode,
480	.validate	= lynx_28g_validate,
481	.owner		= THIS_MODULE,
482};
483
484static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
485{
486	struct lynx_28g_pll *pll;
487	int i;
488
489	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
490		pll = &priv->pll[i];
491		pll->priv = priv;
492		pll->id = i;
493
494		pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
495		pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
496		pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
497
498		if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
499			continue;
500
501		switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
502		case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
503		case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
504			/* 5GHz clock net */
505			__set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
506			__set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
507			break;
508		case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
509			/* 10.3125GHz clock net */
510			__set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
511			break;
512		default:
513			/* 6GHz, 12.890625GHz, 8GHz */
514			break;
515		}
516	}
517}
518
519#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)
520
521static void lynx_28g_cdr_lock_check(struct work_struct *work)
522{
523	struct lynx_28g_priv *priv = work_to_lynx(work);
524	struct lynx_28g_lane *lane;
525	u32 rrstctl;
526	int i;
527
528	for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
529		lane = &priv->lane[i];
530
531		mutex_lock(&lane->phy->mutex);
532
533		if (!lane->init || !lane->powered_up) {
534			mutex_unlock(&lane->phy->mutex);
535			continue;
536		}
537
538		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
539		if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
540			lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
541			do {
542				rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
543			} while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
544		}
545
546		mutex_unlock(&lane->phy->mutex);
547	}
548	queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
549			   msecs_to_jiffies(1000));
550}
551
552static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
553{
554	u32 pss, protocol;
555
556	pss = lynx_28g_lane_read(lane, LNaPSS);
557	protocol = LYNX_28G_LNaPSS_TYPE(pss);
558	switch (protocol) {
559	case LYNX_28G_LNaPSS_TYPE_SGMII:
560		lane->interface = PHY_INTERFACE_MODE_SGMII;
561		break;
562	case LYNX_28G_LNaPSS_TYPE_XFI:
563		lane->interface = PHY_INTERFACE_MODE_10GBASER;
564		break;
565	default:
566		lane->interface = PHY_INTERFACE_MODE_NA;
567	}
568}
569
570static struct phy *lynx_28g_xlate(struct device *dev,
571				  const struct of_phandle_args *args)
572{
573	struct lynx_28g_priv *priv = dev_get_drvdata(dev);
574	int idx = args->args[0];
575
576	if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
577		return ERR_PTR(-EINVAL);
578
579	return priv->lane[idx].phy;
580}
581
582static int lynx_28g_probe(struct platform_device *pdev)
583{
584	struct device *dev = &pdev->dev;
585	struct phy_provider *provider;
586	struct lynx_28g_priv *priv;
587	int i;
588
589	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
590	if (!priv)
591		return -ENOMEM;
592	priv->dev = &pdev->dev;
593
594	priv->base = devm_platform_ioremap_resource(pdev, 0);
595	if (IS_ERR(priv->base))
596		return PTR_ERR(priv->base);
597
598	lynx_28g_pll_read_configuration(priv);
599
600	for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
601		struct lynx_28g_lane *lane = &priv->lane[i];
602		struct phy *phy;
603
604		memset(lane, 0, sizeof(*lane));
605
606		phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
607		if (IS_ERR(phy))
608			return PTR_ERR(phy);
609
610		lane->priv = priv;
611		lane->phy = phy;
612		lane->id = i;
613		phy_set_drvdata(phy, lane);
614		lynx_28g_lane_read_configuration(lane);
615	}
616
617	dev_set_drvdata(dev, priv);
618
619	spin_lock_init(&priv->pcc_lock);
620	INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
621
622	queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
623			   msecs_to_jiffies(1000));
624
625	dev_set_drvdata(&pdev->dev, priv);
626	provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
627
628	return PTR_ERR_OR_ZERO(provider);
629}
630
631static void lynx_28g_remove(struct platform_device *pdev)
632{
633	struct device *dev = &pdev->dev;
634	struct lynx_28g_priv *priv = dev_get_drvdata(dev);
635
636	cancel_delayed_work_sync(&priv->cdr_check);
637}
638
639static const struct of_device_id lynx_28g_of_match_table[] = {
640	{ .compatible = "fsl,lynx-28g" },
641	{ },
642};
643MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
644
645static struct platform_driver lynx_28g_driver = {
646	.probe = lynx_28g_probe,
647	.remove = lynx_28g_remove,
648	.driver = {
649		.name = "lynx-28g",
650		.of_match_table = lynx_28g_of_match_table,
651	},
652};
653module_platform_driver(lynx_28g_driver);
654
655MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
656MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
657MODULE_LICENSE("GPL v2");
~/ Read-only file preview.