651 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Driver for Microsemi VSC85xx PHYs4 *5 * Author: Bjarni Jonasson <bjarni.jonassoni@microchip.com>6 * License: Dual MIT/GPL7 * Copyright (c) 2021 Microsemi Corporation8 */9 10#include <linux/phy.h>11#include "mscc_serdes.h"12#include "mscc.h"13 14static int pll5g_detune(struct phy_device *phydev)15{16 u32 rd_dat;17 int ret;18 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);24 if (ret)25 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);26 return ret;27}28 29static int pll5g_tune(struct phy_device *phydev)30{31 u32 rd_dat;32 int ret;33 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);38 if (ret)39 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);40 return ret;41}42 43static 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)47{48 int ret;49 50 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,51 PHY_S6G_PLL_CFG,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));55 if (ret)56 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);57 return ret;58}59 60static int vsc85xx_sd6g_common_cfg_wr(struct phy_device *phydev,61 const u32 sys_rst,62 const u32 ena_lane,63 const u32 ena_loop,64 const u32 qrate,65 const u32 if_mode,66 const u32 pwd_tx)67{68 /* ena_loop = 8 for eloop */69 /* = 4 for floop */70 /* = 2 for iloop */71 /* = 1 for ploop */72 /* qrate = 1 for SGMII, 0 for QSGMII */73 /* if_mode = 1 for SGMII, 3 for QSGMII */74 75 int ret;76 77 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,78 PHY_S6G_COMMON_CFG,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));84 if (ret)85 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);86 return ret;87}88 89static 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,93 const u32 des_bw_ana,94 const u32 des_cpmd_sel)95{96 u32 reg_val;97 int ret;98 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,106 PHY_S6G_DES_CFG,107 reg_val);108 if (ret)109 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);110 return ret;111}112 113static 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)118{119 u32 base_val;120 u32 reg_val;121 int ret;122 123 /* constant terms */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) |129 (ib_cal_ena << 3);130 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,131 PHY_S6G_IB_CFG0,132 reg_val);133 if (ret)134 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);135 return ret;136}137 138static int vsc85xx_sd6g_ib_cfg1_wr(struct phy_device *phydev,139 const u32 ib_tjtag,140 const u32 ib_tsdet,141 const u32 ib_scaly,142 const u32 ib_frc_offset,143 const u32 ib_filt_offset)144{145 u32 ib_filt_val;146 u32 reg_val = 0;147 int ret;148 149 /* constant terms */150 ib_filt_val = 0xe0;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,155 PHY_S6G_IB_CFG1,156 reg_val);157 if (ret)158 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);159 return ret;160}161 162static int vsc85xx_sd6g_ib_cfg2_wr(struct phy_device *phydev,163 const u32 ib_tinfv,164 const u32 ib_tcalv,165 const u32 ib_ureg)166{167 u32 ib_cfg2_val;168 u32 base_val;169 int ret;170 171 /* constant terms */172 base_val = 0x0f878010;173 /* configurable terms */174 ib_cfg2_val = base_val | ((ib_tinfv) << 28) | ((ib_tcalv) << 5) |175 (ib_ureg << 0);176 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,177 PHY_S6G_IB_CFG2,178 ib_cfg2_val);179 if (ret)180 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);181 return ret;182}183 184static int vsc85xx_sd6g_ib_cfg3_wr(struct phy_device *phydev,185 const u32 ib_ini_hp,186 const u32 ib_ini_mid,187 const u32 ib_ini_lp,188 const u32 ib_ini_offset)189{190 u32 reg_val;191 int ret;192 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,196 PHY_S6G_IB_CFG3,197 reg_val);198 if (ret)199 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);200 return ret;201}202 203static int vsc85xx_sd6g_ib_cfg4_wr(struct phy_device *phydev,204 const u32 ib_max_hp,205 const u32 ib_max_mid,206 const u32 ib_max_lp,207 const u32 ib_max_offset)208{209 u32 reg_val;210 int ret;211 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,215 PHY_S6G_IB_CFG4,216 reg_val);217 if (ret)218 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);219 return ret;220}221 222static int vsc85xx_sd6g_misc_cfg_wr(struct phy_device *phydev,223 const u32 lane_rst)224{225 int ret;226 227 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,228 PHY_S6G_MISC_CFG,229 lane_rst);230 if (ret)231 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);232 return ret;233}234 235static int vsc85xx_sd6g_gp_cfg_wr(struct phy_device *phydev, const u32 gp_cfg_val)236{237 int ret;238 239 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,240 PHY_S6G_GP_CFG,241 gp_cfg_val);242 if (ret)243 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);244 return ret;245}246 247static int vsc85xx_sd6g_dft_cfg2_wr(struct phy_device *phydev,248 const u32 rx_ji_ampl,249 const u32 rx_step_freq,250 const u32 rx_ji_ena,251 const u32 rx_waveform_sel,252 const u32 rx_freqoff_dir,253 const u32 rx_freqoff_ena)254{255 u32 reg_val;256 int ret;257 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,263 PHY_S6G_IB_DFT_CFG2,264 reg_val);265 if (ret)266 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);267 return ret;268}269 270static int vsc85xx_sd6g_dft_cfg0_wr(struct phy_device *phydev,271 const u32 prbs_sel,272 const u32 test_mode,273 const u32 rx_dft_ena)274{275 u32 reg_val;276 int ret;277 278 /* configurable terms */279 reg_val = (prbs_sel << 20) | (test_mode << 16) | (rx_dft_ena << 2);280 ret = vsc85xx_csr_write(phydev, MACRO_CTRL,281 PHY_S6G_DFT_CFG0,282 reg_val);283 if (ret)284 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);285 return ret;286}287 288/* Access LCPLL Cfg_0 */289static int vsc85xx_pll5g_cfg0_wr(struct phy_device *phydev,290 const u32 selbgv820)291{292 u32 base_val;293 u32 reg_val;294 int ret;295 296 /* constant terms */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);302 if (ret)303 dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);304 return ret;305}306 307int vsc85xx_sd6g_config_v2(struct phy_device *phydev)308{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;315 u32 ib_tsdet_mm = 5;316 u32 ib_rtrm_adj;317 u32 if_mode = 1;318 u32 gp_iter = 5;319 u32 val32 = 0;320 u32 qrate = 1;321 u32 iter;322 int val = 0;323 int ret;324 325 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);326 327 /* Detune/Unlock LCPLL */328 ret = pll5g_detune(phydev);329 if (ret)330 return ret;331 332 /* 0. Reset RCPLL */333 ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 0);334 if (ret)335 return ret;336 ret = vsc85xx_sd6g_common_cfg_wr(phydev, 0, 0, 0, qrate, if_mode, 0);337 if (ret)338 return ret;339 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);340 if (ret)341 return ret;342 ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 0);343 if (ret)344 return ret;345 346 /* 1. Configure sd6g for SGMII prior to sd6g_IB_CAL */347 ib_rtrm_adj = 13;348 ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_mm, 0, 0);349 if (ret)350 return ret;351 ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_mm, 15, 0, 1);352 if (ret)353 return ret;354 ret = vsc85xx_sd6g_ib_cfg2_wr(phydev, 3, 13, 5);355 if (ret)356 return ret;357 ret = vsc85xx_sd6g_ib_cfg3_wr(phydev, 0, 31, 1, 31);358 if (ret)359 return ret;360 ret = vsc85xx_sd6g_ib_cfg4_wr(phydev, 63, 63, 2, 63);361 if (ret)362 return ret;363 ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 0);364 if (ret)365 return ret;366 ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 1);367 if (ret)368 return ret;369 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);370 if (ret)371 return ret;372 373 /* 2. Start rcpll_fsm */374 ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 1);375 if (ret)376 return ret;377 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);378 if (ret)379 return ret;380 381 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);382 do {383 usleep_range(500, 1000);384 ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);385 if (ret)386 return ret;387 val32 = vsc85xx_csr_read(phydev, MACRO_CTRL,388 PHY_S6G_PLL_STATUS);389 /* wait for bit 12 to clear */390 } while (time_before(jiffies, deadline) && (val32 & BIT(12)));391 392 if (val32 & BIT(12))393 return -ETIMEDOUT;394 395 /* 4. Release digital reset and disable transmitter */396 ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 0);397 if (ret)398 return ret;399 ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 1);400 if (ret)401 return ret;402 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);403 if (ret)404 return ret;405 406 /* 5. Apply a frequency offset on RX-side (using internal FoJi logic) */407 ret = vsc85xx_sd6g_gp_cfg_wr(phydev, 768);408 if (ret)409 return ret;410 ret = vsc85xx_sd6g_dft_cfg2_wr(phydev, 0, 2, 0, 0, 0, 1);411 if (ret)412 return ret;413 ret = vsc85xx_sd6g_dft_cfg0_wr(phydev, 0, 0, 1);414 if (ret)415 return ret;416 ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 2);417 if (ret)418 return ret;419 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);420 if (ret)421 return ret;422 423 /* 6. Prepare required settings for IBCAL */424 ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_cal, 15, 1, 0);425 if (ret)426 return ret;427 ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_cal, 0, 0);428 if (ret)429 return ret;430 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);431 if (ret)432 return ret;433 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);437 if (ret)438 return ret;439 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);440 if (ret)441 return ret;442 /* 11 cycles (for ViperA) or 5 cycles (for ViperB & Elise) w/ SW clock */443 for (iter = 0; iter < gp_iter; iter++) {444 /* set gp(0) */445 ret = vsc85xx_sd6g_gp_cfg_wr(phydev, 769);446 if (ret)447 return ret;448 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);449 if (ret)450 return ret;451 /* clear gp(0) */452 ret = vsc85xx_sd6g_gp_cfg_wr(phydev, 768);453 if (ret)454 return ret;455 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);456 if (ret)457 return ret;458 }459 460 ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_cal, 15, 1, 1);461 if (ret)462 return ret;463 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);464 if (ret)465 return ret;466 ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_cal, 15, 0, 1);467 if (ret)468 return ret;469 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);470 if (ret)471 return ret;472 473 /* 8. Wait for IB cal to complete */474 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);475 do {476 usleep_range(500, 1000);477 ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);478 if (ret)479 return ret;480 val32 = vsc85xx_csr_read(phydev, MACRO_CTRL,481 PHY_S6G_IB_STATUS0);482 /* wait for bit 8 to set */483 } while (time_before(jiffies, deadline) && (~val32 & BIT(8)));484 485 if (~val32 & BIT(8))486 return -ETIMEDOUT;487 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);490 if (ret)491 return ret;492 ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_mm, 15, 0, 1);493 if (ret)494 return ret;495 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);496 if (ret)497 return ret;498 499 /* 10. Re-enable transmitter */500 ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 0);501 if (ret)502 return ret;503 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);504 if (ret)505 return ret;506 507 /* 11. Disable frequency offset generation (using internal FoJi logic) */508 ret = vsc85xx_sd6g_dft_cfg2_wr(phydev, 0, 0, 0, 0, 0, 0);509 if (ret)510 return ret;511 ret = vsc85xx_sd6g_dft_cfg0_wr(phydev, 0, 0, 0);512 if (ret)513 return ret;514 ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 0);515 if (ret)516 return ret;517 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);518 if (ret)519 return ret;520 521 /* Tune/Re-lock LCPLL */522 ret = pll5g_tune(phydev);523 if (ret)524 return ret;525 526 /* 12. Configure for Final Configuration and Settings */527 /* a. Reset RCPLL */528 ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 0);529 if (ret)530 return ret;531 ret = vsc85xx_sd6g_common_cfg_wr(phydev, 0, 1, 0, qrate, if_mode, 0);532 if (ret)533 return ret;534 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);535 if (ret)536 return ret;537 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) {542 /* QSGMII */543 pll_fsm_ctrl_data = 120;544 qrate = 0;545 if_mode = 3;546 des_bw_ana_val = 5;547 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |548 PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_QSGMII_MAC;549 550 ret = vsc8584_cmd(phydev, val);551 if (ret) {552 dev_err(&phydev->mdio.dev, "%s: QSGMII error: %d\n",553 __func__, ret);554 return ret;555 }556 557 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);558 } else if ((ret & MAC_CFG_MASK) == MAC_CFG_SGMII) {559 /* SGMII */560 pll_fsm_ctrl_data = 60;561 qrate = 1;562 if_mode = 1;563 des_bw_ana_val = 3;564 565 val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |566 PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_SGMII_MAC;567 568 ret = vsc8584_cmd(phydev, val);569 if (ret) {570 dev_err(&phydev->mdio.dev, "%s: SGMII error: %d\n",571 __func__, ret);572 return ret;573 }574 575 phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);576 } else {577 dev_err(&phydev->mdio.dev, "%s: invalid mac_if: %x\n",578 __func__, ret);579 }580 581 ret = phy_update_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);582 if (ret)583 return ret;584 ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);585 if (ret)586 return ret;587 ret = vsc85xx_pll5g_cfg0_wr(phydev, 4);588 if (ret)589 return ret;590 ret = phy_commit_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);591 if (ret)592 return ret;593 ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 0);594 if (ret)595 return ret;596 ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_mm, 0, 1);597 if (ret)598 return ret;599 ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_mm, 15, 0, 1);600 if (ret)601 return ret;602 ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 0);603 if (ret)604 return ret;605 ret = vsc85xx_sd6g_ib_cfg2_wr(phydev, 3, 13, 5);606 if (ret)607 return ret;608 ret = vsc85xx_sd6g_ib_cfg3_wr(phydev, 0, 31, 1, 31);609 if (ret)610 return ret;611 ret = vsc85xx_sd6g_ib_cfg4_wr(phydev, 63, 63, 2, 63);612 if (ret)613 return ret;614 ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 1);615 if (ret)616 return ret;617 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);618 if (ret)619 return ret;620 621 /* 13. Start rcpll_fsm */622 ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 1);623 if (ret)624 return ret;625 ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);626 if (ret)627 return ret;628 629 /* 14. Wait for PLL cal to complete */630 deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);631 do {632 usleep_range(500, 1000);633 ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);634 if (ret)635 return ret;636 val32 = vsc85xx_csr_read(phydev, MACRO_CTRL,637 PHY_S6G_PLL_STATUS);638 /* wait for bit 12 to clear */639 } while (time_before(jiffies, deadline) && (val32 & BIT(12)));640 641 if (val32 & BIT(12))642 return -ETIMEDOUT;643 644 /* release lane reset */645 ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 0);646 if (ret)647 return ret;648 649 return phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);650}651