Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2001-2023 Intel Corporation
3 : : */
4 : :
5 : : #include "ice_type.h"
6 : : #include "ice_common.h"
7 : : #include "ice_ptp_hw.h"
8 : : #include "ice_ptp_consts.h"
9 : : #include "ice_cgu_regs.h"
10 : :
11 : : /* Low level functions for interacting with and managing the device clock used
12 : : * for the Precision Time Protocol.
13 : : *
14 : : * The ice hardware represents the current time using three registers:
15 : : *
16 : : * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R
17 : : * +---------------+ +---------------+ +---------------+
18 : : * | 32 bits | | 32 bits | | 32 bits |
19 : : * +---------------+ +---------------+ +---------------+
20 : : *
21 : : * The registers are incremented every clock tick using a 40bit increment
22 : : * value defined over two registers:
23 : : *
24 : : * GLTSYN_INCVAL_H GLTSYN_INCVAL_L
25 : : * +---------------+ +---------------+
26 : : * | 8 bit s | | 32 bits |
27 : : * +---------------+ +---------------+
28 : : *
29 : : * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
30 : : * registers every clock source tick. Depending on the specific device
31 : : * configuration, the clock source frequency could be one of a number of
32 : : * values.
33 : : *
34 : : * For E810 devices, the increment frequency is 812.5 MHz
35 : : *
36 : : * For E822 devices the clock can be derived from different sources, and the
37 : : * increment has an effective frequency of one of the following:
38 : : * - 823.4375 MHz
39 : : * - 783.36 MHz
40 : : * - 796.875 MHz
41 : : * - 816 MHz
42 : : * - 830.078125 MHz
43 : : * - 783.36 MHz
44 : : *
45 : : * The hardware captures timestamps in the PHY for incoming packets, and for
46 : : * outgoing packets on request. To support this, the PHY maintains a timer
47 : : * that matches the lower 64 bits of the global source timer.
48 : : *
49 : : * In order to ensure that the PHY timers and the source timer are equivalent,
50 : : * shadow registers are used to prepare the desired initial values. A special
51 : : * sync command is issued to trigger copying from the shadow registers into
52 : : * the appropriate source and PHY registers simultaneously.
53 : : *
54 : : * The driver supports devices which have different PHYs with subtly different
55 : : * mechanisms to program and control the timers. We divide the devices into
56 : : * families named after the first major device, E810 and similar devices, and
57 : : * E822 and similar devices.
58 : : *
59 : : * - E822 based devices have additional support for fine grained Vernier
60 : : * calibration which requires significant setup
61 : : * - The layout of timestamp data in the PHY register blocks is different
62 : : * - The way timer synchronization commands are issued is different.
63 : : *
64 : : * To support this, very low level functions have an e810 or e822 suffix
65 : : * indicating what type of device they work on. Higher level abstractions for
66 : : * tasks that can be done on both devices do not have the suffix and will
67 : : * correctly look up the appropriate low level function when running.
68 : : *
69 : : * Functions which only make sense on a single device family may not have
70 : : * a suitable generic implementation
71 : : */
72 : :
73 : : /**
74 : : * ice_get_ptp_src_clock_index - determine source clock index
75 : : * @hw: pointer to HW struct
76 : : *
77 : : * Determine the source clock index currently in use, based on device
78 : : * capabilities reported during initialization.
79 : : */
80 : 0 : u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
81 : : {
82 : 0 : return hw->func_caps.ts_func_info.tmr_index_assoc;
83 : : }
84 : :
85 : : /**
86 : : * ice_ptp_read_src_incval - Read source timer increment value
87 : : * @hw: pointer to HW struct
88 : : *
89 : : * Read the increment value of the source timer and return it.
90 : : */
91 : 0 : u64 ice_ptp_read_src_incval(struct ice_hw *hw)
92 : : {
93 : : u32 lo, hi;
94 : : u8 tmr_idx;
95 : :
96 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
97 : :
98 : 0 : lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
99 : 0 : hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
100 : :
101 : 0 : return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;
102 : : }
103 : :
104 : : /**
105 : : * ice_read_cgu_reg_e822 - Read a CGU register
106 : : * @hw: pointer to the HW struct
107 : : * @addr: Register address to read
108 : : * @val: storage for register value read
109 : : *
110 : : * Read the contents of a register of the Clock Generation Unit. Only
111 : : * applicable to E822 devices.
112 : : */
113 : : static enum ice_status
114 : 0 : ice_read_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 *val)
115 : : {
116 : : struct ice_sbq_msg_input cgu_msg;
117 : : enum ice_status status;
118 : :
119 : 0 : cgu_msg.opcode = ice_sbq_msg_rd;
120 : 0 : cgu_msg.dest_dev = cgu;
121 : 0 : cgu_msg.msg_addr_low = addr;
122 : 0 : cgu_msg.msg_addr_high = 0x0;
123 : :
124 : 0 : status = ice_sbq_rw_reg_lp(hw, &cgu_msg, true);
125 [ # # ]: 0 : if (status) {
126 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, status %d\n",
127 : : addr, status);
128 : 0 : return status;
129 : : }
130 : :
131 : 0 : *val = cgu_msg.data;
132 : :
133 : 0 : return ICE_SUCCESS;
134 : : }
135 : :
136 : : /**
137 : : * ice_write_cgu_reg_e822 - Write a CGU register
138 : : * @hw: pointer to the HW struct
139 : : * @addr: Register address to write
140 : : * @val: value to write into the register
141 : : *
142 : : * Write the specified value to a register of the Clock Generation Unit. Only
143 : : * applicable to E822 devices.
144 : : */
145 : : static enum ice_status
146 : 0 : ice_write_cgu_reg_e822(struct ice_hw *hw, u16 addr, u32 val)
147 : : {
148 : : struct ice_sbq_msg_input cgu_msg;
149 : : enum ice_status status;
150 : :
151 : 0 : cgu_msg.opcode = ice_sbq_msg_wr;
152 : 0 : cgu_msg.dest_dev = cgu;
153 : 0 : cgu_msg.msg_addr_low = addr;
154 : 0 : cgu_msg.msg_addr_high = 0x0;
155 : 0 : cgu_msg.data = val;
156 : :
157 : 0 : status = ice_sbq_rw_reg_lp(hw, &cgu_msg, true);
158 [ # # ]: 0 : if (status) {
159 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, status %d\n",
160 : : addr, status);
161 : 0 : return status;
162 : : }
163 : :
164 : : return ICE_SUCCESS;
165 : : }
166 : :
167 : : /**
168 : : * ice_clk_freq_str - Convert time_ref_freq to string
169 : : * @clk_freq: Clock frequency
170 : : *
171 : : * Convert the specified TIME_REF clock frequency to a string.
172 : : */
173 : : static const char *ice_clk_freq_str(u8 clk_freq)
174 : : {
175 [ # # # # : 0 : switch ((enum ice_time_ref_freq)clk_freq) {
# # ]
176 : : case ICE_TIME_REF_FREQ_25_000:
177 : : return "25 MHz";
178 : 0 : case ICE_TIME_REF_FREQ_122_880:
179 : 0 : return "122.88 MHz";
180 : 0 : case ICE_TIME_REF_FREQ_125_000:
181 : 0 : return "125 MHz";
182 : 0 : case ICE_TIME_REF_FREQ_153_600:
183 : 0 : return "153.6 MHz";
184 : 0 : case ICE_TIME_REF_FREQ_156_250:
185 : 0 : return "156.25 MHz";
186 : 0 : case ICE_TIME_REF_FREQ_245_760:
187 : 0 : return "245.76 MHz";
188 : 0 : default:
189 : 0 : return "Unknown";
190 : : }
191 : : }
192 : :
193 : : /**
194 : : * ice_clk_src_str - Convert time_ref_src to string
195 : : * @clk_src: Clock source
196 : : *
197 : : * Convert the specified clock source to its string name.
198 : : */
199 : : static const char *ice_clk_src_str(u8 clk_src)
200 : : {
201 [ # # # ]: 0 : switch ((enum ice_clk_src)clk_src) {
202 : : case ICE_CLK_SRC_TCX0:
203 : : return "TCX0";
204 : 0 : case ICE_CLK_SRC_TIME_REF:
205 : 0 : return "TIME_REF";
206 : 0 : default:
207 : 0 : return "Unknown";
208 : : }
209 : : }
210 : :
211 : : /**
212 : : * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit
213 : : * @hw: pointer to the HW struct
214 : : * @clk_freq: Clock frequency to program
215 : : * @clk_src: Clock source to select (TIME_REF, or TCX0)
216 : : *
217 : : * Configure the Clock Generation Unit with the desired clock frequency and
218 : : * time reference, enabling the PLL which drives the PTP hardware clock.
219 : : */
220 : : enum ice_status
221 : 0 : ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
222 : : enum ice_clk_src clk_src)
223 : : {
224 : : union tspll_ro_bwm_lf bwm_lf;
225 : : union nac_cgu_dword19 dw19;
226 : : union nac_cgu_dword22 dw22;
227 : : union nac_cgu_dword24 dw24;
228 : : union nac_cgu_dword9 dw9;
229 : : enum ice_status status;
230 : :
231 [ # # ]: 0 : if (clk_freq >= NUM_ICE_TIME_REF_FREQ) {
232 [ # # ]: 0 : ice_warn(hw, "Invalid TIME_REF frequency %u\n", clk_freq);
233 : 0 : return ICE_ERR_PARAM;
234 : : }
235 : :
236 [ # # ]: 0 : if (clk_src >= NUM_ICE_CLK_SRC) {
237 [ # # ]: 0 : ice_warn(hw, "Invalid clock source %u\n", clk_src);
238 : 0 : return ICE_ERR_PARAM;
239 : : }
240 : :
241 : 0 : if (clk_src == ICE_CLK_SRC_TCX0 &&
242 [ # # ]: 0 : clk_freq != ICE_TIME_REF_FREQ_25_000) {
243 [ # # ]: 0 : ice_warn(hw, "TCX0 only supports 25 MHz frequency\n");
244 : 0 : return ICE_ERR_PARAM;
245 : : }
246 : :
247 : 0 : status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val);
248 [ # # ]: 0 : if (status)
249 : : return status;
250 : :
251 : 0 : status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
252 [ # # ]: 0 : if (status)
253 : : return status;
254 : :
255 : 0 : status = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
256 [ # # ]: 0 : if (status)
257 : : return status;
258 : :
259 : : /* Log the current clock configuration */
260 [ # # # # : 0 : ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
# # # # #
# # # # #
# # ]
261 : : dw24.field.ts_pll_enable ? "enabled" : "disabled",
262 : : ice_clk_src_str(dw24.field.time_ref_sel),
263 : : ice_clk_freq_str(dw9.field.time_ref_freq_sel),
264 : : bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
265 : :
266 : : /* Disable the PLL before changing the clock source or frequency */
267 [ # # ]: 0 : if (dw24.field.ts_pll_enable) {
268 : 0 : dw24.field.ts_pll_enable = 0;
269 : :
270 : 0 : status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
271 [ # # ]: 0 : if (status)
272 : : return status;
273 : : }
274 : :
275 : : /* Set the frequency */
276 : 0 : dw9.field.time_ref_freq_sel = clk_freq;
277 : 0 : status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val);
278 [ # # ]: 0 : if (status)
279 : : return status;
280 : :
281 : : /* Configure the TS PLL feedback divisor */
282 : 0 : status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val);
283 [ # # ]: 0 : if (status)
284 : : return status;
285 : :
286 : 0 : dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
287 : 0 : dw19.field.tspll_ndivratio = 1;
288 : :
289 : 0 : status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val);
290 [ # # ]: 0 : if (status)
291 : : return status;
292 : :
293 : : /* Configure the TS PLL post divisor */
294 : 0 : status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val);
295 [ # # ]: 0 : if (status)
296 : : return status;
297 : :
298 : 0 : dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
299 : 0 : dw22.field.time1588clk_sel_div2 = 0;
300 : :
301 : 0 : status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val);
302 [ # # ]: 0 : if (status)
303 : : return status;
304 : :
305 : : /* Configure the TS PLL pre divisor and clock source */
306 : 0 : status = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
307 [ # # ]: 0 : if (status)
308 : : return status;
309 : :
310 : 0 : dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div;
311 : 0 : dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
312 : 0 : dw24.field.time_ref_sel = clk_src;
313 : :
314 : 0 : status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
315 [ # # ]: 0 : if (status)
316 : : return status;
317 : :
318 : : /* Finally, enable the PLL */
319 : 0 : dw24.field.ts_pll_enable = 1;
320 : :
321 : 0 : status = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
322 [ # # ]: 0 : if (status)
323 : : return status;
324 : :
325 : : /* Wait to verify if the PLL locks */
326 : 0 : ice_msec_delay(1, true);
327 : :
328 : 0 : status = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
329 [ # # ]: 0 : if (status)
330 : : return status;
331 : :
332 [ # # ]: 0 : if (!bwm_lf.field.plllock_true_lock_cri) {
333 [ # # ]: 0 : ice_warn(hw, "CGU PLL failed to lock\n");
334 : 0 : return ICE_ERR_NOT_READY;
335 : : }
336 : :
337 : : /* Log the current clock configuration */
338 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
339 : : dw24.field.ts_pll_enable ? "enabled" : "disabled",
340 : : ice_clk_src_str(dw24.field.time_ref_sel),
341 : : ice_clk_freq_str(dw9.field.time_ref_freq_sel),
342 : : bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
343 : :
344 : : return ICE_SUCCESS;
345 : : }
346 : :
347 : : /**
348 : : * ice_init_cgu_e822 - Initialize CGU with settings from firmware
349 : : * @hw: pointer to the HW structure
350 : : *
351 : : * Initialize the Clock Generation Unit of the E822 device.
352 : : */
353 : 0 : static enum ice_status ice_init_cgu_e822(struct ice_hw *hw)
354 : : {
355 : : struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
356 : : union tspll_cntr_bist_settings cntr_bist;
357 : : enum ice_status status;
358 : :
359 : 0 : status = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
360 : : &cntr_bist.val);
361 [ # # ]: 0 : if (status)
362 : : return status;
363 : :
364 : : /* Disable sticky lock detection so lock status reported is accurate */
365 : 0 : cntr_bist.field.i_plllock_sel_0 = 0;
366 : 0 : cntr_bist.field.i_plllock_sel_1 = 0;
367 : :
368 : 0 : status = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
369 : : cntr_bist.val);
370 [ # # ]: 0 : if (status)
371 : : return status;
372 : :
373 : : /* Configure the CGU PLL using the parameters from the function
374 : : * capabilities.
375 : : */
376 : 0 : status = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref,
377 : 0 : (enum ice_clk_src)ts_info->clk_src);
378 [ # # ]: 0 : if (status)
379 : 0 : return status;
380 : :
381 : : return ICE_SUCCESS;
382 : : }
383 : :
384 : : /**
385 : : * ice_ptp_src_cmd - Prepare source timer for a timer command
386 : : * @hw: pointer to HW structure
387 : : * @cmd: Timer command
388 : : *
389 : : * Prepare the source timer for an upcoming timer sync command.
390 : : */
391 : 0 : void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
392 : : {
393 : : u32 cmd_val;
394 : : u8 tmr_idx;
395 : :
396 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
397 : 0 : cmd_val = tmr_idx << SEL_CPK_SRC;
398 : :
399 [ # # # # : 0 : switch (cmd) {
# # # ]
400 : 0 : case ICE_PTP_INIT_TIME:
401 : 0 : cmd_val |= GLTSYN_CMD_INIT_TIME;
402 : 0 : break;
403 : 0 : case ICE_PTP_INIT_INCVAL:
404 : 0 : cmd_val |= GLTSYN_CMD_INIT_INCVAL;
405 : 0 : break;
406 : 0 : case ICE_PTP_ADJ_TIME:
407 : 0 : cmd_val |= GLTSYN_CMD_ADJ_TIME;
408 : 0 : break;
409 : 0 : case ICE_PTP_ADJ_TIME_AT_TIME:
410 : 0 : cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
411 : 0 : break;
412 : 0 : case ICE_PTP_READ_TIME:
413 : 0 : cmd_val |= GLTSYN_CMD_READ_TIME;
414 : 0 : break;
415 : : case ICE_PTP_NOP:
416 : : break;
417 : 0 : default:
418 [ # # ]: 0 : ice_warn(hw, "Unknown timer command %u\n", cmd);
419 : : return;
420 : : }
421 : :
422 : 0 : wr32(hw, GLTSYN_CMD, cmd_val);
423 : : }
424 : :
425 : : /**
426 : : * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands
427 : : * @hw: pointer to HW struct
428 : : *
429 : : * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the
430 : : * write immediately. This triggers the hardware to begin executing all of the
431 : : * source and PHY timer commands synchronously.
432 : : */
433 : : static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
434 : : {
435 : 0 : wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
436 : 0 : ice_flush(hw);
437 : : }
438 : :
439 : : /**
440 : : * ice_ptp_clean_cmd - Clean the timer command register
441 : : * @hw: pointer to HW struct
442 : : *
443 : : * Zero out the GLTSYN_CMD to avoid any residual command execution.
444 : : */
445 : : static void ice_ptp_clean_cmd(struct ice_hw *hw)
446 : : {
447 : 0 : wr32(hw, GLTSYN_CMD, 0);
448 : 0 : ice_flush(hw);
449 : : }
450 : :
451 : : /* 56G PHY access functions */
452 : : static const u32 eth56g_port_base[ICE_NUM_PHY_PORTS] = {
453 : : ICE_PHY0_BASE,
454 : : ICE_PHY1_BASE,
455 : : ICE_PHY2_BASE,
456 : : ICE_PHY3_BASE,
457 : : ICE_PHY4_BASE,
458 : : };
459 : :
460 : : /**
461 : : * ice_write_phy_eth56g_raw_lp - Write a PHY port register with lock parameter
462 : : * @hw: pointer to the HW struct
463 : : * @reg_addr: PHY register address
464 : : * @val: Value to write
465 : : * @lock_sbq: true to lock the sideband queue
466 : : */
467 : : static enum ice_status
468 : 0 : ice_write_phy_eth56g_raw_lp(struct ice_hw *hw, u32 reg_addr, u32 val,
469 : : bool lock_sbq)
470 : : {
471 : : struct ice_sbq_msg_input phy_msg;
472 : : enum ice_status status;
473 : :
474 : 0 : phy_msg.opcode = ice_sbq_msg_wr;
475 : :
476 : 0 : phy_msg.msg_addr_low = ICE_LO_WORD(reg_addr);
477 : 0 : phy_msg.msg_addr_high = ICE_HI_WORD(reg_addr);
478 : :
479 : 0 : phy_msg.data = val;
480 : 0 : phy_msg.dest_dev = phy_56g;
481 : :
482 : 0 : status = ice_sbq_rw_reg_lp(hw, &phy_msg, lock_sbq);
483 : :
484 [ # # ]: 0 : if (status)
485 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "PTP failed to send msg to phy %d\n",
486 : : status);
487 : :
488 : 0 : return status;
489 : : }
490 : :
491 : : /**
492 : : * ice_read_phy_eth56g_raw_lp - Read a PHY port register with lock parameter
493 : : * @hw: pointer to the HW struct
494 : : * @reg_addr: PHY port register address
495 : : * @val: Pointer to the value to read (out param)
496 : : * @lock_sbq: true to lock the sideband queue
497 : : */
498 : : static enum ice_status
499 : 0 : ice_read_phy_eth56g_raw_lp(struct ice_hw *hw, u32 reg_addr, u32 *val,
500 : : bool lock_sbq)
501 : : {
502 : : struct ice_sbq_msg_input phy_msg;
503 : : enum ice_status status;
504 : :
505 : 0 : phy_msg.opcode = ice_sbq_msg_rd;
506 : :
507 : 0 : phy_msg.msg_addr_low = ICE_LO_WORD(reg_addr);
508 : 0 : phy_msg.msg_addr_high = ICE_HI_WORD(reg_addr);
509 : :
510 : 0 : phy_msg.dest_dev = phy_56g;
511 : :
512 : 0 : status = ice_sbq_rw_reg_lp(hw, &phy_msg, lock_sbq);
513 : :
514 [ # # ]: 0 : if (status)
515 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "PTP failed to send msg to phy %d\n",
516 : : status);
517 : : else
518 : 0 : *val = phy_msg.data;
519 : :
520 : 0 : return status;
521 : : }
522 : :
523 : : /**
524 : : * ice_phy_port_reg_address_eth56g - Calculate a PHY port register address
525 : : * @port: Port number to be written
526 : : * @offset: Offset from PHY port register base
527 : : * @address: The result address
528 : : */
529 : : static enum ice_status
530 : : ice_phy_port_reg_address_eth56g(u8 port, u16 offset, u32 *address)
531 : : {
532 : : u8 phy, lane;
533 : :
534 : 0 : if (port >= ICE_NUM_EXTERNAL_PORTS)
535 : : return ICE_ERR_OUT_OF_RANGE;
536 : :
537 : 0 : phy = port / ICE_PORTS_PER_QUAD;
538 : 0 : lane = port % ICE_PORTS_PER_QUAD;
539 : :
540 : 0 : *address = offset + eth56g_port_base[phy] +
541 : 0 : PHY_PTP_LANE_ADDR_STEP * lane;
542 : :
543 : : return ICE_SUCCESS;
544 : : }
545 : :
546 : : /**
547 : : * ice_phy_port_mem_address_eth56g - Calculate a PHY port memory address
548 : : * @port: Port number to be written
549 : : * @offset: Offset from PHY port register base
550 : : * @address: The result address
551 : : */
552 : : static enum ice_status
553 : : ice_phy_port_mem_address_eth56g(u8 port, u16 offset, u32 *address)
554 : : {
555 : : u8 phy, lane;
556 : :
557 : 0 : if (port >= ICE_NUM_EXTERNAL_PORTS)
558 : : return ICE_ERR_OUT_OF_RANGE;
559 : :
560 : 0 : phy = port / ICE_PORTS_PER_QUAD;
561 : 0 : lane = port % ICE_PORTS_PER_QUAD;
562 : :
563 : 0 : *address = offset + eth56g_port_base[phy] +
564 : 0 : PHY_PTP_MEM_START + PHY_PTP_MEM_LANE_STEP * lane;
565 : :
566 : : return ICE_SUCCESS;
567 : : }
568 : :
569 : : /**
570 : : * ice_write_phy_reg_eth56g_lp - Write a PHY port register with lock parameter
571 : : * @hw: pointer to the HW struct
572 : : * @port: Port number to be written
573 : : * @offset: Offset from PHY port register base
574 : : * @val: Value to write
575 : : * @lock_sbq: true to lock the sideband queue
576 : : */
577 : : static enum ice_status
578 [ # # ]: 0 : ice_write_phy_reg_eth56g_lp(struct ice_hw *hw, u8 port, u16 offset, u32 val,
579 : : bool lock_sbq)
580 : : {
581 : : enum ice_status status;
582 : : u32 reg_addr;
583 : :
584 : : status = ice_phy_port_reg_address_eth56g(port, offset, ®_addr);
585 : : if (status)
586 : : return status;
587 : :
588 : 0 : return ice_write_phy_eth56g_raw_lp(hw, reg_addr, val, lock_sbq);
589 : : }
590 : :
591 : : /**
592 : : * ice_write_phy_reg_eth56g - Write a PHY port register with sbq locked
593 : : * @hw: pointer to the HW struct
594 : : * @port: Port number to be written
595 : : * @offset: Offset from PHY port register base
596 : : * @val: Value to write
597 : : */
598 : : enum ice_status
599 : 0 : ice_write_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 val)
600 : : {
601 : 0 : return ice_write_phy_reg_eth56g_lp(hw, port, offset, val, true);
602 : : }
603 : :
604 : : /**
605 : : * ice_read_phy_reg_eth56g_lp - Read a PHY port register with
606 : : * lock parameter
607 : : * @hw: pointer to the HW struct
608 : : * @port: Port number to be read
609 : : * @offset: Offset from PHY port register base
610 : : * @val: Pointer to the value to read (out param)
611 : : * @lock_sbq: true to lock the sideband queue
612 : : */
613 : : static enum ice_status
614 [ # # ]: 0 : ice_read_phy_reg_eth56g_lp(struct ice_hw *hw, u8 port, u16 offset, u32 *val,
615 : : bool lock_sbq)
616 : : {
617 : : enum ice_status status;
618 : : u32 reg_addr;
619 : :
620 : : status = ice_phy_port_reg_address_eth56g(port, offset, ®_addr);
621 : : if (status)
622 : : return status;
623 : :
624 : 0 : return ice_read_phy_eth56g_raw_lp(hw, reg_addr, val, lock_sbq);
625 : : }
626 : :
627 : : /**
628 : : * ice_read_phy_reg_eth56g - Read a PHY port register with sbq locked
629 : : * @hw: pointer to the HW struct
630 : : * @port: Port number to be read
631 : : * @offset: Offset from PHY port register base
632 : : * @val: Pointer to the value to read (out param)
633 : : */
634 : : enum ice_status
635 : 0 : ice_read_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
636 : : {
637 : 0 : return ice_read_phy_reg_eth56g_lp(hw, port, offset, val, true);
638 : : }
639 : :
640 : : /**
641 : : * ice_phy_port_mem_read_eth56g_lp - Read a PHY port memory location
642 : : * with lock parameter
643 : : * @hw: pointer to the HW struct
644 : : * @port: Port number to be read
645 : : * @offset: Offset from PHY port register base
646 : : * @val: Pointer to the value to read (out param)
647 : : * @lock_sbq: true to lock the sideband queue
648 : : */
649 : : static enum ice_status
650 [ # # ]: 0 : ice_phy_port_mem_read_eth56g_lp(struct ice_hw *hw, u8 port, u16 offset,
651 : : u32 *val, bool lock_sbq)
652 : : {
653 : : enum ice_status status;
654 : : u32 mem_addr;
655 : :
656 : : status = ice_phy_port_mem_address_eth56g(port, offset, &mem_addr);
657 : : if (status)
658 : : return status;
659 : :
660 : 0 : return ice_read_phy_eth56g_raw_lp(hw, mem_addr, val, lock_sbq);
661 : : }
662 : :
663 : : /**
664 : : * ice_phy_port_mem_read_eth56g - Read a PHY port memory location with
665 : : * sbq locked
666 : : * @hw: pointer to the HW struct
667 : : * @port: Port number to be read
668 : : * @offset: Offset from PHY port register base
669 : : * @val: Pointer to the value to read (out param)
670 : : */
671 : : static enum ice_status
672 : : ice_phy_port_mem_read_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
673 : : {
674 : 0 : return ice_phy_port_mem_read_eth56g_lp(hw, port, offset, val, true);
675 : : }
676 : :
677 : : /**
678 : : * ice_phy_port_mem_write_eth56g_lp - Write a PHY port memory location with
679 : : * lock parameter
680 : : * @hw: pointer to the HW struct
681 : : * @port: Port number to be read
682 : : * @offset: Offset from PHY port register base
683 : : * @val: Pointer to the value to read (out param)
684 : : * @lock_sbq: true to lock the sideband queue
685 : : */
686 : : static enum ice_status
687 [ # # ]: 0 : ice_phy_port_mem_write_eth56g_lp(struct ice_hw *hw, u8 port, u16 offset,
688 : : u32 val, bool lock_sbq)
689 : : {
690 : : enum ice_status status;
691 : : u32 mem_addr;
692 : :
693 : : status = ice_phy_port_mem_address_eth56g(port, offset, &mem_addr);
694 : : if (status)
695 : : return status;
696 : :
697 : 0 : return ice_write_phy_eth56g_raw_lp(hw, mem_addr, val, lock_sbq);
698 : : }
699 : :
700 : : /**
701 : : * ice_phy_port_mem_write_eth56g - Write a PHY port memory location with
702 : : * sbq locked
703 : : * @hw: pointer to the HW struct
704 : : * @port: Port number to be read
705 : : * @offset: Offset from PHY port register base
706 : : * @val: Pointer to the value to read (out param)
707 : : */
708 : : static enum ice_status
709 : : ice_phy_port_mem_write_eth56g(struct ice_hw *hw, u8 port, u16 offset, u32 val)
710 : : {
711 : 0 : return ice_phy_port_mem_write_eth56g_lp(hw, port, offset, val, true);
712 : : }
713 : :
714 : : /**
715 : : * ice_is_64b_phy_reg_eth56g - Check if this is a 64bit PHY register
716 : : * @low_addr: the low address to check
717 : : *
718 : : * Checks if the provided low address is one of the known 64bit PHY values
719 : : * represented as two 32bit registers.
720 : : */
721 : : static bool ice_is_64b_phy_reg_eth56g(u16 low_addr)
722 : : {
723 : 0 : switch (low_addr) {
724 : : case PHY_REG_TX_TIMER_INC_PRE_L:
725 : : case PHY_REG_RX_TIMER_INC_PRE_L:
726 : : case PHY_REG_TX_CAPTURE_L:
727 : : case PHY_REG_RX_CAPTURE_L:
728 : : case PHY_REG_TOTAL_TX_OFFSET_L:
729 : : case PHY_REG_TOTAL_RX_OFFSET_L:
730 : : return true;
731 : : default:
732 : : return false;
733 : : }
734 : : }
735 : :
736 : : /**
737 : : * ice_is_40b_phy_reg_eth56g - Check if this is a 40bit PHY register
738 : : * @low_addr: the low address to check
739 : : *
740 : : * Checks if the provided low address is one of the known 40bit PHY values
741 : : * split into two registers with the lower 8 bits in the low register and the
742 : : * upper 32 bits in the high register.
743 : : */
744 : : static bool ice_is_40b_phy_reg_eth56g(u16 low_addr)
745 : : {
746 : 0 : switch (low_addr) {
747 : : case PHY_REG_TIMETUS_L:
748 : : return true;
749 : : default:
750 : : return false;
751 : : }
752 : : }
753 : :
754 : : /**
755 : : * ice_read_40b_phy_reg_eth56g - Read a 40bit value from PHY registers
756 : : * @hw: pointer to the HW struct
757 : : * @port: PHY port to read from
758 : : * @low_addr: offset of the lower register to read from
759 : : * @val: on return, the contents of the 40bit value from the PHY registers
760 : : *
761 : : * Reads the two registers associated with a 40bit value and returns it in the
762 : : * val pointer.
763 : : * This function checks that the caller has specified a known 40 bit register
764 : : * offset
765 : : */
766 : : static enum ice_status
767 [ # # ]: 0 : ice_read_40b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
768 : : {
769 : : u16 high_addr = low_addr + sizeof(u32);
770 : : enum ice_status status;
771 : : u32 lo, hi;
772 : :
773 : : if (!ice_is_40b_phy_reg_eth56g(low_addr))
774 : : return ICE_ERR_PARAM;
775 : :
776 : 0 : status = ice_read_phy_reg_eth56g(hw, port, low_addr, &lo);
777 [ # # ]: 0 : if (status) {
778 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register %#08x\n, status %d",
779 : : (int)low_addr, status);
780 : 0 : return status;
781 : : }
782 : :
783 : 0 : status = ice_read_phy_reg_eth56g(hw, port, low_addr + sizeof(u32), &hi);
784 [ # # ]: 0 : if (status) {
785 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register %08x\n, status %d",
786 : : high_addr, status);
787 : 0 : return status;
788 : : }
789 : :
790 : 0 : *val = ((u64)hi << P_REG_40B_HIGH_S) | (lo & P_REG_40B_LOW_M);
791 : :
792 : 0 : return ICE_SUCCESS;
793 : : }
794 : :
795 : : /**
796 : : * ice_read_64b_phy_reg_eth56g - Read a 64bit value from PHY registers
797 : : * @hw: pointer to the HW struct
798 : : * @port: PHY port to read from
799 : : * @low_addr: offset of the lower register to read from
800 : : * @val: on return, the contents of the 64bit value from the PHY registers
801 : : *
802 : : * Reads the two registers associated with a 64bit value and returns it in the
803 : : * val pointer.
804 : : * This function checks that the caller has specified a known 64 bit register
805 : : * offset
806 : : */
807 : : static enum ice_status
808 : 0 : ice_read_64b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
809 : : {
810 : 0 : u16 high_addr = low_addr + sizeof(u32);
811 : : enum ice_status status;
812 : : u32 lo, hi;
813 : :
814 [ # # ]: 0 : if (!ice_is_64b_phy_reg_eth56g(low_addr))
815 : : return ICE_ERR_PARAM;
816 : :
817 : 0 : status = ice_read_phy_reg_eth56g(hw, port, low_addr, &lo);
818 [ # # ]: 0 : if (status) {
819 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register %#08x\n, status %d",
820 : : low_addr, status);
821 : 0 : return status;
822 : : }
823 : :
824 : 0 : status = ice_read_phy_reg_eth56g(hw, port, high_addr, &hi);
825 [ # # ]: 0 : if (status) {
826 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register %#08x\n, status %d",
827 : : high_addr, status);
828 : 0 : return status;
829 : : }
830 : :
831 : 0 : *val = ((u64)hi << 32) | lo;
832 : :
833 : 0 : return ICE_SUCCESS;
834 : : }
835 : :
836 : : /**
837 : : * ice_write_40b_phy_reg_eth56g - Write a 40b value to the PHY
838 : : * @hw: pointer to the HW struct
839 : : * @port: port to write to
840 : : * @low_addr: offset of the low register
841 : : * @val: 40b value to write
842 : : *
843 : : * Write the provided 40b value to the two associated registers by splitting
844 : : * it up into two chunks, the lower 8 bits and the upper 32 bits.
845 : : * This function checks that the caller has specified a known 40 bit register
846 : : * offset
847 : : */
848 : : static enum ice_status
849 [ # # ]: 0 : ice_write_40b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
850 : : {
851 : : u16 high_addr = low_addr + sizeof(u32);
852 : : enum ice_status status;
853 : : u32 lo, hi;
854 : :
855 : : if (!ice_is_40b_phy_reg_eth56g(low_addr))
856 : : return ICE_ERR_PARAM;
857 : :
858 : 0 : lo = (u32)(val & P_REG_40B_LOW_M);
859 : 0 : hi = (u32)(val >> P_REG_40B_HIGH_S);
860 : :
861 : 0 : status = ice_write_phy_reg_eth56g(hw, port, low_addr, lo);
862 [ # # ]: 0 : if (status) {
863 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d",
864 : : low_addr, status);
865 : 0 : return status;
866 : : }
867 : :
868 : 0 : status = ice_write_phy_reg_eth56g(hw, port, high_addr, hi);
869 [ # # ]: 0 : if (status) {
870 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d",
871 : : high_addr, status);
872 : 0 : return status;
873 : : }
874 : :
875 : : return ICE_SUCCESS;
876 : : }
877 : :
878 : : /**
879 : : * ice_write_64b_phy_reg_eth56g - Write a 64bit value to PHY registers
880 : : * @hw: pointer to the HW struct
881 : : * @port: PHY port to read from
882 : : * @low_addr: offset of the lower register to read from
883 : : * @val: the contents of the 64bit value to write to PHY
884 : : *
885 : : * Write the 64bit value to the two associated 32bit PHY registers.
886 : : * This function checks that the caller has specified a known 64 bit register
887 : : * offset
888 : : */
889 : : static enum ice_status
890 : 0 : ice_write_64b_phy_reg_eth56g(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
891 : : {
892 : 0 : u16 high_addr = low_addr + sizeof(u32);
893 : : enum ice_status status;
894 : : u32 lo, hi;
895 : :
896 [ # # ]: 0 : if (!ice_is_64b_phy_reg_eth56g(low_addr))
897 : : return ICE_ERR_PARAM;
898 : :
899 : 0 : lo = ICE_LO_DWORD(val);
900 : 0 : hi = ICE_HI_DWORD(val);
901 : :
902 : 0 : status = ice_write_phy_reg_eth56g(hw, port, low_addr, lo);
903 [ # # ]: 0 : if (status) {
904 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d",
905 : : low_addr, status);
906 : 0 : return status;
907 : : }
908 : :
909 : 0 : status = ice_write_phy_reg_eth56g(hw, port, high_addr, hi);
910 [ # # ]: 0 : if (status) {
911 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d",
912 : : high_addr, status);
913 : 0 : return status;
914 : : }
915 : :
916 : : return ICE_SUCCESS;
917 : : }
918 : :
919 : : /**
920 : : * ice_read_phy_tstamp_eth56g - Read a PHY timestamp out of the port memory
921 : : * @hw: pointer to the HW struct
922 : : * @port: the port to read from
923 : : * @idx: the timestamp index to read
924 : : * @tstamp: on return, the 40bit timestamp value
925 : : *
926 : : * Read a 40bit timestamp value out of the two associated entries in the
927 : : * port memory block of the internal PHYs of the 56G devices.
928 : : */
929 : : static enum ice_status
930 : 0 : ice_read_phy_tstamp_eth56g(struct ice_hw *hw, u8 port, u8 idx, u64 *tstamp)
931 : : {
932 : : enum ice_status status;
933 : : u16 lo_addr, hi_addr;
934 : : u32 lo, hi;
935 : :
936 : 0 : lo_addr = (u16)PHY_TSTAMP_L(idx);
937 : 0 : hi_addr = (u16)PHY_TSTAMP_U(idx);
938 : :
939 : 0 : status = ice_phy_port_mem_read_eth56g(hw, port, lo_addr, &lo);
940 [ # # ]: 0 : if (status) {
941 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
942 : : status);
943 : 0 : return status;
944 : : }
945 : :
946 : 0 : status = ice_phy_port_mem_read_eth56g(hw, port, hi_addr, &hi);
947 [ # # ]: 0 : if (status) {
948 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
949 : : status);
950 : 0 : return status;
951 : : }
952 : :
953 : : /* For 56G based internal PHYs, the timestamp is reported with the
954 : : * lower 8 bits in the low register, and the upper 32 bits in the high
955 : : * register.
956 : : */
957 : 0 : *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
958 : :
959 : 0 : return ICE_SUCCESS;
960 : : }
961 : :
962 : : /**
963 : : * ice_clear_phy_tstamp_eth56g - Clear a timestamp from the quad block
964 : : * @hw: pointer to the HW struct
965 : : * @port: the quad to read from
966 : : * @idx: the timestamp index to reset
967 : : *
968 : : * Clear a timestamp, resetting its valid bit, in the PHY port memory of
969 : : * internal PHYs of the 56G devices.
970 : : */
971 : : static enum ice_status
972 : 0 : ice_clear_phy_tstamp_eth56g(struct ice_hw *hw, u8 port, u8 idx)
973 : : {
974 : : enum ice_status status;
975 : : u16 lo_addr;
976 : :
977 : 0 : lo_addr = (u16)PHY_TSTAMP_L(idx);
978 : :
979 : 0 : status = ice_phy_port_mem_write_eth56g(hw, port, lo_addr, 0);
980 [ # # ]: 0 : if (status) {
981 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
982 : : status);
983 : 0 : return status;
984 : : }
985 : :
986 : : return ICE_SUCCESS;
987 : : }
988 : :
989 : : /**
990 : : * ice_ptp_prep_port_phy_time_eth56g - Prepare one PHY port with initial time
991 : : * @hw: pointer to the HW struct
992 : : * @port: port number
993 : : * @phy_time: time to initialize the PHY port clocks to
994 : : *
995 : : * Write a new initial time value into registers of a specific PHY port.
996 : : */
997 : : static enum ice_status
998 : 0 : ice_ptp_prep_port_phy_time_eth56g(struct ice_hw *hw, u8 port, u64 phy_time)
999 : : {
1000 : : enum ice_status status;
1001 : :
1002 : : /* Tx case */
1003 : 0 : status = ice_write_64b_phy_reg_eth56g(hw, port,
1004 : : PHY_REG_TX_TIMER_INC_PRE_L,
1005 : : phy_time);
1006 [ # # ]: 0 : if (status)
1007 : : return status;
1008 : :
1009 : : /* Rx case */
1010 : 0 : return ice_write_64b_phy_reg_eth56g(hw, port,
1011 : : PHY_REG_RX_TIMER_INC_PRE_L,
1012 : : phy_time);
1013 : : }
1014 : :
1015 : : /**
1016 : : * ice_ptp_prep_phy_time_eth56g - Prepare PHY port with initial time
1017 : : * @hw: pointer to the HW struct
1018 : : * @time: Time to initialize the PHY port clocks to
1019 : : *
1020 : : * Program the PHY port registers with a new initial time value. The port
1021 : : * clock will be initialized once the driver issues an ICE_PTP_INIT_TIME sync
1022 : : * command. The time value is the upper 32 bits of the PHY timer, usually in
1023 : : * units of nominal nanoseconds.
1024 : : */
1025 : : static enum ice_status
1026 : 0 : ice_ptp_prep_phy_time_eth56g(struct ice_hw *hw, u32 time)
1027 : : {
1028 : : enum ice_status status;
1029 : : u64 phy_time;
1030 : : u8 port;
1031 : :
1032 : : /* The time represents the upper 32 bits of the PHY timer, so we need
1033 : : * to shift to account for this when programming.
1034 : : */
1035 : 0 : phy_time = (u64)time << 32;
1036 : :
1037 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1038 [ # # ]: 0 : if (!(hw->ena_lports & BIT(port)))
1039 : 0 : continue;
1040 : 0 : status = ice_ptp_prep_port_phy_time_eth56g(hw, port,
1041 : : phy_time);
1042 : :
1043 [ # # ]: 0 : if (status) {
1044 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, status %d\n",
1045 : : port, status);
1046 : 0 : return status;
1047 : : }
1048 : : }
1049 : :
1050 : : return ICE_SUCCESS;
1051 : : }
1052 : :
1053 : : /**
1054 : : * ice_ptp_prep_port_adj_eth56g - Prepare a single port for time adjust
1055 : : * @hw: pointer to HW struct
1056 : : * @port: Port number to be programmed
1057 : : * @time: time in cycles to adjust the port Tx and Rx clocks
1058 : : * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
1059 : : * sq_lock has already been locked at a higher level
1060 : : *
1061 : : * Program the port for an atomic adjustment by writing the Tx and Rx timer
1062 : : * registers. The atomic adjustment won't be completed until the driver issues
1063 : : * an ICE_PTP_ADJ_TIME command.
1064 : : *
1065 : : * Note that time is not in units of nanoseconds. It is in clock time
1066 : : * including the lower sub-nanosecond portion of the port timer.
1067 : : *
1068 : : * Negative adjustments are supported using 2s complement arithmetic.
1069 : : */
1070 : : enum ice_status
1071 : 0 : ice_ptp_prep_port_adj_eth56g(struct ice_hw *hw, u8 port, s64 time,
1072 : : bool lock_sbq)
1073 : : {
1074 : : enum ice_status status;
1075 : : u32 l_time, u_time;
1076 : :
1077 : 0 : l_time = ICE_LO_DWORD(time);
1078 : 0 : u_time = ICE_HI_DWORD(time);
1079 : :
1080 : : /* Tx case */
1081 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1082 : : PHY_REG_TX_TIMER_INC_PRE_L,
1083 : : l_time, lock_sbq);
1084 [ # # ]: 0 : if (status)
1085 : 0 : goto exit_err;
1086 : :
1087 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1088 : : PHY_REG_TX_TIMER_INC_PRE_U,
1089 : : u_time, lock_sbq);
1090 [ # # ]: 0 : if (status)
1091 : 0 : goto exit_err;
1092 : :
1093 : : /* Rx case */
1094 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1095 : : PHY_REG_RX_TIMER_INC_PRE_L,
1096 : : l_time, lock_sbq);
1097 [ # # ]: 0 : if (status)
1098 : 0 : goto exit_err;
1099 : :
1100 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1101 : : PHY_REG_RX_TIMER_INC_PRE_U,
1102 : : u_time, lock_sbq);
1103 [ # # ]: 0 : if (status)
1104 : 0 : goto exit_err;
1105 : :
1106 : : return ICE_SUCCESS;
1107 : :
1108 : 0 : exit_err:
1109 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, status %d\n",
1110 : : port, status);
1111 : : return status;
1112 : : }
1113 : :
1114 : : /**
1115 : : * ice_ptp_prep_phy_adj_eth56g - Prep PHY ports for a time adjustment
1116 : : * @hw: pointer to HW struct
1117 : : * @adj: adjustment in nanoseconds
1118 : : * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
1119 : : * sq_lock has already been locked at a higher level
1120 : : *
1121 : : * Prepare the PHY ports for an atomic time adjustment by programming the PHY
1122 : : * Tx and Rx port registers. The actual adjustment is completed by issuing an
1123 : : * ICE_PTP_ADJ_TIME or ICE_PTP_ADJ_TIME_AT_TIME sync command.
1124 : : */
1125 : : static enum ice_status
1126 : 0 : ice_ptp_prep_phy_adj_eth56g(struct ice_hw *hw, s32 adj, bool lock_sbq)
1127 : : {
1128 : : enum ice_status status = ICE_SUCCESS;
1129 : : s64 cycles;
1130 : : u8 port;
1131 : :
1132 : : /* The port clock supports adjustment of the sub-nanosecond portion of
1133 : : * the clock. We shift the provided adjustment in nanoseconds to
1134 : : * calculate the appropriate adjustment to program into the PHY ports.
1135 : : */
1136 : 0 : cycles = (s64)adj << 32;
1137 : :
1138 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1139 [ # # ]: 0 : if (!(hw->ena_lports & BIT(port)))
1140 : 0 : continue;
1141 : :
1142 : 0 : status = ice_ptp_prep_port_adj_eth56g(hw, port, cycles,
1143 : : lock_sbq);
1144 [ # # ]: 0 : if (status)
1145 : : break;
1146 : : }
1147 : :
1148 : 0 : return status;
1149 : : }
1150 : :
1151 : : /**
1152 : : * ice_ptp_prep_phy_incval_eth56g - Prepare PHY ports for time adjustment
1153 : : * @hw: pointer to HW struct
1154 : : * @incval: new increment value to prepare
1155 : : *
1156 : : * Prepare each of the PHY ports for a new increment value by programming the
1157 : : * port's TIMETUS registers. The new increment value will be updated after
1158 : : * issuing an ICE_PTP_INIT_INCVAL command.
1159 : : */
1160 : : static enum ice_status
1161 : 0 : ice_ptp_prep_phy_incval_eth56g(struct ice_hw *hw, u64 incval)
1162 : : {
1163 : : enum ice_status status;
1164 : : u8 port;
1165 : :
1166 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1167 [ # # ]: 0 : if (!(hw->ena_lports & BIT(port)))
1168 : 0 : continue;
1169 : 0 : status = ice_write_40b_phy_reg_eth56g(hw, port,
1170 : : PHY_REG_TIMETUS_L,
1171 : : incval);
1172 [ # # ]: 0 : if (status) {
1173 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, status %d\n",
1174 : : port, status);
1175 : 0 : return status;
1176 : : }
1177 : : }
1178 : :
1179 : : return ICE_SUCCESS;
1180 : : }
1181 : :
1182 : : /**
1183 : : * ice_ptp_read_phy_incval_eth56g - Read a PHY port's current incval
1184 : : * @hw: pointer to the HW struct
1185 : : * @port: the port to read
1186 : : * @incval: on return, the time_clk_cyc incval for this port
1187 : : *
1188 : : * Read the time_clk_cyc increment value for a given PHY port.
1189 : : */
1190 : : enum ice_status
1191 : 0 : ice_ptp_read_phy_incval_eth56g(struct ice_hw *hw, u8 port, u64 *incval)
1192 : : {
1193 : : enum ice_status status;
1194 : :
1195 : 0 : status = ice_read_40b_phy_reg_eth56g(hw, port, PHY_REG_TIMETUS_L,
1196 : : incval);
1197 [ # # ]: 0 : if (status) {
1198 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read TIMETUS_L, status %d\n",
1199 : : status);
1200 : 0 : return status;
1201 : : }
1202 : :
1203 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "read INCVAL = 0x%016llx\n",
1204 : : (unsigned long long)*incval);
1205 : :
1206 : : return ICE_SUCCESS;
1207 : : }
1208 : :
1209 : : /**
1210 : : * ice_ptp_prep_phy_adj_target_eth56g - Prepare PHY for adjust at target time
1211 : : * @hw: pointer to HW struct
1212 : : * @target_time: target time to program
1213 : : *
1214 : : * Program the PHY port Tx and Rx TIMER_CNT_ADJ registers used for the
1215 : : * ICE_PTP_ADJ_TIME_AT_TIME command. This should be used in conjunction with
1216 : : * ice_ptp_prep_phy_adj_eth56g to program an atomic adjustment that is
1217 : : * delayed until a specified target time.
1218 : : *
1219 : : * Note that a target time adjustment is not currently supported on E810
1220 : : * devices.
1221 : : */
1222 : : static enum ice_status
1223 : 0 : ice_ptp_prep_phy_adj_target_eth56g(struct ice_hw *hw, u32 target_time)
1224 : : {
1225 : : enum ice_status status;
1226 : : u8 port;
1227 : :
1228 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1229 [ # # ]: 0 : if (!(hw->ena_lports & BIT(port)))
1230 : 0 : continue;
1231 : :
1232 : : /* Tx case */
1233 : : /* No sub-nanoseconds data */
1234 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1235 : : PHY_REG_TX_TIMER_CNT_ADJ_L,
1236 : : 0, true);
1237 [ # # ]: 0 : if (status)
1238 : 0 : goto exit_err;
1239 : :
1240 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1241 : : PHY_REG_TX_TIMER_CNT_ADJ_U,
1242 : : target_time, true);
1243 [ # # ]: 0 : if (status)
1244 : 0 : goto exit_err;
1245 : :
1246 : : /* Rx case */
1247 : : /* No sub-nanoseconds data */
1248 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1249 : : PHY_REG_RX_TIMER_CNT_ADJ_L,
1250 : : 0, true);
1251 [ # # ]: 0 : if (status)
1252 : 0 : goto exit_err;
1253 : :
1254 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port,
1255 : : PHY_REG_RX_TIMER_CNT_ADJ_U,
1256 : : target_time, true);
1257 [ # # ]: 0 : if (status)
1258 : 0 : goto exit_err;
1259 : : }
1260 : :
1261 : : return ICE_SUCCESS;
1262 : :
1263 : 0 : exit_err:
1264 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write target time for port %u, status %d\n",
1265 : : port, status);
1266 : :
1267 : : return status;
1268 : : }
1269 : :
1270 : : /**
1271 : : * ice_ptp_read_port_capture_eth56g - Read a port's local time capture
1272 : : * @hw: pointer to HW struct
1273 : : * @port: Port number to read
1274 : : * @tx_ts: on return, the Tx port time capture
1275 : : * @rx_ts: on return, the Rx port time capture
1276 : : *
1277 : : * Read the port's Tx and Rx local time capture values.
1278 : : */
1279 : : enum ice_status
1280 : 0 : ice_ptp_read_port_capture_eth56g(struct ice_hw *hw, u8 port, u64 *tx_ts,
1281 : : u64 *rx_ts)
1282 : : {
1283 : : enum ice_status status;
1284 : :
1285 : : /* Tx case */
1286 : 0 : status = ice_read_64b_phy_reg_eth56g(hw, port, PHY_REG_TX_CAPTURE_L,
1287 : : tx_ts);
1288 [ # # ]: 0 : if (status) {
1289 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, status %d\n",
1290 : : status);
1291 : 0 : return status;
1292 : : }
1293 : :
1294 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "tx_init = %#016llx\n",
1295 : : (unsigned long long)*tx_ts);
1296 : :
1297 : : /* Rx case */
1298 : 0 : status = ice_read_64b_phy_reg_eth56g(hw, port, PHY_REG_RX_CAPTURE_L,
1299 : : rx_ts);
1300 [ # # ]: 0 : if (status) {
1301 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, status %d\n",
1302 : : status);
1303 : 0 : return status;
1304 : : }
1305 : :
1306 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "rx_init = %#016llx\n",
1307 : : (unsigned long long)*rx_ts);
1308 : :
1309 : : return ICE_SUCCESS;
1310 : : }
1311 : :
1312 : : /**
1313 : : * ice_ptp_one_port_cmd_eth56g - Prepare a single PHY port for a timer command
1314 : : * @hw: pointer to HW struct
1315 : : * @port: Port to which cmd has to be sent
1316 : : * @cmd: Command to be sent to the port
1317 : : * @lock_sbq: true if the sideband queue lock must be acquired
1318 : : *
1319 : : * Prepare the requested port for an upcoming timer sync command.
1320 : : */
1321 : : enum ice_status
1322 : 0 : ice_ptp_one_port_cmd_eth56g(struct ice_hw *hw, u8 port,
1323 : : enum ice_ptp_tmr_cmd cmd, bool lock_sbq)
1324 : : {
1325 : : enum ice_status status;
1326 : : u32 cmd_val, val;
1327 : : u8 tmr_idx;
1328 : :
1329 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
1330 : 0 : cmd_val = tmr_idx << SEL_PHY_SRC;
1331 [ # # # # : 0 : switch (cmd) {
# # ]
1332 : 0 : case ICE_PTP_INIT_TIME:
1333 : 0 : cmd_val |= PHY_CMD_INIT_TIME;
1334 : 0 : break;
1335 : 0 : case ICE_PTP_INIT_INCVAL:
1336 : 0 : cmd_val |= PHY_CMD_INIT_INCVAL;
1337 : 0 : break;
1338 : 0 : case ICE_PTP_ADJ_TIME:
1339 : 0 : cmd_val |= PHY_CMD_ADJ_TIME;
1340 : 0 : break;
1341 : 0 : case ICE_PTP_ADJ_TIME_AT_TIME:
1342 : 0 : cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
1343 : 0 : break;
1344 : 0 : case ICE_PTP_READ_TIME:
1345 : 0 : cmd_val |= PHY_CMD_READ_TIME;
1346 : 0 : break;
1347 : 0 : default:
1348 [ # # ]: 0 : ice_warn(hw, "Unknown timer command %u\n", cmd);
1349 : : return ICE_ERR_PARAM;
1350 : : }
1351 : :
1352 : : /* Tx case */
1353 : : /* Read, modify, write */
1354 : 0 : status = ice_read_phy_reg_eth56g_lp(hw, port, PHY_REG_TX_TMR_CMD, &val,
1355 : : lock_sbq);
1356 [ # # ]: 0 : if (status) {
1357 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, status %d\n",
1358 : : status);
1359 : 0 : return status;
1360 : : }
1361 : :
1362 : : /* Modify necessary bits only and perform write */
1363 : 0 : val &= ~TS_CMD_MASK;
1364 : 0 : val |= cmd_val;
1365 : :
1366 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port, PHY_REG_TX_TMR_CMD, val,
1367 : : lock_sbq);
1368 [ # # ]: 0 : if (status) {
1369 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, status %d\n",
1370 : : status);
1371 : 0 : return status;
1372 : : }
1373 : :
1374 : : /* Rx case */
1375 : : /* Read, modify, write */
1376 : 0 : status = ice_read_phy_reg_eth56g_lp(hw, port, PHY_REG_RX_TMR_CMD, &val,
1377 : : lock_sbq);
1378 [ # # ]: 0 : if (status) {
1379 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, status %d\n",
1380 : : status);
1381 : 0 : return status;
1382 : : }
1383 : :
1384 : : /* Modify necessary bits only and perform write */
1385 : 0 : val &= ~TS_CMD_MASK;
1386 : 0 : val |= cmd_val;
1387 : :
1388 : 0 : status = ice_write_phy_reg_eth56g_lp(hw, port, PHY_REG_RX_TMR_CMD, val,
1389 : : lock_sbq);
1390 [ # # ]: 0 : if (status) {
1391 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, status %d\n",
1392 : : status);
1393 : 0 : return status;
1394 : : }
1395 : :
1396 : : return ICE_SUCCESS;
1397 : : }
1398 : :
1399 : : /**
1400 : : * ice_ptp_port_cmd_eth56g - Prepare all ports for a timer command
1401 : : * @hw: pointer to the HW struct
1402 : : * @cmd: timer command to prepare
1403 : : * @lock_sbq: true if the sideband queue lock must be acquired
1404 : : *
1405 : : * Prepare all ports connected to this device for an upcoming timer sync
1406 : : * command.
1407 : : */
1408 : : static enum ice_status
1409 : 0 : ice_ptp_port_cmd_eth56g(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,
1410 : : bool lock_sbq)
1411 : : {
1412 : : enum ice_status status;
1413 : : u8 port;
1414 : :
1415 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1416 [ # # ]: 0 : if (!(hw->ena_lports & BIT(port)))
1417 : 0 : continue;
1418 : :
1419 : 0 : status = ice_ptp_one_port_cmd_eth56g(hw, port, cmd, lock_sbq);
1420 [ # # ]: 0 : if (status)
1421 : 0 : return status;
1422 : : }
1423 : :
1424 : : return ICE_SUCCESS;
1425 : : }
1426 : :
1427 : : /**
1428 : : * ice_calc_fixed_tx_offset_eth56g - Calculated Fixed Tx offset for a port
1429 : : * @hw: pointer to the HW struct
1430 : : * @link_spd: the Link speed to calculate for
1431 : : *
1432 : : * Calculate the fixed offset due to known static latency data.
1433 : : */
1434 : : static u64
1435 : : ice_calc_fixed_tx_offset_eth56g(struct ice_hw *hw,
1436 : : enum ice_ptp_link_spd link_spd)
1437 : : {
1438 : : u64 fixed_offset = 0;
1439 : : return fixed_offset;
1440 : : }
1441 : :
1442 : : /**
1443 : : * ice_phy_cfg_tx_offset_eth56g - Configure total Tx timestamp offset
1444 : : * @hw: pointer to the HW struct
1445 : : * @port: the PHY port to configure
1446 : : *
1447 : : * Program the PHY_REG_TOTAL_TX_OFFSET register with the total number of TUs to
1448 : : * adjust Tx timestamps by.
1449 : : *
1450 : : * To avoid overflow, when calculating the offset based on the known static
1451 : : * latency values, we use measurements in 1/100th of a nanosecond, and divide
1452 : : * the TUs per second up front. This avoids overflow while allowing
1453 : : * calculation of the adjustment using integer arithmetic.
1454 : : */
1455 : 0 : enum ice_status ice_phy_cfg_tx_offset_eth56g(struct ice_hw *hw, u8 port)
1456 : : {
1457 : : enum ice_ptp_link_spd link_spd = ICE_PTP_LNK_SPD_10G;
1458 : : enum ice_status status;
1459 : : u64 total_offset;
1460 : :
1461 : : total_offset = ice_calc_fixed_tx_offset_eth56g(hw, link_spd);
1462 : :
1463 : : /* Now that the total offset has been calculated, program it to the
1464 : : * PHY and indicate that the Tx offset is ready. After this,
1465 : : * timestamps will be enabled.
1466 : : */
1467 : 0 : status = ice_write_64b_phy_reg_eth56g(hw, port,
1468 : : PHY_REG_TOTAL_TX_OFFSET_L,
1469 : : total_offset);
1470 [ # # ]: 0 : if (status)
1471 : : return status;
1472 : :
1473 : 0 : return ice_write_phy_reg_eth56g(hw, port, PHY_REG_TX_OFFSET_READY, 1);
1474 : : }
1475 : :
1476 : : /**
1477 : : * ice_calc_fixed_rx_offset_eth56g - Calculated the fixed Rx offset for a port
1478 : : * @hw: pointer to HW struct
1479 : : * @link_spd: The Link speed to calculate for
1480 : : *
1481 : : * Determine the fixed Rx latency for a given link speed.
1482 : : */
1483 : : static u64
1484 : : ice_calc_fixed_rx_offset_eth56g(struct ice_hw *hw,
1485 : : enum ice_ptp_link_spd link_spd)
1486 : : {
1487 : : u64 fixed_offset = 0;
1488 : : return fixed_offset;
1489 : : }
1490 : :
1491 : : /**
1492 : : * ice_phy_cfg_rx_offset_eth56g - Configure total Rx timestamp offset
1493 : : * @hw: pointer to the HW struct
1494 : : * @port: the PHY port to configure
1495 : : *
1496 : : * Program the PHY_REG_TOTAL_RX_OFFSET register with the number of Time Units to
1497 : : * adjust Rx timestamps by. This combines calculations from the Vernier offset
1498 : : * measurements taken in hardware with some data about known fixed delay as
1499 : : * well as adjusting for multi-lane alignment delay.
1500 : : *
1501 : : * This function must be called only after the offset registers are valid,
1502 : : * i.e. after the Vernier calibration wait has passed, to ensure that the PHY
1503 : : * has measured the offset.
1504 : : *
1505 : : * To avoid overflow, when calculating the offset based on the known static
1506 : : * latency values, we use measurements in 1/100th of a nanosecond, and divide
1507 : : * the TUs per second up front. This avoids overflow while allowing
1508 : : * calculation of the adjustment using integer arithmetic.
1509 : : */
1510 : 0 : enum ice_status ice_phy_cfg_rx_offset_eth56g(struct ice_hw *hw, u8 port)
1511 : : {
1512 : : enum ice_status status;
1513 : : u64 total_offset;
1514 : :
1515 : : total_offset = ice_calc_fixed_rx_offset_eth56g(hw, 0);
1516 : :
1517 : : /* Now that the total offset has been calculated, program it to the
1518 : : * PHY and indicate that the Rx offset is ready. After this,
1519 : : * timestamps will be enabled.
1520 : : */
1521 : 0 : status = ice_write_64b_phy_reg_eth56g(hw, port,
1522 : : PHY_REG_TOTAL_RX_OFFSET_L,
1523 : : total_offset);
1524 [ # # ]: 0 : if (status)
1525 : : return status;
1526 : :
1527 : 0 : return ice_write_phy_reg_eth56g(hw, port, PHY_REG_RX_OFFSET_READY, 1);
1528 : : }
1529 : :
1530 : : /**
1531 : : * ice_read_phy_and_phc_time_eth56g - Simultaneously capture PHC and PHY time
1532 : : * @hw: pointer to the HW struct
1533 : : * @port: the PHY port to read
1534 : : * @phy_time: on return, the 64bit PHY timer value
1535 : : * @phc_time: on return, the lower 64bits of PHC time
1536 : : *
1537 : : * Issue a ICE_PTP_READ_TIME timer command to simultaneously capture the PHY
1538 : : * and PHC timer values.
1539 : : */
1540 : : static enum ice_status
1541 : 0 : ice_read_phy_and_phc_time_eth56g(struct ice_hw *hw, u8 port, u64 *phy_time,
1542 : : u64 *phc_time)
1543 : : {
1544 : : enum ice_status status;
1545 : : u64 tx_time, rx_time;
1546 : : u32 zo, lo;
1547 : : u8 tmr_idx;
1548 : :
1549 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
1550 : :
1551 : : /* Prepare the PHC timer for a ICE_PTP_READ_TIME capture command */
1552 : 0 : ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
1553 : :
1554 : : /* Prepare the PHY timer for a ICE_PTP_READ_TIME capture command */
1555 : 0 : status = ice_ptp_one_port_cmd_eth56g(hw, port, ICE_PTP_READ_TIME, true);
1556 [ # # ]: 0 : if (status)
1557 : : return status;
1558 : :
1559 : : /* Issue the sync to start the ICE_PTP_READ_TIME capture */
1560 : : ice_ptp_exec_tmr_cmd(hw);
1561 : : ice_ptp_clean_cmd(hw);
1562 : :
1563 : : /* Read the captured PHC time from the shadow time registers */
1564 : 0 : zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
1565 : 0 : lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
1566 : 0 : *phc_time = (u64)lo << 32 | zo;
1567 : :
1568 : : /* Read the captured PHY time from the PHY shadow registers */
1569 : 0 : status = ice_ptp_read_port_capture_eth56g(hw, port, &tx_time, &rx_time);
1570 [ # # ]: 0 : if (status)
1571 : : return status;
1572 : :
1573 : : /* If the PHY Tx and Rx timers don't match, log a warning message.
1574 : : * Note that this should not happen in normal circumstances since the
1575 : : * driver always programs them together.
1576 : : */
1577 [ # # ]: 0 : if (tx_time != rx_time)
1578 [ # # ]: 0 : ice_warn(hw, "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n",
1579 : : port, (unsigned long long)tx_time,
1580 : : (unsigned long long)rx_time);
1581 : :
1582 : 0 : *phy_time = tx_time;
1583 : :
1584 : 0 : return ICE_SUCCESS;
1585 : : }
1586 : :
1587 : : /**
1588 : : * ice_sync_phy_timer_eth56g - Synchronize the PHY timer with PHC timer
1589 : : * @hw: pointer to the HW struct
1590 : : * @port: the PHY port to synchronize
1591 : : *
1592 : : * Perform an adjustment to ensure that the PHY and PHC timers are in sync.
1593 : : * This is done by issuing a ICE_PTP_READ_TIME command which triggers a
1594 : : * simultaneous read of the PHY timer and PHC timer. Then we use the
1595 : : * difference to calculate an appropriate 2s complement addition to add
1596 : : * to the PHY timer in order to ensure it reads the same value as the
1597 : : * primary PHC timer.
1598 : : */
1599 : 0 : static enum ice_status ice_sync_phy_timer_eth56g(struct ice_hw *hw, u8 port)
1600 : : {
1601 : : u64 phc_time, phy_time, difference;
1602 : : enum ice_status status;
1603 : :
1604 [ # # ]: 0 : if (!ice_ptp_lock(hw)) {
1605 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n");
1606 : 0 : return ICE_ERR_NOT_READY;
1607 : : }
1608 : :
1609 : 0 : status = ice_read_phy_and_phc_time_eth56g(hw, port, &phy_time,
1610 : : &phc_time);
1611 [ # # ]: 0 : if (status)
1612 : 0 : goto err_unlock;
1613 : :
1614 : : /* Calculate the amount required to add to the port time in order for
1615 : : * it to match the PHC time.
1616 : : *
1617 : : * Note that the port adjustment is done using 2s complement
1618 : : * arithmetic. This is convenient since it means that we can simply
1619 : : * calculate the difference between the PHC time and the port time,
1620 : : * and it will be interpreted correctly.
1621 : : */
1622 : :
1623 : 0 : ice_ptp_src_cmd(hw, ICE_PTP_NOP);
1624 : 0 : difference = phc_time - phy_time;
1625 : :
1626 : 0 : status = ice_ptp_prep_port_adj_eth56g(hw, port, (s64)difference, true);
1627 [ # # ]: 0 : if (status)
1628 : 0 : goto err_unlock;
1629 : :
1630 : 0 : status = ice_ptp_one_port_cmd_eth56g(hw, port, ICE_PTP_ADJ_TIME, true);
1631 [ # # ]: 0 : if (status)
1632 : 0 : goto err_unlock;
1633 : :
1634 : : /* Issue the sync to activate the time adjustment */
1635 : : ice_ptp_exec_tmr_cmd(hw);
1636 : : ice_ptp_clean_cmd(hw);
1637 : :
1638 : : /* Re-capture the timer values to flush the command registers and
1639 : : * verify that the time was properly adjusted.
1640 : : */
1641 : :
1642 : 0 : status = ice_read_phy_and_phc_time_eth56g(hw, port, &phy_time,
1643 : : &phc_time);
1644 [ # # ]: 0 : if (status)
1645 : 0 : goto err_unlock;
1646 : :
1647 [ # # ]: 0 : ice_info(hw, "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n",
1648 : : port, (unsigned long long)phy_time,
1649 : : (unsigned long long)phc_time);
1650 : :
1651 : 0 : err_unlock:
1652 : 0 : ice_ptp_unlock(hw);
1653 : 0 : return status;
1654 : : }
1655 : :
1656 : : /**
1657 : : * ice_stop_phy_timer_eth56g - Stop the PHY clock timer
1658 : : * @hw: pointer to the HW struct
1659 : : * @port: the PHY port to stop
1660 : : * @soft_reset: if true, hold the SOFT_RESET bit of PHY_REG_PS
1661 : : *
1662 : : * Stop the clock of a PHY port. This must be done as part of the flow to
1663 : : * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
1664 : : * initialized or when link speed changes.
1665 : : */
1666 : : enum ice_status
1667 : 0 : ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset)
1668 : : {
1669 : : enum ice_status status;
1670 : :
1671 : 0 : status = ice_write_phy_reg_eth56g(hw, port, PHY_REG_TX_OFFSET_READY, 0);
1672 [ # # ]: 0 : if (status)
1673 : : return status;
1674 : :
1675 : 0 : status = ice_write_phy_reg_eth56g(hw, port, PHY_REG_RX_OFFSET_READY, 0);
1676 [ # # ]: 0 : if (status)
1677 : : return status;
1678 : :
1679 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port);
1680 : :
1681 : : return ICE_SUCCESS;
1682 : : }
1683 : :
1684 : : /**
1685 : : * ice_start_phy_timer_eth56g - Start the PHY clock timer
1686 : : * @hw: pointer to the HW struct
1687 : : * @port: the PHY port to start
1688 : : * @bypass: unused, for compatibility
1689 : : *
1690 : : * Start the clock of a PHY port. This must be done as part of the flow to
1691 : : * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
1692 : : * initialized or when link speed changes.
1693 : : *
1694 : : */
1695 : : enum ice_status
1696 : 0 : ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool bypass)
1697 : : {
1698 : : enum ice_status status;
1699 : : u32 lo, hi;
1700 : : u64 incval;
1701 : : u8 tmr_idx;
1702 : :
1703 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
1704 : :
1705 : 0 : status = ice_stop_phy_timer_eth56g(hw, port, false);
1706 [ # # ]: 0 : if (status)
1707 : : return status;
1708 : :
1709 : 0 : ice_ptp_src_cmd(hw, ICE_PTP_NOP);
1710 : :
1711 : 0 : lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
1712 : 0 : hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
1713 : 0 : incval = (u64)hi << 32 | lo;
1714 : :
1715 : 0 : status = ice_write_40b_phy_reg_eth56g(hw, port, PHY_REG_TIMETUS_L,
1716 : : incval);
1717 [ # # ]: 0 : if (status)
1718 : : return status;
1719 : :
1720 : 0 : status = ice_ptp_one_port_cmd_eth56g(hw, port, ICE_PTP_INIT_INCVAL,
1721 : : true);
1722 [ # # ]: 0 : if (status)
1723 : : return status;
1724 : :
1725 : : ice_ptp_exec_tmr_cmd(hw);
1726 : :
1727 : 0 : status = ice_sync_phy_timer_eth56g(hw, port);
1728 [ # # ]: 0 : if (status)
1729 : : return status;
1730 : :
1731 : : /* Program the Tx offset */
1732 : 0 : status = ice_phy_cfg_tx_offset_eth56g(hw, port);
1733 [ # # ]: 0 : if (status)
1734 : : return status;
1735 : :
1736 : : /* Program the Rx offset */
1737 : 0 : status = ice_phy_cfg_rx_offset_eth56g(hw, port);
1738 [ # # ]: 0 : if (status)
1739 : : return status;
1740 : :
1741 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
1742 : :
1743 : : return ICE_SUCCESS;
1744 : : }
1745 : :
1746 : : /**
1747 : : * ice_ptp_init_phc_eth56g - Perform E822 specific PHC initialization
1748 : : * @hw: pointer to HW struct
1749 : : *
1750 : : * Perform PHC initialization steps specific to E822 devices.
1751 : : */
1752 : : static enum ice_status ice_ptp_init_phc_eth56g(struct ice_hw *hw)
1753 : : {
1754 : : enum ice_status status = ICE_SUCCESS;
1755 : : u32 regval;
1756 : :
1757 : : /* Enable reading switch and PHY registers over the sideband queue */
1758 : : #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
1759 : : #define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
1760 : 0 : regval = rd32(hw, PF_SB_REM_DEV_CTL);
1761 : 0 : regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
1762 : : PF_SB_REM_DEV_CTL_PHY0);
1763 : 0 : wr32(hw, PF_SB_REM_DEV_CTL, regval);
1764 : :
1765 : : /* Initialize the Clock Generation Unit */
1766 : 0 : status = ice_init_cgu_e822(hw);
1767 : :
1768 : : return status;
1769 : : }
1770 : :
1771 : : /**
1772 : : * ice_ptp_read_tx_hwtstamp_status_eth56g - Get the current TX timestamp
1773 : : * status mask. Returns the mask of ports where TX timestamps are available
1774 : : * @hw: pointer to the HW struct
1775 : : * @ts_status: the timestamp mask pointer
1776 : : */
1777 : : enum ice_status
1778 : 0 : ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)
1779 : : {
1780 : : enum ice_status status;
1781 : :
1782 : 0 : status = ice_read_phy_eth56g_raw_lp(hw, PHY_PTP_INT_STATUS, ts_status,
1783 : : true);
1784 [ # # ]: 0 : if (status)
1785 : : return status;
1786 : :
1787 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "PHY interrupt status: %x\n", *ts_status);
1788 : :
1789 : : return ICE_SUCCESS;
1790 : : }
1791 : :
1792 : : /**
1793 : : * ice_ptp_init_phy_cfg - Get the current TX timestamp status
1794 : : * mask. Returns the mask of ports where TX timestamps are available
1795 : : * @hw: pointer to the HW struct
1796 : : */
1797 : : enum ice_status
1798 : 0 : ice_ptp_init_phy_cfg(struct ice_hw *hw)
1799 : : {
1800 : : enum ice_status status;
1801 : : u32 phy_rev;
1802 : :
1803 : 0 : status = ice_read_phy_eth56g_raw_lp(hw, PHY_REG_REVISION, &phy_rev,
1804 : : true);
1805 [ # # ]: 0 : if (status)
1806 : : return status;
1807 : :
1808 [ # # ]: 0 : if (phy_rev == PHY_REVISION_ETH56G) {
1809 : 0 : hw->phy_cfg = ICE_PHY_ETH56G;
1810 : 0 : return ICE_SUCCESS;
1811 : : }
1812 : :
1813 [ # # ]: 0 : if (ice_is_e810(hw))
1814 : 0 : hw->phy_cfg = ICE_PHY_E810;
1815 : : else
1816 : 0 : hw->phy_cfg = ICE_PHY_E822;
1817 : :
1818 : : return ICE_SUCCESS;
1819 : : }
1820 : :
1821 : : /* ----------------------------------------------------------------------------
1822 : : * E822 family functions
1823 : : *
1824 : : * The following functions operate on the E822 family of devices.
1825 : : */
1826 : :
1827 : : /**
1828 : : * ice_fill_phy_msg_e822 - Fill message data for a PHY register access
1829 : : * @msg: the PHY message buffer to fill in
1830 : : * @port: the port to access
1831 : : * @offset: the register offset
1832 : : */
1833 : : static void
1834 : 0 : ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
1835 : : {
1836 : : int phy_port, phy, quadtype;
1837 : :
1838 : 0 : phy_port = port % ICE_PORTS_PER_PHY_E822;
1839 : 0 : phy = port / ICE_PORTS_PER_PHY_E822;
1840 : 0 : quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_QUADS_PER_PHY_E822;
1841 : :
1842 [ # # ]: 0 : if (quadtype == 0) {
1843 : 0 : msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
1844 : 0 : msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port);
1845 : : } else {
1846 : 0 : msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port);
1847 : 0 : msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port);
1848 : : }
1849 : :
1850 [ # # ]: 0 : if (phy == 0)
1851 : 0 : msg->dest_dev = rmn_0;
1852 [ # # ]: 0 : else if (phy == 1)
1853 : 0 : msg->dest_dev = rmn_1;
1854 : : else
1855 : 0 : msg->dest_dev = rmn_2;
1856 : 0 : }
1857 : :
1858 : : /**
1859 : : * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register
1860 : : * @low_addr: the low address to check
1861 : : * @high_addr: on return, contains the high address of the 64bit register
1862 : : *
1863 : : * Checks if the provided low address is one of the known 64bit PHY values
1864 : : * represented as two 32bit registers. If it is, return the appropriate high
1865 : : * register offset to use.
1866 : : */
1867 : 0 : static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
1868 : : {
1869 [ # # # # : 0 : switch (low_addr) {
# # # # #
# # # # ]
1870 : 0 : case P_REG_PAR_PCS_TX_OFFSET_L:
1871 : 0 : *high_addr = P_REG_PAR_PCS_TX_OFFSET_U;
1872 : 0 : return true;
1873 : 0 : case P_REG_PAR_PCS_RX_OFFSET_L:
1874 : 0 : *high_addr = P_REG_PAR_PCS_RX_OFFSET_U;
1875 : 0 : return true;
1876 : 0 : case P_REG_PAR_TX_TIME_L:
1877 : 0 : *high_addr = P_REG_PAR_TX_TIME_U;
1878 : 0 : return true;
1879 : 0 : case P_REG_PAR_RX_TIME_L:
1880 : 0 : *high_addr = P_REG_PAR_RX_TIME_U;
1881 : 0 : return true;
1882 : 0 : case P_REG_TOTAL_TX_OFFSET_L:
1883 : 0 : *high_addr = P_REG_TOTAL_TX_OFFSET_U;
1884 : 0 : return true;
1885 : 0 : case P_REG_TOTAL_RX_OFFSET_L:
1886 : 0 : *high_addr = P_REG_TOTAL_RX_OFFSET_U;
1887 : 0 : return true;
1888 : 0 : case P_REG_UIX66_10G_40G_L:
1889 : 0 : *high_addr = P_REG_UIX66_10G_40G_U;
1890 : 0 : return true;
1891 : 0 : case P_REG_UIX66_25G_100G_L:
1892 : 0 : *high_addr = P_REG_UIX66_25G_100G_U;
1893 : 0 : return true;
1894 : 0 : case P_REG_TX_CAPTURE_L:
1895 : 0 : *high_addr = P_REG_TX_CAPTURE_U;
1896 : 0 : return true;
1897 : 0 : case P_REG_RX_CAPTURE_L:
1898 : 0 : *high_addr = P_REG_RX_CAPTURE_U;
1899 : 0 : return true;
1900 : 0 : case P_REG_TX_TIMER_INC_PRE_L:
1901 : 0 : *high_addr = P_REG_TX_TIMER_INC_PRE_U;
1902 : 0 : return true;
1903 : 0 : case P_REG_RX_TIMER_INC_PRE_L:
1904 : 0 : *high_addr = P_REG_RX_TIMER_INC_PRE_U;
1905 : 0 : return true;
1906 : : default:
1907 : : return false;
1908 : : }
1909 : : }
1910 : :
1911 : : /**
1912 : : * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register
1913 : : * @low_addr: the low address to check
1914 : : * @high_addr: on return, contains the high address of the 40bit value
1915 : : *
1916 : : * Checks if the provided low address is one of the known 40bit PHY values
1917 : : * split into two registers with the lower 8 bits in the low register and the
1918 : : * upper 32 bits in the high register. If it is, return the appropriate high
1919 : : * register offset to use.
1920 : : */
1921 : 0 : static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
1922 : : {
1923 [ # # # # : 0 : switch (low_addr) {
# # # # #
# ]
1924 : 0 : case P_REG_TIMETUS_L:
1925 : 0 : *high_addr = P_REG_TIMETUS_U;
1926 : 0 : return true;
1927 : 0 : case P_REG_PAR_RX_TUS_L:
1928 : 0 : *high_addr = P_REG_PAR_RX_TUS_U;
1929 : 0 : return true;
1930 : 0 : case P_REG_PAR_TX_TUS_L:
1931 : 0 : *high_addr = P_REG_PAR_TX_TUS_U;
1932 : 0 : return true;
1933 : 0 : case P_REG_PCS_RX_TUS_L:
1934 : 0 : *high_addr = P_REG_PCS_RX_TUS_U;
1935 : 0 : return true;
1936 : 0 : case P_REG_PCS_TX_TUS_L:
1937 : 0 : *high_addr = P_REG_PCS_TX_TUS_U;
1938 : 0 : return true;
1939 : 0 : case P_REG_DESK_PAR_RX_TUS_L:
1940 : 0 : *high_addr = P_REG_DESK_PAR_RX_TUS_U;
1941 : 0 : return true;
1942 : 0 : case P_REG_DESK_PAR_TX_TUS_L:
1943 : 0 : *high_addr = P_REG_DESK_PAR_TX_TUS_U;
1944 : 0 : return true;
1945 : 0 : case P_REG_DESK_PCS_RX_TUS_L:
1946 : 0 : *high_addr = P_REG_DESK_PCS_RX_TUS_U;
1947 : 0 : return true;
1948 : 0 : case P_REG_DESK_PCS_TX_TUS_L:
1949 : 0 : *high_addr = P_REG_DESK_PCS_TX_TUS_U;
1950 : 0 : return true;
1951 : : default:
1952 : : return false;
1953 : : }
1954 : : }
1955 : :
1956 : : /**
1957 : : * ice_read_phy_reg_e822_lp - Read a PHY register
1958 : : * @hw: pointer to the HW struct
1959 : : * @port: PHY port to read from
1960 : : * @offset: PHY register offset to read
1961 : : * @val: on return, the contents read from the PHY
1962 : : * @lock_sbq: true if the sideband queue lock must be acquired
1963 : : *
1964 : : * Read a PHY register for the given port over the device sideband queue.
1965 : : */
1966 : : static enum ice_status
1967 : 0 : ice_read_phy_reg_e822_lp(struct ice_hw *hw, u8 port, u16 offset, u32 *val,
1968 : : bool lock_sbq)
1969 : : {
1970 : 0 : struct ice_sbq_msg_input msg = {0};
1971 : : enum ice_status status;
1972 : :
1973 : 0 : ice_fill_phy_msg_e822(&msg, port, offset);
1974 : : msg.opcode = ice_sbq_msg_rd;
1975 : :
1976 : 0 : status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
1977 [ # # ]: 0 : if (status) {
1978 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
1979 : : status);
1980 : 0 : return status;
1981 : : }
1982 : :
1983 : 0 : *val = msg.data;
1984 : :
1985 : 0 : return ICE_SUCCESS;
1986 : : }
1987 : :
1988 : : enum ice_status
1989 : 0 : ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
1990 : : {
1991 : 0 : return ice_read_phy_reg_e822_lp(hw, port, offset, val, true);
1992 : : }
1993 : :
1994 : : /**
1995 : : * ice_read_40b_phy_reg_e822 - Read a 40bit value from PHY registers
1996 : : * @hw: pointer to the HW struct
1997 : : * @port: PHY port to read from
1998 : : * @low_addr: offset of the lower register to read from
1999 : : * @val: on return, the contents of the 40bit value from the PHY registers
2000 : : *
2001 : : * Reads the two registers associated with a 40bit value and returns it in the
2002 : : * val pointer. The offset always specifies the lower register offset to use.
2003 : : * The high offset is looked up. This function only operates on registers
2004 : : * known to be split into a lower 8 bit chunk and an upper 32 bit chunk.
2005 : : */
2006 : : static enum ice_status
2007 : 0 : ice_read_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
2008 : : {
2009 : : enum ice_status status;
2010 : : u32 low, high;
2011 : : u16 high_addr;
2012 : :
2013 : : /* Only operate on registers known to be split into two 32bit
2014 : : * registers.
2015 : : */
2016 [ # # ]: 0 : if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
2017 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
2018 : : low_addr);
2019 : 0 : return ICE_ERR_PARAM;
2020 : : }
2021 : :
2022 : 0 : status = ice_read_phy_reg_e822(hw, port, low_addr, &low);
2023 [ # # ]: 0 : if (status) {
2024 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, status %d",
2025 : : low_addr, status);
2026 : 0 : return status;
2027 : : }
2028 : :
2029 : 0 : status = ice_read_phy_reg_e822(hw, port, high_addr, &high);
2030 [ # # ]: 0 : if (status) {
2031 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, status %d",
2032 : : high_addr, status);
2033 : 0 : return status;
2034 : : }
2035 : :
2036 : 0 : *val = (u64)high << P_REG_40B_HIGH_S | (low & P_REG_40B_LOW_M);
2037 : :
2038 : 0 : return ICE_SUCCESS;
2039 : : }
2040 : :
2041 : : /**
2042 : : * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers
2043 : : * @hw: pointer to the HW struct
2044 : : * @port: PHY port to read from
2045 : : * @low_addr: offset of the lower register to read from
2046 : : * @val: on return, the contents of the 64bit value from the PHY registers
2047 : : *
2048 : : * Reads the two registers associated with a 64bit value and returns it in the
2049 : : * val pointer. The offset always specifies the lower register offset to use.
2050 : : * The high offset is looked up. This function only operates on registers
2051 : : * known to be two parts of a 64bit value.
2052 : : */
2053 : : static enum ice_status
2054 : 0 : ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
2055 : : {
2056 : : enum ice_status status;
2057 : : u32 low, high;
2058 : : u16 high_addr;
2059 : :
2060 : : /* Only operate on registers known to be split into two 32bit
2061 : : * registers.
2062 : : */
2063 [ # # ]: 0 : if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
2064 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
2065 : : low_addr);
2066 : 0 : return ICE_ERR_PARAM;
2067 : : }
2068 : :
2069 : 0 : status = ice_read_phy_reg_e822(hw, port, low_addr, &low);
2070 [ # # ]: 0 : if (status) {
2071 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, status %d",
2072 : : low_addr, status);
2073 : 0 : return status;
2074 : : }
2075 : :
2076 : 0 : status = ice_read_phy_reg_e822(hw, port, high_addr, &high);
2077 [ # # ]: 0 : if (status) {
2078 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, status %d",
2079 : : high_addr, status);
2080 : 0 : return status;
2081 : : }
2082 : :
2083 : 0 : *val = (u64)high << 32 | low;
2084 : :
2085 : 0 : return ICE_SUCCESS;
2086 : : }
2087 : :
2088 : : /**
2089 : : * ice_write_phy_reg_e822_lp - Write a PHY register
2090 : : * @hw: pointer to the HW struct
2091 : : * @port: PHY port to write to
2092 : : * @offset: PHY register offset to write
2093 : : * @val: The value to write to the register
2094 : : * @lock_sbq: true if the sideband queue lock must be acquired
2095 : : *
2096 : : * Write a PHY register for the given port over the device sideband queue.
2097 : : */
2098 : : static enum ice_status
2099 : 0 : ice_write_phy_reg_e822_lp(struct ice_hw *hw, u8 port, u16 offset, u32 val,
2100 : : bool lock_sbq)
2101 : : {
2102 : 0 : struct ice_sbq_msg_input msg = {0};
2103 : : enum ice_status status;
2104 : :
2105 : 0 : ice_fill_phy_msg_e822(&msg, port, offset);
2106 : 0 : msg.opcode = ice_sbq_msg_wr;
2107 : 0 : msg.data = val;
2108 : :
2109 : 0 : status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
2110 [ # # ]: 0 : if (status) {
2111 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
2112 : : status);
2113 : 0 : return status;
2114 : : }
2115 : :
2116 : : return ICE_SUCCESS;
2117 : : }
2118 : :
2119 : : enum ice_status
2120 : 0 : ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
2121 : : {
2122 : 0 : return ice_write_phy_reg_e822_lp(hw, port, offset, val, true);
2123 : : }
2124 : :
2125 : : /**
2126 : : * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY
2127 : : * @hw: pointer to the HW struct
2128 : : * @port: port to write to
2129 : : * @low_addr: offset of the low register
2130 : : * @val: 40b value to write
2131 : : *
2132 : : * Write the provided 40b value to the two associated registers by splitting
2133 : : * it up into two chunks, the lower 8 bits and the upper 32 bits.
2134 : : */
2135 : : static enum ice_status
2136 : 0 : ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
2137 : : {
2138 : : enum ice_status status;
2139 : : u32 low, high;
2140 : : u16 high_addr;
2141 : :
2142 : : /* Only operate on registers known to be split into a lower 8 bit
2143 : : * register and an upper 32 bit register.
2144 : : */
2145 [ # # ]: 0 : if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
2146 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n",
2147 : : low_addr);
2148 : 0 : return ICE_ERR_PARAM;
2149 : : }
2150 : :
2151 : 0 : low = (u32)(val & P_REG_40B_LOW_M);
2152 : 0 : high = (u32)(val >> P_REG_40B_HIGH_S);
2153 : :
2154 : 0 : status = ice_write_phy_reg_e822(hw, port, low_addr, low);
2155 [ # # ]: 0 : if (status) {
2156 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d",
2157 : : low_addr, status);
2158 : 0 : return status;
2159 : : }
2160 : :
2161 : 0 : status = ice_write_phy_reg_e822(hw, port, high_addr, high);
2162 [ # # ]: 0 : if (status) {
2163 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d",
2164 : : high_addr, status);
2165 : 0 : return status;
2166 : : }
2167 : :
2168 : : return ICE_SUCCESS;
2169 : : }
2170 : :
2171 : : /**
2172 : : * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers
2173 : : * @hw: pointer to the HW struct
2174 : : * @port: PHY port to read from
2175 : : * @low_addr: offset of the lower register to read from
2176 : : * @val: the contents of the 64bit value to write to PHY
2177 : : *
2178 : : * Write the 64bit value to the two associated 32bit PHY registers. The offset
2179 : : * is always specified as the lower register, and the high address is looked
2180 : : * up. This function only operates on registers known to be two parts of
2181 : : * a 64bit value.
2182 : : */
2183 : : static enum ice_status
2184 : 0 : ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
2185 : : {
2186 : : enum ice_status status;
2187 : : u32 low, high;
2188 : : u16 high_addr;
2189 : :
2190 : : /* Only operate on registers known to be split into two 32bit
2191 : : * registers.
2192 : : */
2193 [ # # ]: 0 : if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
2194 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
2195 : : low_addr);
2196 : 0 : return ICE_ERR_PARAM;
2197 : : }
2198 : :
2199 : 0 : low = ICE_LO_DWORD(val);
2200 : 0 : high = ICE_HI_DWORD(val);
2201 : :
2202 : 0 : status = ice_write_phy_reg_e822(hw, port, low_addr, low);
2203 [ # # ]: 0 : if (status) {
2204 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, status %d",
2205 : : low_addr, status);
2206 : 0 : return status;
2207 : : }
2208 : :
2209 : 0 : status = ice_write_phy_reg_e822(hw, port, high_addr, high);
2210 [ # # ]: 0 : if (status) {
2211 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, status %d",
2212 : : high_addr, status);
2213 : 0 : return status;
2214 : : }
2215 : :
2216 : : return ICE_SUCCESS;
2217 : : }
2218 : :
2219 : : /**
2220 : : * ice_fill_quad_msg_e822 - Fill message data for quad register access
2221 : : * @msg: the PHY message buffer to fill in
2222 : : * @quad: the quad to access
2223 : : * @offset: the register offset
2224 : : *
2225 : : * Fill a message buffer for accessing a register in a quad shared between
2226 : : * multiple PHYs.
2227 : : */
2228 : : static enum ice_status
2229 : : ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
2230 : : {
2231 : : u32 addr;
2232 : :
2233 : 0 : if (quad >= ICE_MAX_QUAD)
2234 : : return ICE_ERR_PARAM;
2235 : :
2236 : 0 : msg->dest_dev = rmn_0;
2237 : :
2238 [ # # # # ]: 0 : if ((quad % ICE_QUADS_PER_PHY_E822) == 0)
2239 : 0 : addr = Q_0_BASE + offset;
2240 : : else
2241 : 0 : addr = Q_1_BASE + offset;
2242 : :
2243 : 0 : msg->msg_addr_low = ICE_LO_WORD(addr);
2244 : 0 : msg->msg_addr_high = ICE_HI_WORD(addr);
2245 : :
2246 : : return ICE_SUCCESS;
2247 : : }
2248 : :
2249 : : /**
2250 : : * ice_read_quad_reg_e822_lp - Read a PHY quad register
2251 : : * @hw: pointer to the HW struct
2252 : : * @quad: quad to read from
2253 : : * @offset: quad register offset to read
2254 : : * @val: on return, the contents read from the quad
2255 : : * @lock_sbq: true if the sideband queue lock must be acquired
2256 : : *
2257 : : * Read a quad register over the device sideband queue. Quad registers are
2258 : : * shared between multiple PHYs.
2259 : : */
2260 : : static enum ice_status
2261 : 0 : ice_read_quad_reg_e822_lp(struct ice_hw *hw, u8 quad, u16 offset, u32 *val,
2262 : : bool lock_sbq)
2263 : : {
2264 : 0 : struct ice_sbq_msg_input msg = {0};
2265 : : enum ice_status status;
2266 : :
2267 [ # # ]: 0 : status = ice_fill_quad_msg_e822(&msg, quad, offset);
2268 : : if (status)
2269 : 0 : goto exit_err;
2270 : :
2271 : : msg.opcode = ice_sbq_msg_rd;
2272 : :
2273 : 0 : status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
2274 : 0 : exit_err:
2275 [ # # ]: 0 : if (status)
2276 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
2277 : : status);
2278 : : else
2279 : 0 : *val = msg.data;
2280 : :
2281 : 0 : return status;
2282 : : }
2283 : :
2284 : : enum ice_status
2285 : 0 : ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
2286 : : {
2287 : 0 : return ice_read_quad_reg_e822_lp(hw, quad, offset, val, true);
2288 : : }
2289 : :
2290 : : /**
2291 : : * ice_write_quad_reg_e822_lp - Write a PHY quad register
2292 : : * @hw: pointer to the HW struct
2293 : : * @quad: quad to write to
2294 : : * @offset: quad register offset to write
2295 : : * @val: The value to write to the register
2296 : : * @lock_sbq: true if the sideband queue lock must be acquired
2297 : : *
2298 : : * Write a quad register over the device sideband queue. Quad registers are
2299 : : * shared between multiple PHYs.
2300 : : */
2301 : : static enum ice_status
2302 : 0 : ice_write_quad_reg_e822_lp(struct ice_hw *hw, u8 quad, u16 offset, u32 val,
2303 : : bool lock_sbq)
2304 : : {
2305 : 0 : struct ice_sbq_msg_input msg = {0};
2306 : : enum ice_status status;
2307 : :
2308 [ # # ]: 0 : status = ice_fill_quad_msg_e822(&msg, quad, offset);
2309 : : if (status)
2310 : 0 : goto exit_err;
2311 : :
2312 : 0 : msg.opcode = ice_sbq_msg_wr;
2313 : 0 : msg.data = val;
2314 : :
2315 : 0 : status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
2316 : 0 : exit_err:
2317 [ # # ]: 0 : if (status)
2318 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
2319 : : status);
2320 : :
2321 : 0 : return status;
2322 : : }
2323 : :
2324 : : enum ice_status
2325 : 0 : ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
2326 : : {
2327 : 0 : return ice_write_quad_reg_e822_lp(hw, quad, offset, val, true);
2328 : : }
2329 : :
2330 : : /**
2331 : : * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block
2332 : : * @hw: pointer to the HW struct
2333 : : * @quad: the quad to read from
2334 : : * @idx: the timestamp index to read
2335 : : * @tstamp: on return, the 40bit timestamp value
2336 : : *
2337 : : * Read a 40bit timestamp value out of the two associated registers in the
2338 : : * quad memory block that is shared between the internal PHYs of the E822
2339 : : * family of devices.
2340 : : */
2341 : : static enum ice_status
2342 : 0 : ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
2343 : : {
2344 : : enum ice_status status;
2345 : : u16 lo_addr, hi_addr;
2346 : : u32 lo, hi;
2347 : :
2348 : 0 : lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
2349 : 0 : hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
2350 : :
2351 : 0 : status = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);
2352 [ # # ]: 0 : if (status) {
2353 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
2354 : : status);
2355 : 0 : return status;
2356 : : }
2357 : :
2358 : 0 : status = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);
2359 [ # # ]: 0 : if (status) {
2360 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
2361 : : status);
2362 : 0 : return status;
2363 : : }
2364 : :
2365 : : /* For E822 based internal PHYs, the timestamp is reported with the
2366 : : * lower 8 bits in the low register, and the upper 32 bits in the high
2367 : : * register.
2368 : : */
2369 : 0 : *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
2370 : :
2371 : 0 : return ICE_SUCCESS;
2372 : : }
2373 : :
2374 : : /**
2375 : : * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block
2376 : : * @hw: pointer to the HW struct
2377 : : * @quad: the quad to read from
2378 : : * @idx: the timestamp index to reset
2379 : : *
2380 : : * Clear a timestamp, resetting its valid bit, from the PHY quad block that is
2381 : : * shared between the internal PHYs on the E822 devices.
2382 : : */
2383 : : static enum ice_status
2384 : 0 : ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
2385 : : {
2386 : : enum ice_status status;
2387 : : u16 lo_addr, hi_addr;
2388 : :
2389 : 0 : lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
2390 : 0 : hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
2391 : :
2392 : 0 : status = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);
2393 [ # # ]: 0 : if (status) {
2394 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
2395 : : status);
2396 : 0 : return status;
2397 : : }
2398 : :
2399 : 0 : status = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);
2400 [ # # ]: 0 : if (status) {
2401 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, status %d\n",
2402 : : status);
2403 : 0 : return status;
2404 : : }
2405 : :
2406 : : return ICE_SUCCESS;
2407 : : }
2408 : :
2409 : : /**
2410 : : * ice_ptp_set_vernier_wl - Set the window length for vernier calibration
2411 : : * @hw: pointer to the HW struct
2412 : : *
2413 : : * Set the window length used for the vernier port calibration process.
2414 : : */
2415 : 0 : enum ice_status ice_ptp_set_vernier_wl(struct ice_hw *hw)
2416 : : {
2417 : : u8 port;
2418 : :
2419 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
2420 : : enum ice_status status;
2421 : :
2422 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_WL,
2423 : : PTP_VERNIER_WL, true);
2424 [ # # ]: 0 : if (status) {
2425 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, status %d\n",
2426 : : port, status);
2427 : 0 : return status;
2428 : : }
2429 : : }
2430 : :
2431 : : return ICE_SUCCESS;
2432 : : }
2433 : :
2434 : : /**
2435 : : * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization
2436 : : * @hw: pointer to HW struct
2437 : : *
2438 : : * Perform PHC initialization steps specific to E822 devices.
2439 : : */
2440 : 0 : static enum ice_status ice_ptp_init_phc_e822(struct ice_hw *hw)
2441 : : {
2442 : : enum ice_status status;
2443 : : u32 regval;
2444 : :
2445 : : /* Enable reading switch and PHY registers over the sideband queue */
2446 : : #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
2447 : : #define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
2448 : 0 : regval = rd32(hw, PF_SB_REM_DEV_CTL);
2449 : 0 : regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
2450 : : PF_SB_REM_DEV_CTL_PHY0);
2451 : 0 : wr32(hw, PF_SB_REM_DEV_CTL, regval);
2452 : :
2453 : : /* Initialize the Clock Generation Unit */
2454 : 0 : status = ice_init_cgu_e822(hw);
2455 [ # # ]: 0 : if (status)
2456 : : return status;
2457 : :
2458 : : /* Set window length for all the ports */
2459 : 0 : return ice_ptp_set_vernier_wl(hw);
2460 : : }
2461 : :
2462 : : /**
2463 : : * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time
2464 : : * @hw: pointer to the HW struct
2465 : : * @time: Time to initialize the PHY port clocks to
2466 : : *
2467 : : * Program the PHY port registers with a new initial time value. The port
2468 : : * clock will be initialized once the driver issues an ICE_PTP_INIT_TIME sync
2469 : : * command. The time value is the upper 32 bits of the PHY timer, usually in
2470 : : * units of nominal nanoseconds.
2471 : : */
2472 : : static enum ice_status
2473 : 0 : ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
2474 : : {
2475 : : enum ice_status status;
2476 : : u64 phy_time;
2477 : : u8 port;
2478 : :
2479 : : /* The time represents the upper 32 bits of the PHY timer, so we need
2480 : : * to shift to account for this when programming.
2481 : : */
2482 : 0 : phy_time = (u64)time << 32;
2483 : :
2484 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
2485 : :
2486 : : /* Tx case */
2487 : 0 : status = ice_write_64b_phy_reg_e822(hw, port,
2488 : : P_REG_TX_TIMER_INC_PRE_L,
2489 : : phy_time);
2490 [ # # ]: 0 : if (status)
2491 : 0 : goto exit_err;
2492 : :
2493 : : /* Rx case */
2494 : 0 : status = ice_write_64b_phy_reg_e822(hw, port,
2495 : : P_REG_RX_TIMER_INC_PRE_L,
2496 : : phy_time);
2497 [ # # ]: 0 : if (status)
2498 : 0 : goto exit_err;
2499 : : }
2500 : :
2501 : : return ICE_SUCCESS;
2502 : :
2503 : 0 : exit_err:
2504 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, status %d\n",
2505 : : port, status);
2506 : :
2507 : : return status;
2508 : : }
2509 : :
2510 : : /**
2511 : : * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust
2512 : : * @hw: pointer to HW struct
2513 : : * @port: Port number to be programmed
2514 : : * @time: time in cycles to adjust the port Tx and Rx clocks
2515 : : * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
2516 : : * sq_lock has already been locked at a higher level
2517 : : *
2518 : : * Program the port for an atomic adjustment by writing the Tx and Rx timer
2519 : : * registers. The atomic adjustment won't be completed until the driver issues
2520 : : * an ICE_PTP_ADJ_TIME command.
2521 : : *
2522 : : * Note that time is not in units of nanoseconds. It is in clock time
2523 : : * including the lower sub-nanosecond portion of the port timer.
2524 : : *
2525 : : * Negative adjustments are supported using 2s complement arithmetic.
2526 : : */
2527 : : enum ice_status
2528 : 0 : ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time,
2529 : : bool lock_sbq)
2530 : : {
2531 : : enum ice_status status;
2532 : : u32 l_time, u_time;
2533 : :
2534 : 0 : l_time = ICE_LO_DWORD(time);
2535 : 0 : u_time = ICE_HI_DWORD(time);
2536 : :
2537 : : /* Tx case */
2538 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TIMER_INC_PRE_L,
2539 : : l_time, lock_sbq);
2540 [ # # ]: 0 : if (status)
2541 : 0 : goto exit_err;
2542 : :
2543 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TIMER_INC_PRE_U,
2544 : : u_time, lock_sbq);
2545 [ # # ]: 0 : if (status)
2546 : 0 : goto exit_err;
2547 : :
2548 : : /* Rx case */
2549 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TIMER_INC_PRE_L,
2550 : : l_time, lock_sbq);
2551 [ # # ]: 0 : if (status)
2552 : 0 : goto exit_err;
2553 : :
2554 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TIMER_INC_PRE_U,
2555 : : u_time, lock_sbq);
2556 [ # # ]: 0 : if (status)
2557 : 0 : goto exit_err;
2558 : :
2559 : : return ICE_SUCCESS;
2560 : :
2561 : 0 : exit_err:
2562 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, status %d\n",
2563 : : port, status);
2564 : : return status;
2565 : : }
2566 : :
2567 : : /**
2568 : : * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment
2569 : : * @hw: pointer to HW struct
2570 : : * @adj: adjustment in nanoseconds
2571 : : * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
2572 : : * sq_lock has already been locked at a higher level
2573 : : *
2574 : : * Prepare the PHY ports for an atomic time adjustment by programming the PHY
2575 : : * Tx and Rx port registers. The actual adjustment is completed by issuing an
2576 : : * ICE_PTP_ADJ_TIME or ICE_PTP_ADJ_TIME_AT_TIME sync command.
2577 : : */
2578 : : static enum ice_status
2579 : 0 : ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj, bool lock_sbq)
2580 : : {
2581 : : s64 cycles;
2582 : : u8 port;
2583 : :
2584 : : /* The port clock supports adjustment of the sub-nanosecond portion of
2585 : : * the clock. We shift the provided adjustment in nanoseconds to
2586 : : * calculate the appropriate adjustment to program into the PHY ports.
2587 : : */
2588 [ # # ]: 0 : if (adj > 0)
2589 : 0 : cycles = (s64)adj << 32;
2590 : : else
2591 : 0 : cycles = -(((s64)-adj) << 32);
2592 : :
2593 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
2594 : : enum ice_status status;
2595 : :
2596 : 0 : status = ice_ptp_prep_port_adj_e822(hw, port, cycles,
2597 : : lock_sbq);
2598 [ # # ]: 0 : if (status)
2599 : 0 : return status;
2600 : : }
2601 : :
2602 : : return ICE_SUCCESS;
2603 : : }
2604 : :
2605 : : /**
2606 : : * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment
2607 : : * @hw: pointer to HW struct
2608 : : * @incval: new increment value to prepare
2609 : : *
2610 : : * Prepare each of the PHY ports for a new increment value by programming the
2611 : : * port's TIMETUS registers. The new increment value will be updated after
2612 : : * issuing an ICE_PTP_INIT_INCVAL command.
2613 : : */
2614 : : static enum ice_status
2615 : 0 : ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
2616 : : {
2617 : : enum ice_status status;
2618 : : u8 port;
2619 : :
2620 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
2621 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,
2622 : : incval);
2623 [ # # ]: 0 : if (status)
2624 : 0 : goto exit_err;
2625 : : }
2626 : :
2627 : : return ICE_SUCCESS;
2628 : :
2629 : : exit_err:
2630 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, status %d\n",
2631 : : port, status);
2632 : :
2633 : : return status;
2634 : : }
2635 : :
2636 : : /**
2637 : : * ice_ptp_read_phy_incval_e822 - Read a PHY port's current incval
2638 : : * @hw: pointer to the HW struct
2639 : : * @port: the port to read
2640 : : * @incval: on return, the time_clk_cyc incval for this port
2641 : : *
2642 : : * Read the time_clk_cyc increment value for a given PHY port.
2643 : : */
2644 : : enum ice_status
2645 : 0 : ice_ptp_read_phy_incval_e822(struct ice_hw *hw, u8 port, u64 *incval)
2646 : : {
2647 : : enum ice_status status;
2648 : :
2649 : 0 : status = ice_read_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
2650 [ # # ]: 0 : if (status) {
2651 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read TIMETUS_L, status %d\n",
2652 : : status);
2653 : 0 : return status;
2654 : : }
2655 : :
2656 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "read INCVAL = 0x%016llx\n",
2657 : : (unsigned long long)*incval);
2658 : :
2659 : : return ICE_SUCCESS;
2660 : : }
2661 : :
2662 : : /**
2663 : : * ice_ptp_prep_phy_adj_target_e822 - Prepare PHY for adjust at target time
2664 : : * @hw: pointer to HW struct
2665 : : * @target_time: target time to program
2666 : : *
2667 : : * Program the PHY port Tx and Rx TIMER_CNT_ADJ registers used for the
2668 : : * ICE_PTP_ADJ_TIME_AT_TIME command. This should be used in conjunction with
2669 : : * ice_ptp_prep_phy_adj_e822 to program an atomic adjustment that is
2670 : : * delayed until a specified target time.
2671 : : *
2672 : : * Note that a target time adjustment is not currently supported on E810
2673 : : * devices.
2674 : : */
2675 : : static enum ice_status
2676 : 0 : ice_ptp_prep_phy_adj_target_e822(struct ice_hw *hw, u32 target_time)
2677 : : {
2678 : : enum ice_status status;
2679 : : u8 port;
2680 : :
2681 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
2682 : :
2683 : : /* Tx case */
2684 : : /* No sub-nanoseconds data */
2685 : 0 : status = ice_write_phy_reg_e822_lp(hw, port,
2686 : : P_REG_TX_TIMER_CNT_ADJ_L,
2687 : : 0, true);
2688 [ # # ]: 0 : if (status)
2689 : 0 : goto exit_err;
2690 : :
2691 : 0 : status = ice_write_phy_reg_e822_lp(hw, port,
2692 : : P_REG_TX_TIMER_CNT_ADJ_U,
2693 : : target_time, true);
2694 [ # # ]: 0 : if (status)
2695 : 0 : goto exit_err;
2696 : :
2697 : : /* Rx case */
2698 : : /* No sub-nanoseconds data */
2699 : 0 : status = ice_write_phy_reg_e822_lp(hw, port,
2700 : : P_REG_RX_TIMER_CNT_ADJ_L,
2701 : : 0, true);
2702 [ # # ]: 0 : if (status)
2703 : 0 : goto exit_err;
2704 : :
2705 : 0 : status = ice_write_phy_reg_e822_lp(hw, port,
2706 : : P_REG_RX_TIMER_CNT_ADJ_U,
2707 : : target_time, true);
2708 [ # # ]: 0 : if (status)
2709 : 0 : goto exit_err;
2710 : : }
2711 : :
2712 : : return ICE_SUCCESS;
2713 : :
2714 : 0 : exit_err:
2715 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write target time for port %u, status %d\n",
2716 : : port, status);
2717 : :
2718 : : return status;
2719 : : }
2720 : :
2721 : : /**
2722 : : * ice_ptp_read_port_capture_e822 - Read a port's local time capture
2723 : : * @hw: pointer to HW struct
2724 : : * @port: Port number to read
2725 : : * @tx_ts: on return, the Tx port time capture
2726 : : * @rx_ts: on return, the Rx port time capture
2727 : : *
2728 : : * Read the port's Tx and Rx local time capture values.
2729 : : *
2730 : : * Note this has no equivalent for the E810 devices.
2731 : : */
2732 : : enum ice_status
2733 : 0 : ice_ptp_read_port_capture_e822(struct ice_hw *hw, u8 port, u64 *tx_ts,
2734 : : u64 *rx_ts)
2735 : : {
2736 : : enum ice_status status;
2737 : :
2738 : : /* Tx case */
2739 : 0 : status = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
2740 [ # # ]: 0 : if (status) {
2741 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, status %d\n",
2742 : : status);
2743 : 0 : return status;
2744 : : }
2745 : :
2746 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n",
2747 : : (unsigned long long)*tx_ts);
2748 : :
2749 : : /* Rx case */
2750 : 0 : status = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
2751 [ # # ]: 0 : if (status) {
2752 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, status %d\n",
2753 : : status);
2754 : 0 : return status;
2755 : : }
2756 : :
2757 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n",
2758 : : (unsigned long long)*rx_ts);
2759 : :
2760 : : return ICE_SUCCESS;
2761 : : }
2762 : :
2763 : : /**
2764 : : * ice_ptp_one_port_cmd_e822 - Prepare a single PHY port for a timer command
2765 : : * @hw: pointer to HW struct
2766 : : * @port: Port to which cmd has to be sent
2767 : : * @cmd: Command to be sent to the port
2768 : : * @lock_sbq: true if the sideband queue lock must be acquired
2769 : : *
2770 : : * Prepare the requested port for an upcoming timer sync command.
2771 : : *
2772 : : * Note there is no equivalent of this operation on E810, as that device
2773 : : * always handles all external PHYs internally.
2774 : : */
2775 : : enum ice_status
2776 : 0 : ice_ptp_one_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd,
2777 : : bool lock_sbq)
2778 : : {
2779 : : enum ice_status status;
2780 : : u32 cmd_val, val;
2781 : : u8 tmr_idx;
2782 : :
2783 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
2784 : 0 : cmd_val = tmr_idx << SEL_PHY_SRC;
2785 [ # # # # : 0 : switch (cmd) {
# # ]
2786 : 0 : case ICE_PTP_INIT_TIME:
2787 : 0 : cmd_val |= PHY_CMD_INIT_TIME;
2788 : 0 : break;
2789 : 0 : case ICE_PTP_INIT_INCVAL:
2790 : 0 : cmd_val |= PHY_CMD_INIT_INCVAL;
2791 : 0 : break;
2792 : 0 : case ICE_PTP_ADJ_TIME:
2793 : 0 : cmd_val |= PHY_CMD_ADJ_TIME;
2794 : 0 : break;
2795 : 0 : case ICE_PTP_ADJ_TIME_AT_TIME:
2796 : 0 : cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
2797 : 0 : break;
2798 : 0 : case ICE_PTP_READ_TIME:
2799 : 0 : cmd_val |= PHY_CMD_READ_TIME;
2800 : 0 : break;
2801 : 0 : default:
2802 [ # # ]: 0 : ice_warn(hw, "Unknown timer command %u\n", cmd);
2803 : : return ICE_ERR_PARAM;
2804 : : }
2805 : :
2806 : : /* Tx case */
2807 : : /* Read, modify, write */
2808 : 0 : status = ice_read_phy_reg_e822_lp(hw, port, P_REG_TX_TMR_CMD, &val,
2809 : : lock_sbq);
2810 [ # # ]: 0 : if (status) {
2811 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, status %d\n",
2812 : : status);
2813 : 0 : return status;
2814 : : }
2815 : :
2816 : : /* Modify necessary bits only and perform write */
2817 : 0 : val &= ~TS_CMD_MASK;
2818 : 0 : val |= cmd_val;
2819 : :
2820 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_TX_TMR_CMD, val,
2821 : : lock_sbq);
2822 [ # # ]: 0 : if (status) {
2823 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, status %d\n",
2824 : : status);
2825 : 0 : return status;
2826 : : }
2827 : :
2828 : : /* Rx case */
2829 : : /* Read, modify, write */
2830 : 0 : status = ice_read_phy_reg_e822_lp(hw, port, P_REG_RX_TMR_CMD, &val,
2831 : : lock_sbq);
2832 [ # # ]: 0 : if (status) {
2833 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, status %d\n",
2834 : : status);
2835 : 0 : return status;
2836 : : }
2837 : :
2838 : : /* Modify necessary bits only and perform write */
2839 : 0 : val &= ~TS_CMD_MASK;
2840 : 0 : val |= cmd_val;
2841 : :
2842 : 0 : status = ice_write_phy_reg_e822_lp(hw, port, P_REG_RX_TMR_CMD, val,
2843 : : lock_sbq);
2844 [ # # ]: 0 : if (status) {
2845 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, status %d\n",
2846 : : status);
2847 : 0 : return status;
2848 : : }
2849 : :
2850 : : return ICE_SUCCESS;
2851 : : }
2852 : :
2853 : : /**
2854 : : * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
2855 : : * @hw: pointer to the HW struct
2856 : : * @cmd: timer command to prepare
2857 : : * @lock_sbq: true if the sideband queue lock must be acquired
2858 : : *
2859 : : * Prepare all ports connected to this device for an upcoming timer sync
2860 : : * command.
2861 : : */
2862 : : static enum ice_status
2863 : : ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,
2864 : : bool lock_sbq)
2865 : : {
2866 : : u8 port;
2867 : :
2868 [ # # ]: 0 : for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
2869 : : enum ice_status status;
2870 : :
2871 : 0 : status = ice_ptp_one_port_cmd_e822(hw, port, cmd, lock_sbq);
2872 [ # # ]: 0 : if (status)
2873 : : return status;
2874 : : }
2875 : :
2876 : : return ICE_SUCCESS;
2877 : : }
2878 : :
2879 : : /* E822 Vernier calibration functions
2880 : : *
2881 : : * The following functions are used as part of the vernier calibration of
2882 : : * a port. This calibration increases the precision of the timestamps on the
2883 : : * port.
2884 : : */
2885 : :
2886 : : /**
2887 : : * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode
2888 : : * @hw: pointer to HW struct
2889 : : * @port: the port to read from
2890 : : * @link_out: if non-NULL, holds link speed on success
2891 : : * @fec_out: if non-NULL, holds FEC algorithm on success
2892 : : *
2893 : : * Read the serdes data for the PHY port and extract the link speed and FEC
2894 : : * algorithm.
2895 : : */
2896 : : enum ice_status
2897 : 0 : ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
2898 : : enum ice_ptp_link_spd *link_out,
2899 : : enum ice_ptp_fec_mode *fec_out)
2900 : : {
2901 : : enum ice_ptp_link_spd link;
2902 : : enum ice_ptp_fec_mode fec;
2903 : : enum ice_status status;
2904 : : u32 serdes;
2905 : :
2906 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);
2907 [ # # ]: 0 : if (status) {
2908 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n");
2909 : 0 : return status;
2910 : : }
2911 : :
2912 : : /* Determine the FEC algorithm */
2913 : 0 : fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes);
2914 : :
2915 : 0 : serdes &= P_REG_LINK_SPEED_SERDES_M;
2916 : :
2917 : : /* Determine the link speed */
2918 [ # # ]: 0 : if (fec == ICE_PTP_FEC_MODE_RS_FEC) {
2919 [ # # # # ]: 0 : switch (serdes) {
2920 : : case ICE_PTP_SERDES_25G:
2921 : : link = ICE_PTP_LNK_SPD_25G_RS;
2922 : : break;
2923 : 0 : case ICE_PTP_SERDES_50G:
2924 : : link = ICE_PTP_LNK_SPD_50G_RS;
2925 : 0 : break;
2926 : 0 : case ICE_PTP_SERDES_100G:
2927 : : link = ICE_PTP_LNK_SPD_100G_RS;
2928 : 0 : break;
2929 : : default:
2930 : : return ICE_ERR_OUT_OF_RANGE;
2931 : : }
2932 : : } else {
2933 : : switch (serdes) {
2934 : : case ICE_PTP_SERDES_1G:
2935 : : link = ICE_PTP_LNK_SPD_1G;
2936 : : break;
2937 : : case ICE_PTP_SERDES_10G:
2938 : : link = ICE_PTP_LNK_SPD_10G;
2939 : : break;
2940 : : case ICE_PTP_SERDES_25G:
2941 : : link = ICE_PTP_LNK_SPD_25G;
2942 : : break;
2943 : : case ICE_PTP_SERDES_40G:
2944 : : link = ICE_PTP_LNK_SPD_40G;
2945 : : break;
2946 : : case ICE_PTP_SERDES_50G:
2947 : : link = ICE_PTP_LNK_SPD_50G;
2948 : : break;
2949 : : default:
2950 : : return ICE_ERR_OUT_OF_RANGE;
2951 : : }
2952 : : }
2953 : :
2954 [ # # ]: 0 : if (link_out)
2955 : 0 : *link_out = link;
2956 [ # # ]: 0 : if (fec_out)
2957 : 0 : *fec_out = fec;
2958 : :
2959 : : return ICE_SUCCESS;
2960 : : }
2961 : :
2962 : : /**
2963 : : * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp
2964 : : * @hw: pointer to HW struct
2965 : : * @port: to configure the quad for
2966 : : */
2967 : 0 : void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
2968 : : {
2969 : : enum ice_ptp_link_spd link_spd;
2970 : : enum ice_status status;
2971 : : u32 val;
2972 : : u8 quad;
2973 : :
2974 : 0 : status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);
2975 [ # # ]: 0 : if (status) {
2976 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, status %d\n",
2977 : : status);
2978 : 0 : return;
2979 : : }
2980 : :
2981 : 0 : quad = port / ICE_PORTS_PER_QUAD;
2982 : :
2983 : 0 : status = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
2984 [ # # ]: 0 : if (status) {
2985 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, status %d\n",
2986 : : status);
2987 : 0 : return;
2988 : : }
2989 : :
2990 [ # # ]: 0 : if (link_spd >= ICE_PTP_LNK_SPD_40G)
2991 : 0 : val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
2992 : : else
2993 : 0 : val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
2994 : :
2995 : 0 : status = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
2996 [ # # ]: 0 : if (status) {
2997 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, status %d\n",
2998 : : status);
2999 : 0 : return;
3000 : : }
3001 : : }
3002 : :
3003 : : /**
3004 : : * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822
3005 : : * @hw: pointer to the HW structure
3006 : : * @port: the port to configure
3007 : : *
3008 : : * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC
3009 : : * hardware clock time units (TUs). That is, determine the number of TUs per
3010 : : * serdes unit interval, and program the UIX registers with this conversion.
3011 : : *
3012 : : * This conversion is used as part of the calibration process when determining
3013 : : * the additional error of a timestamp vs the real time of transmission or
3014 : : * receipt of the packet.
3015 : : *
3016 : : * Hardware uses the number of TUs per 66 UIs, written to the UIX registers
3017 : : * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks.
3018 : : *
3019 : : * To calculate the conversion ratio, we use the following facts:
3020 : : *
3021 : : * a) the clock frequency in Hz (cycles per second)
3022 : : * b) the number of TUs per cycle (the increment value of the clock)
3023 : : * c) 1 second per 1 billion nanoseconds
3024 : : * d) the duration of 66 UIs in nanoseconds
3025 : : *
3026 : : * Given these facts, we can use the following table to work out what ratios
3027 : : * to multiply in order to get the number of TUs per 66 UIs:
3028 : : *
3029 : : * cycles | 1 second | incval (TUs) | nanoseconds
3030 : : * -------+--------------+--------------+-------------
3031 : : * second | 1 billion ns | cycle | 66 UIs
3032 : : *
3033 : : * To perform the multiplication using integers without too much loss of
3034 : : * precision, we can take use the following equation:
3035 : : *
3036 : : * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion)
3037 : : *
3038 : : * We scale up to using 6600 UI instead of 66 in order to avoid fractional
3039 : : * nanosecond UIs (66 UI at 10G/40G is 6.4 ns)
3040 : : *
3041 : : * The increment value has a maximum expected range of about 34 bits, while
3042 : : * the frequency value is about 29 bits. Multiplying these values shouldn't
3043 : : * overflow the 64 bits. However, we must then further multiply them again by
3044 : : * the Serdes unit interval duration. To avoid overflow here, we split the
3045 : : * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and
3046 : : * a divide by 390,625,000. This does lose some precision, but avoids
3047 : : * miscalculation due to arithmetic overflow.
3048 : : */
3049 : 0 : static enum ice_status ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
3050 : : {
3051 : : u64 cur_freq, clk_incval, tu_per_sec, uix;
3052 : : enum ice_status status;
3053 : :
3054 : : cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
3055 : 0 : clk_incval = ice_ptp_read_src_incval(hw);
3056 : :
3057 : : /* Calculate TUs per second divided by 256 */
3058 : 0 : tu_per_sec = (cur_freq * clk_incval) >> 8;
3059 : :
3060 : : #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */
3061 : : #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */
3062 : :
3063 : : /* Program the 10Gb/40Gb conversion ratio */
3064 : 0 : uix = DIV_U64(tu_per_sec * LINE_UI_10G_40G, 390625000);
3065 : :
3066 : 0 : status = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
3067 : : uix);
3068 [ # # ]: 0 : if (status) {
3069 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, status %d\n",
3070 : : status);
3071 : 0 : return status;
3072 : : }
3073 : :
3074 : : /* Program the 25Gb/100Gb conversion ratio */
3075 : 0 : uix = DIV_U64(tu_per_sec * LINE_UI_25G_100G, 390625000);
3076 : :
3077 : 0 : status = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
3078 : : uix);
3079 [ # # ]: 0 : if (status) {
3080 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, status %d\n",
3081 : : status);
3082 : 0 : return status;
3083 : : }
3084 : :
3085 : : return ICE_SUCCESS;
3086 : : }
3087 : :
3088 : : /**
3089 : : * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle
3090 : : * @hw: pointer to the HW struct
3091 : : * @port: port to configure
3092 : : *
3093 : : * Configure the number of TUs for the PAR and PCS clocks used as part of the
3094 : : * timestamp calibration process. This depends on the link speed, as the PHY
3095 : : * uses different markers depending on the speed.
3096 : : *
3097 : : * 1Gb/10Gb/25Gb:
3098 : : * - Tx/Rx PAR/PCS markers
3099 : : *
3100 : : * 25Gb RS:
3101 : : * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
3102 : : *
3103 : : * 40Gb/50Gb:
3104 : : * - Tx/Rx PAR/PCS markers
3105 : : * - Rx Deskew PAR/PCS markers
3106 : : *
3107 : : * 50G RS and 100GB RS:
3108 : : * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
3109 : : * - Rx Deskew PAR/PCS markers
3110 : : * - Tx PAR/PCS markers
3111 : : *
3112 : : * To calculate the conversion, we use the PHC clock frequency (cycles per
3113 : : * second), the increment value (TUs per cycle), and the related PHY clock
3114 : : * frequency to calculate the TUs per unit of the PHY link clock. The
3115 : : * following table shows how the units convert:
3116 : : *
3117 : : * cycles | TUs | second
3118 : : * -------+-------+--------
3119 : : * second | cycle | cycles
3120 : : *
3121 : : * For each conversion register, look up the appropriate frequency from the
3122 : : * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program
3123 : : * this to the appropriate register, preparing hardware to perform timestamp
3124 : : * calibration to calculate the total Tx or Rx offset to adjust the timestamp
3125 : : * in order to calibrate for the internal PHY delays.
3126 : : *
3127 : : * Note that the increment value ranges up to ~34 bits, and the clock
3128 : : * frequency is ~29 bits, so multiplying them together should fit within the
3129 : : * 64 bit arithmetic.
3130 : : */
3131 : 0 : static enum ice_status ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
3132 : : {
3133 : : u64 cur_freq, clk_incval, tu_per_sec, phy_tus;
3134 : : enum ice_ptp_link_spd link_spd;
3135 : : enum ice_ptp_fec_mode fec_mode;
3136 : : enum ice_status status;
3137 : :
3138 : 0 : status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
3139 [ # # ]: 0 : if (status)
3140 : : return status;
3141 : :
3142 : : cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
3143 : 0 : clk_incval = ice_ptp_read_src_incval(hw);
3144 : :
3145 : : /* Calculate TUs per cycle of the PHC clock */
3146 : 0 : tu_per_sec = cur_freq * clk_incval;
3147 : :
3148 : : /* For each PHY conversion register, look up the appropriate link
3149 : : * speed frequency and determine the TUs per that clock's cycle time.
3150 : : * Split this into a high and low value and then program the
3151 : : * appropriate register. If that link speed does not use the
3152 : : * associated register, write zeros to clear it instead.
3153 : : */
3154 : :
3155 : : /* P_REG_PAR_TX_TUS */
3156 [ # # ]: 0 : if (e822_vernier[link_spd].tx_par_clk)
3157 : 0 : phy_tus = DIV_U64(tu_per_sec,
3158 : : e822_vernier[link_spd].tx_par_clk);
3159 : : else
3160 : : phy_tus = 0;
3161 : :
3162 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,
3163 : : phy_tus);
3164 [ # # ]: 0 : if (status)
3165 : : return status;
3166 : :
3167 : : /* P_REG_PAR_RX_TUS */
3168 [ # # ]: 0 : if (e822_vernier[link_spd].rx_par_clk)
3169 : 0 : phy_tus = DIV_U64(tu_per_sec,
3170 : : e822_vernier[link_spd].rx_par_clk);
3171 : : else
3172 : : phy_tus = 0;
3173 : :
3174 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,
3175 : : phy_tus);
3176 [ # # ]: 0 : if (status)
3177 : : return status;
3178 : :
3179 : : /* P_REG_PCS_TX_TUS */
3180 [ # # ]: 0 : if (e822_vernier[link_spd].tx_pcs_clk)
3181 : 0 : phy_tus = DIV_U64(tu_per_sec,
3182 : : e822_vernier[link_spd].tx_pcs_clk);
3183 : : else
3184 : : phy_tus = 0;
3185 : :
3186 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,
3187 : : phy_tus);
3188 [ # # ]: 0 : if (status)
3189 : : return status;
3190 : :
3191 : : /* P_REG_PCS_RX_TUS */
3192 [ # # ]: 0 : if (e822_vernier[link_spd].rx_pcs_clk)
3193 : 0 : phy_tus = DIV_U64(tu_per_sec,
3194 : : e822_vernier[link_spd].rx_pcs_clk);
3195 : : else
3196 : : phy_tus = 0;
3197 : :
3198 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,
3199 : : phy_tus);
3200 [ # # ]: 0 : if (status)
3201 : : return status;
3202 : :
3203 : : /* P_REG_DESK_PAR_TX_TUS */
3204 [ # # ]: 0 : if (e822_vernier[link_spd].tx_desk_rsgb_par)
3205 : 0 : phy_tus = DIV_U64(tu_per_sec,
3206 : : e822_vernier[link_spd].tx_desk_rsgb_par);
3207 : : else
3208 : : phy_tus = 0;
3209 : :
3210 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,
3211 : : phy_tus);
3212 [ # # ]: 0 : if (status)
3213 : : return status;
3214 : :
3215 : : /* P_REG_DESK_PAR_RX_TUS */
3216 [ # # ]: 0 : if (e822_vernier[link_spd].rx_desk_rsgb_par)
3217 : 0 : phy_tus = DIV_U64(tu_per_sec,
3218 : : e822_vernier[link_spd].rx_desk_rsgb_par);
3219 : : else
3220 : : phy_tus = 0;
3221 : :
3222 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,
3223 : : phy_tus);
3224 [ # # ]: 0 : if (status)
3225 : : return status;
3226 : :
3227 : : /* P_REG_DESK_PCS_TX_TUS */
3228 [ # # ]: 0 : if (e822_vernier[link_spd].tx_desk_rsgb_pcs)
3229 : 0 : phy_tus = DIV_U64(tu_per_sec,
3230 : : e822_vernier[link_spd].tx_desk_rsgb_pcs);
3231 : : else
3232 : : phy_tus = 0;
3233 : :
3234 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,
3235 : : phy_tus);
3236 [ # # ]: 0 : if (status)
3237 : : return status;
3238 : :
3239 : : /* P_REG_DESK_PCS_RX_TUS */
3240 [ # # ]: 0 : if (e822_vernier[link_spd].rx_desk_rsgb_pcs)
3241 : 0 : phy_tus = DIV_U64(tu_per_sec,
3242 : : e822_vernier[link_spd].rx_desk_rsgb_pcs);
3243 : : else
3244 : : phy_tus = 0;
3245 : :
3246 : 0 : return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,
3247 : : phy_tus);
3248 : : }
3249 : :
3250 : : /**
3251 : : * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port
3252 : : * @hw: pointer to the HW struct
3253 : : * @link_spd: the Link speed to calculate for
3254 : : *
3255 : : * Calculate the fixed offset due to known static latency data.
3256 : : */
3257 : : static u64
3258 : 0 : ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
3259 : : {
3260 : : u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
3261 : :
3262 : : cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
3263 : 0 : clk_incval = ice_ptp_read_src_incval(hw);
3264 : :
3265 : : /* Calculate TUs per second */
3266 : 0 : tu_per_sec = cur_freq * clk_incval;
3267 : :
3268 : : /* Calculate number of TUs to add for the fixed Tx latency. Since the
3269 : : * latency measurement is in 1/100th of a nanosecond, we need to
3270 : : * multiply by tu_per_sec and then divide by 1e11. This calculation
3271 : : * overflows 64 bit integer arithmetic, so break it up into two
3272 : : * divisions by 1e4 first then by 1e7.
3273 : : */
3274 : : fixed_offset = DIV_U64(tu_per_sec, 10000);
3275 : 0 : fixed_offset *= e822_vernier[link_spd].tx_fixed_delay;
3276 : : fixed_offset = DIV_U64(fixed_offset, 10000000);
3277 : :
3278 : 0 : return fixed_offset;
3279 : : }
3280 : :
3281 : : /**
3282 : : * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset
3283 : : * @hw: pointer to the HW struct
3284 : : * @port: the PHY port to configure
3285 : : *
3286 : : * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to
3287 : : * adjust Tx timestamps by. This is calculated by combining some known static
3288 : : * latency along with the Vernier offset computations done by hardware.
3289 : : *
3290 : : * This function must be called only after the offset registers are valid,
3291 : : * i.e. after the Vernier calibration wait has passed, to ensure that the PHY
3292 : : * has measured the offset.
3293 : : *
3294 : : * To avoid overflow, when calculating the offset based on the known static
3295 : : * latency values, we use measurements in 1/100th of a nanosecond, and divide
3296 : : * the TUs per second up front. This avoids overflow while allowing
3297 : : * calculation of the adjustment using integer arithmetic.
3298 : : */
3299 : 0 : enum ice_status ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
3300 : : {
3301 : : enum ice_ptp_link_spd link_spd;
3302 : : enum ice_ptp_fec_mode fec_mode;
3303 : : enum ice_status status;
3304 : : u64 total_offset, val;
3305 : :
3306 : 0 : status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
3307 [ # # ]: 0 : if (status)
3308 : : return status;
3309 : :
3310 : 0 : total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
3311 : :
3312 : : /* Read the first Vernier offset from the PHY register and add it to
3313 : : * the total offset.
3314 : : */
3315 : 0 : if (link_spd == ICE_PTP_LNK_SPD_1G ||
3316 : : link_spd == ICE_PTP_LNK_SPD_10G ||
3317 : : link_spd == ICE_PTP_LNK_SPD_25G ||
3318 : : link_spd == ICE_PTP_LNK_SPD_25G_RS ||
3319 [ # # ]: 0 : link_spd == ICE_PTP_LNK_SPD_40G ||
3320 : : link_spd == ICE_PTP_LNK_SPD_50G) {
3321 : 0 : status = ice_read_64b_phy_reg_e822(hw, port,
3322 : : P_REG_PAR_PCS_TX_OFFSET_L,
3323 : : &val);
3324 [ # # ]: 0 : if (status)
3325 : : return status;
3326 : :
3327 : 0 : total_offset += val;
3328 : : }
3329 : :
3330 : : /* For Tx, we only need to use the second Vernier offset for
3331 : : * multi-lane link speeds with RS-FEC. The lanes will always be
3332 : : * aligned.
3333 : : */
3334 [ # # ]: 0 : if (link_spd == ICE_PTP_LNK_SPD_50G_RS ||
3335 : : link_spd == ICE_PTP_LNK_SPD_100G_RS) {
3336 : 0 : status = ice_read_64b_phy_reg_e822(hw, port,
3337 : : P_REG_PAR_TX_TIME_L,
3338 : : &val);
3339 [ # # ]: 0 : if (status)
3340 : : return status;
3341 : :
3342 : 0 : total_offset += val;
3343 : : }
3344 : :
3345 : : /* Now that the total offset has been calculated, program it to the
3346 : : * PHY and indicate that the Tx offset is ready. After this,
3347 : : * timestamps will be enabled.
3348 : : */
3349 : 0 : status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
3350 : : total_offset);
3351 [ # # ]: 0 : if (status)
3352 : : return status;
3353 : :
3354 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
3355 [ # # ]: 0 : if (status)
3356 : 0 : return status;
3357 : :
3358 : : return ICE_SUCCESS;
3359 : : }
3360 : :
3361 : : /**
3362 : : * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode
3363 : : * @hw: pointer to the HW struct
3364 : : * @port: the PHY port to configure
3365 : : *
3366 : : * Calculate and program the fixed Tx offset, and indicate that the offset is
3367 : : * ready. This can be used when operating in bypass mode.
3368 : : */
3369 : : static enum ice_status
3370 : 0 : ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port)
3371 : : {
3372 : : enum ice_ptp_link_spd link_spd;
3373 : : enum ice_ptp_fec_mode fec_mode;
3374 : : enum ice_status status;
3375 : : u64 total_offset;
3376 : :
3377 : 0 : status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
3378 [ # # ]: 0 : if (status)
3379 : : return status;
3380 : :
3381 : 0 : total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
3382 : :
3383 : : /* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L
3384 : : * register, then indicate that the Tx offset is ready. After this,
3385 : : * timestamps will be enabled.
3386 : : *
3387 : : * Note that this skips including the more precise offsets generated
3388 : : * by the Vernier calibration.
3389 : : */
3390 : 0 : status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
3391 : : total_offset);
3392 [ # # ]: 0 : if (status)
3393 : : return status;
3394 : :
3395 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
3396 [ # # ]: 0 : if (status)
3397 : 0 : return status;
3398 : :
3399 : : return ICE_SUCCESS;
3400 : : }
3401 : :
3402 : : /**
3403 : : * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx
3404 : : * @hw: pointer to the HW struct
3405 : : * @port: the PHY port to adjust for
3406 : : * @link_spd: the current link speed of the PHY
3407 : : * @fec_mode: the current FEC mode of the PHY
3408 : : * @pmd_adj: on return, the amount to adjust the Rx total offset by
3409 : : *
3410 : : * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY.
3411 : : * This varies by link speed and FEC mode. The value calculated accounts for
3412 : : * various delays caused when receiving a packet.
3413 : : */
3414 : : static enum ice_status
3415 : 0 : ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
3416 : : enum ice_ptp_link_spd link_spd,
3417 : : enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj)
3418 : : {
3419 : : u64 cur_freq, clk_incval, tu_per_sec, mult, adj;
3420 : : u32 pmd_adj_divisor, val;
3421 : : enum ice_status status;
3422 : : u8 pmd_align;
3423 : :
3424 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val);
3425 [ # # ]: 0 : if (status) {
3426 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, status %d\n",
3427 : : status);
3428 : 0 : return status;
3429 : : }
3430 : :
3431 : 0 : pmd_align = (u8)val;
3432 : :
3433 : : cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
3434 : 0 : clk_incval = ice_ptp_read_src_incval(hw);
3435 : :
3436 : : /* Calculate TUs per second */
3437 : 0 : tu_per_sec = cur_freq * clk_incval;
3438 : :
3439 : : /* Get the link speed dependent PMD adjustment divisor */
3440 : 0 : pmd_adj_divisor = e822_vernier[link_spd].pmd_adj_divisor;
3441 : :
3442 : : /* The PMD alignment adjustment measurement depends on the link speed,
3443 : : * and whether FEC is enabled. For each link speed, the alignment
3444 : : * adjustment is calculated by dividing a value by the length of
3445 : : * a Time Unit in nanoseconds.
3446 : : *
3447 : : * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8
3448 : : * 10G: align == 65 ? 0 : (align * 0.1 * 32/33)
3449 : : * 10G w/FEC: align * 0.1 * 32/33
3450 : : * 25G: align == 65 ? 0 : (align * 0.4 * 32/33)
3451 : : * 25G w/FEC: align * 0.4 * 32/33
3452 : : * 40G: align == 65 ? 0 : (align * 0.1 * 32/33)
3453 : : * 40G w/FEC: align * 0.1 * 32/33
3454 : : * 50G: align == 65 ? 0 : (align * 0.4 * 32/33)
3455 : : * 50G w/FEC: align * 0.8 * 32/33
3456 : : *
3457 : : * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33.
3458 : : *
3459 : : * To allow for calculating this value using integer arithmetic, we
3460 : : * instead start with the number of TUs per second, (inverse of the
3461 : : * length of a Time Unit in nanoseconds), multiply by a value based
3462 : : * on the PMD alignment register, and then divide by the right value
3463 : : * calculated based on the table above. To avoid integer overflow this
3464 : : * division is broken up into a step of dividing by 125 first.
3465 : : */
3466 [ # # ]: 0 : if (link_spd == ICE_PTP_LNK_SPD_1G) {
3467 [ # # ]: 0 : if (pmd_align == 4)
3468 : : mult = 10;
3469 : : else
3470 : 0 : mult = (pmd_align + 6) % 10;
3471 : 0 : } else if (link_spd == ICE_PTP_LNK_SPD_10G ||
3472 : 0 : link_spd == ICE_PTP_LNK_SPD_25G ||
3473 [ # # # # ]: 0 : link_spd == ICE_PTP_LNK_SPD_40G ||
3474 : : link_spd == ICE_PTP_LNK_SPD_50G) {
3475 : : /* If Clause 74 FEC, always calculate PMD adjust */
3476 [ # # ]: 0 : if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74)
3477 : 0 : mult = pmd_align;
3478 : : else
3479 : : mult = 0;
3480 : 0 : } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS ||
3481 [ # # # # ]: 0 : link_spd == ICE_PTP_LNK_SPD_50G_RS ||
3482 : : link_spd == ICE_PTP_LNK_SPD_100G_RS) {
3483 [ # # ]: 0 : if (pmd_align < 17)
3484 : 0 : mult = pmd_align + 40;
3485 : : else
3486 : 0 : mult = pmd_align;
3487 : : } else {
3488 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n",
3489 : : link_spd);
3490 : : mult = 0;
3491 : : }
3492 : :
3493 : : /* In some cases, there's no need to adjust for the PMD alignment */
3494 [ # # ]: 0 : if (!mult) {
3495 : 0 : *pmd_adj = 0;
3496 : 0 : return ICE_SUCCESS;
3497 : : }
3498 : :
3499 : : /* Calculate the adjustment by multiplying TUs per second by the
3500 : : * appropriate multiplier and divisor. To avoid overflow, we first
3501 : : * divide by 125, and then handle remaining divisor based on the link
3502 : : * speed pmd_adj_divisor value.
3503 : : */
3504 : : adj = DIV_U64(tu_per_sec, 125);
3505 : 0 : adj *= mult;
3506 : 0 : adj = DIV_U64(adj, pmd_adj_divisor);
3507 : :
3508 : : /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx
3509 : : * cycle count is necessary.
3510 : : */
3511 [ # # ]: 0 : if (link_spd == ICE_PTP_LNK_SPD_25G_RS) {
3512 : : u64 cycle_adj;
3513 : : u8 rx_cycle;
3514 : :
3515 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT,
3516 : : &val);
3517 [ # # ]: 0 : if (status) {
3518 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, status %d\n",
3519 : : status);
3520 : 0 : return status;
3521 : : }
3522 : :
3523 : 0 : rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M;
3524 [ # # ]: 0 : if (rx_cycle) {
3525 : 0 : mult = (4 - rx_cycle) * 40;
3526 : :
3527 : : cycle_adj = DIV_U64(tu_per_sec, 125);
3528 : 0 : cycle_adj *= mult;
3529 : : cycle_adj = DIV_U64(cycle_adj, pmd_adj_divisor);
3530 : :
3531 : 0 : adj += cycle_adj;
3532 : : }
3533 [ # # ]: 0 : } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) {
3534 : : u64 cycle_adj;
3535 : : u8 rx_cycle;
3536 : :
3537 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT,
3538 : : &val);
3539 [ # # ]: 0 : if (status) {
3540 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, status %d\n",
3541 : : status);
3542 : 0 : return status;
3543 : : }
3544 : :
3545 : 0 : rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M;
3546 [ # # ]: 0 : if (rx_cycle) {
3547 : : mult = rx_cycle * 40;
3548 : :
3549 : : cycle_adj = DIV_U64(tu_per_sec, 125);
3550 : 0 : cycle_adj *= mult;
3551 : : cycle_adj = DIV_U64(cycle_adj, pmd_adj_divisor);
3552 : :
3553 : 0 : adj += cycle_adj;
3554 : : }
3555 : : }
3556 : :
3557 : : /* Return the calculated adjustment */
3558 : 0 : *pmd_adj = adj;
3559 : :
3560 : 0 : return ICE_SUCCESS;
3561 : : }
3562 : :
3563 : : /**
3564 : : * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port
3565 : : * @hw: pointer to HW struct
3566 : : * @link_spd: The Link speed to calculate for
3567 : : *
3568 : : * Determine the fixed Rx latency for a given link speed.
3569 : : */
3570 : : static u64
3571 : 0 : ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
3572 : : {
3573 : : u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
3574 : :
3575 : : cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
3576 : 0 : clk_incval = ice_ptp_read_src_incval(hw);
3577 : :
3578 : : /* Calculate TUs per second */
3579 : 0 : tu_per_sec = cur_freq * clk_incval;
3580 : :
3581 : : /* Calculate number of TUs to add for the fixed Rx latency. Since the
3582 : : * latency measurement is in 1/100th of a nanosecond, we need to
3583 : : * multiply by tu_per_sec and then divide by 1e11. This calculation
3584 : : * overflows 64 bit integer arithmetic, so break it up into two
3585 : : * divisions by 1e4 first then by 1e7.
3586 : : */
3587 : : fixed_offset = DIV_U64(tu_per_sec, 10000);
3588 : 0 : fixed_offset *= e822_vernier[link_spd].rx_fixed_delay;
3589 : : fixed_offset = DIV_U64(fixed_offset, 10000000);
3590 : :
3591 : 0 : return fixed_offset;
3592 : : }
3593 : :
3594 : : /**
3595 : : * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset
3596 : : * @hw: pointer to the HW struct
3597 : : * @port: the PHY port to configure
3598 : : *
3599 : : * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to
3600 : : * adjust Rx timestamps by. This combines calculations from the Vernier offset
3601 : : * measurements taken in hardware with some data about known fixed delay as
3602 : : * well as adjusting for multi-lane alignment delay.
3603 : : *
3604 : : * This function must be called only after the offset registers are valid,
3605 : : * i.e. after the Vernier calibration wait has passed, to ensure that the PHY
3606 : : * has measured the offset.
3607 : : *
3608 : : * To avoid overflow, when calculating the offset based on the known static
3609 : : * latency values, we use measurements in 1/100th of a nanosecond, and divide
3610 : : * the TUs per second up front. This avoids overflow while allowing
3611 : : * calculation of the adjustment using integer arithmetic.
3612 : : */
3613 : 0 : enum ice_status ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
3614 : : {
3615 : : enum ice_ptp_link_spd link_spd;
3616 : : enum ice_ptp_fec_mode fec_mode;
3617 : : u64 total_offset, pmd, val;
3618 : : enum ice_status status;
3619 : :
3620 : 0 : status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
3621 [ # # ]: 0 : if (status)
3622 : : return status;
3623 : :
3624 : 0 : total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
3625 : :
3626 : : /* Read the first Vernier offset from the PHY register and add it to
3627 : : * the total offset.
3628 : : */
3629 : 0 : status = ice_read_64b_phy_reg_e822(hw, port,
3630 : : P_REG_PAR_PCS_RX_OFFSET_L,
3631 : : &val);
3632 [ # # ]: 0 : if (status)
3633 : : return status;
3634 : :
3635 : 0 : total_offset += val;
3636 : :
3637 : : /* For Rx, all multi-lane link speeds include a second Vernier
3638 : : * calibration, because the lanes might not be aligned.
3639 : : */
3640 : 0 : if (link_spd == ICE_PTP_LNK_SPD_40G ||
3641 : : link_spd == ICE_PTP_LNK_SPD_50G ||
3642 [ # # ]: 0 : link_spd == ICE_PTP_LNK_SPD_50G_RS ||
3643 : : link_spd == ICE_PTP_LNK_SPD_100G_RS) {
3644 : 0 : status = ice_read_64b_phy_reg_e822(hw, port,
3645 : : P_REG_PAR_RX_TIME_L,
3646 : : &val);
3647 [ # # ]: 0 : if (status)
3648 : : return status;
3649 : :
3650 : 0 : total_offset += val;
3651 : : }
3652 : :
3653 : : /* In addition, Rx must account for the PMD alignment */
3654 : 0 : status = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd);
3655 [ # # ]: 0 : if (status)
3656 : : return status;
3657 : :
3658 : : /* For RS-FEC, this adjustment adds delay, but for other modes, it
3659 : : * subtracts delay.
3660 : : */
3661 [ # # ]: 0 : if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC)
3662 : 0 : total_offset += pmd;
3663 : : else
3664 : 0 : total_offset -= pmd;
3665 : :
3666 : : /* Now that the total offset has been calculated, program it to the
3667 : : * PHY and indicate that the Rx offset is ready. After this,
3668 : : * timestamps will be enabled.
3669 : : */
3670 : 0 : status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
3671 : : total_offset);
3672 [ # # ]: 0 : if (status)
3673 : : return status;
3674 : :
3675 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
3676 [ # # ]: 0 : if (status)
3677 : 0 : return status;
3678 : :
3679 : : return ICE_SUCCESS;
3680 : : }
3681 : :
3682 : : /**
3683 : : * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode
3684 : : * @hw: pointer to the HW struct
3685 : : * @port: the PHY port to configure
3686 : : *
3687 : : * Calculate and program the fixed Rx offset, and indicate that the offset is
3688 : : * ready. This can be used when operating in bypass mode.
3689 : : */
3690 : : static enum ice_status
3691 : 0 : ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port)
3692 : : {
3693 : : enum ice_ptp_link_spd link_spd;
3694 : : enum ice_ptp_fec_mode fec_mode;
3695 : : enum ice_status status;
3696 : : u64 total_offset;
3697 : :
3698 : 0 : status = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
3699 [ # # ]: 0 : if (status)
3700 : : return status;
3701 : :
3702 : 0 : total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
3703 : :
3704 : : /* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L
3705 : : * register, then indicate that the Rx offset is ready. After this,
3706 : : * timestamps will be enabled.
3707 : : *
3708 : : * Note that this skips including the more precise offsets generated
3709 : : * by Vernier calibration.
3710 : : */
3711 : 0 : status = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
3712 : : total_offset);
3713 [ # # ]: 0 : if (status)
3714 : : return status;
3715 : :
3716 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
3717 [ # # ]: 0 : if (status)
3718 : 0 : return status;
3719 : :
3720 : : return ICE_SUCCESS;
3721 : : }
3722 : :
3723 : : /**
3724 : : * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time
3725 : : * @hw: pointer to the HW struct
3726 : : * @port: the PHY port to read
3727 : : * @phy_time: on return, the 64bit PHY timer value
3728 : : * @phc_time: on return, the lower 64bits of PHC time
3729 : : *
3730 : : * Issue a ICE_PTP_READ_TIME timer command to simultaneously capture the PHY
3731 : : * and PHC timer values.
3732 : : */
3733 : : static enum ice_status
3734 : 0 : ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
3735 : : u64 *phc_time)
3736 : : {
3737 : : enum ice_status status;
3738 : : u64 tx_time, rx_time;
3739 : : u32 zo, lo;
3740 : : u8 tmr_idx;
3741 : :
3742 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
3743 : :
3744 : : /* Prepare the PHC timer for a ICE_PTP_READ_TIME capture command */
3745 : 0 : ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
3746 : :
3747 : : /* Prepare the PHY timer for a ICE_PTP_READ_TIME capture command */
3748 : 0 : status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_READ_TIME, true);
3749 [ # # ]: 0 : if (status)
3750 : : return status;
3751 : :
3752 : : /* Issue the sync to start the ICE_PTP_READ_TIME capture */
3753 : : ice_ptp_exec_tmr_cmd(hw);
3754 : : ice_ptp_clean_cmd(hw);
3755 : :
3756 : : /* Read the captured PHC time from the shadow time registers */
3757 : 0 : zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
3758 : 0 : lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
3759 : 0 : *phc_time = (u64)lo << 32 | zo;
3760 : :
3761 : : /* Read the captured PHY time from the PHY shadow registers */
3762 : 0 : status = ice_ptp_read_port_capture_e822(hw, port, &tx_time, &rx_time);
3763 [ # # ]: 0 : if (status)
3764 : : return status;
3765 : :
3766 : : /* If the PHY Tx and Rx timers don't match, log a warning message.
3767 : : * Note that this should not happen in normal circumstances since the
3768 : : * driver always programs them together.
3769 : : */
3770 [ # # ]: 0 : if (tx_time != rx_time)
3771 [ # # ]: 0 : ice_warn(hw, "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n",
3772 : : port, (unsigned long long)tx_time,
3773 : : (unsigned long long)rx_time);
3774 : :
3775 : 0 : *phy_time = tx_time;
3776 : :
3777 : 0 : return ICE_SUCCESS;
3778 : : }
3779 : :
3780 : : /**
3781 : : * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer
3782 : : * @hw: pointer to the HW struct
3783 : : * @port: the PHY port to synchronize
3784 : : *
3785 : : * Perform an adjustment to ensure that the PHY and PHC timers are in sync.
3786 : : * This is done by issuing a ICE_PTP_READ_TIME command which triggers a
3787 : : * simultaneous read of the PHY timer and PHC timer. Then we use the
3788 : : * difference to calculate an appropriate 2s complement addition to add
3789 : : * to the PHY timer in order to ensure it reads the same value as the
3790 : : * primary PHC timer.
3791 : : */
3792 : 0 : static enum ice_status ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
3793 : : {
3794 : : u64 phc_time, phy_time, difference;
3795 : : enum ice_status status;
3796 : :
3797 [ # # ]: 0 : if (!ice_ptp_lock(hw)) {
3798 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n");
3799 : 0 : return ICE_ERR_NOT_READY;
3800 : : }
3801 : :
3802 : 0 : status = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
3803 [ # # ]: 0 : if (status)
3804 : 0 : goto err_unlock;
3805 : :
3806 : : /* Calculate the amount required to add to the port time in order for
3807 : : * it to match the PHC time.
3808 : : *
3809 : : * Note that the port adjustment is done using 2s complement
3810 : : * arithmetic. This is convenient since it means that we can simply
3811 : : * calculate the difference between the PHC time and the port time,
3812 : : * and it will be interpreted correctly.
3813 : : */
3814 : 0 : difference = phc_time - phy_time;
3815 : :
3816 : 0 : status = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference, true);
3817 [ # # ]: 0 : if (status)
3818 : 0 : goto err_unlock;
3819 : :
3820 : 0 : status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_ADJ_TIME, true);
3821 [ # # ]: 0 : if (status)
3822 : 0 : goto err_unlock;
3823 : :
3824 : : /* Init PHC mstr/src cmd for exec during sync */
3825 : 0 : ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
3826 : :
3827 : : /* Issue the sync to activate the time adjustment */
3828 : : ice_ptp_exec_tmr_cmd(hw);
3829 : : ice_ptp_clean_cmd(hw);
3830 : :
3831 : : /* Re-capture the timer values to flush the command registers and
3832 : : * verify that the time was properly adjusted.
3833 : : */
3834 : 0 : status = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
3835 [ # # ]: 0 : if (status)
3836 : 0 : goto err_unlock;
3837 : :
3838 [ # # ]: 0 : ice_info(hw, "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n",
3839 : : port, (unsigned long long)phy_time,
3840 : : (unsigned long long)phc_time);
3841 : :
3842 : 0 : ice_ptp_unlock(hw);
3843 : :
3844 : 0 : return ICE_SUCCESS;
3845 : :
3846 : 0 : err_unlock:
3847 : 0 : ice_ptp_unlock(hw);
3848 : 0 : return status;
3849 : : }
3850 : :
3851 : : /**
3852 : : * ice_stop_phy_timer_e822 - Stop the PHY clock timer
3853 : : * @hw: pointer to the HW struct
3854 : : * @port: the PHY port to stop
3855 : : * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS
3856 : : *
3857 : : * Stop the clock of a PHY port. This must be done as part of the flow to
3858 : : * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
3859 : : * initialized or when link speed changes.
3860 : : */
3861 : : enum ice_status
3862 : 0 : ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
3863 : : {
3864 : : enum ice_status status;
3865 : : u32 val;
3866 : :
3867 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);
3868 [ # # ]: 0 : if (status)
3869 : : return status;
3870 : :
3871 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);
3872 [ # # ]: 0 : if (status)
3873 : : return status;
3874 : :
3875 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
3876 [ # # ]: 0 : if (status)
3877 : : return status;
3878 : :
3879 : 0 : val &= ~P_REG_PS_START_M;
3880 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3881 [ # # ]: 0 : if (status)
3882 : : return status;
3883 : :
3884 : 0 : val &= ~P_REG_PS_ENA_CLK_M;
3885 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3886 [ # # ]: 0 : if (status)
3887 : : return status;
3888 : :
3889 [ # # ]: 0 : if (soft_reset) {
3890 : 0 : val |= P_REG_PS_SFT_RESET_M;
3891 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3892 [ # # ]: 0 : if (status)
3893 : : return status;
3894 : : }
3895 : :
3896 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port);
3897 : :
3898 : : return ICE_SUCCESS;
3899 : : }
3900 : :
3901 : : /**
3902 : : * ice_start_phy_timer_e822 - Start the PHY clock timer
3903 : : * @hw: pointer to the HW struct
3904 : : * @port: the PHY port to start
3905 : : * @bypass: if true, start the PHY in bypass mode
3906 : : *
3907 : : * Start the clock of a PHY port. This must be done as part of the flow to
3908 : : * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
3909 : : * initialized or when link speed changes.
3910 : : *
3911 : : * Bypass mode enables timestamps immediately without waiting for Vernier
3912 : : * calibration to complete. Hardware will still continue taking Vernier
3913 : : * measurements on Tx or Rx of packets, but they will not be applied to
3914 : : * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware
3915 : : * has completed offset calculation.
3916 : : */
3917 : : enum ice_status
3918 : 0 : ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass)
3919 : : {
3920 : : enum ice_status status;
3921 : : u32 lo, hi, val;
3922 : : u64 incval;
3923 : : u8 tmr_idx;
3924 : :
3925 : : ice_ptp_clean_cmd(hw);
3926 : 0 : tmr_idx = ice_get_ptp_src_clock_index(hw);
3927 : :
3928 : 0 : status = ice_stop_phy_timer_e822(hw, port, false);
3929 [ # # ]: 0 : if (status)
3930 : : return status;
3931 : :
3932 : 0 : ice_phy_cfg_lane_e822(hw, port);
3933 : :
3934 : 0 : status = ice_phy_cfg_uix_e822(hw, port);
3935 [ # # ]: 0 : if (status)
3936 : : return status;
3937 : :
3938 : 0 : status = ice_phy_cfg_parpcs_e822(hw, port);
3939 [ # # ]: 0 : if (status)
3940 : : return status;
3941 : :
3942 : 0 : lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
3943 : 0 : hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
3944 : 0 : incval = (u64)hi << 32 | lo;
3945 : :
3946 : 0 : status = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
3947 [ # # ]: 0 : if (status)
3948 : : return status;
3949 : :
3950 : 0 : status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_INIT_INCVAL, true);
3951 [ # # ]: 0 : if (status)
3952 : : return status;
3953 : :
3954 : : /* Init PHC mstr/src cmd for exec during sync */
3955 : 0 : ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
3956 : :
3957 : : ice_ptp_exec_tmr_cmd(hw);
3958 : :
3959 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
3960 [ # # ]: 0 : if (status)
3961 : : return status;
3962 : :
3963 : 0 : val |= P_REG_PS_SFT_RESET_M;
3964 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3965 [ # # ]: 0 : if (status)
3966 : : return status;
3967 : :
3968 : 0 : val |= P_REG_PS_START_M;
3969 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3970 [ # # ]: 0 : if (status)
3971 : : return status;
3972 : :
3973 : 0 : val &= ~P_REG_PS_SFT_RESET_M;
3974 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3975 [ # # ]: 0 : if (status)
3976 : : return status;
3977 : :
3978 : 0 : status = ice_ptp_one_port_cmd_e822(hw, port, ICE_PTP_INIT_INCVAL, true);
3979 [ # # ]: 0 : if (status)
3980 : : return status;
3981 : :
3982 : : ice_ptp_exec_tmr_cmd(hw);
3983 : :
3984 : 0 : val |= P_REG_PS_ENA_CLK_M;
3985 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3986 [ # # ]: 0 : if (status)
3987 : : return status;
3988 : :
3989 : 0 : val |= P_REG_PS_LOAD_OFFSET_M;
3990 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
3991 [ # # ]: 0 : if (status)
3992 : : return status;
3993 : :
3994 : : ice_ptp_exec_tmr_cmd(hw);
3995 : :
3996 : 0 : status = ice_sync_phy_timer_e822(hw, port);
3997 [ # # ]: 0 : if (status)
3998 : : return status;
3999 : :
4000 [ # # ]: 0 : if (bypass) {
4001 : 0 : val |= P_REG_PS_BYPASS_MODE_M;
4002 : : /* Enter BYPASS mode, enabling timestamps immediately. */
4003 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
4004 [ # # ]: 0 : if (status)
4005 : : return status;
4006 : :
4007 : : /* Program the fixed Tx offset */
4008 : 0 : status = ice_phy_cfg_fixed_tx_offset_e822(hw, port);
4009 [ # # ]: 0 : if (status)
4010 : : return status;
4011 : :
4012 : : /* Program the fixed Rx offset */
4013 : 0 : status = ice_phy_cfg_fixed_rx_offset_e822(hw, port);
4014 [ # # ]: 0 : if (status)
4015 : : return status;
4016 : : }
4017 : :
4018 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
4019 : :
4020 : : return ICE_SUCCESS;
4021 : : }
4022 : :
4023 : : /**
4024 : : * ice_phy_exit_bypass_e822 - Exit bypass mode, after vernier calculations
4025 : : * @hw: pointer to the HW struct
4026 : : * @port: the PHY port to configure
4027 : : *
4028 : : * After hardware finishes vernier calculations for the Tx and Rx offset, this
4029 : : * function can be used to exit bypass mode by updating the total Tx and Rx
4030 : : * offsets, and then disabling bypass. This will enable hardware to include
4031 : : * the more precise offset calibrations, increasing precision of the generated
4032 : : * timestamps.
4033 : : *
4034 : : * This cannot be done until hardware has measured the offsets, which requires
4035 : : * waiting until at least one packet has been sent and received by the device.
4036 : : */
4037 : 0 : enum ice_status ice_phy_exit_bypass_e822(struct ice_hw *hw, u8 port)
4038 : : {
4039 : : enum ice_status status;
4040 : : u32 val;
4041 : :
4042 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val);
4043 [ # # ]: 0 : if (status) {
4044 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, status %d\n",
4045 : : port, status);
4046 : 0 : return status;
4047 : : }
4048 : :
4049 [ # # ]: 0 : if (!(val & P_REG_TX_OV_STATUS_OV_M)) {
4050 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n",
4051 : : port);
4052 : 0 : return ICE_ERR_NOT_READY;
4053 : : }
4054 : :
4055 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val);
4056 [ # # ]: 0 : if (status) {
4057 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, status %d\n",
4058 : : port, status);
4059 : 0 : return status;
4060 : : }
4061 : :
4062 [ # # ]: 0 : if (!(val & P_REG_TX_OV_STATUS_OV_M)) {
4063 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n",
4064 : : port);
4065 : 0 : return ICE_ERR_NOT_READY;
4066 : : }
4067 : :
4068 : 0 : status = ice_phy_cfg_tx_offset_e822(hw, port);
4069 [ # # ]: 0 : if (status) {
4070 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, status %d\n",
4071 : : port, status);
4072 : 0 : return status;
4073 : : }
4074 : :
4075 : 0 : status = ice_phy_cfg_rx_offset_e822(hw, port);
4076 [ # # ]: 0 : if (status) {
4077 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, status %d\n",
4078 : : port, status);
4079 : 0 : return status;
4080 : : }
4081 : :
4082 : : /* Exit bypass mode now that the offset has been updated */
4083 : 0 : status = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
4084 [ # # ]: 0 : if (status) {
4085 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read P_REG_PS for port %u, status %d\n",
4086 : : port, status);
4087 : 0 : return status;
4088 : : }
4089 : :
4090 [ # # ]: 0 : if (!(val & P_REG_PS_BYPASS_MODE_M))
4091 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Port %u not in bypass mode\n",
4092 : : port);
4093 : :
4094 : 0 : val &= ~P_REG_PS_BYPASS_MODE_M;
4095 : 0 : status = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
4096 [ # # ]: 0 : if (status) {
4097 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to disable bypass for port %u, status %d\n",
4098 : : port, status);
4099 : 0 : return status;
4100 : : }
4101 : :
4102 [ # # ]: 0 : ice_info(hw, "Exiting bypass mode on PHY port %u\n", port);
4103 : :
4104 : : return ICE_SUCCESS;
4105 : : }
4106 : :
4107 : : /* E810 functions
4108 : : *
4109 : : * The following functions operate on the E810 series devices which use
4110 : : * a separate external PHY.
4111 : : */
4112 : :
4113 : : /**
4114 : : * ice_read_phy_reg_e810_lp - Read register from external PHY on E810
4115 : : * @hw: pointer to the HW struct
4116 : : * @addr: the address to read from
4117 : : * @val: On return, the value read from the PHY
4118 : : * @lock_sbq: true if the sideband queue lock must be acquired
4119 : : *
4120 : : * Read a register from the external PHY on the E810 device.
4121 : : */
4122 : : static enum ice_status
4123 : 0 : ice_read_phy_reg_e810_lp(struct ice_hw *hw, u32 addr, u32 *val, bool lock_sbq)
4124 : : {
4125 : 0 : struct ice_sbq_msg_input msg = {0};
4126 : : enum ice_status status;
4127 : :
4128 : 0 : msg.msg_addr_low = ICE_LO_WORD(addr);
4129 : 0 : msg.msg_addr_high = ICE_HI_WORD(addr);
4130 : : msg.opcode = ice_sbq_msg_rd;
4131 : 0 : msg.dest_dev = rmn_0;
4132 : :
4133 : 0 : status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
4134 [ # # ]: 0 : if (status) {
4135 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
4136 : : status);
4137 : 0 : return status;
4138 : : }
4139 : :
4140 : 0 : *val = msg.data;
4141 : :
4142 : 0 : return ICE_SUCCESS;
4143 : : }
4144 : :
4145 : : static enum ice_status
4146 : : ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
4147 : : {
4148 : 0 : return ice_read_phy_reg_e810_lp(hw, addr, val, true);
4149 : : }
4150 : :
4151 : : /**
4152 : : * ice_write_phy_reg_e810_lp - Write register on external PHY on E810
4153 : : * @hw: pointer to the HW struct
4154 : : * @addr: the address to writem to
4155 : : * @val: the value to write to the PHY
4156 : : * @lock_sbq: true if the sideband queue lock must be acquired
4157 : : *
4158 : : * Write a value to a register of the external PHY on the E810 device.
4159 : : */
4160 : : static enum ice_status
4161 : 0 : ice_write_phy_reg_e810_lp(struct ice_hw *hw, u32 addr, u32 val, bool lock_sbq)
4162 : : {
4163 : : struct ice_sbq_msg_input msg = {0};
4164 : : enum ice_status status;
4165 : :
4166 : 0 : msg.msg_addr_low = ICE_LO_WORD(addr);
4167 : 0 : msg.msg_addr_high = ICE_HI_WORD(addr);
4168 : 0 : msg.opcode = ice_sbq_msg_wr;
4169 : 0 : msg.dest_dev = rmn_0;
4170 : 0 : msg.data = val;
4171 : :
4172 : 0 : status = ice_sbq_rw_reg_lp(hw, &msg, lock_sbq);
4173 [ # # ]: 0 : if (status) {
4174 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to send message to phy, status %d\n",
4175 : : status);
4176 : 0 : return status;
4177 : : }
4178 : :
4179 : : return ICE_SUCCESS;
4180 : : }
4181 : :
4182 : : static enum ice_status
4183 : : ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
4184 : : {
4185 : 0 : return ice_write_phy_reg_e810_lp(hw, addr, val, true);
4186 : : }
4187 : :
4188 : : /**
4189 : : * ice_read_phy_tstamp_ll_e810 - Read a PHY timestamp registers through the FW
4190 : : * @hw: pointer to the HW struct
4191 : : * @idx: the timestamp index to read
4192 : : * @hi: 8 bit timestamp high value
4193 : : * @lo: 32 bit timestamp low value
4194 : : *
4195 : : * Read a 8bit timestamp high value and 32 bit timestamp low value out of the
4196 : : * timestamp block of the external PHY on the E810 device using the low latency
4197 : : * timestamp read.
4198 : : */
4199 : : static enum ice_status
4200 : 0 : ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
4201 : : {
4202 : : u8 i;
4203 : :
4204 : : /* Write TS index to read to the PF register so the FW can read it */
4205 : 0 : wr32(hw, PF_SB_ATQBAL, TS_LL_READ_TS_IDX(idx));
4206 : :
4207 : : /* Read the register repeatedly until the FW provides us the TS */
4208 [ # # ]: 0 : for (i = TS_LL_READ_RETRIES; i > 0; i--) {
4209 : 0 : u32 val = rd32(hw, PF_SB_ATQBAL);
4210 : :
4211 : : /* When the bit is cleared, the TS is ready in the register */
4212 [ # # ]: 0 : if (!(val & TS_LL_READ_TS)) {
4213 : : /* High 8 bit value of the TS is on the bits 16:23 */
4214 : 0 : *hi = (u8)(val >> TS_LL_READ_TS_HIGH_S);
4215 : :
4216 : : /* Read the low 32 bit value and set the TS valid bit */
4217 : 0 : *lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID;
4218 : 0 : return ICE_SUCCESS;
4219 : : }
4220 : :
4221 : 0 : ice_usec_delay(10, false);
4222 : : }
4223 : :
4224 : : /* FW failed to provide the TS in time */
4225 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
4226 : : return ICE_ERR_NOT_READY;
4227 : : }
4228 : :
4229 : : /**
4230 : : * ice_read_phy_tstamp_sbq_e810 - Read a PHY timestamp registers through the sbq
4231 : : * @hw: pointer to the HW struct
4232 : : * @lport: the lport to read from
4233 : : * @idx: the timestamp index to read
4234 : : * @hi: 8 bit timestamp high value
4235 : : * @lo: 32 bit timestamp low value
4236 : : *
4237 : : * Read a 8bit timestamp high value and 32 bit timestamp low value out of the
4238 : : * timestamp block of the external PHY on the E810 device using sideband queue.
4239 : : */
4240 : : static enum ice_status
4241 : 0 : ice_read_phy_tstamp_sbq_e810(struct ice_hw *hw, u8 lport, u8 idx, u8 *hi,
4242 : : u32 *lo)
4243 : : {
4244 : 0 : u32 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
4245 : 0 : u32 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
4246 : : enum ice_status status;
4247 : : u32 lo_val, hi_val;
4248 : :
4249 : : status = ice_read_phy_reg_e810(hw, lo_addr, &lo_val);
4250 [ # # ]: 0 : if (status) {
4251 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
4252 : : status);
4253 : 0 : return status;
4254 : : }
4255 : :
4256 : : status = ice_read_phy_reg_e810(hw, hi_addr, &hi_val);
4257 [ # # ]: 0 : if (status) {
4258 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
4259 : : status);
4260 : 0 : return status;
4261 : : }
4262 : :
4263 : 0 : *lo = lo_val;
4264 : 0 : *hi = (u8)hi_val;
4265 : :
4266 : 0 : return ICE_SUCCESS;
4267 : : }
4268 : :
4269 : : /**
4270 : : * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
4271 : : * @hw: pointer to the HW struct
4272 : : * @lport: the lport to read from
4273 : : * @idx: the timestamp index to read
4274 : : * @tstamp: on return, the 40bit timestamp value
4275 : : *
4276 : : * Read a 40bit timestamp value out of the timestamp block of the external PHY
4277 : : * on the E810 device.
4278 : : */
4279 : : static enum ice_status
4280 : 0 : ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
4281 : : {
4282 : : enum ice_status status;
4283 : 0 : u32 lo = 0;
4284 : 0 : u8 hi = 0;
4285 : :
4286 [ # # ]: 0 : if (hw->dev_caps.ts_dev_info.ts_ll_read)
4287 : 0 : status = ice_read_phy_tstamp_ll_e810(hw, idx, &hi, &lo);
4288 : : else
4289 : 0 : status = ice_read_phy_tstamp_sbq_e810(hw, lport, idx, &hi, &lo);
4290 : :
4291 [ # # ]: 0 : if (status)
4292 : : return status;
4293 : :
4294 : : /* For E810 devices, the timestamp is reported with the lower 32 bits
4295 : : * in the low register, and the upper 8 bits in the high register.
4296 : : */
4297 : 0 : *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
4298 : :
4299 : 0 : return ICE_SUCCESS;
4300 : : }
4301 : :
4302 : : /**
4303 : : * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
4304 : : * @hw: pointer to the HW struct
4305 : : * @lport: the lport to read from
4306 : : * @idx: the timestamp index to reset
4307 : : *
4308 : : * Clear a timestamp, resetting its valid bit, from the timestamp block of the
4309 : : * external PHY on the E810 device.
4310 : : */
4311 : : static enum ice_status
4312 : 0 : ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
4313 : : {
4314 : : enum ice_status status;
4315 : : u32 lo_addr, hi_addr;
4316 : :
4317 : 0 : lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
4318 : 0 : hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
4319 : :
4320 : : status = ice_write_phy_reg_e810(hw, lo_addr, 0);
4321 [ # # ]: 0 : if (status) {
4322 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
4323 : : status);
4324 : 0 : return status;
4325 : : }
4326 : :
4327 : : status = ice_write_phy_reg_e810(hw, hi_addr, 0);
4328 [ # # ]: 0 : if (status) {
4329 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, status %d\n",
4330 : : status);
4331 : 0 : return status;
4332 : : }
4333 : :
4334 : : return ICE_SUCCESS;
4335 : : }
4336 : :
4337 : : /**
4338 : : * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
4339 : : * @hw: pointer to HW struct
4340 : : *
4341 : : * Enable the timesync PTP functionality for the external PHY connected to
4342 : : * this function.
4343 : : *
4344 : : * Note there is no equivalent function needed on E822 based devices.
4345 : : */
4346 : 0 : enum ice_status ice_ptp_init_phy_e810(struct ice_hw *hw)
4347 : : {
4348 : : enum ice_status status;
4349 : : u8 tmr_idx;
4350 : :
4351 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4352 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
4353 : : GLTSYN_ENA_TSYN_ENA_M);
4354 [ # # ]: 0 : if (status)
4355 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
4356 : : status);
4357 : :
4358 : 0 : return status;
4359 : : }
4360 : :
4361 : : /**
4362 : : * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization
4363 : : * @hw: pointer to HW struct
4364 : : *
4365 : : * Perform E810-specific PTP hardware clock initialization steps.
4366 : : */
4367 : : static enum ice_status ice_ptp_init_phc_e810(struct ice_hw *hw)
4368 : : {
4369 : : /* Ensure synchronization delay is zero */
4370 : 0 : wr32(hw, GLTSYN_SYNC_DLAY, 0);
4371 : :
4372 : : /* Initialize the PHY */
4373 : 0 : return ice_ptp_init_phy_e810(hw);
4374 : : }
4375 : :
4376 : : /**
4377 : : * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
4378 : : * @hw: Board private structure
4379 : : * @time: Time to initialize the PHY port clock to
4380 : : *
4381 : : * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
4382 : : * initial clock time. The time will not actually be programmed until the
4383 : : * driver issues an ICE_PTP_INIT_TIME command.
4384 : : *
4385 : : * The time value is the upper 32 bits of the PHY timer, usually in units of
4386 : : * nominal nanoseconds.
4387 : : */
4388 : 0 : static enum ice_status ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
4389 : : {
4390 : : enum ice_status status;
4391 : : u8 tmr_idx;
4392 : :
4393 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4394 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
4395 [ # # ]: 0 : if (status) {
4396 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, status %d\n",
4397 : : status);
4398 : 0 : return status;
4399 : : }
4400 : :
4401 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
4402 [ # # ]: 0 : if (status) {
4403 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, status %d\n",
4404 : : status);
4405 : 0 : return status;
4406 : : }
4407 : :
4408 : : return ICE_SUCCESS;
4409 : : }
4410 : :
4411 : : /**
4412 : : * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
4413 : : * @hw: pointer to HW struct
4414 : : * @adj: adjustment value to program
4415 : : * @lock_sbq: true if the sideband queue luck must be acquired
4416 : : *
4417 : : * Prepare the PHY port for an atomic adjustment by programming the PHY
4418 : : * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
4419 : : * is completed by issuing an ICE_PTP_ADJ_TIME sync command.
4420 : : *
4421 : : * The adjustment value only contains the portion used for the upper 32bits of
4422 : : * the PHY timer, usually in units of nominal nanoseconds. Negative
4423 : : * adjustments are supported using 2s complement arithmetic.
4424 : : */
4425 : : static enum ice_status
4426 : 0 : ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj, bool lock_sbq)
4427 : : {
4428 : : enum ice_status status;
4429 : : u8 tmr_idx;
4430 : :
4431 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4432 : :
4433 : : /* Adjustments are represented as signed 2's complement values in
4434 : : * nanoseconds. Sub-nanosecond adjustment is not supported.
4435 : : */
4436 : 0 : status = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_SHADJ_L(tmr_idx),
4437 : : 0, lock_sbq);
4438 [ # # ]: 0 : if (status) {
4439 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, status %d\n",
4440 : : status);
4441 : 0 : return status;
4442 : : }
4443 : :
4444 : 0 : status = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_SHADJ_H(tmr_idx),
4445 : : adj, lock_sbq);
4446 [ # # ]: 0 : if (status) {
4447 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, status %d\n",
4448 : : status);
4449 : 0 : return status;
4450 : : }
4451 : :
4452 : : return ICE_SUCCESS;
4453 : : }
4454 : :
4455 : : /**
4456 : : * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
4457 : : * @hw: pointer to HW struct
4458 : : * @incval: The new 40bit increment value to prepare
4459 : : *
4460 : : * Prepare the PHY port for a new increment value by programming the PHY
4461 : : * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
4462 : : * completed by issuing an ICE_PTP_INIT_INCVAL command.
4463 : : */
4464 : : static enum ice_status
4465 : 0 : ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
4466 : : {
4467 : : enum ice_status status;
4468 : : u32 high, low;
4469 : : u8 tmr_idx;
4470 : :
4471 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4472 : 0 : low = ICE_LO_DWORD(incval);
4473 : 0 : high = ICE_HI_DWORD(incval);
4474 : :
4475 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
4476 [ # # ]: 0 : if (status) {
4477 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, status %d\n",
4478 : : status);
4479 : 0 : return status;
4480 : : }
4481 : :
4482 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
4483 [ # # ]: 0 : if (status) {
4484 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, status %d\n",
4485 : : status);
4486 : 0 : return status;
4487 : : }
4488 : :
4489 : : return ICE_SUCCESS;
4490 : : }
4491 : :
4492 : : /**
4493 : : * ice_ptp_prep_phy_adj_target_e810 - Prepare PHY port with adjust target
4494 : : * @hw: Board private structure
4495 : : * @target_time: Time to trigger the clock adjustment at
4496 : : *
4497 : : * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation for
4498 : : * a target time adjust, which will trigger an adjustment of the clock in the
4499 : : * future. The actual adjustment will occur the next time the PHY port timer
4500 : : * crosses over the provided value after the driver issues an
4501 : : * ICE_PTP_ADJ_TIME_AT_TIME command.
4502 : : *
4503 : : * The time value is the upper 32 bits of the PHY timer, usually in units of
4504 : : * nominal nanoseconds.
4505 : : */
4506 : : static enum ice_status
4507 : 0 : ice_ptp_prep_phy_adj_target_e810(struct ice_hw *hw, u32 target_time)
4508 : : {
4509 : : enum ice_status status;
4510 : : u8 tmr_idx;
4511 : :
4512 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4513 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
4514 [ # # ]: 0 : if (status) {
4515 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write target time to SHTIME_0, status %d\n",
4516 : : status);
4517 : 0 : return status;
4518 : : }
4519 : :
4520 : 0 : status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx),
4521 : : target_time);
4522 [ # # ]: 0 : if (status) {
4523 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write target time to SHTIME_L, status %d\n",
4524 : : status);
4525 : 0 : return status;
4526 : : }
4527 : :
4528 : : return ICE_SUCCESS;
4529 : : }
4530 : :
4531 : : /**
4532 : : * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
4533 : : * @hw: pointer to HW struct
4534 : : * @cmd: Command to be sent to the port
4535 : : * @lock_sbq: true if the sideband queue lock must be acquired
4536 : : *
4537 : : * Prepare the external PHYs connected to this device for a timer sync
4538 : : * command.
4539 : : */
4540 : : static enum ice_status
4541 [ # # ]: 0 : ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd,
4542 : : bool lock_sbq)
4543 : : {
4544 : : enum ice_status status;
4545 : : u32 cmd_val, val;
4546 : :
4547 : : switch (cmd) {
4548 : : case ICE_PTP_INIT_TIME:
4549 : : cmd_val = GLTSYN_CMD_INIT_TIME;
4550 : : break;
4551 : : case ICE_PTP_INIT_INCVAL:
4552 : : cmd_val = GLTSYN_CMD_INIT_INCVAL;
4553 : : break;
4554 : : case ICE_PTP_ADJ_TIME:
4555 : : cmd_val = GLTSYN_CMD_ADJ_TIME;
4556 : : break;
4557 : : case ICE_PTP_ADJ_TIME_AT_TIME:
4558 : : cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
4559 : : break;
4560 : : case ICE_PTP_READ_TIME:
4561 : : cmd_val = GLTSYN_CMD_READ_TIME;
4562 : : break;
4563 : 0 : default:
4564 [ # # ]: 0 : ice_warn(hw, "Unknown timer command %u\n", cmd);
4565 : : return ICE_ERR_PARAM;
4566 : : }
4567 : :
4568 : : /* Read, modify, write */
4569 : 0 : status = ice_read_phy_reg_e810_lp(hw, ETH_GLTSYN_CMD, &val, lock_sbq);
4570 [ # # ]: 0 : if (status) {
4571 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, status %d\n",
4572 : : status);
4573 : 0 : return status;
4574 : : }
4575 : :
4576 : : /* Modify necessary bits only and perform write */
4577 : 0 : val &= ~TS_CMD_MASK_E810;
4578 : 0 : val |= cmd_val;
4579 : :
4580 : 0 : status = ice_write_phy_reg_e810_lp(hw, ETH_GLTSYN_CMD, val, lock_sbq);
4581 [ # # ]: 0 : if (status) {
4582 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, status %d\n",
4583 : : status);
4584 : 0 : return status;
4585 : : }
4586 : :
4587 : : return ICE_SUCCESS;
4588 : : }
4589 : :
4590 : : /* E810T SMA functions
4591 : : *
4592 : : * The following functions operate specifically on E810T hardware and are used
4593 : : * to access the extended GPIOs available.
4594 : : */
4595 : :
4596 : : /**
4597 : : * ice_get_pca9575_handle
4598 : : * @hw: pointer to the hw struct
4599 : : * @pca9575_handle: GPIO controller's handle
4600 : : *
4601 : : * Find and return the GPIO controller's handle in the netlist.
4602 : : * When found - the value will be cached in the hw structure and following calls
4603 : : * will return cached value
4604 : : */
4605 : : static enum ice_status
4606 : 0 : ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
4607 : : {
4608 : : struct ice_aqc_get_link_topo cmd;
4609 : : u8 node_part_number, idx;
4610 : : enum ice_status status;
4611 : : u16 node_handle;
4612 : :
4613 [ # # ]: 0 : if (!hw || !pca9575_handle)
4614 : : return ICE_ERR_PARAM;
4615 : :
4616 : : /* If handle was read previously return cached value */
4617 [ # # ]: 0 : if (hw->io_expander_handle) {
4618 : 0 : *pca9575_handle = hw->io_expander_handle;
4619 : 0 : return ICE_SUCCESS;
4620 : : }
4621 : :
4622 : : memset(&cmd, 0, sizeof(cmd));
4623 : :
4624 : : /* Set node type to GPIO controller */
4625 : 0 : cmd.addr.topo_params.node_type_ctx =
4626 : : (ICE_AQC_LINK_TOPO_NODE_TYPE_M &
4627 : : ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
4628 : :
4629 : : #define SW_PCA9575_SFP_TOPO_IDX 2
4630 : : #define SW_PCA9575_QSFP_TOPO_IDX 1
4631 : :
4632 : : /* Check if the SW IO expander controlling SMA exists in the netlist. */
4633 [ # # ]: 0 : if (hw->device_id == ICE_DEV_ID_E810C_SFP)
4634 : : idx = SW_PCA9575_SFP_TOPO_IDX;
4635 [ # # ]: 0 : else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
4636 : : idx = SW_PCA9575_QSFP_TOPO_IDX;
4637 : : else
4638 : : return ICE_ERR_NOT_SUPPORTED;
4639 : :
4640 : 0 : cmd.addr.topo_params.index = idx;
4641 : :
4642 : 0 : status = ice_aq_get_netlist_node(hw, &cmd, &node_part_number,
4643 : : &node_handle);
4644 [ # # ]: 0 : if (status)
4645 : : return ICE_ERR_NOT_SUPPORTED;
4646 : :
4647 : : /* Verify if we found the right IO expander type */
4648 [ # # ]: 0 : if (node_part_number != ICE_ACQ_GET_LINK_TOPO_NODE_NR_PCA9575)
4649 : : return ICE_ERR_NOT_SUPPORTED;
4650 : :
4651 : : /* If present save the handle and return it */
4652 : 0 : hw->io_expander_handle = node_handle;
4653 : 0 : *pca9575_handle = hw->io_expander_handle;
4654 : :
4655 : 0 : return ICE_SUCCESS;
4656 : : }
4657 : :
4658 : : /**
4659 : : * ice_is_gps_present_e810t
4660 : : * @hw: pointer to the hw struct
4661 : : *
4662 : : * Check if the GPS generic device is present in the netlist
4663 : : */
4664 : 0 : bool ice_is_gps_present_e810t(struct ice_hw *hw)
4665 : : {
4666 [ # # ]: 0 : if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_GPS,
4667 : : ICE_ACQ_GET_LINK_TOPO_NODE_NR_GEN_GPS, NULL))
4668 : 0 : return false;
4669 : :
4670 : : return true;
4671 : : }
4672 : :
4673 : : /**
4674 : : * ice_read_pca9575_reg_e810t
4675 : : * @hw: pointer to the hw struct
4676 : : * @offset: GPIO controller register offset
4677 : : * @data: pointer to data to be read from the GPIO controller
4678 : : *
4679 : : * Read the register from the GPIO controller
4680 : : */
4681 : : enum ice_status
4682 : 0 : ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data)
4683 : : {
4684 : : struct ice_aqc_link_topo_addr link_topo;
4685 : : enum ice_status status;
4686 : : __le16 addr;
4687 : : u16 handle;
4688 : :
4689 : : memset(&link_topo, 0, sizeof(link_topo));
4690 : :
4691 : 0 : status = ice_get_pca9575_handle(hw, &handle);
4692 [ # # ]: 0 : if (status)
4693 : : return status;
4694 : :
4695 : 0 : link_topo.handle = CPU_TO_LE16(handle);
4696 : 0 : link_topo.topo_params.node_type_ctx =
4697 : : (ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED <<
4698 : : ICE_AQC_LINK_TOPO_NODE_CTX_S);
4699 : :
4700 : : addr = CPU_TO_LE16((u16)offset);
4701 : :
4702 : 0 : return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL);
4703 : : }
4704 : :
4705 : : /**
4706 : : * ice_write_pca9575_reg_e810t
4707 : : * @hw: pointer to the hw struct
4708 : : * @offset: GPIO controller register offset
4709 : : * @data: data to be written to the GPIO controller
4710 : : *
4711 : : * Write the data to the GPIO controller register
4712 : : */
4713 : : enum ice_status
4714 : 0 : ice_write_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 data)
4715 : : {
4716 : : struct ice_aqc_link_topo_addr link_topo;
4717 : : enum ice_status status;
4718 : : __le16 addr;
4719 : : u16 handle;
4720 : :
4721 : : memset(&link_topo, 0, sizeof(link_topo));
4722 : :
4723 : 0 : status = ice_get_pca9575_handle(hw, &handle);
4724 [ # # ]: 0 : if (status)
4725 : : return status;
4726 : :
4727 : 0 : link_topo.handle = CPU_TO_LE16(handle);
4728 : 0 : link_topo.topo_params.node_type_ctx =
4729 : : (ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED <<
4730 : : ICE_AQC_LINK_TOPO_NODE_CTX_S);
4731 : :
4732 : : addr = CPU_TO_LE16((u16)offset);
4733 : :
4734 : 0 : return ice_aq_write_i2c(hw, link_topo, 0, addr, 1, &data, NULL);
4735 : : }
4736 : :
4737 : : /**
4738 : : * ice_read_sma_ctrl_e810t
4739 : : * @hw: pointer to the hw struct
4740 : : * @data: pointer to data to be read from the GPIO controller
4741 : : *
4742 : : * Read the SMA controller state. Only bits 3-7 in data are valid.
4743 : : */
4744 : 0 : enum ice_status ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
4745 : : {
4746 : : enum ice_status status;
4747 : : u16 handle;
4748 : : u8 i;
4749 : :
4750 : 0 : status = ice_get_pca9575_handle(hw, &handle);
4751 [ # # ]: 0 : if (status)
4752 : : return status;
4753 : :
4754 : 0 : *data = 0;
4755 : :
4756 [ # # ]: 0 : for (i = ICE_E810T_SMA_MIN_BIT; i <= ICE_E810T_SMA_MAX_BIT; i++) {
4757 : : bool pin;
4758 : :
4759 : 0 : status = ice_aq_get_gpio(hw, handle, i + ICE_E810T_P1_OFFSET,
4760 : : &pin, NULL);
4761 [ # # ]: 0 : if (status)
4762 : : break;
4763 : 0 : *data |= (u8)(!pin) << i;
4764 : : }
4765 : :
4766 : : return status;
4767 : : }
4768 : :
4769 : : /**
4770 : : * ice_write_sma_ctrl_e810t
4771 : : * @hw: pointer to the hw struct
4772 : : * @data: data to be written to the GPIO controller
4773 : : *
4774 : : * Write the data to the SMA controller. Only bits 3-7 in data are valid.
4775 : : */
4776 : 0 : enum ice_status ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
4777 : : {
4778 : : enum ice_status status;
4779 : : u16 handle;
4780 : : u8 i;
4781 : :
4782 : 0 : status = ice_get_pca9575_handle(hw, &handle);
4783 [ # # ]: 0 : if (status)
4784 : : return status;
4785 : :
4786 [ # # ]: 0 : for (i = ICE_E810T_SMA_MIN_BIT; i <= ICE_E810T_SMA_MAX_BIT; i++) {
4787 : : bool pin;
4788 : :
4789 : 0 : pin = !(data & (1 << i));
4790 : 0 : status = ice_aq_set_gpio(hw, handle, i + ICE_E810T_P1_OFFSET,
4791 : : pin, NULL);
4792 [ # # ]: 0 : if (status)
4793 : : break;
4794 : : }
4795 : :
4796 : : return status;
4797 : : }
4798 : :
4799 : : /**
4800 : : * ice_is_pca9575_present
4801 : : * @hw: pointer to the hw struct
4802 : : *
4803 : : * Check if the SW IO expander is present in the netlist
4804 : : */
4805 : 0 : bool ice_is_pca9575_present(struct ice_hw *hw)
4806 : : {
4807 : : enum ice_status status;
4808 : 0 : u16 handle = 0;
4809 : :
4810 : 0 : status = ice_get_pca9575_handle(hw, &handle);
4811 [ # # # # ]: 0 : if (!status && handle)
4812 : 0 : return true;
4813 : :
4814 : : return false;
4815 : : }
4816 : :
4817 : : /* Device agnostic functions
4818 : : *
4819 : : * The following functions implement shared behavior common to both E822/E823
4820 : : * and E810 devices, possibly calling a device specific implementation where
4821 : : * necessary.
4822 : : */
4823 : :
4824 : : /**
4825 : : * ice_ptp_lock - Acquire PTP global semaphore register lock
4826 : : * @hw: pointer to the HW struct
4827 : : *
4828 : : * Acquire the global PTP hardware semaphore lock. Returns true if the lock
4829 : : * was acquired, false otherwise.
4830 : : *
4831 : : * The PFTSYN_SEM register sets the busy bit on read, returning the previous
4832 : : * value. If software sees the busy bit cleared, this means that this function
4833 : : * acquired the lock (and the busy bit is now set). If software sees the busy
4834 : : * bit set, it means that another function acquired the lock.
4835 : : *
4836 : : * Software must clear the busy bit with a write to release the lock for other
4837 : : * functions when done.
4838 : : */
4839 : 0 : bool ice_ptp_lock(struct ice_hw *hw)
4840 : : {
4841 : : u32 hw_lock;
4842 : : int i;
4843 : :
4844 : : #define MAX_TRIES 15
4845 : :
4846 [ # # ]: 0 : for (i = 0; i < MAX_TRIES; i++) {
4847 : 0 : hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
4848 : 0 : hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
4849 [ # # ]: 0 : if (hw_lock) {
4850 : : /* Somebody is holding the lock */
4851 : 0 : ice_msec_delay(5, true);
4852 : : continue;
4853 : : }
4854 : :
4855 : : break;
4856 : : }
4857 : :
4858 : 0 : return !hw_lock;
4859 : : }
4860 : :
4861 : : /**
4862 : : * ice_ptp_unlock - Release PTP global semaphore register lock
4863 : : * @hw: pointer to the HW struct
4864 : : *
4865 : : * Release the global PTP hardware semaphore lock. This is done by writing to
4866 : : * the PFTSYN_SEM register.
4867 : : */
4868 : 0 : void ice_ptp_unlock(struct ice_hw *hw)
4869 : : {
4870 : 0 : wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
4871 : 0 : }
4872 : :
4873 : : /**
4874 : : * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
4875 : : * @hw: pointer to HW struct
4876 : : * @cmd: the command to issue
4877 : : * @lock_sbq: true if the sideband queue lock must be acquired
4878 : : *
4879 : : * Prepare the source timer and PHY timers and then trigger the requested
4880 : : * command. This causes the shadow registers previously written in preparation
4881 : : * for the command to be synchronously applied to both the source and PHY
4882 : : * timers.
4883 : : */
4884 : : static enum ice_status
4885 : 0 : ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd, bool lock_sbq)
4886 : : {
4887 : : enum ice_status status;
4888 : :
4889 : : /* First, prepare the source timer */
4890 : 0 : ice_ptp_src_cmd(hw, cmd);
4891 : :
4892 : : /* Next, prepare the ports */
4893 [ # # # # ]: 0 : switch (hw->phy_cfg) {
4894 : 0 : case ICE_PHY_ETH56G:
4895 : 0 : status = ice_ptp_port_cmd_eth56g(hw, cmd, lock_sbq);
4896 : 0 : break;
4897 : 0 : case ICE_PHY_E810:
4898 : 0 : status = ice_ptp_port_cmd_e810(hw, cmd, lock_sbq);
4899 : 0 : break;
4900 : 0 : case ICE_PHY_E822:
4901 : 0 : status = ice_ptp_port_cmd_e822(hw, cmd, lock_sbq);
4902 : : break;
4903 : : default:
4904 : : status = ICE_ERR_NOT_SUPPORTED;
4905 : : }
4906 [ # # ]: 0 : if (status) {
4907 [ # # ]: 0 : ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, status %d\n",
4908 : : cmd, status);
4909 : 0 : return status;
4910 : : }
4911 : :
4912 : : /* Write the sync command register to drive both source and PHY timer
4913 : : * commands synchronously
4914 : : */
4915 : : ice_ptp_exec_tmr_cmd(hw);
4916 : : ice_ptp_clean_cmd(hw);
4917 : :
4918 : 0 : return ICE_SUCCESS;
4919 : : }
4920 : :
4921 : : /**
4922 : : * ice_ptp_init_time - Initialize device time to provided value
4923 : : * @hw: pointer to HW struct
4924 : : * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
4925 : : *
4926 : : * Initialize the device to the specified time provided. This requires a three
4927 : : * step process:
4928 : : *
4929 : : * 1) write the new init time to the source timer shadow registers
4930 : : * 2) write the new init time to the phy timer shadow registers
4931 : : * 3) issue an init_time timer command to synchronously switch both the source
4932 : : * and port timers to the new init time value at the next clock cycle.
4933 : : */
4934 : 0 : enum ice_status ice_ptp_init_time(struct ice_hw *hw, u64 time)
4935 : : {
4936 : : enum ice_status status;
4937 : : u8 tmr_idx;
4938 : :
4939 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4940 : :
4941 : : /* Source timers */
4942 : 0 : wr32(hw, GLTSYN_SHTIME_L(tmr_idx), ICE_LO_DWORD(time));
4943 : 0 : wr32(hw, GLTSYN_SHTIME_H(tmr_idx), ICE_HI_DWORD(time));
4944 : 0 : wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
4945 : :
4946 : : /* PHY Clks */
4947 : : /* Fill Rx and Tx ports and send msg to PHY */
4948 [ # # # # ]: 0 : switch (hw->phy_cfg) {
4949 : 0 : case ICE_PHY_ETH56G:
4950 : 0 : status = ice_ptp_prep_phy_time_eth56g(hw, time & 0xFFFFFFFF);
4951 : 0 : break;
4952 : 0 : case ICE_PHY_E810:
4953 : 0 : status = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
4954 : 0 : break;
4955 : 0 : case ICE_PHY_E822:
4956 : 0 : status = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
4957 : 0 : break;
4958 : : default:
4959 : : status = ICE_ERR_NOT_SUPPORTED;
4960 : : }
4961 : :
4962 [ # # ]: 0 : if (status)
4963 : 0 : return status;
4964 : :
4965 : 0 : return ice_ptp_tmr_cmd(hw, ICE_PTP_INIT_TIME, true);
4966 : : }
4967 : :
4968 : : /**
4969 : : * ice_ptp_write_incval - Program PHC with new increment value
4970 : : * @hw: pointer to HW struct
4971 : : * @incval: Source timer increment value per clock cycle
4972 : : *
4973 : : * Program the PHC with a new increment value. This requires a three-step
4974 : : * process:
4975 : : *
4976 : : * 1) Write the increment value to the source timer shadow registers
4977 : : * 2) Write the increment value to the PHY timer shadow registers
4978 : : * 3) Issue an ICE_PTP_INIT_INCVAL timer command to synchronously switch both
4979 : : * the source and port timers to the new increment value at the next clock
4980 : : * cycle.
4981 : : */
4982 : 0 : enum ice_status ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
4983 : : {
4984 : : enum ice_status status;
4985 : : u8 tmr_idx;
4986 : :
4987 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
4988 : :
4989 : : /* Shadow Adjust */
4990 : 0 : wr32(hw, GLTSYN_SHADJ_L(tmr_idx), ICE_LO_DWORD(incval));
4991 : 0 : wr32(hw, GLTSYN_SHADJ_H(tmr_idx), ICE_HI_DWORD(incval));
4992 : :
4993 [ # # # # ]: 0 : switch (hw->phy_cfg) {
4994 : 0 : case ICE_PHY_ETH56G:
4995 : 0 : status = ice_ptp_prep_phy_incval_eth56g(hw, incval);
4996 : 0 : break;
4997 : 0 : case ICE_PHY_E810:
4998 : 0 : status = ice_ptp_prep_phy_incval_e810(hw, incval);
4999 : 0 : break;
5000 : 0 : case ICE_PHY_E822:
5001 : 0 : status = ice_ptp_prep_phy_incval_e822(hw, incval);
5002 : 0 : break;
5003 : : default:
5004 : : status = ICE_ERR_NOT_SUPPORTED;
5005 : : }
5006 : :
5007 [ # # ]: 0 : if (status)
5008 : 0 : return status;
5009 : :
5010 : 0 : return ice_ptp_tmr_cmd(hw, ICE_PTP_INIT_INCVAL, true);
5011 : : }
5012 : :
5013 : : /**
5014 : : * ice_ptp_write_incval_locked - Program new incval while holding semaphore
5015 : : * @hw: pointer to HW struct
5016 : : * @incval: Source timer increment value per clock cycle
5017 : : *
5018 : : * Program a new PHC incval while holding the PTP semaphore.
5019 : : */
5020 : 0 : enum ice_status ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
5021 : : {
5022 : : enum ice_status status;
5023 : :
5024 [ # # ]: 0 : if (!ice_ptp_lock(hw))
5025 : : return ICE_ERR_NOT_READY;
5026 : :
5027 : 0 : status = ice_ptp_write_incval(hw, incval);
5028 : :
5029 : 0 : ice_ptp_unlock(hw);
5030 : :
5031 : 0 : return status;
5032 : : }
5033 : :
5034 : : /**
5035 : : * ice_ptp_adj_clock - Adjust PHC clock time atomically
5036 : : * @hw: pointer to HW struct
5037 : : * @adj: Adjustment in nanoseconds
5038 : : * @lock_sbq: true to lock the sbq sq_lock (the usual case); false if the
5039 : : * sq_lock has already been locked at a higher level
5040 : : *
5041 : : * Perform an atomic adjustment of the PHC time by the specified number of
5042 : : * nanoseconds. This requires a three-step process:
5043 : : *
5044 : : * 1) Write the adjustment to the source timer shadow registers
5045 : : * 2) Write the adjustment to the PHY timer shadow registers
5046 : : * 3) Issue an ICE_PTP_ADJ_TIME timer command to synchronously apply the
5047 : : * adjustment to both the source and port timers at the next clock cycle.
5048 : : */
5049 : 0 : enum ice_status ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq)
5050 : : {
5051 : : enum ice_status status;
5052 : : u8 tmr_idx;
5053 : :
5054 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
5055 : :
5056 : : /* Write the desired clock adjustment into the GLTSYN_SHADJ register.
5057 : : * For an ICE_PTP_ADJ_TIME command, this set of registers represents
5058 : : * the value to add to the clock time. It supports subtraction by
5059 : : * interpreting the value as a 2's complement integer.
5060 : : */
5061 : 0 : wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
5062 : 0 : wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
5063 : :
5064 [ # # # # ]: 0 : switch (hw->phy_cfg) {
5065 : 0 : case ICE_PHY_ETH56G:
5066 : 0 : status = ice_ptp_prep_phy_adj_eth56g(hw, adj, lock_sbq);
5067 : 0 : break;
5068 : 0 : case ICE_PHY_E810:
5069 : 0 : status = ice_ptp_prep_phy_adj_e810(hw, adj, lock_sbq);
5070 : 0 : break;
5071 : 0 : case ICE_PHY_E822:
5072 : 0 : status = ice_ptp_prep_phy_adj_e822(hw, adj, lock_sbq);
5073 : 0 : break;
5074 : : default:
5075 : : status = ICE_ERR_NOT_SUPPORTED;
5076 : : }
5077 : :
5078 [ # # ]: 0 : if (status)
5079 : 0 : return status;
5080 : :
5081 : 0 : return ice_ptp_tmr_cmd(hw, ICE_PTP_ADJ_TIME, lock_sbq);
5082 : : }
5083 : :
5084 : : /**
5085 : : * ice_ptp_adj_clock_at_time - Adjust PHC atomically at specified time
5086 : : * @hw: pointer to HW struct
5087 : : * @at_time: Time in nanoseconds at which to perform the adjustment
5088 : : * @adj: Adjustment in nanoseconds
5089 : : *
5090 : : * Perform an atomic adjustment to the PHC clock at the specified time. This
5091 : : * requires a five-step process:
5092 : : *
5093 : : * 1) Write the adjustment to the source timer shadow adjust registers
5094 : : * 2) Write the target time to the source timer shadow time registers
5095 : : * 3) Write the adjustment to the PHY timers shadow adjust registers
5096 : : * 4) Write the target time to the PHY timers shadow adjust registers
5097 : : * 5) Issue an ICE_PTP_ADJ_TIME_AT_TIME command to initiate the atomic
5098 : : * adjustment.
5099 : : */
5100 : : enum ice_status
5101 : 0 : ice_ptp_adj_clock_at_time(struct ice_hw *hw, u64 at_time, s32 adj)
5102 : : {
5103 : : enum ice_status status;
5104 : : u32 time_lo, time_hi;
5105 : : u8 tmr_idx;
5106 : :
5107 : 0 : tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
5108 : 0 : time_lo = ICE_LO_DWORD(at_time);
5109 : 0 : time_hi = ICE_HI_DWORD(at_time);
5110 : :
5111 : : /* Write the desired clock adjustment into the GLTSYN_SHADJ register.
5112 : : * For an ICE_PTP_ADJ_TIME_AT_TIME command, this set of registers
5113 : : * represents the value to add to the clock time. It supports
5114 : : * subtraction by interpreting the value as a 2's complement integer.
5115 : : */
5116 : 0 : wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
5117 : 0 : wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
5118 : :
5119 : : /* Write the target time to trigger the adjustment for source clock */
5120 : 0 : wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
5121 : 0 : wr32(hw, GLTSYN_SHTIME_L(tmr_idx), time_lo);
5122 : 0 : wr32(hw, GLTSYN_SHTIME_H(tmr_idx), time_hi);
5123 : :
5124 : : /* Prepare PHY port adjustments */
5125 [ # # # # ]: 0 : switch (hw->phy_cfg) {
5126 : 0 : case ICE_PHY_ETH56G:
5127 : 0 : status = ice_ptp_prep_phy_adj_eth56g(hw, adj, true);
5128 : 0 : break;
5129 : 0 : case ICE_PHY_E810:
5130 : 0 : status = ice_ptp_prep_phy_adj_e810(hw, adj, true);
5131 : 0 : break;
5132 : 0 : case ICE_PHY_E822:
5133 : 0 : status = ice_ptp_prep_phy_adj_e822(hw, adj, true);
5134 : 0 : break;
5135 : : default:
5136 : : status = ICE_ERR_NOT_SUPPORTED;
5137 : : }
5138 : :
5139 [ # # ]: 0 : if (status)
5140 : 0 : return status;
5141 : :
5142 : : /* Set target time for each PHY port */
5143 [ # # # # ]: 0 : switch (hw->phy_cfg) {
5144 : 0 : case ICE_PHY_ETH56G:
5145 : 0 : status = ice_ptp_prep_phy_adj_target_eth56g(hw, time_lo);
5146 : 0 : break;
5147 : 0 : case ICE_PHY_E810:
5148 : 0 : status = ice_ptp_prep_phy_adj_target_e810(hw, time_lo);
5149 : 0 : break;
5150 : 0 : case ICE_PHY_E822:
5151 : 0 : status = ice_ptp_prep_phy_adj_target_e822(hw, time_lo);
5152 : 0 : break;
5153 : : default:
5154 : : status = ICE_ERR_NOT_SUPPORTED;
5155 : : }
5156 : :
5157 [ # # ]: 0 : if (status)
5158 : 0 : return status;
5159 : :
5160 : 0 : return ice_ptp_tmr_cmd(hw, ICE_PTP_ADJ_TIME_AT_TIME, true);
5161 : : }
5162 : :
5163 : : /**
5164 : : * ice_read_phy_tstamp - Read a PHY timestamp from the timestamp block
5165 : : * @hw: pointer to the HW struct
5166 : : * @block: the block/port to read from
5167 : : * @idx: the timestamp index to read
5168 : : * @tstamp: on return, the 40bit timestamp value
5169 : : *
5170 : : * Read a 40bit timestamp value out of the timestamp block. For E822 devices,
5171 : : * the block is the quad to read from. For E810 devices, the block is the
5172 : : * logical port to read from.
5173 : : */
5174 : : enum ice_status
5175 : 0 : ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
5176 : : {
5177 : : enum ice_status status;
5178 : :
5179 [ # # # # ]: 0 : switch (hw->phy_cfg) {
5180 : 0 : case ICE_PHY_ETH56G:
5181 : 0 : status = ice_read_phy_tstamp_eth56g(hw, block, idx, tstamp);
5182 : 0 : break;
5183 : 0 : case ICE_PHY_E810:
5184 : 0 : status = ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
5185 : 0 : break;
5186 : 0 : case ICE_PHY_E822:
5187 : 0 : status = ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
5188 : 0 : break;
5189 : : default:
5190 : : status = ICE_ERR_NOT_SUPPORTED;
5191 : : }
5192 : :
5193 : 0 : return status;
5194 : : }
5195 : :
5196 : : /**
5197 : : * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
5198 : : * @hw: pointer to the HW struct
5199 : : * @block: the block to read from
5200 : : * @idx: the timestamp index to reset
5201 : : *
5202 : : * Clear a timestamp, resetting its valid bit, from the timestamp block. For
5203 : : * E822 devices, the block is the quad to clear from. For E810 devices, the
5204 : : * block is the logical port to clear from.
5205 : : */
5206 : : enum ice_status
5207 : 0 : ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
5208 : : {
5209 : : enum ice_status status;
5210 : :
5211 [ # # # # ]: 0 : switch (hw->phy_cfg) {
5212 : 0 : case ICE_PHY_ETH56G:
5213 : 0 : status = ice_clear_phy_tstamp_eth56g(hw, block, idx);
5214 : 0 : break;
5215 : 0 : case ICE_PHY_E810:
5216 : 0 : status = ice_clear_phy_tstamp_e810(hw, block, idx);
5217 : 0 : break;
5218 : 0 : case ICE_PHY_E822:
5219 : 0 : status = ice_clear_phy_tstamp_e822(hw, block, idx);
5220 : 0 : break;
5221 : : default:
5222 : : status = ICE_ERR_NOT_SUPPORTED;
5223 : : }
5224 : :
5225 : 0 : return status;
5226 : : }
5227 : :
5228 : : /**
5229 : : * ice_ptp_init_phc - Initialize PTP hardware clock
5230 : : * @hw: pointer to the HW struct
5231 : : *
5232 : : * Perform the steps required to initialize the PTP hardware clock.
5233 : : */
5234 : 0 : enum ice_status ice_ptp_init_phc(struct ice_hw *hw)
5235 : : {
5236 : : enum ice_status status;
5237 : 0 : u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
5238 : :
5239 : : /* Enable source clocks */
5240 : 0 : wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
5241 : :
5242 : : /* Clear event status indications for auxiliary pins */
5243 : 0 : (void)rd32(hw, GLTSYN_STAT(src_idx));
5244 : :
5245 [ # # # # ]: 0 : switch (hw->phy_cfg) {
5246 : : case ICE_PHY_ETH56G:
5247 : : status = ice_ptp_init_phc_eth56g(hw);
5248 : 0 : break;
5249 : : case ICE_PHY_E810:
5250 : : status = ice_ptp_init_phc_e810(hw);
5251 : 0 : break;
5252 : 0 : case ICE_PHY_E822:
5253 : 0 : status = ice_ptp_init_phc_e822(hw);
5254 : 0 : break;
5255 : : default:
5256 : : status = ICE_ERR_NOT_SUPPORTED;
5257 : : }
5258 : :
5259 : 0 : return status;
5260 : : }
|