1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021, Intel Corporation. */
3
4 #include "ice_common.h"
5 #include "ice_ptp_hw.h"
6
7 /* Low level functions for interacting with and managing the device clock used
8 * for the Precision Time Protocol.
9 *
10 * The ice hardware represents the current time using three registers:
11 *
12 * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R
13 * +---------------+ +---------------+ +---------------+
14 * | 32 bits | | 32 bits | | 32 bits |
15 * +---------------+ +---------------+ +---------------+
16 *
17 * The registers are incremented every clock tick using a 40bit increment
18 * value defined over two registers:
19 *
20 * GLTSYN_INCVAL_H GLTSYN_INCVAL_L
21 * +---------------+ +---------------+
22 * | 8 bit s | | 32 bits |
23 * +---------------+ +---------------+
24 *
25 * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
26 * registers every clock source tick. Depending on the specific device
27 * configuration, the clock source frequency could be one of a number of
28 * values.
29 *
30 * For E810 devices, the increment frequency is 812.5 MHz
31 *
32 * The hardware captures timestamps in the PHY for incoming packets, and for
33 * outgoing packets on request. To support this, the PHY maintains a timer
34 * that matches the lower 64 bits of the global source timer.
35 *
36 * In order to ensure that the PHY timers and the source timer are equivalent,
37 * shadow registers are used to prepare the desired initial values. A special
38 * sync command is issued to trigger copying from the shadow registers into
39 * the appropriate source and PHY registers simultaneously.
40 */
41
42 /**
43 * ice_get_ptp_src_clock_index - determine source clock index
44 * @hw: pointer to HW struct
45 *
46 * Determine the source clock index currently in use, based on device
47 * capabilities reported during initialization.
48 */
ice_get_ptp_src_clock_index(struct ice_hw * hw)49 u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
50 {
51 return hw->func_caps.ts_func_info.tmr_index_assoc;
52 }
53
54 /* E810 functions
55 *
56 * The following functions operate on the E810 series devices which use
57 * a separate external PHY.
58 */
59
60 /**
61 * ice_read_phy_reg_e810 - Read register from external PHY on E810
62 * @hw: pointer to the HW struct
63 * @addr: the address to read from
64 * @val: On return, the value read from the PHY
65 *
66 * Read a register from the external PHY on the E810 device.
67 */
ice_read_phy_reg_e810(struct ice_hw * hw,u32 addr,u32 * val)68 static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
69 {
70 struct ice_sbq_msg_input msg = {0};
71 int status;
72
73 msg.msg_addr_low = lower_16_bits(addr);
74 msg.msg_addr_high = upper_16_bits(addr);
75 msg.opcode = ice_sbq_msg_rd;
76 msg.dest_dev = rmn_0;
77
78 status = ice_sbq_rw_reg(hw, &msg);
79 if (status) {
80 ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, status %d\n",
81 status);
82 return status;
83 }
84
85 *val = msg.data;
86
87 return 0;
88 }
89
90 /**
91 * ice_write_phy_reg_e810 - Write register on external PHY on E810
92 * @hw: pointer to the HW struct
93 * @addr: the address to writem to
94 * @val: the value to write to the PHY
95 *
96 * Write a value to a register of the external PHY on the E810 device.
97 */
ice_write_phy_reg_e810(struct ice_hw * hw,u32 addr,u32 val)98 static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
99 {
100 struct ice_sbq_msg_input msg = {0};
101 int status;
102
103 msg.msg_addr_low = lower_16_bits(addr);
104 msg.msg_addr_high = upper_16_bits(addr);
105 msg.opcode = ice_sbq_msg_wr;
106 msg.dest_dev = rmn_0;
107 msg.data = val;
108
109 status = ice_sbq_rw_reg(hw, &msg);
110 if (status) {
111 ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, status %d\n",
112 status);
113 return status;
114 }
115
116 return 0;
117 }
118
119 /**
120 * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
121 * @hw: pointer to the HW struct
122 * @lport: the lport to read from
123 * @idx: the timestamp index to read
124 * @tstamp: on return, the 40bit timestamp value
125 *
126 * Read a 40bit timestamp value out of the timestamp block of the external PHY
127 * on the E810 device.
128 */
129 static int
ice_read_phy_tstamp_e810(struct ice_hw * hw,u8 lport,u8 idx,u64 * tstamp)130 ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
131 {
132 u32 lo_addr, hi_addr, lo, hi;
133 int status;
134
135 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
136 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
137
138 status = ice_read_phy_reg_e810(hw, lo_addr, &lo);
139 if (status) {
140 ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, status %d\n",
141 status);
142 return status;
143 }
144
145 status = ice_read_phy_reg_e810(hw, hi_addr, &hi);
146 if (status) {
147 ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, status %d\n",
148 status);
149 return status;
150 }
151
152 /* For E810 devices, the timestamp is reported with the lower 32 bits
153 * in the low register, and the upper 8 bits in the high register.
154 */
155 *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
156
157 return 0;
158 }
159
160 /**
161 * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
162 * @hw: pointer to the HW struct
163 * @lport: the lport to read from
164 * @idx: the timestamp index to reset
165 *
166 * Clear a timestamp, resetting its valid bit, from the timestamp block of the
167 * external PHY on the E810 device.
168 */
ice_clear_phy_tstamp_e810(struct ice_hw * hw,u8 lport,u8 idx)169 static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
170 {
171 u32 lo_addr, hi_addr;
172 int status;
173
174 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
175 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
176
177 status = ice_write_phy_reg_e810(hw, lo_addr, 0);
178 if (status) {
179 ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, status %d\n",
180 status);
181 return status;
182 }
183
184 status = ice_write_phy_reg_e810(hw, hi_addr, 0);
185 if (status) {
186 ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, status %d\n",
187 status);
188 return status;
189 }
190
191 return 0;
192 }
193
194 /**
195 * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
196 * @hw: pointer to HW struct
197 *
198 * Enable the timesync PTP functionality for the external PHY connected to
199 * this function.
200 */
ice_ptp_init_phy_e810(struct ice_hw * hw)201 int ice_ptp_init_phy_e810(struct ice_hw *hw)
202 {
203 int status;
204 u8 tmr_idx;
205
206 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
207 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
208 GLTSYN_ENA_TSYN_ENA_M);
209 if (status)
210 ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
211 status);
212
213 return status;
214 }
215
216 /**
217 * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
218 * @hw: Board private structure
219 * @time: Time to initialize the PHY port clock to
220 *
221 * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
222 * initial clock time. The time will not actually be programmed until the
223 * driver issues an INIT_TIME command.
224 *
225 * The time value is the upper 32 bits of the PHY timer, usually in units of
226 * nominal nanoseconds.
227 */
ice_ptp_prep_phy_time_e810(struct ice_hw * hw,u32 time)228 static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
229 {
230 int status;
231 u8 tmr_idx;
232
233 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
234 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
235 if (status) {
236 ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, status %d\n",
237 status);
238 return status;
239 }
240
241 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
242 if (status) {
243 ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, status %d\n",
244 status);
245 return status;
246 }
247
248 return 0;
249 }
250
251 /**
252 * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
253 * @hw: pointer to HW struct
254 * @adj: adjustment value to program
255 *
256 * Prepare the PHY port for an atomic adjustment by programming the PHY
257 * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
258 * is completed by issuing an ADJ_TIME sync command.
259 *
260 * The adjustment value only contains the portion used for the upper 32bits of
261 * the PHY timer, usually in units of nominal nanoseconds. Negative
262 * adjustments are supported using 2s complement arithmetic.
263 */
ice_ptp_prep_phy_adj_e810(struct ice_hw * hw,s32 adj)264 static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
265 {
266 int status;
267 u8 tmr_idx;
268
269 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
270
271 /* Adjustments are represented as signed 2's complement values in
272 * nanoseconds. Sub-nanosecond adjustment is not supported.
273 */
274 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0);
275 if (status) {
276 ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, status %d\n",
277 status);
278 return status;
279 }
280
281 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj);
282 if (status) {
283 ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, status %d\n",
284 status);
285 return status;
286 }
287
288 return 0;
289 }
290
291 /**
292 * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
293 * @hw: pointer to HW struct
294 * @incval: The new 40bit increment value to prepare
295 *
296 * Prepare the PHY port for a new increment value by programming the PHY
297 * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
298 * completed by issuing an INIT_INCVAL command.
299 */
ice_ptp_prep_phy_incval_e810(struct ice_hw * hw,u64 incval)300 static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
301 {
302 u32 high, low;
303 int status;
304 u8 tmr_idx;
305
306 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
307 low = lower_32_bits(incval);
308 high = upper_32_bits(incval);
309
310 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
311 if (status) {
312 ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, status %d\n",
313 status);
314 return status;
315 }
316
317 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
318 if (status) {
319 ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, status %d\n",
320 status);
321 return status;
322 }
323
324 return 0;
325 }
326
327 /**
328 * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
329 * @hw: pointer to HW struct
330 * @cmd: Command to be sent to the port
331 *
332 * Prepare the external PHYs connected to this device for a timer sync
333 * command.
334 */
ice_ptp_port_cmd_e810(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)335 static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
336 {
337 u32 cmd_val, val;
338 int status;
339
340 switch (cmd) {
341 case INIT_TIME:
342 cmd_val = GLTSYN_CMD_INIT_TIME;
343 break;
344 case INIT_INCVAL:
345 cmd_val = GLTSYN_CMD_INIT_INCVAL;
346 break;
347 case ADJ_TIME:
348 cmd_val = GLTSYN_CMD_ADJ_TIME;
349 break;
350 case READ_TIME:
351 cmd_val = GLTSYN_CMD_READ_TIME;
352 break;
353 case ADJ_TIME_AT_TIME:
354 cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
355 break;
356 }
357
358 /* Read, modify, write */
359 status = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val);
360 if (status) {
361 ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, status %d\n", status);
362 return status;
363 }
364
365 /* Modify necessary bits only and perform write */
366 val &= ~TS_CMD_MASK_E810;
367 val |= cmd_val;
368
369 status = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val);
370 if (status) {
371 ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, status %d\n", status);
372 return status;
373 }
374
375 return 0;
376 }
377
378 /* Device agnostic functions
379 *
380 * The following functions implement useful behavior to hide the differences
381 * between E810 and other devices. They call the device-specific
382 * implementations where necessary.
383 *
384 * Currently, the driver only supports E810, but future work will enable
385 * support for E822-based devices.
386 */
387
388 /**
389 * ice_ptp_lock - Acquire PTP global semaphore register lock
390 * @hw: pointer to the HW struct
391 *
392 * Acquire the global PTP hardware semaphore lock. Returns true if the lock
393 * was acquired, false otherwise.
394 *
395 * The PFTSYN_SEM register sets the busy bit on read, returning the previous
396 * value. If software sees the busy bit cleared, this means that this function
397 * acquired the lock (and the busy bit is now set). If software sees the busy
398 * bit set, it means that another function acquired the lock.
399 *
400 * Software must clear the busy bit with a write to release the lock for other
401 * functions when done.
402 */
ice_ptp_lock(struct ice_hw * hw)403 bool ice_ptp_lock(struct ice_hw *hw)
404 {
405 u32 hw_lock;
406 int i;
407
408 #define MAX_TRIES 5
409
410 for (i = 0; i < MAX_TRIES; i++) {
411 hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
412 hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
413 if (!hw_lock)
414 break;
415
416 /* Somebody is holding the lock */
417 usleep_range(10000, 20000);
418 }
419
420 return !hw_lock;
421 }
422
423 /**
424 * ice_ptp_unlock - Release PTP global semaphore register lock
425 * @hw: pointer to the HW struct
426 *
427 * Release the global PTP hardware semaphore lock. This is done by writing to
428 * the PFTSYN_SEM register.
429 */
ice_ptp_unlock(struct ice_hw * hw)430 void ice_ptp_unlock(struct ice_hw *hw)
431 {
432 wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
433 }
434
435 /**
436 * ice_ptp_src_cmd - Prepare source timer for a timer command
437 * @hw: pointer to HW structure
438 * @cmd: Timer command
439 *
440 * Prepare the source timer for an upcoming timer sync command.
441 */
ice_ptp_src_cmd(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)442 static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
443 {
444 u32 cmd_val;
445 u8 tmr_idx;
446
447 tmr_idx = ice_get_ptp_src_clock_index(hw);
448 cmd_val = tmr_idx << SEL_CPK_SRC;
449
450 switch (cmd) {
451 case INIT_TIME:
452 cmd_val |= GLTSYN_CMD_INIT_TIME;
453 break;
454 case INIT_INCVAL:
455 cmd_val |= GLTSYN_CMD_INIT_INCVAL;
456 break;
457 case ADJ_TIME:
458 cmd_val |= GLTSYN_CMD_ADJ_TIME;
459 break;
460 case ADJ_TIME_AT_TIME:
461 cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
462 break;
463 case READ_TIME:
464 cmd_val |= GLTSYN_CMD_READ_TIME;
465 break;
466 }
467
468 wr32(hw, GLTSYN_CMD, cmd_val);
469 }
470
471 /**
472 * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
473 * @hw: pointer to HW struct
474 * @cmd: the command to issue
475 *
476 * Prepare the source timer and PHY timers and then trigger the requested
477 * command. This causes the shadow registers previously written in preparation
478 * for the command to be synchronously applied to both the source and PHY
479 * timers.
480 */
ice_ptp_tmr_cmd(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)481 static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
482 {
483 int status;
484
485 /* First, prepare the source timer */
486 ice_ptp_src_cmd(hw, cmd);
487
488 /* Next, prepare the ports */
489 status = ice_ptp_port_cmd_e810(hw, cmd);
490 if (status) {
491 ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, status %d\n",
492 cmd, status);
493 return status;
494 }
495
496 /* Write the sync command register to drive both source and PHY timer commands
497 * synchronously
498 */
499 wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
500
501 return 0;
502 }
503
504 /**
505 * ice_ptp_init_time - Initialize device time to provided value
506 * @hw: pointer to HW struct
507 * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
508 *
509 * Initialize the device to the specified time provided. This requires a three
510 * step process:
511 *
512 * 1) write the new init time to the source timer shadow registers
513 * 2) write the new init time to the PHY timer shadow registers
514 * 3) issue an init_time timer command to synchronously switch both the source
515 * and port timers to the new init time value at the next clock cycle.
516 */
ice_ptp_init_time(struct ice_hw * hw,u64 time)517 int ice_ptp_init_time(struct ice_hw *hw, u64 time)
518 {
519 int status;
520 u8 tmr_idx;
521
522 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
523
524 /* Source timers */
525 wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time));
526 wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time));
527 wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
528
529 /* PHY timers */
530 /* Fill Rx and Tx ports and send msg to PHY */
531 status = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
532 if (status)
533 return status;
534
535 return ice_ptp_tmr_cmd(hw, INIT_TIME);
536 }
537
538 /**
539 * ice_ptp_write_incval - Program PHC with new increment value
540 * @hw: pointer to HW struct
541 * @incval: Source timer increment value per clock cycle
542 *
543 * Program the PHC with a new increment value. This requires a three-step
544 * process:
545 *
546 * 1) Write the increment value to the source timer shadow registers
547 * 2) Write the increment value to the PHY timer shadow registers
548 * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
549 * source and port timers to the new increment value at the next clock
550 * cycle.
551 */
ice_ptp_write_incval(struct ice_hw * hw,u64 incval)552 int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
553 {
554 int status;
555 u8 tmr_idx;
556
557 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
558
559 /* Shadow Adjust */
560 wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
561 wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
562
563 status = ice_ptp_prep_phy_incval_e810(hw, incval);
564 if (status)
565 return status;
566
567 return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
568 }
569
570 /**
571 * ice_ptp_write_incval_locked - Program new incval while holding semaphore
572 * @hw: pointer to HW struct
573 * @incval: Source timer increment value per clock cycle
574 *
575 * Program a new PHC incval while holding the PTP semaphore.
576 */
ice_ptp_write_incval_locked(struct ice_hw * hw,u64 incval)577 int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
578 {
579 int status;
580
581 if (!ice_ptp_lock(hw))
582 return -EBUSY;
583
584 status = ice_ptp_write_incval(hw, incval);
585
586 ice_ptp_unlock(hw);
587
588 return status;
589 }
590
591 /**
592 * ice_ptp_adj_clock - Adjust PHC clock time atomically
593 * @hw: pointer to HW struct
594 * @adj: Adjustment in nanoseconds
595 *
596 * Perform an atomic adjustment of the PHC time by the specified number of
597 * nanoseconds. This requires a three-step process:
598 *
599 * 1) Write the adjustment to the source timer shadow registers
600 * 2) Write the adjustment to the PHY timer shadow registers
601 * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
602 * both the source and port timers at the next clock cycle.
603 */
ice_ptp_adj_clock(struct ice_hw * hw,s32 adj)604 int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
605 {
606 int status;
607 u8 tmr_idx;
608
609 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
610
611 /* Write the desired clock adjustment into the GLTSYN_SHADJ register.
612 * For an ADJ_TIME command, this set of registers represents the value
613 * to add to the clock time. It supports subtraction by interpreting
614 * the value as a 2's complement integer.
615 */
616 wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
617 wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
618
619 status = ice_ptp_prep_phy_adj_e810(hw, adj);
620 if (status)
621 return status;
622
623 return ice_ptp_tmr_cmd(hw, ADJ_TIME);
624 }
625
626 /**
627 * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
628 * @hw: pointer to the HW struct
629 * @block: the block to read from
630 * @idx: the timestamp index to read
631 * @tstamp: on return, the 40bit timestamp value
632 *
633 * Read a 40bit timestamp value out of the timestamp block.
634 */
ice_read_phy_tstamp(struct ice_hw * hw,u8 block,u8 idx,u64 * tstamp)635 int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
636 {
637 return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
638 }
639
640 /**
641 * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
642 * @hw: pointer to the HW struct
643 * @block: the block to read from
644 * @idx: the timestamp index to reset
645 *
646 * Clear a timestamp, resetting its valid bit, from the timestamp block.
647 */
ice_clear_phy_tstamp(struct ice_hw * hw,u8 block,u8 idx)648 int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
649 {
650 return ice_clear_phy_tstamp_e810(hw, block, idx);
651 }
652