mscc_serdes.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /*
  3. * Driver for Microsemi VSC85xx PHYs
  4. *
  5. * Author: Bjarni Jonasson <[email protected]>
  6. * License: Dual MIT/GPL
  7. * Copyright (c) 2021 Microsemi Corporation
  8. */
  9. #include <linux/phy.h>
  10. #include "mscc_serdes.h"
  11. #include "mscc.h"
  12. static int pll5g_detune(struct phy_device *phydev)
  13. {
  14. u32 rd_dat;
  15. int ret;
  16. rd_dat = vsc85xx_csr_read(phydev, MACRO_CTRL, PHY_S6G_PLL5G_CFG2);
  17. rd_dat &= ~PHY_S6G_PLL5G_CFG2_GAIN_MASK;
  18. rd_dat |= PHY_S6G_PLL5G_CFG2_ENA_GAIN;
  19. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  20. PHY_S6G_PLL5G_CFG2, rd_dat);
  21. if (ret)
  22. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  23. return ret;
  24. }
  25. static int pll5g_tune(struct phy_device *phydev)
  26. {
  27. u32 rd_dat;
  28. int ret;
  29. rd_dat = vsc85xx_csr_read(phydev, MACRO_CTRL, PHY_S6G_PLL5G_CFG2);
  30. rd_dat &= ~PHY_S6G_PLL5G_CFG2_ENA_GAIN;
  31. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  32. PHY_S6G_PLL5G_CFG2, rd_dat);
  33. if (ret)
  34. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  35. return ret;
  36. }
  37. static int vsc85xx_sd6g_pll_cfg_wr(struct phy_device *phydev,
  38. const u32 pll_ena_offs,
  39. const u32 pll_fsm_ctrl_data,
  40. const u32 pll_fsm_ena)
  41. {
  42. int ret;
  43. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  44. PHY_S6G_PLL_CFG,
  45. (pll_fsm_ena << PHY_S6G_PLL_ENA_OFFS_POS) |
  46. (pll_fsm_ctrl_data << PHY_S6G_PLL_FSM_CTRL_DATA_POS) |
  47. (pll_ena_offs << PHY_S6G_PLL_FSM_ENA_POS));
  48. if (ret)
  49. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  50. return ret;
  51. }
  52. static int vsc85xx_sd6g_common_cfg_wr(struct phy_device *phydev,
  53. const u32 sys_rst,
  54. const u32 ena_lane,
  55. const u32 ena_loop,
  56. const u32 qrate,
  57. const u32 if_mode,
  58. const u32 pwd_tx)
  59. {
  60. /* ena_loop = 8 for eloop */
  61. /* = 4 for floop */
  62. /* = 2 for iloop */
  63. /* = 1 for ploop */
  64. /* qrate = 1 for SGMII, 0 for QSGMII */
  65. /* if_mode = 1 for SGMII, 3 for QSGMII */
  66. int ret;
  67. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  68. PHY_S6G_COMMON_CFG,
  69. (sys_rst << PHY_S6G_SYS_RST_POS) |
  70. (ena_lane << PHY_S6G_ENA_LANE_POS) |
  71. (ena_loop << PHY_S6G_ENA_LOOP_POS) |
  72. (qrate << PHY_S6G_QRATE_POS) |
  73. (if_mode << PHY_S6G_IF_MODE_POS));
  74. if (ret)
  75. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  76. return ret;
  77. }
  78. static int vsc85xx_sd6g_des_cfg_wr(struct phy_device *phydev,
  79. const u32 des_phy_ctrl,
  80. const u32 des_mbtr_ctrl,
  81. const u32 des_bw_hyst,
  82. const u32 des_bw_ana,
  83. const u32 des_cpmd_sel)
  84. {
  85. u32 reg_val;
  86. int ret;
  87. /* configurable terms */
  88. reg_val = (des_phy_ctrl << PHY_S6G_DES_PHY_CTRL_POS) |
  89. (des_mbtr_ctrl << PHY_S6G_DES_MBTR_CTRL_POS) |
  90. (des_cpmd_sel << PHY_S6G_DES_CPMD_SEL_POS) |
  91. (des_bw_hyst << PHY_S6G_DES_BW_HYST_POS) |
  92. (des_bw_ana << PHY_S6G_DES_BW_ANA_POS);
  93. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  94. PHY_S6G_DES_CFG,
  95. reg_val);
  96. if (ret)
  97. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  98. return ret;
  99. }
  100. static int vsc85xx_sd6g_ib_cfg0_wr(struct phy_device *phydev,
  101. const u32 ib_rtrm_adj,
  102. const u32 ib_sig_det_clk_sel,
  103. const u32 ib_reg_pat_sel_offset,
  104. const u32 ib_cal_ena)
  105. {
  106. u32 base_val;
  107. u32 reg_val;
  108. int ret;
  109. /* constant terms */
  110. base_val = 0x60a85837;
  111. /* configurable terms */
  112. reg_val = base_val | (ib_rtrm_adj << 25) |
  113. (ib_sig_det_clk_sel << 16) |
  114. (ib_reg_pat_sel_offset << 8) |
  115. (ib_cal_ena << 3);
  116. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  117. PHY_S6G_IB_CFG0,
  118. reg_val);
  119. if (ret)
  120. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  121. return ret;
  122. }
  123. static int vsc85xx_sd6g_ib_cfg1_wr(struct phy_device *phydev,
  124. const u32 ib_tjtag,
  125. const u32 ib_tsdet,
  126. const u32 ib_scaly,
  127. const u32 ib_frc_offset,
  128. const u32 ib_filt_offset)
  129. {
  130. u32 ib_filt_val;
  131. u32 reg_val = 0;
  132. int ret;
  133. /* constant terms */
  134. ib_filt_val = 0xe0;
  135. /* configurable terms */
  136. reg_val = (ib_tjtag << 17) + (ib_tsdet << 12) + (ib_scaly << 8) +
  137. ib_filt_val + (ib_filt_offset << 4) + (ib_frc_offset << 0);
  138. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  139. PHY_S6G_IB_CFG1,
  140. reg_val);
  141. if (ret)
  142. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  143. return ret;
  144. }
  145. static int vsc85xx_sd6g_ib_cfg2_wr(struct phy_device *phydev,
  146. const u32 ib_tinfv,
  147. const u32 ib_tcalv,
  148. const u32 ib_ureg)
  149. {
  150. u32 ib_cfg2_val;
  151. u32 base_val;
  152. int ret;
  153. /* constant terms */
  154. base_val = 0x0f878010;
  155. /* configurable terms */
  156. ib_cfg2_val = base_val | ((ib_tinfv) << 28) | ((ib_tcalv) << 5) |
  157. (ib_ureg << 0);
  158. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  159. PHY_S6G_IB_CFG2,
  160. ib_cfg2_val);
  161. if (ret)
  162. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  163. return ret;
  164. }
  165. static int vsc85xx_sd6g_ib_cfg3_wr(struct phy_device *phydev,
  166. const u32 ib_ini_hp,
  167. const u32 ib_ini_mid,
  168. const u32 ib_ini_lp,
  169. const u32 ib_ini_offset)
  170. {
  171. u32 reg_val;
  172. int ret;
  173. reg_val = (ib_ini_hp << 24) + (ib_ini_mid << 16) +
  174. (ib_ini_lp << 8) + (ib_ini_offset << 0);
  175. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  176. PHY_S6G_IB_CFG3,
  177. reg_val);
  178. if (ret)
  179. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  180. return ret;
  181. }
  182. static int vsc85xx_sd6g_ib_cfg4_wr(struct phy_device *phydev,
  183. const u32 ib_max_hp,
  184. const u32 ib_max_mid,
  185. const u32 ib_max_lp,
  186. const u32 ib_max_offset)
  187. {
  188. u32 reg_val;
  189. int ret;
  190. reg_val = (ib_max_hp << 24) + (ib_max_mid << 16) +
  191. (ib_max_lp << 8) + (ib_max_offset << 0);
  192. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  193. PHY_S6G_IB_CFG4,
  194. reg_val);
  195. if (ret)
  196. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  197. return ret;
  198. }
  199. static int vsc85xx_sd6g_misc_cfg_wr(struct phy_device *phydev,
  200. const u32 lane_rst)
  201. {
  202. int ret;
  203. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  204. PHY_S6G_MISC_CFG,
  205. lane_rst);
  206. if (ret)
  207. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  208. return ret;
  209. }
  210. static int vsc85xx_sd6g_gp_cfg_wr(struct phy_device *phydev, const u32 gp_cfg_val)
  211. {
  212. int ret;
  213. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  214. PHY_S6G_GP_CFG,
  215. gp_cfg_val);
  216. if (ret)
  217. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  218. return ret;
  219. }
  220. static int vsc85xx_sd6g_dft_cfg2_wr(struct phy_device *phydev,
  221. const u32 rx_ji_ampl,
  222. const u32 rx_step_freq,
  223. const u32 rx_ji_ena,
  224. const u32 rx_waveform_sel,
  225. const u32 rx_freqoff_dir,
  226. const u32 rx_freqoff_ena)
  227. {
  228. u32 reg_val;
  229. int ret;
  230. /* configurable terms */
  231. reg_val = (rx_ji_ampl << 8) | (rx_step_freq << 4) |
  232. (rx_ji_ena << 3) | (rx_waveform_sel << 2) |
  233. (rx_freqoff_dir << 1) | rx_freqoff_ena;
  234. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  235. PHY_S6G_IB_DFT_CFG2,
  236. reg_val);
  237. if (ret)
  238. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  239. return ret;
  240. }
  241. static int vsc85xx_sd6g_dft_cfg0_wr(struct phy_device *phydev,
  242. const u32 prbs_sel,
  243. const u32 test_mode,
  244. const u32 rx_dft_ena)
  245. {
  246. u32 reg_val;
  247. int ret;
  248. /* configurable terms */
  249. reg_val = (prbs_sel << 20) | (test_mode << 16) | (rx_dft_ena << 2);
  250. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  251. PHY_S6G_DFT_CFG0,
  252. reg_val);
  253. if (ret)
  254. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  255. return ret;
  256. }
  257. /* Access LCPLL Cfg_0 */
  258. static int vsc85xx_pll5g_cfg0_wr(struct phy_device *phydev,
  259. const u32 selbgv820)
  260. {
  261. u32 base_val;
  262. u32 reg_val;
  263. int ret;
  264. /* constant terms */
  265. base_val = 0x7036f145;
  266. /* configurable terms */
  267. reg_val = base_val | (selbgv820 << 23);
  268. ret = vsc85xx_csr_write(phydev, MACRO_CTRL,
  269. PHY_S6G_PLL5G_CFG0, reg_val);
  270. if (ret)
  271. dev_err(&phydev->mdio.dev, "%s: write error\n", __func__);
  272. return ret;
  273. }
  274. int vsc85xx_sd6g_config_v2(struct phy_device *phydev)
  275. {
  276. u32 ib_sig_det_clk_sel_cal = 0;
  277. u32 ib_sig_det_clk_sel_mm = 7;
  278. u32 pll_fsm_ctrl_data = 60;
  279. unsigned long deadline;
  280. u32 des_bw_ana_val = 3;
  281. u32 ib_tsdet_cal = 16;
  282. u32 ib_tsdet_mm = 5;
  283. u32 ib_rtrm_adj;
  284. u32 if_mode = 1;
  285. u32 gp_iter = 5;
  286. u32 val32 = 0;
  287. u32 qrate = 1;
  288. u32 iter;
  289. int val = 0;
  290. int ret;
  291. phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
  292. /* Detune/Unlock LCPLL */
  293. ret = pll5g_detune(phydev);
  294. if (ret)
  295. return ret;
  296. /* 0. Reset RCPLL */
  297. ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 0);
  298. if (ret)
  299. return ret;
  300. ret = vsc85xx_sd6g_common_cfg_wr(phydev, 0, 0, 0, qrate, if_mode, 0);
  301. if (ret)
  302. return ret;
  303. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  304. if (ret)
  305. return ret;
  306. ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 0);
  307. if (ret)
  308. return ret;
  309. /* 1. Configure sd6g for SGMII prior to sd6g_IB_CAL */
  310. ib_rtrm_adj = 13;
  311. ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_mm, 0, 0);
  312. if (ret)
  313. return ret;
  314. ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_mm, 15, 0, 1);
  315. if (ret)
  316. return ret;
  317. ret = vsc85xx_sd6g_ib_cfg2_wr(phydev, 3, 13, 5);
  318. if (ret)
  319. return ret;
  320. ret = vsc85xx_sd6g_ib_cfg3_wr(phydev, 0, 31, 1, 31);
  321. if (ret)
  322. return ret;
  323. ret = vsc85xx_sd6g_ib_cfg4_wr(phydev, 63, 63, 2, 63);
  324. if (ret)
  325. return ret;
  326. ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 0);
  327. if (ret)
  328. return ret;
  329. ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 1);
  330. if (ret)
  331. return ret;
  332. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  333. if (ret)
  334. return ret;
  335. /* 2. Start rcpll_fsm */
  336. ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 1);
  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. deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
  343. do {
  344. usleep_range(500, 1000);
  345. ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  346. if (ret)
  347. return ret;
  348. val32 = vsc85xx_csr_read(phydev, MACRO_CTRL,
  349. PHY_S6G_PLL_STATUS);
  350. /* wait for bit 12 to clear */
  351. } while (time_before(jiffies, deadline) && (val32 & BIT(12)));
  352. if (val32 & BIT(12))
  353. return -ETIMEDOUT;
  354. /* 4. Release digital reset and disable transmitter */
  355. ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 0);
  356. if (ret)
  357. return ret;
  358. ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 1);
  359. if (ret)
  360. return ret;
  361. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  362. if (ret)
  363. return ret;
  364. /* 5. Apply a frequency offset on RX-side (using internal FoJi logic) */
  365. ret = vsc85xx_sd6g_gp_cfg_wr(phydev, 768);
  366. if (ret)
  367. return ret;
  368. ret = vsc85xx_sd6g_dft_cfg2_wr(phydev, 0, 2, 0, 0, 0, 1);
  369. if (ret)
  370. return ret;
  371. ret = vsc85xx_sd6g_dft_cfg0_wr(phydev, 0, 0, 1);
  372. if (ret)
  373. return ret;
  374. ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 2);
  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. /* 6. Prepare required settings for IBCAL */
  381. ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_cal, 15, 1, 0);
  382. if (ret)
  383. return ret;
  384. ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_cal, 0, 0);
  385. if (ret)
  386. return ret;
  387. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  388. if (ret)
  389. return ret;
  390. /* 7. Start IB_CAL */
  391. ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj,
  392. ib_sig_det_clk_sel_cal, 0, 1);
  393. if (ret)
  394. return ret;
  395. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  396. if (ret)
  397. return ret;
  398. /* 11 cycles (for ViperA) or 5 cycles (for ViperB & Elise) w/ SW clock */
  399. for (iter = 0; iter < gp_iter; iter++) {
  400. /* set gp(0) */
  401. ret = vsc85xx_sd6g_gp_cfg_wr(phydev, 769);
  402. if (ret)
  403. return ret;
  404. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  405. if (ret)
  406. return ret;
  407. /* clear gp(0) */
  408. ret = vsc85xx_sd6g_gp_cfg_wr(phydev, 768);
  409. if (ret)
  410. return ret;
  411. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  412. if (ret)
  413. return ret;
  414. }
  415. ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_cal, 15, 1, 1);
  416. if (ret)
  417. return ret;
  418. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  419. if (ret)
  420. return ret;
  421. ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_cal, 15, 0, 1);
  422. if (ret)
  423. return ret;
  424. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  425. if (ret)
  426. return ret;
  427. /* 8. Wait for IB cal to complete */
  428. deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
  429. do {
  430. usleep_range(500, 1000);
  431. ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  432. if (ret)
  433. return ret;
  434. val32 = vsc85xx_csr_read(phydev, MACRO_CTRL,
  435. PHY_S6G_IB_STATUS0);
  436. /* wait for bit 8 to set */
  437. } while (time_before(jiffies, deadline) && (~val32 & BIT(8)));
  438. if (~val32 & BIT(8))
  439. return -ETIMEDOUT;
  440. /* 9. Restore cfg values for mission mode */
  441. ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_mm, 0, 1);
  442. if (ret)
  443. return ret;
  444. ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_mm, 15, 0, 1);
  445. if (ret)
  446. return ret;
  447. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  448. if (ret)
  449. return ret;
  450. /* 10. Re-enable transmitter */
  451. ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 0);
  452. if (ret)
  453. return ret;
  454. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  455. if (ret)
  456. return ret;
  457. /* 11. Disable frequency offset generation (using internal FoJi logic) */
  458. ret = vsc85xx_sd6g_dft_cfg2_wr(phydev, 0, 0, 0, 0, 0, 0);
  459. if (ret)
  460. return ret;
  461. ret = vsc85xx_sd6g_dft_cfg0_wr(phydev, 0, 0, 0);
  462. if (ret)
  463. return ret;
  464. ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 0);
  465. if (ret)
  466. return ret;
  467. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  468. if (ret)
  469. return ret;
  470. /* Tune/Re-lock LCPLL */
  471. ret = pll5g_tune(phydev);
  472. if (ret)
  473. return ret;
  474. /* 12. Configure for Final Configuration and Settings */
  475. /* a. Reset RCPLL */
  476. ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 0);
  477. if (ret)
  478. return ret;
  479. ret = vsc85xx_sd6g_common_cfg_wr(phydev, 0, 1, 0, qrate, if_mode, 0);
  480. if (ret)
  481. return ret;
  482. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  483. if (ret)
  484. return ret;
  485. /* b. Configure sd6g for desired operating mode */
  486. phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_GPIO);
  487. ret = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK);
  488. if ((ret & MAC_CFG_MASK) == MAC_CFG_QSGMII) {
  489. /* QSGMII */
  490. pll_fsm_ctrl_data = 120;
  491. qrate = 0;
  492. if_mode = 3;
  493. des_bw_ana_val = 5;
  494. val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
  495. PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_QSGMII_MAC;
  496. ret = vsc8584_cmd(phydev, val);
  497. if (ret) {
  498. dev_err(&phydev->mdio.dev, "%s: QSGMII error: %d\n",
  499. __func__, ret);
  500. return ret;
  501. }
  502. phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
  503. } else if ((ret & MAC_CFG_MASK) == MAC_CFG_SGMII) {
  504. /* SGMII */
  505. pll_fsm_ctrl_data = 60;
  506. qrate = 1;
  507. if_mode = 1;
  508. des_bw_ana_val = 3;
  509. val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
  510. PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_SGMII_MAC;
  511. ret = vsc8584_cmd(phydev, val);
  512. if (ret) {
  513. dev_err(&phydev->mdio.dev, "%s: SGMII error: %d\n",
  514. __func__, ret);
  515. return ret;
  516. }
  517. phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
  518. } else {
  519. dev_err(&phydev->mdio.dev, "%s: invalid mac_if: %x\n",
  520. __func__, ret);
  521. }
  522. ret = phy_update_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
  523. if (ret)
  524. return ret;
  525. ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  526. if (ret)
  527. return ret;
  528. ret = vsc85xx_pll5g_cfg0_wr(phydev, 4);
  529. if (ret)
  530. return ret;
  531. ret = phy_commit_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, 0);
  532. if (ret)
  533. return ret;
  534. ret = vsc85xx_sd6g_des_cfg_wr(phydev, 6, 2, 5, des_bw_ana_val, 0);
  535. if (ret)
  536. return ret;
  537. ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel_mm, 0, 1);
  538. if (ret)
  539. return ret;
  540. ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, 8, ib_tsdet_mm, 15, 0, 1);
  541. if (ret)
  542. return ret;
  543. ret = vsc85xx_sd6g_common_cfg_wr(phydev, 1, 1, 0, qrate, if_mode, 0);
  544. if (ret)
  545. return ret;
  546. ret = vsc85xx_sd6g_ib_cfg2_wr(phydev, 3, 13, 5);
  547. if (ret)
  548. return ret;
  549. ret = vsc85xx_sd6g_ib_cfg3_wr(phydev, 0, 31, 1, 31);
  550. if (ret)
  551. return ret;
  552. ret = vsc85xx_sd6g_ib_cfg4_wr(phydev, 63, 63, 2, 63);
  553. if (ret)
  554. return ret;
  555. ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 1);
  556. if (ret)
  557. return ret;
  558. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  559. if (ret)
  560. return ret;
  561. /* 13. Start rcpll_fsm */
  562. ret = vsc85xx_sd6g_pll_cfg_wr(phydev, 3, pll_fsm_ctrl_data, 1);
  563. if (ret)
  564. return ret;
  565. ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  566. if (ret)
  567. return ret;
  568. /* 14. Wait for PLL cal to complete */
  569. deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
  570. do {
  571. usleep_range(500, 1000);
  572. ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  573. if (ret)
  574. return ret;
  575. val32 = vsc85xx_csr_read(phydev, MACRO_CTRL,
  576. PHY_S6G_PLL_STATUS);
  577. /* wait for bit 12 to clear */
  578. } while (time_before(jiffies, deadline) && (val32 & BIT(12)));
  579. if (val32 & BIT(12))
  580. return -ETIMEDOUT;
  581. /* release lane reset */
  582. ret = vsc85xx_sd6g_misc_cfg_wr(phydev, 0);
  583. if (ret)
  584. return ret;
  585. return phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, 0);
  586. }