162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/* Copyright (c) 2021-2022 NXP. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci#include <linux/of.h>
662306a36Sopenharmony_ci#include <linux/phy.h>
762306a36Sopenharmony_ci#include <linux/phy/phy.h>
862306a36Sopenharmony_ci#include <linux/platform_device.h>
962306a36Sopenharmony_ci#include <linux/workqueue.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define LYNX_28G_NUM_LANE			8
1262306a36Sopenharmony_ci#define LYNX_28G_NUM_PLL			2
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* General registers per SerDes block */
1562306a36Sopenharmony_ci#define LYNX_28G_PCC8				0x10a0
1662306a36Sopenharmony_ci#define LYNX_28G_PCC8_SGMII			0x1
1762306a36Sopenharmony_ci#define LYNX_28G_PCC8_SGMII_DIS			0x0
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define LYNX_28G_PCCC				0x10b0
2062306a36Sopenharmony_ci#define LYNX_28G_PCCC_10GBASER			0x9
2162306a36Sopenharmony_ci#define LYNX_28G_PCCC_USXGMII			0x1
2262306a36Sopenharmony_ci#define LYNX_28G_PCCC_SXGMII_DIS		0x0
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define LYNX_28G_LNa_PCC_OFFSET(lane)		(4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Per PLL registers */
2762306a36Sopenharmony_ci#define LYNX_28G_PLLnRSTCTL(pll)		(0x400 + (pll) * 0x100 + 0x0)
2862306a36Sopenharmony_ci#define LYNX_28G_PLLnRSTCTL_DIS(rstctl)		(((rstctl) & BIT(24)) >> 24)
2962306a36Sopenharmony_ci#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl)	(((rstctl) & BIT(23)) >> 23)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0(pll)			(0x400 + (pll) * 0x100 + 0x4)
3262306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0)	(((cr0) & GENMASK(20, 16)))
3362306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ	0x0
3462306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ	0x10000
3562306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ	0x20000
3662306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ	0x30000
3762306a36Sopenharmony_ci#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ	0x40000
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1(pll)			(0x400 + (pll) * 0x100 + 0x8)
4062306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1)		(((cr1) & GENMASK(28, 24)))
4162306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO	0x0
4262306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO	0x10000000
4362306a36Sopenharmony_ci#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO	0x6000000
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Per SerDes lane registers */
4662306a36Sopenharmony_ci/* Lane a General Control Register */
4762306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0(lane)			(0x800 + (lane) * 0x100 + 0x0)
4862306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK		GENMASK(7, 3)
4962306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII	0x8
5062306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI		0x50
5162306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK		GENMASK(2, 0)
5262306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT	0x0
5362306a36Sopenharmony_ci#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT	0x2
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Lane a Tx Reset Control Register */
5662306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL(lane)		(0x800 + (lane) * 0x100 + 0x20)
5762306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL_HLT_REQ		BIT(27)
5862306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL_RST_DONE		BIT(30)
5962306a36Sopenharmony_ci#define LYNX_28G_LNaTRSTCTL_RST_REQ		BIT(31)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Lane a Tx General Control Register */
6262306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0(lane)			(0x800 + (lane) * 0x100 + 0x24)
6362306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_USE_PLLF		0x0
6462306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_USE_PLLS		BIT(28)
6562306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_USE_PLL_MSK		BIT(28)
6662306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_FULL		0x0
6762306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_HALF		0x1000000
6862306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER	0x2000000
6962306a36Sopenharmony_ci#define LYNX_28G_LNaTGCR0_N_RATE_MSK		GENMASK(26, 24)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define LYNX_28G_LNaTECR0(lane)			(0x800 + (lane) * 0x100 + 0x30)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Lane a Rx Reset Control Register */
7462306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL(lane)		(0x800 + (lane) * 0x100 + 0x40)
7562306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_HLT_REQ		BIT(27)
7662306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_RST_DONE		BIT(30)
7762306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_RST_REQ		BIT(31)
7862306a36Sopenharmony_ci#define LYNX_28G_LNaRRSTCTL_CDR_LOCK		BIT(12)
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Lane a Rx General Control Register */
8162306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0(lane)			(0x800 + (lane) * 0x100 + 0x44)
8262306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_USE_PLLF		0x0
8362306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_USE_PLLS		BIT(28)
8462306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_USE_PLL_MSK		BIT(28)
8562306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_MSK		GENMASK(26, 24)
8662306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_FULL		0x0
8762306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_HALF		0x1000000
8862306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER	0x2000000
8962306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR0_N_RATE_MSK		GENMASK(26, 24)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define LYNX_28G_LNaRGCR1(lane)			(0x800 + (lane) * 0x100 + 0x48)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define LYNX_28G_LNaRECR0(lane)			(0x800 + (lane) * 0x100 + 0x50)
9462306a36Sopenharmony_ci#define LYNX_28G_LNaRECR1(lane)			(0x800 + (lane) * 0x100 + 0x54)
9562306a36Sopenharmony_ci#define LYNX_28G_LNaRECR2(lane)			(0x800 + (lane) * 0x100 + 0x58)
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define LYNX_28G_LNaRSCCR0(lane)		(0x800 + (lane) * 0x100 + 0x74)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define LYNX_28G_LNaPSS(lane)			(0x1000 + (lane) * 0x4)
10062306a36Sopenharmony_ci#define LYNX_28G_LNaPSS_TYPE(pss)		(((pss) & GENMASK(30, 24)) >> 24)
10162306a36Sopenharmony_ci#define LYNX_28G_LNaPSS_TYPE_SGMII		0x4
10262306a36Sopenharmony_ci#define LYNX_28G_LNaPSS_TYPE_XFI		0x28
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1(lane)		(0x1804 + (lane) * 0x10)
10562306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1_SGPCS_EN		BIT(11)
10662306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1_SGPCS_DIS		0x0
10762306a36Sopenharmony_ci#define LYNX_28G_SGMIIaCR1_SGPCS_MSK		BIT(11)
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistruct lynx_28g_priv;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct lynx_28g_pll {
11262306a36Sopenharmony_ci	struct lynx_28g_priv *priv;
11362306a36Sopenharmony_ci	u32 rstctl, cr0, cr1;
11462306a36Sopenharmony_ci	int id;
11562306a36Sopenharmony_ci	DECLARE_PHY_INTERFACE_MASK(supported);
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct lynx_28g_lane {
11962306a36Sopenharmony_ci	struct lynx_28g_priv *priv;
12062306a36Sopenharmony_ci	struct phy *phy;
12162306a36Sopenharmony_ci	bool powered_up;
12262306a36Sopenharmony_ci	bool init;
12362306a36Sopenharmony_ci	unsigned int id;
12462306a36Sopenharmony_ci	phy_interface_t interface;
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistruct lynx_28g_priv {
12862306a36Sopenharmony_ci	void __iomem *base;
12962306a36Sopenharmony_ci	struct device *dev;
13062306a36Sopenharmony_ci	/* Serialize concurrent access to registers shared between lanes,
13162306a36Sopenharmony_ci	 * like PCCn
13262306a36Sopenharmony_ci	 */
13362306a36Sopenharmony_ci	spinlock_t pcc_lock;
13462306a36Sopenharmony_ci	struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
13562306a36Sopenharmony_ci	struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	struct delayed_work cdr_check;
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
14162306a36Sopenharmony_ci			 u32 val, u32 mask)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	void __iomem *reg = priv->base + off;
14462306a36Sopenharmony_ci	u32 orig, tmp;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	orig = ioread32(reg);
14762306a36Sopenharmony_ci	tmp = orig & ~mask;
14862306a36Sopenharmony_ci	tmp |= val;
14962306a36Sopenharmony_ci	iowrite32(tmp, reg);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define lynx_28g_lane_rmw(lane, reg, val, mask)	\
15362306a36Sopenharmony_ci	lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
15462306a36Sopenharmony_ci		     LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
15562306a36Sopenharmony_ci#define lynx_28g_lane_read(lane, reg)			\
15662306a36Sopenharmony_ci	ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
15762306a36Sopenharmony_ci#define lynx_28g_pll_read(pll, reg)			\
15862306a36Sopenharmony_ci	ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	int i;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
16562306a36Sopenharmony_ci		if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
16662306a36Sopenharmony_ci			continue;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		if (test_bit(intf, priv->pll[i].supported))
16962306a36Sopenharmony_ci			return true;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return false;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
17662306a36Sopenharmony_ci					     phy_interface_t intf)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct lynx_28g_pll *pll;
17962306a36Sopenharmony_ci	int i;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
18262306a36Sopenharmony_ci		pll = &priv->pll[i];
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
18562306a36Sopenharmony_ci			continue;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		if (test_bit(intf, pll->supported))
18862306a36Sopenharmony_ci			return pll;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return NULL;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
19562306a36Sopenharmony_ci				    struct lynx_28g_pll *pll,
19662306a36Sopenharmony_ci				    phy_interface_t intf)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
19962306a36Sopenharmony_ci	case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
20062306a36Sopenharmony_ci	case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
20162306a36Sopenharmony_ci		switch (intf) {
20262306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_SGMII:
20362306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_1000BASEX:
20462306a36Sopenharmony_ci			lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
20562306a36Sopenharmony_ci			lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		default:
20862306a36Sopenharmony_ci			break;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		break;
21162306a36Sopenharmony_ci	case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
21262306a36Sopenharmony_ci		switch (intf) {
21362306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_10GBASER:
21462306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_USXGMII:
21562306a36Sopenharmony_ci			lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
21662306a36Sopenharmony_ci			lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		default:
21962306a36Sopenharmony_ci			break;
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci		break;
22262306a36Sopenharmony_ci	default:
22362306a36Sopenharmony_ci		break;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
22862306a36Sopenharmony_ci				  struct lynx_28g_pll *pll)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	if (pll->id == 0) {
23162306a36Sopenharmony_ci		lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
23262306a36Sopenharmony_ci		lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
23362306a36Sopenharmony_ci	} else {
23462306a36Sopenharmony_ci		lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
23562306a36Sopenharmony_ci		lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
24262306a36Sopenharmony_ci	struct lynx_28g_priv *priv = lane->priv;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/* Cleanup the protocol configuration registers of the current protocol */
24562306a36Sopenharmony_ci	switch (lane->interface) {
24662306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
24762306a36Sopenharmony_ci		lynx_28g_rmw(priv, LYNX_28G_PCCC,
24862306a36Sopenharmony_ci			     LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
24962306a36Sopenharmony_ci			     GENMASK(3, 0) << lane_offset);
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_SGMII:
25262306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_1000BASEX:
25362306a36Sopenharmony_ci		lynx_28g_rmw(priv, LYNX_28G_PCC8,
25462306a36Sopenharmony_ci			     LYNX_28G_PCC8_SGMII_DIS << lane_offset,
25562306a36Sopenharmony_ci			     GENMASK(3, 0) << lane_offset);
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci	default:
25862306a36Sopenharmony_ci		break;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
26562306a36Sopenharmony_ci	struct lynx_28g_priv *priv = lane->priv;
26662306a36Sopenharmony_ci	struct lynx_28g_pll *pll;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	lynx_28g_cleanup_lane(lane);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* Setup the lane to run in SGMII */
27162306a36Sopenharmony_ci	lynx_28g_rmw(priv, LYNX_28G_PCC8,
27262306a36Sopenharmony_ci		     LYNX_28G_PCC8_SGMII << lane_offset,
27362306a36Sopenharmony_ci		     GENMASK(3, 0) << lane_offset);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Setup the protocol select and SerDes parallel interface width */
27662306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
27762306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Switch to the PLL that works with this interface type */
28062306a36Sopenharmony_ci	pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
28162306a36Sopenharmony_ci	lynx_28g_lane_set_pll(lane, pll);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Choose the portion of clock net to be used on this lane */
28462306a36Sopenharmony_ci	lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Enable the SGMII PCS */
28762306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* Configure the appropriate equalization parameters for the protocol */
29062306a36Sopenharmony_ci	iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
29162306a36Sopenharmony_ci	iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
29262306a36Sopenharmony_ci	iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
29362306a36Sopenharmony_ci	iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
29462306a36Sopenharmony_ci	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
29562306a36Sopenharmony_ci	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
30162306a36Sopenharmony_ci	struct lynx_28g_priv *priv = lane->priv;
30262306a36Sopenharmony_ci	struct lynx_28g_pll *pll;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	lynx_28g_cleanup_lane(lane);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Enable the SXGMII lane */
30762306a36Sopenharmony_ci	lynx_28g_rmw(priv, LYNX_28G_PCCC,
30862306a36Sopenharmony_ci		     LYNX_28G_PCCC_10GBASER << lane_offset,
30962306a36Sopenharmony_ci		     GENMASK(3, 0) << lane_offset);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Setup the protocol select and SerDes parallel interface width */
31262306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
31362306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Switch to the PLL that works with this interface type */
31662306a36Sopenharmony_ci	pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
31762306a36Sopenharmony_ci	lynx_28g_lane_set_pll(lane, pll);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Choose the portion of clock net to be used on this lane */
32062306a36Sopenharmony_ci	lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* Disable the SGMII PCS */
32362306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* Configure the appropriate equalization parameters for the protocol */
32662306a36Sopenharmony_ci	iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
32762306a36Sopenharmony_ci	iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
32862306a36Sopenharmony_ci	iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
32962306a36Sopenharmony_ci	iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
33062306a36Sopenharmony_ci	iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
33162306a36Sopenharmony_ci	iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic int lynx_28g_power_off(struct phy *phy)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
33762306a36Sopenharmony_ci	u32 trstctl, rrstctl;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!lane->powered_up)
34062306a36Sopenharmony_ci		return 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Issue a halt request */
34362306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
34462306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* Wait until the halting process is complete */
34762306a36Sopenharmony_ci	do {
34862306a36Sopenharmony_ci		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
34962306a36Sopenharmony_ci		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
35062306a36Sopenharmony_ci	} while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
35162306a36Sopenharmony_ci		 (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	lane->powered_up = false;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int lynx_28g_power_on(struct phy *phy)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
36162306a36Sopenharmony_ci	u32 trstctl, rrstctl;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (lane->powered_up)
36462306a36Sopenharmony_ci		return 0;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* Issue a reset request on the lane */
36762306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
36862306a36Sopenharmony_ci	lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Wait until the reset sequence is completed */
37162306a36Sopenharmony_ci	do {
37262306a36Sopenharmony_ci		trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
37362306a36Sopenharmony_ci		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
37462306a36Sopenharmony_ci	} while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
37562306a36Sopenharmony_ci		 !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	lane->powered_up = true;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return 0;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
38562306a36Sopenharmony_ci	struct lynx_28g_priv *priv = lane->priv;
38662306a36Sopenharmony_ci	int powered_up = lane->powered_up;
38762306a36Sopenharmony_ci	int err = 0;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (mode != PHY_MODE_ETHERNET)
39062306a36Sopenharmony_ci		return -EOPNOTSUPP;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (lane->interface == PHY_INTERFACE_MODE_NA)
39362306a36Sopenharmony_ci		return -EOPNOTSUPP;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (!lynx_28g_supports_interface(priv, submode))
39662306a36Sopenharmony_ci		return -EOPNOTSUPP;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* If the lane is powered up, put the lane into the halt state while
39962306a36Sopenharmony_ci	 * the reconfiguration is being done.
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci	if (powered_up)
40262306a36Sopenharmony_ci		lynx_28g_power_off(phy);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	spin_lock(&priv->pcc_lock);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	switch (submode) {
40762306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_SGMII:
40862306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_1000BASEX:
40962306a36Sopenharmony_ci		lynx_28g_lane_set_sgmii(lane);
41062306a36Sopenharmony_ci		break;
41162306a36Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
41262306a36Sopenharmony_ci		lynx_28g_lane_set_10gbaser(lane);
41362306a36Sopenharmony_ci		break;
41462306a36Sopenharmony_ci	default:
41562306a36Sopenharmony_ci		err = -EOPNOTSUPP;
41662306a36Sopenharmony_ci		goto out;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	lane->interface = submode;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ciout:
42262306a36Sopenharmony_ci	spin_unlock(&priv->pcc_lock);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Power up the lane if necessary */
42562306a36Sopenharmony_ci	if (powered_up)
42662306a36Sopenharmony_ci		lynx_28g_power_on(phy);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return err;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
43262306a36Sopenharmony_ci			     union phy_configure_opts *opts __always_unused)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
43562306a36Sopenharmony_ci	struct lynx_28g_priv *priv = lane->priv;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (mode != PHY_MODE_ETHERNET)
43862306a36Sopenharmony_ci		return -EOPNOTSUPP;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (!lynx_28g_supports_interface(priv, submode))
44162306a36Sopenharmony_ci		return -EOPNOTSUPP;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic int lynx_28g_init(struct phy *phy)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct lynx_28g_lane *lane = phy_get_drvdata(phy);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* Mark the fact that the lane was init */
45162306a36Sopenharmony_ci	lane->init = true;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* SerDes lanes are powered on at boot time.  Any lane that is managed
45462306a36Sopenharmony_ci	 * by this driver will get powered down at init time aka at dpaa2-eth
45562306a36Sopenharmony_ci	 * probe time.
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci	lane->powered_up = true;
45862306a36Sopenharmony_ci	lynx_28g_power_off(phy);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return 0;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic const struct phy_ops lynx_28g_ops = {
46462306a36Sopenharmony_ci	.init		= lynx_28g_init,
46562306a36Sopenharmony_ci	.power_on	= lynx_28g_power_on,
46662306a36Sopenharmony_ci	.power_off	= lynx_28g_power_off,
46762306a36Sopenharmony_ci	.set_mode	= lynx_28g_set_mode,
46862306a36Sopenharmony_ci	.validate	= lynx_28g_validate,
46962306a36Sopenharmony_ci	.owner		= THIS_MODULE,
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct lynx_28g_pll *pll;
47562306a36Sopenharmony_ci	int i;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
47862306a36Sopenharmony_ci		pll = &priv->pll[i];
47962306a36Sopenharmony_ci		pll->priv = priv;
48062306a36Sopenharmony_ci		pll->id = i;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
48362306a36Sopenharmony_ci		pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
48462306a36Sopenharmony_ci		pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
48762306a36Sopenharmony_ci			continue;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
49062306a36Sopenharmony_ci		case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
49162306a36Sopenharmony_ci		case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
49262306a36Sopenharmony_ci			/* 5GHz clock net */
49362306a36Sopenharmony_ci			__set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
49462306a36Sopenharmony_ci			__set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
49562306a36Sopenharmony_ci			break;
49662306a36Sopenharmony_ci		case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
49762306a36Sopenharmony_ci			/* 10.3125GHz clock net */
49862306a36Sopenharmony_ci			__set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
49962306a36Sopenharmony_ci			break;
50062306a36Sopenharmony_ci		default:
50162306a36Sopenharmony_ci			/* 6GHz, 12.890625GHz, 8GHz */
50262306a36Sopenharmony_ci			break;
50362306a36Sopenharmony_ci		}
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic void lynx_28g_cdr_lock_check(struct work_struct *work)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct lynx_28g_priv *priv = work_to_lynx(work);
51262306a36Sopenharmony_ci	struct lynx_28g_lane *lane;
51362306a36Sopenharmony_ci	u32 rrstctl;
51462306a36Sopenharmony_ci	int i;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
51762306a36Sopenharmony_ci		lane = &priv->lane[i];
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		mutex_lock(&lane->phy->mutex);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		if (!lane->init || !lane->powered_up) {
52262306a36Sopenharmony_ci			mutex_unlock(&lane->phy->mutex);
52362306a36Sopenharmony_ci			continue;
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
52762306a36Sopenharmony_ci		if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
52862306a36Sopenharmony_ci			lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
52962306a36Sopenharmony_ci			do {
53062306a36Sopenharmony_ci				rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
53162306a36Sopenharmony_ci			} while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
53262306a36Sopenharmony_ci		}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		mutex_unlock(&lane->phy->mutex);
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
53762306a36Sopenharmony_ci			   msecs_to_jiffies(1000));
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	u32 pss, protocol;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	pss = lynx_28g_lane_read(lane, LNaPSS);
54562306a36Sopenharmony_ci	protocol = LYNX_28G_LNaPSS_TYPE(pss);
54662306a36Sopenharmony_ci	switch (protocol) {
54762306a36Sopenharmony_ci	case LYNX_28G_LNaPSS_TYPE_SGMII:
54862306a36Sopenharmony_ci		lane->interface = PHY_INTERFACE_MODE_SGMII;
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case LYNX_28G_LNaPSS_TYPE_XFI:
55162306a36Sopenharmony_ci		lane->interface = PHY_INTERFACE_MODE_10GBASER;
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	default:
55462306a36Sopenharmony_ci		lane->interface = PHY_INTERFACE_MODE_NA;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic struct phy *lynx_28g_xlate(struct device *dev,
55962306a36Sopenharmony_ci				  struct of_phandle_args *args)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct lynx_28g_priv *priv = dev_get_drvdata(dev);
56262306a36Sopenharmony_ci	int idx = args->args[0];
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
56562306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return priv->lane[idx].phy;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int lynx_28g_probe(struct platform_device *pdev)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
57362306a36Sopenharmony_ci	struct phy_provider *provider;
57462306a36Sopenharmony_ci	struct lynx_28g_priv *priv;
57562306a36Sopenharmony_ci	int i;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
57862306a36Sopenharmony_ci	if (!priv)
57962306a36Sopenharmony_ci		return -ENOMEM;
58062306a36Sopenharmony_ci	priv->dev = &pdev->dev;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	priv->base = devm_platform_ioremap_resource(pdev, 0);
58362306a36Sopenharmony_ci	if (IS_ERR(priv->base))
58462306a36Sopenharmony_ci		return PTR_ERR(priv->base);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	lynx_28g_pll_read_configuration(priv);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
58962306a36Sopenharmony_ci		struct lynx_28g_lane *lane = &priv->lane[i];
59062306a36Sopenharmony_ci		struct phy *phy;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		memset(lane, 0, sizeof(*lane));
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
59562306a36Sopenharmony_ci		if (IS_ERR(phy))
59662306a36Sopenharmony_ci			return PTR_ERR(phy);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		lane->priv = priv;
59962306a36Sopenharmony_ci		lane->phy = phy;
60062306a36Sopenharmony_ci		lane->id = i;
60162306a36Sopenharmony_ci		phy_set_drvdata(phy, lane);
60262306a36Sopenharmony_ci		lynx_28g_lane_read_configuration(lane);
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	dev_set_drvdata(dev, priv);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	spin_lock_init(&priv->pcc_lock);
60862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
61162306a36Sopenharmony_ci			   msecs_to_jiffies(1000));
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	dev_set_drvdata(&pdev->dev, priv);
61462306a36Sopenharmony_ci	provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(provider);
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void lynx_28g_remove(struct platform_device *pdev)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
62262306a36Sopenharmony_ci	struct lynx_28g_priv *priv = dev_get_drvdata(dev);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	cancel_delayed_work_sync(&priv->cdr_check);
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic const struct of_device_id lynx_28g_of_match_table[] = {
62862306a36Sopenharmony_ci	{ .compatible = "fsl,lynx-28g" },
62962306a36Sopenharmony_ci	{ },
63062306a36Sopenharmony_ci};
63162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic struct platform_driver lynx_28g_driver = {
63462306a36Sopenharmony_ci	.probe	= lynx_28g_probe,
63562306a36Sopenharmony_ci	.remove_new = lynx_28g_remove,
63662306a36Sopenharmony_ci	.driver	= {
63762306a36Sopenharmony_ci		.name = "lynx-28g",
63862306a36Sopenharmony_ci		.of_match_table = lynx_28g_of_match_table,
63962306a36Sopenharmony_ci	},
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_cimodule_platform_driver(lynx_28g_driver);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ciMODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
64462306a36Sopenharmony_ciMODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
64562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
646