Mention branches and keyring.
[releases.git] / freescale / phy-fsl-lynx-28g.c
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
108 struct lynx_28g_priv;
109
110 struct 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
117 struct 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
126 struct 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
135 static 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
155 static 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
170 static 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
189 static 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
222 static 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
234 static 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
257 static 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
293 static 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
329 static 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
353 static 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
377 static 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
414 out:
415         /* Power up the lane if necessary */
416         if (powered_up)
417                 lynx_28g_power_on(phy);
418
419         return err;
420 }
421
422 static 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
437 static 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
454 static 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
463 static 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
500 static 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
528 static 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
546 static 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
558 static 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
606 static const struct of_device_id lynx_28g_of_match_table[] = {
607         { .compatible = "fsl,lynx-28g" },
608         { },
609 };
610 MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
611
612 static 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 };
619 module_platform_driver(lynx_28g_driver);
620
621 MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
622 MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
623 MODULE_LICENSE("GPL v2");