1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 * SerDes PHY driver for Microsemi Ocelot
5 * Copyright (c) 2018 Microsemi
10 #include <linux/mfd/syscon.h>
11 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 #include <linux/phy.h>
15 #include <linux/phy/phy.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <soc/mscc/ocelot_hsio.h>
19 #include <dt-bindings/phy/phy-ocelot-serdes.h>
24 struct phy
*phys
[SERDES_MAX
];
29 /* Not used when in QSGMII or PCIe mode */
31 struct serdes_ctrl
*ctrl
;
34 #define MCB_S6G_CFG_TIMEOUT 50
36 static int __serdes_write_mcb_s6g(struct regmap
*regmap
, u8 macro
, u32 op
)
38 unsigned int regval
= 0;
40 regmap_write(regmap
, HSIO_MCB_S6G_ADDR_CFG
, op
|
41 HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR(BIT(macro
)));
43 return regmap_read_poll_timeout(regmap
, HSIO_MCB_S6G_ADDR_CFG
, regval
,
44 (regval
& op
) != op
, 100,
45 MCB_S6G_CFG_TIMEOUT
* 1000);
48 static int serdes_commit_mcb_s6g(struct regmap
*regmap
, u8 macro
)
50 return __serdes_write_mcb_s6g(regmap
, macro
,
51 HSIO_MCB_S6G_ADDR_CFG_SERDES6G_WR_ONE_SHOT
);
54 static int serdes_update_mcb_s6g(struct regmap
*regmap
, u8 macro
)
56 return __serdes_write_mcb_s6g(regmap
, macro
,
57 HSIO_MCB_S6G_ADDR_CFG_SERDES6G_RD_ONE_SHOT
);
60 static int serdes_init_s6g(struct regmap
*regmap
, u8 serdes
, int mode
)
62 u32 pll_fsm_ctrl_data
;
71 if (mode
== PHY_INTERFACE_MODE_QSGMII
) {
72 pll_fsm_ctrl_data
= 120;
80 pll_fsm_ctrl_data
= 60;
89 ret
= serdes_update_mcb_s6g(regmap
, serdes
);
95 regmap_update_bits(regmap
, HSIO_S6G_COMMON_CFG
,
96 HSIO_S6G_COMMON_CFG_SYS_RST
, 0);
98 regmap_update_bits(regmap
, HSIO_S6G_PLL_CFG
,
99 HSIO_S6G_PLL_CFG_PLL_FSM_ENA
, 0);
101 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG
,
102 HSIO_S6G_IB_CFG_IB_SIG_DET_ENA
|
103 HSIO_S6G_IB_CFG_IB_REG_ENA
|
104 HSIO_S6G_IB_CFG_IB_SAM_ENA
|
105 HSIO_S6G_IB_CFG_IB_EQZ_ENA
|
106 HSIO_S6G_IB_CFG_IB_CONCUR
|
107 HSIO_S6G_IB_CFG_IB_CAL_ENA
,
108 HSIO_S6G_IB_CFG_IB_SIG_DET_ENA
|
109 HSIO_S6G_IB_CFG_IB_REG_ENA
|
110 HSIO_S6G_IB_CFG_IB_SAM_ENA
|
111 HSIO_S6G_IB_CFG_IB_EQZ_ENA
|
112 HSIO_S6G_IB_CFG_IB_CONCUR
);
114 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG1
,
115 HSIO_S6G_IB_CFG1_IB_FRC_OFFSET
|
116 HSIO_S6G_IB_CFG1_IB_FRC_LP
|
117 HSIO_S6G_IB_CFG1_IB_FRC_MID
|
118 HSIO_S6G_IB_CFG1_IB_FRC_HP
|
119 HSIO_S6G_IB_CFG1_IB_FILT_OFFSET
|
120 HSIO_S6G_IB_CFG1_IB_FILT_LP
|
121 HSIO_S6G_IB_CFG1_IB_FILT_MID
|
122 HSIO_S6G_IB_CFG1_IB_FILT_HP
,
123 HSIO_S6G_IB_CFG1_IB_FILT_OFFSET
|
124 HSIO_S6G_IB_CFG1_IB_FILT_HP
|
125 HSIO_S6G_IB_CFG1_IB_FILT_LP
|
126 HSIO_S6G_IB_CFG1_IB_FILT_MID
);
128 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG2
,
129 HSIO_S6G_IB_CFG2_IB_UREG_M
,
130 HSIO_S6G_IB_CFG2_IB_UREG(4));
132 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG3
,
133 HSIO_S6G_IB_CFG3_IB_INI_OFFSET_M
|
134 HSIO_S6G_IB_CFG3_IB_INI_LP_M
|
135 HSIO_S6G_IB_CFG3_IB_INI_MID_M
|
136 HSIO_S6G_IB_CFG3_IB_INI_HP_M
,
137 HSIO_S6G_IB_CFG3_IB_INI_OFFSET(31) |
138 HSIO_S6G_IB_CFG3_IB_INI_LP(1) |
139 HSIO_S6G_IB_CFG3_IB_INI_MID(31) |
140 HSIO_S6G_IB_CFG3_IB_INI_HP(0));
142 regmap_update_bits(regmap
, HSIO_S6G_MISC_CFG
,
143 HSIO_S6G_MISC_CFG_LANE_RST
,
144 HSIO_S6G_MISC_CFG_LANE_RST
);
146 ret
= serdes_commit_mcb_s6g(regmap
, serdes
);
150 /* OB + DES + IB + SER CFG */
151 regmap_update_bits(regmap
, HSIO_S6G_OB_CFG
,
152 HSIO_S6G_OB_CFG_OB_IDLE
|
153 HSIO_S6G_OB_CFG_OB_ENA1V_MODE
|
154 HSIO_S6G_OB_CFG_OB_POST0_M
|
155 HSIO_S6G_OB_CFG_OB_PREC_M
,
156 (ob_ena1v_mode
? HSIO_S6G_OB_CFG_OB_ENA1V_MODE
: 0) |
157 HSIO_S6G_OB_CFG_OB_POST0(0) |
158 HSIO_S6G_OB_CFG_OB_PREC(0));
160 regmap_update_bits(regmap
, HSIO_S6G_OB_CFG1
,
161 HSIO_S6G_OB_CFG1_OB_ENA_CAS_M
|
162 HSIO_S6G_OB_CFG1_OB_LEV_M
,
163 HSIO_S6G_OB_CFG1_OB_LEV(ob_lev
) |
164 HSIO_S6G_OB_CFG1_OB_ENA_CAS(ob_ena_cas
));
166 regmap_update_bits(regmap
, HSIO_S6G_DES_CFG
,
167 HSIO_S6G_DES_CFG_DES_PHS_CTRL_M
|
168 HSIO_S6G_DES_CFG_DES_CPMD_SEL_M
|
169 HSIO_S6G_DES_CFG_DES_BW_ANA_M
,
170 HSIO_S6G_DES_CFG_DES_PHS_CTRL(2) |
171 HSIO_S6G_DES_CFG_DES_CPMD_SEL(0) |
172 HSIO_S6G_DES_CFG_DES_BW_ANA(des_bw_ana
));
174 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG
,
175 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M
|
176 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M
,
177 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(0) |
178 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(0));
180 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG1
,
181 HSIO_S6G_IB_CFG1_IB_TSDET_M
,
182 HSIO_S6G_IB_CFG1_IB_TSDET(16));
184 regmap_update_bits(regmap
, HSIO_S6G_SER_CFG
,
185 HSIO_S6G_SER_CFG_SER_ALISEL_M
|
186 HSIO_S6G_SER_CFG_SER_ENALI
,
187 HSIO_S6G_SER_CFG_SER_ALISEL(0));
189 regmap_update_bits(regmap
, HSIO_S6G_PLL_CFG
,
190 HSIO_S6G_PLL_CFG_PLL_DIV4
|
191 HSIO_S6G_PLL_CFG_PLL_ENA_ROT
|
192 HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_M
|
193 HSIO_S6G_PLL_CFG_PLL_ROT_DIR
|
194 HSIO_S6G_PLL_CFG_PLL_ROT_FRQ
,
195 HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA
196 (pll_fsm_ctrl_data
));
198 regmap_update_bits(regmap
, HSIO_S6G_COMMON_CFG
,
199 HSIO_S6G_COMMON_CFG_SYS_RST
|
200 HSIO_S6G_COMMON_CFG_ENA_LANE
|
201 HSIO_S6G_COMMON_CFG_PWD_RX
|
202 HSIO_S6G_COMMON_CFG_PWD_TX
|
203 HSIO_S6G_COMMON_CFG_HRATE
|
204 HSIO_S6G_COMMON_CFG_QRATE
|
205 HSIO_S6G_COMMON_CFG_ENA_ELOOP
|
206 HSIO_S6G_COMMON_CFG_ENA_FLOOP
|
207 HSIO_S6G_COMMON_CFG_IF_MODE_M
,
208 HSIO_S6G_COMMON_CFG_SYS_RST
|
209 HSIO_S6G_COMMON_CFG_ENA_LANE
|
210 (qrate
? HSIO_S6G_COMMON_CFG_QRATE
: 0) |
211 HSIO_S6G_COMMON_CFG_IF_MODE(if_mode
));
213 regmap_update_bits(regmap
, HSIO_S6G_MISC_CFG
,
214 HSIO_S6G_MISC_CFG_LANE_RST
|
215 HSIO_S6G_MISC_CFG_DES_100FX_CPMD_ENA
|
216 HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA
|
217 HSIO_S6G_MISC_CFG_TX_LPI_MODE_ENA
,
218 HSIO_S6G_MISC_CFG_LANE_RST
|
219 HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA
);
222 ret
= serdes_commit_mcb_s6g(regmap
, serdes
);
226 regmap_update_bits(regmap
, HSIO_S6G_PLL_CFG
,
227 HSIO_S6G_PLL_CFG_PLL_FSM_ENA
,
228 HSIO_S6G_PLL_CFG_PLL_FSM_ENA
);
230 ret
= serdes_commit_mcb_s6g(regmap
, serdes
);
234 /* Wait for PLL bringup */
237 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG
,
238 HSIO_S6G_IB_CFG_IB_CAL_ENA
,
239 HSIO_S6G_IB_CFG_IB_CAL_ENA
);
241 regmap_update_bits(regmap
, HSIO_S6G_MISC_CFG
,
242 HSIO_S6G_MISC_CFG_LANE_RST
, 0);
244 ret
= serdes_commit_mcb_s6g(regmap
, serdes
);
248 /* Wait for calibration */
251 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG
,
252 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M
|
253 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M
,
254 HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(0) |
255 HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(7));
257 regmap_update_bits(regmap
, HSIO_S6G_IB_CFG1
,
258 HSIO_S6G_IB_CFG1_IB_TSDET_M
,
259 HSIO_S6G_IB_CFG1_IB_TSDET(3));
266 #define MCB_S1G_CFG_TIMEOUT 50
268 static int __serdes_write_mcb_s1g(struct regmap
*regmap
, u8 macro
, u32 op
)
272 regmap_write(regmap
, HSIO_MCB_S1G_ADDR_CFG
, op
|
273 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_ADDR(BIT(macro
)));
275 return regmap_read_poll_timeout(regmap
, HSIO_MCB_S1G_ADDR_CFG
, regval
,
276 (regval
& op
) != op
, 100,
277 MCB_S1G_CFG_TIMEOUT
* 1000);
280 static int serdes_commit_mcb_s1g(struct regmap
*regmap
, u8 macro
)
282 return __serdes_write_mcb_s1g(regmap
, macro
,
283 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_WR_ONE_SHOT
);
286 static int serdes_update_mcb_s1g(struct regmap
*regmap
, u8 macro
)
288 return __serdes_write_mcb_s1g(regmap
, macro
,
289 HSIO_MCB_S1G_ADDR_CFG_SERDES1G_RD_ONE_SHOT
);
292 static int serdes_init_s1g(struct regmap
*regmap
, u8 serdes
)
296 ret
= serdes_update_mcb_s1g(regmap
, serdes
);
300 regmap_update_bits(regmap
, HSIO_S1G_COMMON_CFG
,
301 HSIO_S1G_COMMON_CFG_SYS_RST
|
302 HSIO_S1G_COMMON_CFG_ENA_LANE
|
303 HSIO_S1G_COMMON_CFG_ENA_ELOOP
|
304 HSIO_S1G_COMMON_CFG_ENA_FLOOP
,
305 HSIO_S1G_COMMON_CFG_ENA_LANE
);
307 regmap_update_bits(regmap
, HSIO_S1G_PLL_CFG
,
308 HSIO_S1G_PLL_CFG_PLL_FSM_ENA
|
309 HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA_M
,
310 HSIO_S1G_PLL_CFG_PLL_FSM_CTRL_DATA(200) |
311 HSIO_S1G_PLL_CFG_PLL_FSM_ENA
);
313 regmap_update_bits(regmap
, HSIO_S1G_MISC_CFG
,
314 HSIO_S1G_MISC_CFG_DES_100FX_CPMD_ENA
|
315 HSIO_S1G_MISC_CFG_LANE_RST
,
316 HSIO_S1G_MISC_CFG_LANE_RST
);
318 ret
= serdes_commit_mcb_s1g(regmap
, serdes
);
322 regmap_update_bits(regmap
, HSIO_S1G_COMMON_CFG
,
323 HSIO_S1G_COMMON_CFG_SYS_RST
,
324 HSIO_S1G_COMMON_CFG_SYS_RST
);
326 regmap_update_bits(regmap
, HSIO_S1G_MISC_CFG
,
327 HSIO_S1G_MISC_CFG_LANE_RST
, 0);
329 ret
= serdes_commit_mcb_s1g(regmap
, serdes
);
345 #define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \
349 .submode = _submode, \
354 #define SERDES_MUX_SGMII(i, p, m, c) \
355 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_SGMII, m, c)
356 #define SERDES_MUX_QSGMII(i, p, m, c) \
357 SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c)
359 static const struct serdes_mux ocelot_serdes_muxes
[] = {
360 SERDES_MUX_SGMII(SERDES1G(0), 0, 0, 0),
361 SERDES_MUX_SGMII(SERDES1G(1), 1, HSIO_HW_CFG_DEV1G_5_MODE
, 0),
362 SERDES_MUX_SGMII(SERDES1G(1), 5, HSIO_HW_CFG_QSGMII_ENA
|
363 HSIO_HW_CFG_DEV1G_5_MODE
, HSIO_HW_CFG_DEV1G_5_MODE
),
364 SERDES_MUX_SGMII(SERDES1G(2), 2, HSIO_HW_CFG_DEV1G_4_MODE
, 0),
365 SERDES_MUX_SGMII(SERDES1G(2), 4, HSIO_HW_CFG_QSGMII_ENA
|
366 HSIO_HW_CFG_DEV1G_4_MODE
, HSIO_HW_CFG_DEV1G_4_MODE
),
367 SERDES_MUX_SGMII(SERDES1G(3), 3, HSIO_HW_CFG_DEV1G_6_MODE
, 0),
368 SERDES_MUX_SGMII(SERDES1G(3), 6, HSIO_HW_CFG_QSGMII_ENA
|
369 HSIO_HW_CFG_DEV1G_6_MODE
, HSIO_HW_CFG_DEV1G_6_MODE
),
370 SERDES_MUX_SGMII(SERDES1G(4), 4, HSIO_HW_CFG_QSGMII_ENA
|
371 HSIO_HW_CFG_DEV1G_4_MODE
| HSIO_HW_CFG_DEV1G_9_MODE
,
373 SERDES_MUX_SGMII(SERDES1G(4), 9, HSIO_HW_CFG_DEV1G_4_MODE
|
374 HSIO_HW_CFG_DEV1G_9_MODE
, HSIO_HW_CFG_DEV1G_4_MODE
|
375 HSIO_HW_CFG_DEV1G_9_MODE
),
376 SERDES_MUX_SGMII(SERDES1G(5), 5, HSIO_HW_CFG_QSGMII_ENA
|
377 HSIO_HW_CFG_DEV1G_5_MODE
| HSIO_HW_CFG_DEV2G5_10_MODE
,
379 SERDES_MUX_SGMII(SERDES1G(5), 10, HSIO_HW_CFG_PCIE_ENA
|
380 HSIO_HW_CFG_DEV1G_5_MODE
| HSIO_HW_CFG_DEV2G5_10_MODE
,
381 HSIO_HW_CFG_DEV1G_5_MODE
| HSIO_HW_CFG_DEV2G5_10_MODE
),
382 SERDES_MUX_QSGMII(SERDES6G(0), 4, HSIO_HW_CFG_QSGMII_ENA
,
383 HSIO_HW_CFG_QSGMII_ENA
),
384 SERDES_MUX_QSGMII(SERDES6G(0), 5, HSIO_HW_CFG_QSGMII_ENA
,
385 HSIO_HW_CFG_QSGMII_ENA
),
386 SERDES_MUX_QSGMII(SERDES6G(0), 6, HSIO_HW_CFG_QSGMII_ENA
,
387 HSIO_HW_CFG_QSGMII_ENA
),
388 SERDES_MUX_SGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA
, 0),
389 SERDES_MUX_QSGMII(SERDES6G(0), 7, HSIO_HW_CFG_QSGMII_ENA
,
390 HSIO_HW_CFG_QSGMII_ENA
),
391 SERDES_MUX_SGMII(SERDES6G(1), 8, 0, 0),
392 SERDES_MUX_SGMII(SERDES6G(2), 10, HSIO_HW_CFG_PCIE_ENA
|
393 HSIO_HW_CFG_DEV2G5_10_MODE
, 0),
394 SERDES_MUX(SERDES6G(2), 10, PHY_MODE_PCIE
, 0, HSIO_HW_CFG_PCIE_ENA
,
395 HSIO_HW_CFG_PCIE_ENA
),
398 static int serdes_set_mode(struct phy
*phy
, enum phy_mode mode
, int submode
)
400 struct serdes_macro
*macro
= phy_get_drvdata(phy
);
404 /* As of now only PHY_MODE_ETHERNET is supported */
405 if (mode
!= PHY_MODE_ETHERNET
)
408 for (i
= 0; i
< ARRAY_SIZE(ocelot_serdes_muxes
); i
++) {
409 if (macro
->idx
!= ocelot_serdes_muxes
[i
].idx
||
410 mode
!= ocelot_serdes_muxes
[i
].mode
||
411 submode
!= ocelot_serdes_muxes
[i
].submode
)
414 if (submode
!= PHY_INTERFACE_MODE_QSGMII
&&
415 macro
->port
!= ocelot_serdes_muxes
[i
].port
)
418 ret
= regmap_update_bits(macro
->ctrl
->regs
, HSIO_HW_CFG
,
419 ocelot_serdes_muxes
[i
].mask
,
420 ocelot_serdes_muxes
[i
].mux
);
424 if (macro
->idx
<= SERDES1G_MAX
)
425 return serdes_init_s1g(macro
->ctrl
->regs
, macro
->idx
);
426 else if (macro
->idx
<= SERDES6G_MAX
)
427 return serdes_init_s6g(macro
->ctrl
->regs
,
428 macro
->idx
- (SERDES1G_MAX
+ 1),
429 ocelot_serdes_muxes
[i
].submode
);
431 /* PCIe not supported yet */
438 static const struct phy_ops serdes_ops
= {
439 .set_mode
= serdes_set_mode
,
440 .owner
= THIS_MODULE
,
443 static struct phy
*serdes_simple_xlate(struct device
*dev
,
444 struct of_phandle_args
*args
)
446 struct serdes_ctrl
*ctrl
= dev_get_drvdata(dev
);
447 unsigned int port
, idx
, i
;
449 if (args
->args_count
!= 2)
450 return ERR_PTR(-EINVAL
);
452 port
= args
->args
[0];
455 for (i
= 0; i
< SERDES_MAX
; i
++) {
456 struct serdes_macro
*macro
= phy_get_drvdata(ctrl
->phys
[i
]);
458 if (idx
!= macro
->idx
)
461 /* SERDES6G(0) is the only SerDes capable of QSGMII */
462 if (idx
!= SERDES6G(0) && macro
->port
>= 0)
463 return ERR_PTR(-EBUSY
);
466 return ctrl
->phys
[i
];
469 return ERR_PTR(-ENODEV
);
472 static int serdes_phy_create(struct serdes_ctrl
*ctrl
, u8 idx
, struct phy
**phy
)
474 struct serdes_macro
*macro
;
476 *phy
= devm_phy_create(ctrl
->dev
, NULL
, &serdes_ops
);
478 return PTR_ERR(*phy
);
480 macro
= devm_kzalloc(ctrl
->dev
, sizeof(*macro
), GFP_KERNEL
);
488 phy_set_drvdata(*phy
, macro
);
493 static int serdes_probe(struct platform_device
*pdev
)
495 struct phy_provider
*provider
;
496 struct serdes_ctrl
*ctrl
;
500 ctrl
= devm_kzalloc(&pdev
->dev
, sizeof(*ctrl
), GFP_KERNEL
);
504 ctrl
->dev
= &pdev
->dev
;
505 ctrl
->regs
= syscon_node_to_regmap(pdev
->dev
.parent
->of_node
);
506 if (IS_ERR(ctrl
->regs
))
507 return PTR_ERR(ctrl
->regs
);
509 for (i
= 0; i
< SERDES_MAX
; i
++) {
510 ret
= serdes_phy_create(ctrl
, i
, &ctrl
->phys
[i
]);
515 dev_set_drvdata(&pdev
->dev
, ctrl
);
517 provider
= devm_of_phy_provider_register(ctrl
->dev
,
518 serdes_simple_xlate
);
520 return PTR_ERR_OR_ZERO(provider
);
523 static const struct of_device_id serdes_ids
[] = {
524 { .compatible
= "mscc,vsc7514-serdes", },
527 MODULE_DEVICE_TABLE(of
, serdes_ids
);
529 static struct platform_driver mscc_ocelot_serdes
= {
530 .probe
= serdes_probe
,
532 .name
= "mscc,ocelot-serdes",
533 .of_match_table
= of_match_ptr(serdes_ids
),
537 module_platform_driver(mscc_ocelot_serdes
);
539 MODULE_AUTHOR("Quentin Schulz <quentin.schulz@bootlin.com>");
540 MODULE_DESCRIPTION("SerDes driver for Microsemi Ocelot");
541 MODULE_LICENSE("Dual MIT/GPL");