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