cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-fsl-lynx-28g.c (17862B)


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