1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | /* |
3 | * Driver for Microsemi VSC85xx PHYs |
4 | * |
5 | * Author: Bjarni Jonasson <bjarni.jonassoni@microchip.com> |
6 | * License: Dual MIT/GPL |
7 | * Copyright (c) 2021 Microsemi Corporation |
8 | */ |
9 | |
10 | #include <linux/phy.h> |
11 | #include "mscc_serdes.h" |
12 | #include "mscc.h" |
13 | |
14 | static int pll5g_detune(struct phy_device *phydev) |
15 | { |
16 | u32 rd_dat; |
17 | int ret; |
18 | |
19 | rd_dat = vsc85xx_csr_read(phydev, target: 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, target: MACRO_CTRL, |
23 | PHY_S6G_PLL5G_CFG2, val: rd_dat); |
24 | if (ret) |
25 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
26 | return ret; |
27 | } |
28 | |
29 | static int pll5g_tune(struct phy_device *phydev) |
30 | { |
31 | u32 rd_dat; |
32 | int ret; |
33 | |
34 | rd_dat = vsc85xx_csr_read(phydev, target: MACRO_CTRL, PHY_S6G_PLL5G_CFG2); |
35 | rd_dat &= ~PHY_S6G_PLL5G_CFG2_ENA_GAIN; |
36 | ret = vsc85xx_csr_write(phydev, target: MACRO_CTRL, |
37 | PHY_S6G_PLL5G_CFG2, val: rd_dat); |
38 | if (ret) |
39 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
40 | return ret; |
41 | } |
42 | |
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) |
47 | { |
48 | int ret; |
49 | |
50 | ret = vsc85xx_csr_write(phydev, target: MACRO_CTRL, |
51 | PHY_S6G_PLL_CFG, |
52 | val: (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 | |
60 | static 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, target: MACRO_CTRL, |
78 | PHY_S6G_COMMON_CFG, |
79 | val: (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 | |
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, |
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, target: MACRO_CTRL, |
106 | PHY_S6G_DES_CFG, |
107 | val: reg_val); |
108 | if (ret) |
109 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
110 | return ret; |
111 | } |
112 | |
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) |
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, target: MACRO_CTRL, |
131 | PHY_S6G_IB_CFG0, |
132 | val: reg_val); |
133 | if (ret) |
134 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
135 | return ret; |
136 | } |
137 | |
138 | static 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, target: MACRO_CTRL, |
155 | PHY_S6G_IB_CFG1, |
156 | val: reg_val); |
157 | if (ret) |
158 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
159 | return ret; |
160 | } |
161 | |
162 | static 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, target: MACRO_CTRL, |
177 | PHY_S6G_IB_CFG2, |
178 | val: ib_cfg2_val); |
179 | if (ret) |
180 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
181 | return ret; |
182 | } |
183 | |
184 | static 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, target: MACRO_CTRL, |
196 | PHY_S6G_IB_CFG3, |
197 | val: reg_val); |
198 | if (ret) |
199 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
200 | return ret; |
201 | } |
202 | |
203 | static 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, target: MACRO_CTRL, |
215 | PHY_S6G_IB_CFG4, |
216 | val: reg_val); |
217 | if (ret) |
218 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
219 | return ret; |
220 | } |
221 | |
222 | static 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, target: MACRO_CTRL, |
228 | PHY_S6G_MISC_CFG, |
229 | val: lane_rst); |
230 | if (ret) |
231 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
232 | return ret; |
233 | } |
234 | |
235 | static 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, target: MACRO_CTRL, |
240 | PHY_S6G_GP_CFG, |
241 | val: gp_cfg_val); |
242 | if (ret) |
243 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
244 | return ret; |
245 | } |
246 | |
247 | static 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, target: MACRO_CTRL, |
263 | PHY_S6G_IB_DFT_CFG2, |
264 | val: reg_val); |
265 | if (ret) |
266 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
267 | return ret; |
268 | } |
269 | |
270 | static 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, target: MACRO_CTRL, |
281 | PHY_S6G_DFT_CFG0, |
282 | val: 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 */ |
289 | static 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, target: MACRO_CTRL, |
301 | PHY_S6G_PLL5G_CFG0, val: reg_val); |
302 | if (ret) |
303 | dev_err(&phydev->mdio.dev, "%s: write error\n" , __func__); |
304 | return ret; |
305 | } |
306 | |
307 | int 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, pll_ena_offs: 3, pll_fsm_ctrl_data, pll_fsm_ena: 0); |
334 | if (ret) |
335 | return ret; |
336 | ret = vsc85xx_sd6g_common_cfg_wr(phydev, sys_rst: 0, ena_lane: 0, ena_loop: 0, qrate, if_mode, pwd_tx: 0); |
337 | if (ret) |
338 | return ret; |
339 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
340 | if (ret) |
341 | return ret; |
342 | ret = vsc85xx_sd6g_des_cfg_wr(phydev, des_phy_ctrl: 6, des_mbtr_ctrl: 2, des_bw_hyst: 5, des_bw_ana: des_bw_ana_val, des_cpmd_sel: 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: ib_sig_det_clk_sel_mm, ib_reg_pat_sel_offset: 0, ib_cal_ena: 0); |
349 | if (ret) |
350 | return ret; |
351 | ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, ib_tjtag: 8, ib_tsdet: ib_tsdet_mm, ib_scaly: 15, ib_frc_offset: 0, ib_filt_offset: 1); |
352 | if (ret) |
353 | return ret; |
354 | ret = vsc85xx_sd6g_ib_cfg2_wr(phydev, ib_tinfv: 3, ib_tcalv: 13, ib_ureg: 5); |
355 | if (ret) |
356 | return ret; |
357 | ret = vsc85xx_sd6g_ib_cfg3_wr(phydev, ib_ini_hp: 0, ib_ini_mid: 31, ib_ini_lp: 1, ib_ini_offset: 31); |
358 | if (ret) |
359 | return ret; |
360 | ret = vsc85xx_sd6g_ib_cfg4_wr(phydev, ib_max_hp: 63, ib_max_mid: 63, ib_max_lp: 2, ib_max_offset: 63); |
361 | if (ret) |
362 | return ret; |
363 | ret = vsc85xx_sd6g_common_cfg_wr(phydev, sys_rst: 1, ena_lane: 1, ena_loop: 0, qrate, if_mode, pwd_tx: 0); |
364 | if (ret) |
365 | return ret; |
366 | ret = vsc85xx_sd6g_misc_cfg_wr(phydev, lane_rst: 1); |
367 | if (ret) |
368 | return ret; |
369 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
370 | if (ret) |
371 | return ret; |
372 | |
373 | /* 2. Start rcpll_fsm */ |
374 | ret = vsc85xx_sd6g_pll_cfg_wr(phydev, pll_ena_offs: 3, pll_fsm_ctrl_data, pll_fsm_ena: 1); |
375 | if (ret) |
376 | return ret; |
377 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
378 | if (ret) |
379 | return ret; |
380 | |
381 | deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS); |
382 | do { |
383 | usleep_range(min: 500, max: 1000); |
384 | ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
385 | if (ret) |
386 | return ret; |
387 | val32 = vsc85xx_csr_read(phydev, target: 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, lane_rst: 0); |
397 | if (ret) |
398 | return ret; |
399 | ret = vsc85xx_sd6g_common_cfg_wr(phydev, sys_rst: 1, ena_lane: 1, ena_loop: 0, qrate, if_mode, pwd_tx: 1); |
400 | if (ret) |
401 | return ret; |
402 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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, gp_cfg_val: 768); |
408 | if (ret) |
409 | return ret; |
410 | ret = vsc85xx_sd6g_dft_cfg2_wr(phydev, rx_ji_ampl: 0, rx_step_freq: 2, rx_ji_ena: 0, rx_waveform_sel: 0, rx_freqoff_dir: 0, rx_freqoff_ena: 1); |
411 | if (ret) |
412 | return ret; |
413 | ret = vsc85xx_sd6g_dft_cfg0_wr(phydev, prbs_sel: 0, test_mode: 0, rx_dft_ena: 1); |
414 | if (ret) |
415 | return ret; |
416 | ret = vsc85xx_sd6g_des_cfg_wr(phydev, des_phy_ctrl: 6, des_mbtr_ctrl: 2, des_bw_hyst: 5, des_bw_ana: des_bw_ana_val, des_cpmd_sel: 2); |
417 | if (ret) |
418 | return ret; |
419 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
420 | if (ret) |
421 | return ret; |
422 | |
423 | /* 6. Prepare required settings for IBCAL */ |
424 | ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, ib_tjtag: 8, ib_tsdet: ib_tsdet_cal, ib_scaly: 15, ib_frc_offset: 1, ib_filt_offset: 0); |
425 | if (ret) |
426 | return ret; |
427 | ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel: ib_sig_det_clk_sel_cal, ib_reg_pat_sel_offset: 0, ib_cal_ena: 0); |
428 | if (ret) |
429 | return ret; |
430 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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: ib_sig_det_clk_sel_cal, ib_reg_pat_sel_offset: 0, ib_cal_ena: 1); |
437 | if (ret) |
438 | return ret; |
439 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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, gp_cfg_val: 769); |
446 | if (ret) |
447 | return ret; |
448 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
449 | if (ret) |
450 | return ret; |
451 | /* clear gp(0) */ |
452 | ret = vsc85xx_sd6g_gp_cfg_wr(phydev, gp_cfg_val: 768); |
453 | if (ret) |
454 | return ret; |
455 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
456 | if (ret) |
457 | return ret; |
458 | } |
459 | |
460 | ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, ib_tjtag: 8, ib_tsdet: ib_tsdet_cal, ib_scaly: 15, ib_frc_offset: 1, ib_filt_offset: 1); |
461 | if (ret) |
462 | return ret; |
463 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
464 | if (ret) |
465 | return ret; |
466 | ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, ib_tjtag: 8, ib_tsdet: ib_tsdet_cal, ib_scaly: 15, ib_frc_offset: 0, ib_filt_offset: 1); |
467 | if (ret) |
468 | return ret; |
469 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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(min: 500, max: 1000); |
477 | ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
478 | if (ret) |
479 | return ret; |
480 | val32 = vsc85xx_csr_read(phydev, target: 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: ib_sig_det_clk_sel_mm, ib_reg_pat_sel_offset: 0, ib_cal_ena: 1); |
490 | if (ret) |
491 | return ret; |
492 | ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, ib_tjtag: 8, ib_tsdet: ib_tsdet_mm, ib_scaly: 15, ib_frc_offset: 0, ib_filt_offset: 1); |
493 | if (ret) |
494 | return ret; |
495 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
496 | if (ret) |
497 | return ret; |
498 | |
499 | /* 10. Re-enable transmitter */ |
500 | ret = vsc85xx_sd6g_common_cfg_wr(phydev, sys_rst: 1, ena_lane: 1, ena_loop: 0, qrate, if_mode, pwd_tx: 0); |
501 | if (ret) |
502 | return ret; |
503 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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, rx_ji_ampl: 0, rx_step_freq: 0, rx_ji_ena: 0, rx_waveform_sel: 0, rx_freqoff_dir: 0, rx_freqoff_ena: 0); |
509 | if (ret) |
510 | return ret; |
511 | ret = vsc85xx_sd6g_dft_cfg0_wr(phydev, prbs_sel: 0, test_mode: 0, rx_dft_ena: 0); |
512 | if (ret) |
513 | return ret; |
514 | ret = vsc85xx_sd6g_des_cfg_wr(phydev, des_phy_ctrl: 6, des_mbtr_ctrl: 2, des_bw_hyst: 5, des_bw_ana: des_bw_ana_val, des_cpmd_sel: 0); |
515 | if (ret) |
516 | return ret; |
517 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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, pll_ena_offs: 3, pll_fsm_ctrl_data, pll_fsm_ena: 0); |
529 | if (ret) |
530 | return ret; |
531 | ret = vsc85xx_sd6g_common_cfg_wr(phydev, sys_rst: 0, ena_lane: 1, ena_loop: 0, qrate, if_mode, pwd_tx: 0); |
532 | if (ret) |
533 | return ret; |
534 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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, mcb: 0); |
582 | if (ret) |
583 | return ret; |
584 | ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
585 | if (ret) |
586 | return ret; |
587 | ret = vsc85xx_pll5g_cfg0_wr(phydev, selbgv820: 4); |
588 | if (ret) |
589 | return ret; |
590 | ret = phy_commit_mcb_s6g(phydev, PHY_S6G_LCPLL_CFG, mcb: 0); |
591 | if (ret) |
592 | return ret; |
593 | ret = vsc85xx_sd6g_des_cfg_wr(phydev, des_phy_ctrl: 6, des_mbtr_ctrl: 2, des_bw_hyst: 5, des_bw_ana: des_bw_ana_val, des_cpmd_sel: 0); |
594 | if (ret) |
595 | return ret; |
596 | ret = vsc85xx_sd6g_ib_cfg0_wr(phydev, ib_rtrm_adj, ib_sig_det_clk_sel: ib_sig_det_clk_sel_mm, ib_reg_pat_sel_offset: 0, ib_cal_ena: 1); |
597 | if (ret) |
598 | return ret; |
599 | ret = vsc85xx_sd6g_ib_cfg1_wr(phydev, ib_tjtag: 8, ib_tsdet: ib_tsdet_mm, ib_scaly: 15, ib_frc_offset: 0, ib_filt_offset: 1); |
600 | if (ret) |
601 | return ret; |
602 | ret = vsc85xx_sd6g_common_cfg_wr(phydev, sys_rst: 1, ena_lane: 1, ena_loop: 0, qrate, if_mode, pwd_tx: 0); |
603 | if (ret) |
604 | return ret; |
605 | ret = vsc85xx_sd6g_ib_cfg2_wr(phydev, ib_tinfv: 3, ib_tcalv: 13, ib_ureg: 5); |
606 | if (ret) |
607 | return ret; |
608 | ret = vsc85xx_sd6g_ib_cfg3_wr(phydev, ib_ini_hp: 0, ib_ini_mid: 31, ib_ini_lp: 1, ib_ini_offset: 31); |
609 | if (ret) |
610 | return ret; |
611 | ret = vsc85xx_sd6g_ib_cfg4_wr(phydev, ib_max_hp: 63, ib_max_mid: 63, ib_max_lp: 2, ib_max_offset: 63); |
612 | if (ret) |
613 | return ret; |
614 | ret = vsc85xx_sd6g_misc_cfg_wr(phydev, lane_rst: 1); |
615 | if (ret) |
616 | return ret; |
617 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
618 | if (ret) |
619 | return ret; |
620 | |
621 | /* 13. Start rcpll_fsm */ |
622 | ret = vsc85xx_sd6g_pll_cfg_wr(phydev, pll_ena_offs: 3, pll_fsm_ctrl_data, pll_fsm_ena: 1); |
623 | if (ret) |
624 | return ret; |
625 | ret = phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 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(min: 500, max: 1000); |
633 | ret = phy_update_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
634 | if (ret) |
635 | return ret; |
636 | val32 = vsc85xx_csr_read(phydev, target: 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, lane_rst: 0); |
646 | if (ret) |
647 | return ret; |
648 | |
649 | return phy_commit_mcb_s6g(phydev, PHY_MCB_S6G_CFG, mcb: 0); |
650 | } |
651 | |