1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 * Driver for Microsemi VSC85xx PHYs
5 * Author: Bjarni Jonasson <bjarni.jonassoni@microchip.com>
6 * License: Dual MIT/GPL
7 * Copyright (c) 2021 Microsemi Corporation
10 #include <linux/phy.h>
11 #include "mscc_serdes.h"
14 static int pll5g_detune(struct phy_device
*phydev
)
19 rd_dat
= vsc85xx_csr_read(phydev
, MACRO_CTRL
, PHY_S6G_PLL5G_CFG2
);
20 rd_dat
&= ~PHY_S6G_PLL5G_CFG2_GAIN_MASK
;
21 rd_dat
|= PHY_S6G_PLL5G_CFG2_ENA_GAIN
;
22 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
23 PHY_S6G_PLL5G_CFG2
, rd_dat
);
25 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
29 static int pll5g_tune(struct phy_device
*phydev
)
34 rd_dat
= vsc85xx_csr_read(phydev
, MACRO_CTRL
, PHY_S6G_PLL5G_CFG2
);
35 rd_dat
&= ~PHY_S6G_PLL5G_CFG2_ENA_GAIN
;
36 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
37 PHY_S6G_PLL5G_CFG2
, rd_dat
);
39 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
43 static int vsc85xx_sd6g_pll_cfg_wr(struct phy_device
*phydev
,
44 const u32 pll_ena_offs
,
45 const u32 pll_fsm_ctrl_data
,
46 const u32 pll_fsm_ena
)
50 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
52 (pll_fsm_ena
<< PHY_S6G_PLL_ENA_OFFS_POS
) |
53 (pll_fsm_ctrl_data
<< PHY_S6G_PLL_FSM_CTRL_DATA_POS
) |
54 (pll_ena_offs
<< PHY_S6G_PLL_FSM_ENA_POS
));
56 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
60 static int vsc85xx_sd6g_common_cfg_wr(struct phy_device
*phydev
,
68 /* ena_loop = 8 for eloop */
72 /* qrate = 1 for SGMII, 0 for QSGMII */
73 /* if_mode = 1 for SGMII, 3 for QSGMII */
77 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
79 (sys_rst
<< PHY_S6G_SYS_RST_POS
) |
80 (ena_lane
<< PHY_S6G_ENA_LANE_POS
) |
81 (ena_loop
<< PHY_S6G_ENA_LOOP_POS
) |
82 (qrate
<< PHY_S6G_QRATE_POS
) |
83 (if_mode
<< PHY_S6G_IF_MODE_POS
));
85 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
89 static int vsc85xx_sd6g_des_cfg_wr(struct phy_device
*phydev
,
90 const u32 des_phy_ctrl
,
91 const u32 des_mbtr_ctrl
,
92 const u32 des_bw_hyst
,
94 const u32 des_cpmd_sel
)
99 /* configurable terms */
100 reg_val
= (des_phy_ctrl
<< PHY_S6G_DES_PHY_CTRL_POS
) |
101 (des_mbtr_ctrl
<< PHY_S6G_DES_MBTR_CTRL_POS
) |
102 (des_cpmd_sel
<< PHY_S6G_DES_CPMD_SEL_POS
) |
103 (des_bw_hyst
<< PHY_S6G_DES_BW_HYST_POS
) |
104 (des_bw_ana
<< PHY_S6G_DES_BW_ANA_POS
);
105 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
109 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
113 static int vsc85xx_sd6g_ib_cfg0_wr(struct phy_device
*phydev
,
114 const u32 ib_rtrm_adj
,
115 const u32 ib_sig_det_clk_sel
,
116 const u32 ib_reg_pat_sel_offset
,
117 const u32 ib_cal_ena
)
124 base_val
= 0x60a85837;
125 /* configurable terms */
126 reg_val
= base_val
| (ib_rtrm_adj
<< 25) |
127 (ib_sig_det_clk_sel
<< 16) |
128 (ib_reg_pat_sel_offset
<< 8) |
130 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
134 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
138 static int vsc85xx_sd6g_ib_cfg1_wr(struct phy_device
*phydev
,
142 const u32 ib_frc_offset
,
143 const u32 ib_filt_offset
)
151 /* configurable terms */
152 reg_val
= (ib_tjtag
<< 17) + (ib_tsdet
<< 12) + (ib_scaly
<< 8) +
153 ib_filt_val
+ (ib_filt_offset
<< 4) + (ib_frc_offset
<< 0);
154 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
158 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
162 static int vsc85xx_sd6g_ib_cfg2_wr(struct phy_device
*phydev
,
172 base_val
= 0x0f878010;
173 /* configurable terms */
174 ib_cfg2_val
= base_val
| ((ib_tinfv
) << 28) | ((ib_tcalv
) << 5) |
176 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
180 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
184 static int vsc85xx_sd6g_ib_cfg3_wr(struct phy_device
*phydev
,
186 const u32 ib_ini_mid
,
188 const u32 ib_ini_offset
)
193 reg_val
= (ib_ini_hp
<< 24) + (ib_ini_mid
<< 16) +
194 (ib_ini_lp
<< 8) + (ib_ini_offset
<< 0);
195 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
199 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
203 static int vsc85xx_sd6g_ib_cfg4_wr(struct phy_device
*phydev
,
205 const u32 ib_max_mid
,
207 const u32 ib_max_offset
)
212 reg_val
= (ib_max_hp
<< 24) + (ib_max_mid
<< 16) +
213 (ib_max_lp
<< 8) + (ib_max_offset
<< 0);
214 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
218 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
222 static int vsc85xx_sd6g_misc_cfg_wr(struct phy_device
*phydev
,
227 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
231 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
235 static int vsc85xx_sd6g_gp_cfg_wr(struct phy_device
*phydev
, const u32 gp_cfg_val
)
239 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
243 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
247 static int vsc85xx_sd6g_dft_cfg2_wr(struct phy_device
*phydev
,
248 const u32 rx_ji_ampl
,
249 const u32 rx_step_freq
,
251 const u32 rx_waveform_sel
,
252 const u32 rx_freqoff_dir
,
253 const u32 rx_freqoff_ena
)
258 /* configurable terms */
259 reg_val
= (rx_ji_ampl
<< 8) | (rx_step_freq
<< 4) |
260 (rx_ji_ena
<< 3) | (rx_waveform_sel
<< 2) |
261 (rx_freqoff_dir
<< 1) | rx_freqoff_ena
;
262 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
266 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
270 static int vsc85xx_sd6g_dft_cfg0_wr(struct phy_device
*phydev
,
273 const u32 rx_dft_ena
)
278 /* configurable terms */
279 reg_val
= (prbs_sel
<< 20) | (test_mode
<< 16) | (rx_dft_ena
<< 2);
280 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
284 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
288 /* Access LCPLL Cfg_0 */
289 static int vsc85xx_pll5g_cfg0_wr(struct phy_device
*phydev
,
297 base_val
= 0x7036f145;
298 /* configurable terms */
299 reg_val
= base_val
| (selbgv820
<< 23);
300 ret
= vsc85xx_csr_write(phydev
, MACRO_CTRL
,
301 PHY_S6G_PLL5G_CFG0
, reg_val
);
303 dev_err(&phydev
->mdio
.dev
, "%s: write error\n", __func__
);
307 int vsc85xx_sd6g_config_v2(struct phy_device
*phydev
)
309 u32 ib_sig_det_clk_sel_cal
= 0;
310 u32 ib_sig_det_clk_sel_mm
= 7;
311 u32 pll_fsm_ctrl_data
= 60;
312 unsigned long deadline
;
313 u32 des_bw_ana_val
= 3;
314 u32 ib_tsdet_cal
= 16;
325 phy_base_write(phydev
, MSCC_EXT_PAGE_ACCESS
, MSCC_PHY_PAGE_STANDARD
);
327 /* Detune/Unlock LCPLL */
328 ret
= pll5g_detune(phydev
);
333 ret
= vsc85xx_sd6g_pll_cfg_wr(phydev
, 3, pll_fsm_ctrl_data
, 0);
336 ret
= vsc85xx_sd6g_common_cfg_wr(phydev
, 0, 0, 0, qrate
, if_mode
, 0);
339 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
342 ret
= vsc85xx_sd6g_des_cfg_wr(phydev
, 6, 2, 5, des_bw_ana_val
, 0);
346 /* 1. Configure sd6g for SGMII prior to sd6g_IB_CAL */
348 ret
= vsc85xx_sd6g_ib_cfg0_wr(phydev
, ib_rtrm_adj
, ib_sig_det_clk_sel_mm
, 0, 0);
351 ret
= vsc85xx_sd6g_ib_cfg1_wr(phydev
, 8, ib_tsdet_mm
, 15, 0, 1);
354 ret
= vsc85xx_sd6g_ib_cfg2_wr(phydev
, 3, 13, 5);
357 ret
= vsc85xx_sd6g_ib_cfg3_wr(phydev
, 0, 31, 1, 31);
360 ret
= vsc85xx_sd6g_ib_cfg4_wr(phydev
, 63, 63, 2, 63);
363 ret
= vsc85xx_sd6g_common_cfg_wr(phydev
, 1, 1, 0, qrate
, if_mode
, 0);
366 ret
= vsc85xx_sd6g_misc_cfg_wr(phydev
, 1);
369 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
373 /* 2. Start rcpll_fsm */
374 ret
= vsc85xx_sd6g_pll_cfg_wr(phydev
, 3, pll_fsm_ctrl_data
, 1);
377 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
381 deadline
= jiffies
+ msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS
);
383 usleep_range(500, 1000);
384 ret
= phy_update_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
387 val32
= vsc85xx_csr_read(phydev
, MACRO_CTRL
,
389 /* wait for bit 12 to clear */
390 } while (time_before(jiffies
, deadline
) && (val32
& BIT(12)));
395 /* 4. Release digital reset and disable transmitter */
396 ret
= vsc85xx_sd6g_misc_cfg_wr(phydev
, 0);
399 ret
= vsc85xx_sd6g_common_cfg_wr(phydev
, 1, 1, 0, qrate
, if_mode
, 1);
402 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
406 /* 5. Apply a frequency offset on RX-side (using internal FoJi logic) */
407 ret
= vsc85xx_sd6g_gp_cfg_wr(phydev
, 768);
410 ret
= vsc85xx_sd6g_dft_cfg2_wr(phydev
, 0, 2, 0, 0, 0, 1);
413 ret
= vsc85xx_sd6g_dft_cfg0_wr(phydev
, 0, 0, 1);
416 ret
= vsc85xx_sd6g_des_cfg_wr(phydev
, 6, 2, 5, des_bw_ana_val
, 2);
419 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
423 /* 6. Prepare required settings for IBCAL */
424 ret
= vsc85xx_sd6g_ib_cfg1_wr(phydev
, 8, ib_tsdet_cal
, 15, 1, 0);
427 ret
= vsc85xx_sd6g_ib_cfg0_wr(phydev
, ib_rtrm_adj
, ib_sig_det_clk_sel_cal
, 0, 0);
430 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
434 /* 7. Start IB_CAL */
435 ret
= vsc85xx_sd6g_ib_cfg0_wr(phydev
, ib_rtrm_adj
,
436 ib_sig_det_clk_sel_cal
, 0, 1);
439 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
442 /* 11 cycles (for ViperA) or 5 cycles (for ViperB & Elise) w/ SW clock */
443 for (iter
= 0; iter
< gp_iter
; iter
++) {
445 ret
= vsc85xx_sd6g_gp_cfg_wr(phydev
, 769);
448 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
452 ret
= vsc85xx_sd6g_gp_cfg_wr(phydev
, 768);
455 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
460 ret
= vsc85xx_sd6g_ib_cfg1_wr(phydev
, 8, ib_tsdet_cal
, 15, 1, 1);
463 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
466 ret
= vsc85xx_sd6g_ib_cfg1_wr(phydev
, 8, ib_tsdet_cal
, 15, 0, 1);
469 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
473 /* 8. Wait for IB cal to complete */
474 deadline
= jiffies
+ msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS
);
476 usleep_range(500, 1000);
477 ret
= phy_update_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
480 val32
= vsc85xx_csr_read(phydev
, MACRO_CTRL
,
482 /* wait for bit 8 to set */
483 } while (time_before(jiffies
, deadline
) && (~val32
& BIT(8)));
488 /* 9. Restore cfg values for mission mode */
489 ret
= vsc85xx_sd6g_ib_cfg0_wr(phydev
, ib_rtrm_adj
, ib_sig_det_clk_sel_mm
, 0, 1);
492 ret
= vsc85xx_sd6g_ib_cfg1_wr(phydev
, 8, ib_tsdet_mm
, 15, 0, 1);
495 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
499 /* 10. Re-enable transmitter */
500 ret
= vsc85xx_sd6g_common_cfg_wr(phydev
, 1, 1, 0, qrate
, if_mode
, 0);
503 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
507 /* 11. Disable frequency offset generation (using internal FoJi logic) */
508 ret
= vsc85xx_sd6g_dft_cfg2_wr(phydev
, 0, 0, 0, 0, 0, 0);
511 ret
= vsc85xx_sd6g_dft_cfg0_wr(phydev
, 0, 0, 0);
514 ret
= vsc85xx_sd6g_des_cfg_wr(phydev
, 6, 2, 5, des_bw_ana_val
, 0);
517 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
521 /* Tune/Re-lock LCPLL */
522 ret
= pll5g_tune(phydev
);
526 /* 12. Configure for Final Configuration and Settings */
528 ret
= vsc85xx_sd6g_pll_cfg_wr(phydev
, 3, pll_fsm_ctrl_data
, 0);
531 ret
= vsc85xx_sd6g_common_cfg_wr(phydev
, 0, 1, 0, qrate
, if_mode
, 0);
534 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
538 /* b. Configure sd6g for desired operating mode */
539 phy_base_write(phydev
, MSCC_EXT_PAGE_ACCESS
, MSCC_PHY_PAGE_EXTENDED_GPIO
);
540 ret
= phy_base_read(phydev
, MSCC_PHY_MAC_CFG_FASTLINK
);
541 if ((ret
& MAC_CFG_MASK
) == MAC_CFG_QSGMII
) {
543 pll_fsm_ctrl_data
= 120;
547 val
= PROC_CMD_MCB_ACCESS_MAC_CONF
| PROC_CMD_RST_CONF_PORT
|
548 PROC_CMD_READ_MOD_WRITE_PORT
| PROC_CMD_QSGMII_MAC
;
550 ret
= vsc8584_cmd(phydev
, val
);
552 dev_err(&phydev
->mdio
.dev
, "%s: QSGMII error: %d\n",
557 phy_base_write(phydev
, MSCC_EXT_PAGE_ACCESS
, MSCC_PHY_PAGE_STANDARD
);
558 } else if ((ret
& MAC_CFG_MASK
) == MAC_CFG_SGMII
) {
560 pll_fsm_ctrl_data
= 60;
565 val
= PROC_CMD_MCB_ACCESS_MAC_CONF
| PROC_CMD_RST_CONF_PORT
|
566 PROC_CMD_READ_MOD_WRITE_PORT
| PROC_CMD_SGMII_MAC
;
568 ret
= vsc8584_cmd(phydev
, val
);
570 dev_err(&phydev
->mdio
.dev
, "%s: SGMII error: %d\n",
575 phy_base_write(phydev
, MSCC_EXT_PAGE_ACCESS
, MSCC_PHY_PAGE_STANDARD
);
577 dev_err(&phydev
->mdio
.dev
, "%s: invalid mac_if: %x\n",
581 ret
= phy_update_mcb_s6g(phydev
, PHY_S6G_LCPLL_CFG
, 0);
584 ret
= phy_update_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
587 ret
= vsc85xx_pll5g_cfg0_wr(phydev
, 4);
590 ret
= phy_commit_mcb_s6g(phydev
, PHY_S6G_LCPLL_CFG
, 0);
593 ret
= vsc85xx_sd6g_des_cfg_wr(phydev
, 6, 2, 5, des_bw_ana_val
, 0);
596 ret
= vsc85xx_sd6g_ib_cfg0_wr(phydev
, ib_rtrm_adj
, ib_sig_det_clk_sel_mm
, 0, 1);
599 ret
= vsc85xx_sd6g_ib_cfg1_wr(phydev
, 8, ib_tsdet_mm
, 15, 0, 1);
602 ret
= vsc85xx_sd6g_common_cfg_wr(phydev
, 1, 1, 0, qrate
, if_mode
, 0);
605 ret
= vsc85xx_sd6g_ib_cfg2_wr(phydev
, 3, 13, 5);
608 ret
= vsc85xx_sd6g_ib_cfg3_wr(phydev
, 0, 31, 1, 31);
611 ret
= vsc85xx_sd6g_ib_cfg4_wr(phydev
, 63, 63, 2, 63);
614 ret
= vsc85xx_sd6g_misc_cfg_wr(phydev
, 1);
617 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
621 /* 13. Start rcpll_fsm */
622 ret
= vsc85xx_sd6g_pll_cfg_wr(phydev
, 3, pll_fsm_ctrl_data
, 1);
625 ret
= phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
629 /* 14. Wait for PLL cal to complete */
630 deadline
= jiffies
+ msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS
);
632 usleep_range(500, 1000);
633 ret
= phy_update_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);
636 val32
= vsc85xx_csr_read(phydev
, MACRO_CTRL
,
638 /* wait for bit 12 to clear */
639 } while (time_before(jiffies
, deadline
) && (val32
& BIT(12)));
644 /* release lane reset */
645 ret
= vsc85xx_sd6g_misc_cfg_wr(phydev
, 0);
649 return phy_commit_mcb_s6g(phydev
, PHY_MCB_S6G_CFG
, 0);