brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · b86da8e Raw
646 lines · 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			812#define LYNX_28G_NUM_PLL			213 14/* General registers per SerDes block */15#define LYNX_28G_PCC8				0x10a016#define LYNX_28G_PCC8_SGMII			0x117#define LYNX_28G_PCC8_SGMII_DIS			0x018 19#define LYNX_28G_PCCC				0x10b020#define LYNX_28G_PCCC_10GBASER			0x921#define LYNX_28G_PCCC_USXGMII			0x122#define LYNX_28G_PCCC_SXGMII_DIS		0x023 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	0x034#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ	0x1000035#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ	0x2000036#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ	0x3000037#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ	0x4000038 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	0x042#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO	0x1000000043#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO	0x600000044 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	0x850#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI		0x5051#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK		GENMASK(2, 0)52#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT	0x053#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT	0x254 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		0x064#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		0x067#define LYNX_28G_LNaTGCR0_N_RATE_HALF		0x100000068#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER	0x200000069#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		0x083#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		0x087#define LYNX_28G_LNaRGCR0_N_RATE_HALF		0x100000088#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER	0x200000089#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		0x4102#define LYNX_28G_LNaPSS_TYPE_XFI		0x28103 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		0x0107#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 PCCn132	 */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 while399	 * 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 managed454	 * by this driver will get powered down at init time aka at dpaa2-eth455	 * 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