1 // SPDX-License-Identifier: GPL-2.0-or-later
4 #include <linux/module.h>
6 #include <linux/of_platform.h>
8 #include <linux/phy/phy.h>
9 #include <linux/platform_device.h>
11 #include <dt-bindings/phy/phy-lan966x-serdes.h>
12 #include "lan966x_serdes_regs.h"
14 #define PLL_CONF_MASK GENMASK(4, 3)
15 #define PLL_CONF_25MHZ 0
16 #define PLL_CONF_125MHZ 1
17 #define PLL_CONF_SERDES_125MHZ 2
18 #define PLL_CONF_BYPASS 3
20 #define lan_offset_(id, tinst, tcnt, \
21 gbase, ginst, gcnt, gwidth, \
22 raddr, rinst, rcnt, rwidth) \
23 (gbase + ((ginst) * gwidth) + raddr + ((rinst) * rwidth))
24 #define lan_offset(...) lan_offset_(__VA_ARGS__)
26 #define lan_rmw(val, mask, reg, off) \
27 lan_rmw_(val, mask, reg, lan_offset(off))
29 #define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \
33 .submode = _submode, \
38 #define SERDES_MUX_GMII(i, p, m, c) \
39 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_GMII, m, c)
40 #define SERDES_MUX_SGMII(i, p, m, c) \
41 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c)
42 #define SERDES_MUX_QSGMII(i, p, m, c) \
43 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c)
44 #define SERDES_MUX_RGMII(i, p, m, c) \
45 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c), \
46 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_TXID, m, c), \
47 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_RXID, m, c), \
48 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_ID, m, c)
50 static void lan_rmw_(u32 val
, u32 mask
, void __iomem
*mem
, u32 offset
)
54 v
= readl(mem
+ offset
);
55 v
= (v
& ~mask
) | (val
& mask
);
56 writel(v
, mem
+ offset
);
68 static const struct serdes_mux lan966x_serdes_muxes
[] = {
69 SERDES_MUX_QSGMII(SERDES6G(1), 0, HSIO_HW_CFG_QSGMII_ENA
,
70 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
71 SERDES_MUX_QSGMII(SERDES6G(1), 1, HSIO_HW_CFG_QSGMII_ENA
,
72 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
73 SERDES_MUX_QSGMII(SERDES6G(1), 2, HSIO_HW_CFG_QSGMII_ENA
,
74 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
75 SERDES_MUX_QSGMII(SERDES6G(1), 3, HSIO_HW_CFG_QSGMII_ENA
,
76 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(0))),
78 SERDES_MUX_QSGMII(SERDES6G(2), 4, HSIO_HW_CFG_QSGMII_ENA
,
79 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
80 SERDES_MUX_QSGMII(SERDES6G(2), 5, HSIO_HW_CFG_QSGMII_ENA
,
81 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
82 SERDES_MUX_QSGMII(SERDES6G(2), 6, HSIO_HW_CFG_QSGMII_ENA
,
83 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
84 SERDES_MUX_QSGMII(SERDES6G(2), 7, HSIO_HW_CFG_QSGMII_ENA
,
85 HSIO_HW_CFG_QSGMII_ENA_SET(BIT(1))),
87 SERDES_MUX_GMII(CU(0), 0, HSIO_HW_CFG_GMII_ENA
,
88 HSIO_HW_CFG_GMII_ENA_SET(BIT(0))),
89 SERDES_MUX_GMII(CU(1), 1, HSIO_HW_CFG_GMII_ENA
,
90 HSIO_HW_CFG_GMII_ENA_SET(BIT(1))),
92 SERDES_MUX_SGMII(SERDES6G(0), 0, HSIO_HW_CFG_SD6G_0_CFG
, 0),
93 SERDES_MUX_SGMII(SERDES6G(1), 1, HSIO_HW_CFG_SD6G_1_CFG
, 0),
94 SERDES_MUX_SGMII(SERDES6G(0), 2, HSIO_HW_CFG_SD6G_0_CFG
,
95 HSIO_HW_CFG_SD6G_0_CFG_SET(1)),
96 SERDES_MUX_SGMII(SERDES6G(1), 3, HSIO_HW_CFG_SD6G_1_CFG
,
97 HSIO_HW_CFG_SD6G_1_CFG_SET(1)),
99 SERDES_MUX_SGMII(SERDES6G(2), 4, 0, 0),
101 SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG
|
102 HSIO_HW_CFG_RGMII_ENA
|
103 HSIO_HW_CFG_GMII_ENA
,
104 HSIO_HW_CFG_RGMII_0_CFG_SET(0) |
105 HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) |
106 HSIO_HW_CFG_GMII_ENA_SET(BIT(2))),
107 SERDES_MUX_RGMII(RGMII(1), 3, HSIO_HW_CFG_RGMII_1_CFG
|
108 HSIO_HW_CFG_RGMII_ENA
|
109 HSIO_HW_CFG_GMII_ENA
,
110 HSIO_HW_CFG_RGMII_1_CFG_SET(0) |
111 HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) |
112 HSIO_HW_CFG_GMII_ENA_SET(BIT(3))),
113 SERDES_MUX_RGMII(RGMII(0), 5, HSIO_HW_CFG_RGMII_0_CFG
|
114 HSIO_HW_CFG_RGMII_ENA
|
115 HSIO_HW_CFG_GMII_ENA
,
116 HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) |
117 HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) |
118 HSIO_HW_CFG_GMII_ENA_SET(BIT(5))),
119 SERDES_MUX_RGMII(RGMII(1), 6, HSIO_HW_CFG_RGMII_1_CFG
|
120 HSIO_HW_CFG_RGMII_ENA
|
121 HSIO_HW_CFG_GMII_ENA
,
122 HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) |
123 HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) |
124 HSIO_HW_CFG_GMII_ENA_SET(BIT(6))),
130 struct phy
*phys
[SERDES_MAX
];
134 struct serdes_macro
{
137 struct serdes_ctrl
*ctrl
;
139 phy_interface_t mode
;
142 enum lan966x_sd6g40_mode
{
143 LAN966X_SD6G40_MODE_QSGMII
,
144 LAN966X_SD6G40_MODE_SGMII
,
147 enum lan966x_sd6g40_ltx2rx
{
148 LAN966X_SD6G40_TX2RX_LOOP_NONE
,
149 LAN966X_SD6G40_LTX2RX
152 struct lan966x_sd6g40_setup_args
{
153 enum lan966x_sd6g40_mode mode
;
154 enum lan966x_sd6g40_ltx2rx tx2rx_loop
;
161 struct lan966x_sd6g40_mode_args
{
162 enum lan966x_sd6g40_mode mode
;
170 struct lan966x_sd6g40_setup
{
182 static int lan966x_sd6g40_reg_cfg(struct serdes_macro
*macro
,
183 struct lan966x_sd6g40_setup
*res_struct
,
188 /* Note: SerDes HSIO is configured in 1G_LAN mode */
189 lan_rmw(HSIO_SD_CFG_LANE_10BIT_SEL_SET(res_struct
->lane_10bit_sel
) |
190 HSIO_SD_CFG_RX_RATE_SET(res_struct
->rx_rate
) |
191 HSIO_SD_CFG_TX_RATE_SET(res_struct
->tx_rate
) |
192 HSIO_SD_CFG_TX_INVERT_SET(res_struct
->tx_invert
) |
193 HSIO_SD_CFG_RX_INVERT_SET(res_struct
->rx_invert
) |
194 HSIO_SD_CFG_LANE_LOOPBK_EN_SET(res_struct
->lane_loopbk_en
) |
195 HSIO_SD_CFG_RX_RESET_SET(0) |
196 HSIO_SD_CFG_TX_RESET_SET(0),
197 HSIO_SD_CFG_LANE_10BIT_SEL
|
198 HSIO_SD_CFG_RX_RATE
|
199 HSIO_SD_CFG_TX_RATE
|
200 HSIO_SD_CFG_TX_INVERT
|
201 HSIO_SD_CFG_RX_INVERT
|
202 HSIO_SD_CFG_LANE_LOOPBK_EN
|
203 HSIO_SD_CFG_RX_RESET
|
204 HSIO_SD_CFG_TX_RESET
,
205 macro
->ctrl
->regs
, HSIO_SD_CFG(idx
));
207 lan_rmw(HSIO_MPLL_CFG_MPLL_MULTIPLIER_SET(res_struct
->mpll_multiplier
) |
208 HSIO_MPLL_CFG_REF_CLKDIV2_SET(res_struct
->ref_clkdiv2
),
209 HSIO_MPLL_CFG_MPLL_MULTIPLIER
|
210 HSIO_MPLL_CFG_REF_CLKDIV2
,
211 macro
->ctrl
->regs
, HSIO_MPLL_CFG(idx
));
213 lan_rmw(HSIO_SD_CFG_RX_TERM_EN_SET(res_struct
->rx_term_en
),
214 HSIO_SD_CFG_RX_TERM_EN
,
215 macro
->ctrl
->regs
, HSIO_SD_CFG(idx
));
217 lan_rmw(HSIO_MPLL_CFG_REF_SSP_EN_SET(1),
218 HSIO_MPLL_CFG_REF_SSP_EN
,
219 macro
->ctrl
->regs
, HSIO_MPLL_CFG(idx
));
221 usleep_range(USEC_PER_MSEC
, 2 * USEC_PER_MSEC
);
223 lan_rmw(HSIO_SD_CFG_PHY_RESET_SET(0),
224 HSIO_SD_CFG_PHY_RESET
,
225 macro
->ctrl
->regs
, HSIO_SD_CFG(idx
));
227 usleep_range(USEC_PER_MSEC
, 2 * USEC_PER_MSEC
);
229 lan_rmw(HSIO_MPLL_CFG_MPLL_EN_SET(1),
230 HSIO_MPLL_CFG_MPLL_EN
,
231 macro
->ctrl
->regs
, HSIO_MPLL_CFG(idx
));
233 usleep_range(7 * USEC_PER_MSEC
, 8 * USEC_PER_MSEC
);
235 value
= readl(macro
->ctrl
->regs
+ lan_offset(HSIO_SD_STAT(idx
)));
236 value
= HSIO_SD_STAT_MPLL_STATE_GET(value
);
238 dev_err(macro
->ctrl
->dev
,
239 "Unexpected sd_sd_stat[%u] mpll_state was 0x1 but is 0x%x\n",
244 lan_rmw(HSIO_SD_CFG_TX_CM_EN_SET(1),
245 HSIO_SD_CFG_TX_CM_EN
,
246 macro
->ctrl
->regs
, HSIO_SD_CFG(idx
));
248 usleep_range(USEC_PER_MSEC
, 2 * USEC_PER_MSEC
);
250 value
= readl(macro
->ctrl
->regs
+ lan_offset(HSIO_SD_STAT(idx
)));
251 value
= HSIO_SD_STAT_TX_CM_STATE_GET(value
);
253 dev_err(macro
->ctrl
->dev
,
254 "Unexpected sd_sd_stat[%u] tx_cm_state was 0x1 but is 0x%x\n",
259 lan_rmw(HSIO_SD_CFG_RX_PLL_EN_SET(1) |
260 HSIO_SD_CFG_TX_EN_SET(1),
261 HSIO_SD_CFG_RX_PLL_EN
|
263 macro
->ctrl
->regs
, HSIO_SD_CFG(idx
));
265 usleep_range(USEC_PER_MSEC
, 2 * USEC_PER_MSEC
);
267 /* Waiting for serdes 0 rx DPLL to lock... */
268 value
= readl(macro
->ctrl
->regs
+ lan_offset(HSIO_SD_STAT(idx
)));
269 value
= HSIO_SD_STAT_RX_PLL_STATE_GET(value
);
271 dev_err(macro
->ctrl
->dev
,
272 "Unexpected sd_sd_stat[%u] rx_pll_state was 0x1 but is 0x%x\n",
277 /* Waiting for serdes 0 tx operational... */
278 value
= readl(macro
->ctrl
->regs
+ lan_offset(HSIO_SD_STAT(idx
)));
279 value
= HSIO_SD_STAT_TX_STATE_GET(value
);
281 dev_err(macro
->ctrl
->dev
,
282 "Unexpected sd_sd_stat[%u] tx_state was 0x1 but is 0x%x\n",
287 lan_rmw(HSIO_SD_CFG_TX_DATA_EN_SET(1) |
288 HSIO_SD_CFG_RX_DATA_EN_SET(1),
289 HSIO_SD_CFG_TX_DATA_EN
|
290 HSIO_SD_CFG_RX_DATA_EN
,
291 macro
->ctrl
->regs
, HSIO_SD_CFG(idx
));
296 static int lan966x_sd6g40_get_conf_from_mode(struct serdes_macro
*macro
,
297 enum lan966x_sd6g40_mode f_mode
,
299 struct lan966x_sd6g40_mode_args
*ret_val
)
302 case LAN966X_SD6G40_MODE_QSGMII
:
303 ret_val
->lane_10bit_sel
= 0;
305 ret_val
->mpll_multiplier
= 40;
306 ret_val
->ref_clkdiv2
= 0x1;
307 ret_val
->tx_rate
= 0x0;
308 ret_val
->rx_rate
= 0x0;
310 ret_val
->mpll_multiplier
= 100;
311 ret_val
->ref_clkdiv2
= 0x0;
312 ret_val
->tx_rate
= 0x0;
313 ret_val
->rx_rate
= 0x0;
317 case LAN966X_SD6G40_MODE_SGMII
:
318 ret_val
->lane_10bit_sel
= 1;
320 ret_val
->mpll_multiplier
= macro
->speed
== SPEED_2500
? 50 : 40;
321 ret_val
->ref_clkdiv2
= 0x1;
322 ret_val
->tx_rate
= macro
->speed
== SPEED_2500
? 0x1 : 0x2;
323 ret_val
->rx_rate
= macro
->speed
== SPEED_2500
? 0x1 : 0x2;
325 ret_val
->mpll_multiplier
= macro
->speed
== SPEED_2500
? 125 : 100;
326 ret_val
->ref_clkdiv2
= 0x0;
327 ret_val
->tx_rate
= macro
->speed
== SPEED_2500
? 0x1 : 0x2;
328 ret_val
->rx_rate
= macro
->speed
== SPEED_2500
? 0x1 : 0x2;
339 static int lan966x_calc_sd6g40_setup_lane(struct serdes_macro
*macro
,
340 struct lan966x_sd6g40_setup_args config
,
341 struct lan966x_sd6g40_setup
*ret_val
)
343 struct lan966x_sd6g40_mode_args sd6g40_mode
;
344 struct lan966x_sd6g40_mode_args
*mode_args
= &sd6g40_mode
;
347 ret
= lan966x_sd6g40_get_conf_from_mode(macro
, config
.mode
,
348 config
.refclk125M
, mode_args
);
352 ret_val
->lane_10bit_sel
= mode_args
->lane_10bit_sel
;
353 ret_val
->rx_rate
= mode_args
->rx_rate
;
354 ret_val
->tx_rate
= mode_args
->tx_rate
;
355 ret_val
->mpll_multiplier
= mode_args
->mpll_multiplier
;
356 ret_val
->ref_clkdiv2
= mode_args
->ref_clkdiv2
;
357 ret_val
->rx_term_en
= 0;
359 if (config
.tx2rx_loop
== LAN966X_SD6G40_LTX2RX
)
360 ret_val
->lane_loopbk_en
= 1;
362 ret_val
->lane_loopbk_en
= 0;
364 ret_val
->tx_invert
= !!config
.txinvert
;
365 ret_val
->rx_invert
= !!config
.rxinvert
;
370 static int lan966x_sd6g40_setup_lane(struct serdes_macro
*macro
,
371 struct lan966x_sd6g40_setup_args config
,
374 struct lan966x_sd6g40_setup calc_results
= {};
377 ret
= lan966x_calc_sd6g40_setup_lane(macro
, config
, &calc_results
);
381 return lan966x_sd6g40_reg_cfg(macro
, &calc_results
, idx
);
384 static int lan966x_sd6g40_setup(struct serdes_macro
*macro
, u32 idx
, int mode
)
386 struct lan966x_sd6g40_setup_args conf
= {};
388 conf
.refclk125M
= macro
->ctrl
->ref125
;
390 if (mode
== PHY_INTERFACE_MODE_QSGMII
)
391 conf
.mode
= LAN966X_SD6G40_MODE_QSGMII
;
393 conf
.mode
= LAN966X_SD6G40_MODE_SGMII
;
395 return lan966x_sd6g40_setup_lane(macro
, conf
, idx
);
398 static int lan966x_rgmii_setup(struct serdes_macro
*macro
, u32 idx
, int mode
)
400 bool tx_delay
= false;
401 bool rx_delay
= false;
403 /* Configure RGMII */
404 lan_rmw(HSIO_RGMII_CFG_RGMII_RX_RST_SET(0) |
405 HSIO_RGMII_CFG_RGMII_TX_RST_SET(0) |
406 HSIO_RGMII_CFG_TX_CLK_CFG_SET(macro
->speed
== SPEED_1000
? 1 :
407 macro
->speed
== SPEED_100
? 2 :
408 macro
->speed
== SPEED_10
? 3 : 0),
409 HSIO_RGMII_CFG_RGMII_RX_RST
|
410 HSIO_RGMII_CFG_RGMII_TX_RST
|
411 HSIO_RGMII_CFG_TX_CLK_CFG
,
412 macro
->ctrl
->regs
, HSIO_RGMII_CFG(idx
));
414 if (mode
== PHY_INTERFACE_MODE_RGMII
||
415 mode
== PHY_INTERFACE_MODE_RGMII_TXID
)
418 if (mode
== PHY_INTERFACE_MODE_RGMII
||
419 mode
== PHY_INTERFACE_MODE_RGMII_RXID
)
422 /* Setup DLL configuration */
423 lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) |
424 HSIO_DLL_CFG_DLL_ENA_SET(rx_delay
),
425 HSIO_DLL_CFG_DLL_RST
|
426 HSIO_DLL_CFG_DLL_ENA
,
427 macro
->ctrl
->regs
, HSIO_DLL_CFG(idx
== 0 ? 0x0 : 0x2));
429 lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(rx_delay
),
430 HSIO_DLL_CFG_DELAY_ENA
,
431 macro
->ctrl
->regs
, HSIO_DLL_CFG(idx
== 0 ? 0x0 : 0x2));
433 lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) |
434 HSIO_DLL_CFG_DLL_ENA_SET(tx_delay
),
435 HSIO_DLL_CFG_DLL_RST
|
436 HSIO_DLL_CFG_DLL_ENA
,
437 macro
->ctrl
->regs
, HSIO_DLL_CFG(idx
== 0 ? 0x1 : 0x3));
439 lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(tx_delay
),
440 HSIO_DLL_CFG_DELAY_ENA
,
441 macro
->ctrl
->regs
, HSIO_DLL_CFG(idx
== 0 ? 0x1 : 0x3));
446 static int serdes_set_speed(struct phy
*phy
, int speed
)
448 struct serdes_macro
*macro
= phy_get_drvdata(phy
);
450 if (!phy_interface_mode_is_rgmii(macro
->mode
))
453 macro
->speed
= speed
;
454 lan966x_rgmii_setup(macro
, macro
->idx
- (SERDES6G_MAX
+ 1), macro
->mode
);
459 static int serdes_set_mode(struct phy
*phy
, enum phy_mode mode
, int submode
)
461 struct serdes_macro
*macro
= phy_get_drvdata(phy
);
465 /* As of now only PHY_MODE_ETHERNET is supported */
466 if (mode
!= PHY_MODE_ETHERNET
)
469 if (submode
== PHY_INTERFACE_MODE_2500BASEX
)
470 macro
->speed
= SPEED_2500
;
472 macro
->speed
= SPEED_1000
;
474 if (submode
== PHY_INTERFACE_MODE_1000BASEX
||
475 submode
== PHY_INTERFACE_MODE_2500BASEX
)
476 submode
= PHY_INTERFACE_MODE_SGMII
;
478 if (submode
== PHY_INTERFACE_MODE_QUSGMII
)
479 submode
= PHY_INTERFACE_MODE_QSGMII
;
481 for (i
= 0; i
< ARRAY_SIZE(lan966x_serdes_muxes
); i
++) {
482 if (macro
->idx
!= lan966x_serdes_muxes
[i
].idx
||
483 mode
!= lan966x_serdes_muxes
[i
].mode
||
484 submode
!= lan966x_serdes_muxes
[i
].submode
||
485 macro
->port
!= lan966x_serdes_muxes
[i
].port
)
488 val
= readl(macro
->ctrl
->regs
+ lan_offset(HSIO_HW_CFG
));
489 val
|= lan966x_serdes_muxes
[i
].mux
;
490 lan_rmw(val
, lan966x_serdes_muxes
[i
].mask
,
491 macro
->ctrl
->regs
, HSIO_HW_CFG
);
493 macro
->mode
= lan966x_serdes_muxes
[i
].submode
;
495 if (macro
->idx
< CU_MAX
)
498 if (macro
->idx
< SERDES6G_MAX
)
499 return lan966x_sd6g40_setup(macro
,
500 macro
->idx
- (CU_MAX
+ 1),
503 if (macro
->idx
< RGMII_MAX
)
504 return lan966x_rgmii_setup(macro
,
505 macro
->idx
- (SERDES6G_MAX
+ 1),
514 static const struct phy_ops serdes_ops
= {
515 .set_mode
= serdes_set_mode
,
516 .set_speed
= serdes_set_speed
,
517 .owner
= THIS_MODULE
,
520 static struct phy
*serdes_simple_xlate(struct device
*dev
,
521 const struct of_phandle_args
*args
)
523 struct serdes_ctrl
*ctrl
= dev_get_drvdata(dev
);
524 unsigned int port
, idx
, i
;
526 if (args
->args_count
!= 2)
527 return ERR_PTR(-EINVAL
);
529 port
= args
->args
[0];
532 for (i
= 0; i
< SERDES_MAX
; i
++) {
533 struct serdes_macro
*macro
= phy_get_drvdata(ctrl
->phys
[i
]);
535 if (idx
!= macro
->idx
)
539 return ctrl
->phys
[i
];
542 return ERR_PTR(-ENODEV
);
545 static int serdes_phy_create(struct serdes_ctrl
*ctrl
, u8 idx
, struct phy
**phy
)
547 struct serdes_macro
*macro
;
549 *phy
= devm_phy_create(ctrl
->dev
, NULL
, &serdes_ops
);
551 return PTR_ERR(*phy
);
553 macro
= devm_kzalloc(ctrl
->dev
, sizeof(*macro
), GFP_KERNEL
);
561 phy_set_drvdata(*phy
, macro
);
566 static int serdes_probe(struct platform_device
*pdev
)
568 struct phy_provider
*provider
;
569 struct serdes_ctrl
*ctrl
;
570 void __iomem
*hw_stat
;
575 ctrl
= devm_kzalloc(&pdev
->dev
, sizeof(*ctrl
), GFP_KERNEL
);
579 ctrl
->dev
= &pdev
->dev
;
580 ctrl
->regs
= devm_platform_get_and_ioremap_resource(pdev
, 0, NULL
);
581 if (IS_ERR(ctrl
->regs
))
582 return PTR_ERR(ctrl
->regs
);
584 hw_stat
= devm_platform_get_and_ioremap_resource(pdev
, 1, NULL
);
586 return PTR_ERR(hw_stat
);
588 for (i
= 0; i
< SERDES_MAX
; i
++) {
589 ret
= serdes_phy_create(ctrl
, i
, &ctrl
->phys
[i
]);
594 val
= readl(hw_stat
);
595 val
= FIELD_GET(PLL_CONF_MASK
, val
);
596 ctrl
->ref125
= (val
== PLL_CONF_125MHZ
||
597 val
== PLL_CONF_SERDES_125MHZ
);
599 dev_set_drvdata(&pdev
->dev
, ctrl
);
601 provider
= devm_of_phy_provider_register(ctrl
->dev
,
602 serdes_simple_xlate
);
604 return PTR_ERR_OR_ZERO(provider
);
607 static const struct of_device_id serdes_ids
[] = {
608 { .compatible
= "microchip,lan966x-serdes", },
611 MODULE_DEVICE_TABLE(of
, serdes_ids
);
613 static struct platform_driver mscc_lan966x_serdes
= {
614 .probe
= serdes_probe
,
616 .name
= "microchip,lan966x-serdes",
617 .of_match_table
= of_match_ptr(serdes_ids
),
621 module_platform_driver(mscc_lan966x_serdes
);
623 MODULE_DESCRIPTION("Microchip lan966x switch serdes driver");
624 MODULE_AUTHOR("Horatiu Vultur <horatiu.vultur@microchip.com>");
625 MODULE_LICENSE("GPL v2");