0001
0002
0003
0004 #include <linux/module.h>
0005 #include <linux/phy.h>
0006 #include <linux/phy/phy.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/workqueue.h>
0009
0010 #define LYNX_28G_NUM_LANE 8
0011 #define LYNX_28G_NUM_PLL 2
0012
0013
0014 #define LYNX_28G_PCC8 0x10a0
0015 #define LYNX_28G_PCC8_SGMII 0x1
0016 #define LYNX_28G_PCC8_SGMII_DIS 0x0
0017
0018 #define LYNX_28G_PCCC 0x10b0
0019 #define LYNX_28G_PCCC_10GBASER 0x9
0020 #define LYNX_28G_PCCC_USXGMII 0x1
0021 #define LYNX_28G_PCCC_SXGMII_DIS 0x0
0022
0023 #define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
0024
0025
0026 #define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
0027 #define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
0028 #define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
0029
0030 #define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
0031 #define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
0032 #define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0
0033 #define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000
0034 #define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000
0035 #define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000
0036 #define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000
0037
0038 #define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
0039 #define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
0040 #define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0
0041 #define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000
0042 #define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000
0043
0044
0045
0046 #define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
0047 #define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
0048 #define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8
0049 #define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50
0050 #define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
0051 #define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0
0052 #define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2
0053
0054
0055 #define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
0056 #define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27)
0057 #define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30)
0058 #define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31)
0059
0060
0061 #define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
0062 #define LYNX_28G_LNaTGCR0_USE_PLLF 0x0
0063 #define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28)
0064 #define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28)
0065 #define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0
0066 #define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000
0067 #define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000
0068 #define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
0069
0070 #define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
0071
0072
0073 #define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
0074 #define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27)
0075 #define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30)
0076 #define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31)
0077 #define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12)
0078
0079
0080 #define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
0081 #define LYNX_28G_LNaRGCR0_USE_PLLF 0x0
0082 #define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28)
0083 #define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28)
0084 #define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
0085 #define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0
0086 #define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000
0087 #define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000
0088 #define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
0089
0090 #define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
0091
0092 #define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
0093 #define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
0094 #define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
0095
0096 #define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
0097
0098 #define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4)
0099 #define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
0100 #define LYNX_28G_LNaPSS_TYPE_SGMII 0x4
0101 #define LYNX_28G_LNaPSS_TYPE_XFI 0x28
0102
0103 #define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
0104 #define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11)
0105 #define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0
0106 #define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11)
0107
0108 struct lynx_28g_priv;
0109
0110 struct lynx_28g_pll {
0111 struct lynx_28g_priv *priv;
0112 u32 rstctl, cr0, cr1;
0113 int id;
0114 DECLARE_PHY_INTERFACE_MASK(supported);
0115 };
0116
0117 struct lynx_28g_lane {
0118 struct lynx_28g_priv *priv;
0119 struct phy *phy;
0120 bool powered_up;
0121 bool init;
0122 unsigned int id;
0123 phy_interface_t interface;
0124 };
0125
0126 struct lynx_28g_priv {
0127 void __iomem *base;
0128 struct device *dev;
0129 struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
0130 struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
0131
0132 struct delayed_work cdr_check;
0133 };
0134
0135 static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
0136 u32 val, u32 mask)
0137 {
0138 void __iomem *reg = priv->base + off;
0139 u32 orig, tmp;
0140
0141 orig = ioread32(reg);
0142 tmp = orig & ~mask;
0143 tmp |= val;
0144 iowrite32(tmp, reg);
0145 }
0146
0147 #define lynx_28g_lane_rmw(lane, reg, val, mask) \
0148 lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
0149 LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
0150 #define lynx_28g_lane_read(lane, reg) \
0151 ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
0152 #define lynx_28g_pll_read(pll, reg) \
0153 ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
0154
0155 static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
0156 {
0157 int i;
0158
0159 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
0160 if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
0161 continue;
0162
0163 if (test_bit(intf, priv->pll[i].supported))
0164 return true;
0165 }
0166
0167 return false;
0168 }
0169
0170 static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
0171 phy_interface_t intf)
0172 {
0173 struct lynx_28g_pll *pll;
0174 int i;
0175
0176 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
0177 pll = &priv->pll[i];
0178
0179 if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
0180 continue;
0181
0182 if (test_bit(intf, pll->supported))
0183 return pll;
0184 }
0185
0186 return NULL;
0187 }
0188
0189 static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
0190 struct lynx_28g_pll *pll,
0191 phy_interface_t intf)
0192 {
0193 switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
0194 case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
0195 case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
0196 switch (intf) {
0197 case PHY_INTERFACE_MODE_SGMII:
0198 case PHY_INTERFACE_MODE_1000BASEX:
0199 lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
0200 lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
0201 break;
0202 default:
0203 break;
0204 }
0205 break;
0206 case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
0207 switch (intf) {
0208 case PHY_INTERFACE_MODE_10GBASER:
0209 case PHY_INTERFACE_MODE_USXGMII:
0210 lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
0211 lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
0212 break;
0213 default:
0214 break;
0215 }
0216 break;
0217 default:
0218 break;
0219 }
0220 }
0221
0222 static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
0223 struct lynx_28g_pll *pll)
0224 {
0225 if (pll->id == 0) {
0226 lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
0227 lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
0228 } else {
0229 lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
0230 lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
0231 }
0232 }
0233
0234 static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
0235 {
0236 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
0237 struct lynx_28g_priv *priv = lane->priv;
0238
0239
0240 switch (lane->interface) {
0241 case PHY_INTERFACE_MODE_10GBASER:
0242 lynx_28g_rmw(priv, LYNX_28G_PCCC,
0243 LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
0244 GENMASK(3, 0) << lane_offset);
0245 break;
0246 case PHY_INTERFACE_MODE_SGMII:
0247 case PHY_INTERFACE_MODE_1000BASEX:
0248 lynx_28g_rmw(priv, LYNX_28G_PCC8,
0249 LYNX_28G_PCC8_SGMII_DIS << lane_offset,
0250 GENMASK(3, 0) << lane_offset);
0251 break;
0252 default:
0253 break;
0254 }
0255 }
0256
0257 static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
0258 {
0259 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
0260 struct lynx_28g_priv *priv = lane->priv;
0261 struct lynx_28g_pll *pll;
0262
0263 lynx_28g_cleanup_lane(lane);
0264
0265
0266 lynx_28g_rmw(priv, LYNX_28G_PCC8,
0267 LYNX_28G_PCC8_SGMII << lane_offset,
0268 GENMASK(3, 0) << lane_offset);
0269
0270
0271 lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
0272 lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
0273
0274
0275 pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
0276 lynx_28g_lane_set_pll(lane, pll);
0277
0278
0279 lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
0280
0281
0282 lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
0283
0284
0285 iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
0286 iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
0287 iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
0288 iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
0289 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
0290 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
0291 }
0292
0293 static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
0294 {
0295 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
0296 struct lynx_28g_priv *priv = lane->priv;
0297 struct lynx_28g_pll *pll;
0298
0299 lynx_28g_cleanup_lane(lane);
0300
0301
0302 lynx_28g_rmw(priv, LYNX_28G_PCCC,
0303 LYNX_28G_PCCC_10GBASER << lane_offset,
0304 GENMASK(3, 0) << lane_offset);
0305
0306
0307 lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
0308 lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
0309
0310
0311 pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
0312 lynx_28g_lane_set_pll(lane, pll);
0313
0314
0315 lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
0316
0317
0318 lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
0319
0320
0321 iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
0322 iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
0323 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
0324 iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
0325 iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
0326 iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
0327 }
0328
0329 static int lynx_28g_power_off(struct phy *phy)
0330 {
0331 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
0332 u32 trstctl, rrstctl;
0333
0334 if (!lane->powered_up)
0335 return 0;
0336
0337
0338 lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
0339 lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
0340
0341
0342 do {
0343 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
0344 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
0345 } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
0346 (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
0347
0348 lane->powered_up = false;
0349
0350 return 0;
0351 }
0352
0353 static int lynx_28g_power_on(struct phy *phy)
0354 {
0355 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
0356 u32 trstctl, rrstctl;
0357
0358 if (lane->powered_up)
0359 return 0;
0360
0361
0362 lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
0363 lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
0364
0365
0366 do {
0367 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
0368 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
0369 } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
0370 !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
0371
0372 lane->powered_up = true;
0373
0374 return 0;
0375 }
0376
0377 static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
0378 {
0379 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
0380 struct lynx_28g_priv *priv = lane->priv;
0381 int powered_up = lane->powered_up;
0382 int err = 0;
0383
0384 if (mode != PHY_MODE_ETHERNET)
0385 return -EOPNOTSUPP;
0386
0387 if (lane->interface == PHY_INTERFACE_MODE_NA)
0388 return -EOPNOTSUPP;
0389
0390 if (!lynx_28g_supports_interface(priv, submode))
0391 return -EOPNOTSUPP;
0392
0393
0394
0395
0396 if (powered_up)
0397 lynx_28g_power_off(phy);
0398
0399 switch (submode) {
0400 case PHY_INTERFACE_MODE_SGMII:
0401 case PHY_INTERFACE_MODE_1000BASEX:
0402 lynx_28g_lane_set_sgmii(lane);
0403 break;
0404 case PHY_INTERFACE_MODE_10GBASER:
0405 lynx_28g_lane_set_10gbaser(lane);
0406 break;
0407 default:
0408 err = -EOPNOTSUPP;
0409 goto out;
0410 }
0411
0412 lane->interface = submode;
0413
0414 out:
0415
0416 if (powered_up)
0417 lynx_28g_power_on(phy);
0418
0419 return err;
0420 }
0421
0422 static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
0423 union phy_configure_opts *opts __always_unused)
0424 {
0425 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
0426 struct lynx_28g_priv *priv = lane->priv;
0427
0428 if (mode != PHY_MODE_ETHERNET)
0429 return -EOPNOTSUPP;
0430
0431 if (!lynx_28g_supports_interface(priv, submode))
0432 return -EOPNOTSUPP;
0433
0434 return 0;
0435 }
0436
0437 static int lynx_28g_init(struct phy *phy)
0438 {
0439 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
0440
0441
0442 lane->init = true;
0443
0444
0445
0446
0447
0448 lane->powered_up = true;
0449 lynx_28g_power_off(phy);
0450
0451 return 0;
0452 }
0453
0454 static const struct phy_ops lynx_28g_ops = {
0455 .init = lynx_28g_init,
0456 .power_on = lynx_28g_power_on,
0457 .power_off = lynx_28g_power_off,
0458 .set_mode = lynx_28g_set_mode,
0459 .validate = lynx_28g_validate,
0460 .owner = THIS_MODULE,
0461 };
0462
0463 static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
0464 {
0465 struct lynx_28g_pll *pll;
0466 int i;
0467
0468 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
0469 pll = &priv->pll[i];
0470 pll->priv = priv;
0471 pll->id = i;
0472
0473 pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
0474 pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
0475 pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
0476
0477 if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
0478 continue;
0479
0480 switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
0481 case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
0482 case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
0483
0484 __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
0485 __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
0486 break;
0487 case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
0488
0489 __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
0490 break;
0491 default:
0492
0493 break;
0494 }
0495 }
0496 }
0497
0498 #define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)
0499
0500 static void lynx_28g_cdr_lock_check(struct work_struct *work)
0501 {
0502 struct lynx_28g_priv *priv = work_to_lynx(work);
0503 struct lynx_28g_lane *lane;
0504 u32 rrstctl;
0505 int i;
0506
0507 for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
0508 lane = &priv->lane[i];
0509
0510 if (!lane->init)
0511 continue;
0512
0513 if (!lane->powered_up)
0514 continue;
0515
0516 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
0517 if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
0518 lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
0519 do {
0520 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
0521 } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
0522 }
0523 }
0524 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
0525 msecs_to_jiffies(1000));
0526 }
0527
0528 static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
0529 {
0530 u32 pss, protocol;
0531
0532 pss = lynx_28g_lane_read(lane, LNaPSS);
0533 protocol = LYNX_28G_LNaPSS_TYPE(pss);
0534 switch (protocol) {
0535 case LYNX_28G_LNaPSS_TYPE_SGMII:
0536 lane->interface = PHY_INTERFACE_MODE_SGMII;
0537 break;
0538 case LYNX_28G_LNaPSS_TYPE_XFI:
0539 lane->interface = PHY_INTERFACE_MODE_10GBASER;
0540 break;
0541 default:
0542 lane->interface = PHY_INTERFACE_MODE_NA;
0543 }
0544 }
0545
0546 static struct phy *lynx_28g_xlate(struct device *dev,
0547 struct of_phandle_args *args)
0548 {
0549 struct lynx_28g_priv *priv = dev_get_drvdata(dev);
0550 int idx = args->args[0];
0551
0552 if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
0553 return ERR_PTR(-EINVAL);
0554
0555 return priv->lane[idx].phy;
0556 }
0557
0558 static int lynx_28g_probe(struct platform_device *pdev)
0559 {
0560 struct device *dev = &pdev->dev;
0561 struct phy_provider *provider;
0562 struct lynx_28g_priv *priv;
0563 int i;
0564
0565 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0566 if (!priv)
0567 return -ENOMEM;
0568 priv->dev = &pdev->dev;
0569
0570 priv->base = devm_platform_ioremap_resource(pdev, 0);
0571 if (IS_ERR(priv->base))
0572 return PTR_ERR(priv->base);
0573
0574 lynx_28g_pll_read_configuration(priv);
0575
0576 for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
0577 struct lynx_28g_lane *lane = &priv->lane[i];
0578 struct phy *phy;
0579
0580 memset(lane, 0, sizeof(*lane));
0581
0582 phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
0583 if (IS_ERR(phy))
0584 return PTR_ERR(phy);
0585
0586 lane->priv = priv;
0587 lane->phy = phy;
0588 lane->id = i;
0589 phy_set_drvdata(phy, lane);
0590 lynx_28g_lane_read_configuration(lane);
0591 }
0592
0593 dev_set_drvdata(dev, priv);
0594
0595 INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
0596
0597 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
0598 msecs_to_jiffies(1000));
0599
0600 dev_set_drvdata(&pdev->dev, priv);
0601 provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
0602
0603 return PTR_ERR_OR_ZERO(provider);
0604 }
0605
0606 static const struct of_device_id lynx_28g_of_match_table[] = {
0607 { .compatible = "fsl,lynx-28g" },
0608 { },
0609 };
0610 MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
0611
0612 static struct platform_driver lynx_28g_driver = {
0613 .probe = lynx_28g_probe,
0614 .driver = {
0615 .name = "lynx-28g",
0616 .of_match_table = lynx_28g_of_match_table,
0617 },
0618 };
0619 module_platform_driver(lynx_28g_driver);
0620
0621 MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
0622 MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
0623 MODULE_LICENSE("GPL v2");