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  */
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  */
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 err;
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 	err = ice_sbq_rw_reg(hw, &msg);
79 	if (err) {
80 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
81 			  err);
82 		return err;
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  */
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 err;
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 	err = ice_sbq_rw_reg(hw, &msg);
110 	if (err) {
111 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
112 			  err);
113 		return err;
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
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 err;
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 	err = ice_read_phy_reg_e810(hw, lo_addr, &lo);
139 	if (err) {
140 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
141 			  err);
142 		return err;
143 	}
144 
145 	err = ice_read_phy_reg_e810(hw, hi_addr, &hi);
146 	if (err) {
147 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
148 			  err);
149 		return err;
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  */
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 err;
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 	err = ice_write_phy_reg_e810(hw, lo_addr, 0);
178 	if (err) {
179 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
180 			  err);
181 		return err;
182 	}
183 
184 	err = ice_write_phy_reg_e810(hw, hi_addr, 0);
185 	if (err) {
186 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
187 			  err);
188 		return err;
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  */
201 int ice_ptp_init_phy_e810(struct ice_hw *hw)
202 {
203 	u8 tmr_idx;
204 	int err;
205 
206 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
207 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
208 				     GLTSYN_ENA_TSYN_ENA_M);
209 	if (err)
210 		ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
211 			  err);
212 
213 	return err;
214 }
215 
216 /**
217  * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization
218  * @hw: pointer to HW struct
219  *
220  * Perform E810-specific PTP hardware clock initialization steps.
221  */
222 static int ice_ptp_init_phc_e810(struct ice_hw *hw)
223 {
224 	/* Ensure synchronization delay is zero */
225 	wr32(hw, GLTSYN_SYNC_DLAY, 0);
226 
227 	/* Initialize the PHY */
228 	return ice_ptp_init_phy_e810(hw);
229 }
230 
231 /**
232  * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
233  * @hw: Board private structure
234  * @time: Time to initialize the PHY port clock to
235  *
236  * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
237  * initial clock time. The time will not actually be programmed until the
238  * driver issues an INIT_TIME command.
239  *
240  * The time value is the upper 32 bits of the PHY timer, usually in units of
241  * nominal nanoseconds.
242  */
243 static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
244 {
245 	u8 tmr_idx;
246 	int err;
247 
248 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
249 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
250 	if (err) {
251 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n",
252 			  err);
253 		return err;
254 	}
255 
256 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
257 	if (err) {
258 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n",
259 			  err);
260 		return err;
261 	}
262 
263 	return 0;
264 }
265 
266 /**
267  * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
268  * @hw: pointer to HW struct
269  * @adj: adjustment value to program
270  *
271  * Prepare the PHY port for an atomic adjustment by programming the PHY
272  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
273  * is completed by issuing an ADJ_TIME sync command.
274  *
275  * The adjustment value only contains the portion used for the upper 32bits of
276  * the PHY timer, usually in units of nominal nanoseconds. Negative
277  * adjustments are supported using 2s complement arithmetic.
278  */
279 static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
280 {
281 	u8 tmr_idx;
282 	int err;
283 
284 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
285 
286 	/* Adjustments are represented as signed 2's complement values in
287 	 * nanoseconds. Sub-nanosecond adjustment is not supported.
288 	 */
289 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0);
290 	if (err) {
291 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n",
292 			  err);
293 		return err;
294 	}
295 
296 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj);
297 	if (err) {
298 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n",
299 			  err);
300 		return err;
301 	}
302 
303 	return 0;
304 }
305 
306 /**
307  * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
308  * @hw: pointer to HW struct
309  * @incval: The new 40bit increment value to prepare
310  *
311  * Prepare the PHY port for a new increment value by programming the PHY
312  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
313  * completed by issuing an INIT_INCVAL command.
314  */
315 static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
316 {
317 	u32 high, low;
318 	u8 tmr_idx;
319 	int err;
320 
321 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
322 	low = lower_32_bits(incval);
323 	high = upper_32_bits(incval);
324 
325 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
326 	if (err) {
327 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n",
328 			  err);
329 		return err;
330 	}
331 
332 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
333 	if (err) {
334 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n",
335 			  err);
336 		return err;
337 	}
338 
339 	return 0;
340 }
341 
342 /**
343  * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
344  * @hw: pointer to HW struct
345  * @cmd: Command to be sent to the port
346  *
347  * Prepare the external PHYs connected to this device for a timer sync
348  * command.
349  */
350 static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
351 {
352 	u32 cmd_val, val;
353 	int err;
354 
355 	switch (cmd) {
356 	case INIT_TIME:
357 		cmd_val = GLTSYN_CMD_INIT_TIME;
358 		break;
359 	case INIT_INCVAL:
360 		cmd_val = GLTSYN_CMD_INIT_INCVAL;
361 		break;
362 	case ADJ_TIME:
363 		cmd_val = GLTSYN_CMD_ADJ_TIME;
364 		break;
365 	case READ_TIME:
366 		cmd_val = GLTSYN_CMD_READ_TIME;
367 		break;
368 	case ADJ_TIME_AT_TIME:
369 		cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
370 		break;
371 	}
372 
373 	/* Read, modify, write */
374 	err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val);
375 	if (err) {
376 		ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err);
377 		return err;
378 	}
379 
380 	/* Modify necessary bits only and perform write */
381 	val &= ~TS_CMD_MASK_E810;
382 	val |= cmd_val;
383 
384 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val);
385 	if (err) {
386 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err);
387 		return err;
388 	}
389 
390 	return 0;
391 }
392 
393 /* Device agnostic functions
394  *
395  * The following functions implement useful behavior to hide the differences
396  * between E810 and other devices. They call the device-specific
397  * implementations where necessary.
398  *
399  * Currently, the driver only supports E810, but future work will enable
400  * support for E822-based devices.
401  */
402 
403 /**
404  * ice_ptp_lock - Acquire PTP global semaphore register lock
405  * @hw: pointer to the HW struct
406  *
407  * Acquire the global PTP hardware semaphore lock. Returns true if the lock
408  * was acquired, false otherwise.
409  *
410  * The PFTSYN_SEM register sets the busy bit on read, returning the previous
411  * value. If software sees the busy bit cleared, this means that this function
412  * acquired the lock (and the busy bit is now set). If software sees the busy
413  * bit set, it means that another function acquired the lock.
414  *
415  * Software must clear the busy bit with a write to release the lock for other
416  * functions when done.
417  */
418 bool ice_ptp_lock(struct ice_hw *hw)
419 {
420 	u32 hw_lock;
421 	int i;
422 
423 #define MAX_TRIES 5
424 
425 	for (i = 0; i < MAX_TRIES; i++) {
426 		hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
427 		hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
428 		if (!hw_lock)
429 			break;
430 
431 		/* Somebody is holding the lock */
432 		usleep_range(10000, 20000);
433 	}
434 
435 	return !hw_lock;
436 }
437 
438 /**
439  * ice_ptp_unlock - Release PTP global semaphore register lock
440  * @hw: pointer to the HW struct
441  *
442  * Release the global PTP hardware semaphore lock. This is done by writing to
443  * the PFTSYN_SEM register.
444  */
445 void ice_ptp_unlock(struct ice_hw *hw)
446 {
447 	wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
448 }
449 
450 /**
451  * ice_ptp_src_cmd - Prepare source timer for a timer command
452  * @hw: pointer to HW structure
453  * @cmd: Timer command
454  *
455  * Prepare the source timer for an upcoming timer sync command.
456  */
457 static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
458 {
459 	u32 cmd_val;
460 	u8 tmr_idx;
461 
462 	tmr_idx = ice_get_ptp_src_clock_index(hw);
463 	cmd_val = tmr_idx << SEL_CPK_SRC;
464 
465 	switch (cmd) {
466 	case INIT_TIME:
467 		cmd_val |= GLTSYN_CMD_INIT_TIME;
468 		break;
469 	case INIT_INCVAL:
470 		cmd_val |= GLTSYN_CMD_INIT_INCVAL;
471 		break;
472 	case ADJ_TIME:
473 		cmd_val |= GLTSYN_CMD_ADJ_TIME;
474 		break;
475 	case ADJ_TIME_AT_TIME:
476 		cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
477 		break;
478 	case READ_TIME:
479 		cmd_val |= GLTSYN_CMD_READ_TIME;
480 		break;
481 	}
482 
483 	wr32(hw, GLTSYN_CMD, cmd_val);
484 }
485 
486 /**
487  * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
488  * @hw: pointer to HW struct
489  * @cmd: the command to issue
490  *
491  * Prepare the source timer and PHY timers and then trigger the requested
492  * command. This causes the shadow registers previously written in preparation
493  * for the command to be synchronously applied to both the source and PHY
494  * timers.
495  */
496 static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
497 {
498 	int err;
499 
500 	/* First, prepare the source timer */
501 	ice_ptp_src_cmd(hw, cmd);
502 
503 	/* Next, prepare the ports */
504 	err = ice_ptp_port_cmd_e810(hw, cmd);
505 	if (err) {
506 		ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n",
507 			  cmd, err);
508 		return err;
509 	}
510 
511 	/* Write the sync command register to drive both source and PHY timer commands
512 	 * synchronously
513 	 */
514 	wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
515 
516 	return 0;
517 }
518 
519 /**
520  * ice_ptp_init_time - Initialize device time to provided value
521  * @hw: pointer to HW struct
522  * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
523  *
524  * Initialize the device to the specified time provided. This requires a three
525  * step process:
526  *
527  * 1) write the new init time to the source timer shadow registers
528  * 2) write the new init time to the PHY timer shadow registers
529  * 3) issue an init_time timer command to synchronously switch both the source
530  *    and port timers to the new init time value at the next clock cycle.
531  */
532 int ice_ptp_init_time(struct ice_hw *hw, u64 time)
533 {
534 	u8 tmr_idx;
535 	int err;
536 
537 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
538 
539 	/* Source timers */
540 	wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time));
541 	wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time));
542 	wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
543 
544 	/* PHY timers */
545 	/* Fill Rx and Tx ports and send msg to PHY */
546 	err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
547 	if (err)
548 		return err;
549 
550 	return ice_ptp_tmr_cmd(hw, INIT_TIME);
551 }
552 
553 /**
554  * ice_ptp_write_incval - Program PHC with new increment value
555  * @hw: pointer to HW struct
556  * @incval: Source timer increment value per clock cycle
557  *
558  * Program the PHC with a new increment value. This requires a three-step
559  * process:
560  *
561  * 1) Write the increment value to the source timer shadow registers
562  * 2) Write the increment value to the PHY timer shadow registers
563  * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
564  *    source and port timers to the new increment value at the next clock
565  *    cycle.
566  */
567 int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
568 {
569 	u8 tmr_idx;
570 	int err;
571 
572 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
573 
574 	/* Shadow Adjust */
575 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
576 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
577 
578 	err = ice_ptp_prep_phy_incval_e810(hw, incval);
579 	if (err)
580 		return err;
581 
582 	return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
583 }
584 
585 /**
586  * ice_ptp_write_incval_locked - Program new incval while holding semaphore
587  * @hw: pointer to HW struct
588  * @incval: Source timer increment value per clock cycle
589  *
590  * Program a new PHC incval while holding the PTP semaphore.
591  */
592 int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
593 {
594 	int err;
595 
596 	if (!ice_ptp_lock(hw))
597 		return -EBUSY;
598 
599 	err = ice_ptp_write_incval(hw, incval);
600 
601 	ice_ptp_unlock(hw);
602 
603 	return err;
604 }
605 
606 /**
607  * ice_ptp_adj_clock - Adjust PHC clock time atomically
608  * @hw: pointer to HW struct
609  * @adj: Adjustment in nanoseconds
610  *
611  * Perform an atomic adjustment of the PHC time by the specified number of
612  * nanoseconds. This requires a three-step process:
613  *
614  * 1) Write the adjustment to the source timer shadow registers
615  * 2) Write the adjustment to the PHY timer shadow registers
616  * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
617  *    both the source and port timers at the next clock cycle.
618  */
619 int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
620 {
621 	u8 tmr_idx;
622 	int err;
623 
624 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
625 
626 	/* Write the desired clock adjustment into the GLTSYN_SHADJ register.
627 	 * For an ADJ_TIME command, this set of registers represents the value
628 	 * to add to the clock time. It supports subtraction by interpreting
629 	 * the value as a 2's complement integer.
630 	 */
631 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
632 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
633 
634 	err = ice_ptp_prep_phy_adj_e810(hw, adj);
635 	if (err)
636 		return err;
637 
638 	return ice_ptp_tmr_cmd(hw, ADJ_TIME);
639 }
640 
641 /**
642  * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
643  * @hw: pointer to the HW struct
644  * @block: the block to read from
645  * @idx: the timestamp index to read
646  * @tstamp: on return, the 40bit timestamp value
647  *
648  * Read a 40bit timestamp value out of the timestamp block.
649  */
650 int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
651 {
652 	return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
653 }
654 
655 /**
656  * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
657  * @hw: pointer to the HW struct
658  * @block: the block to read from
659  * @idx: the timestamp index to reset
660  *
661  * Clear a timestamp, resetting its valid bit, from the timestamp block.
662  */
663 int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
664 {
665 	return ice_clear_phy_tstamp_e810(hw, block, idx);
666 }
667 
668 /* E810T SMA functions
669  *
670  * The following functions operate specifically on E810T hardware and are used
671  * to access the extended GPIOs available.
672  */
673 
674 /**
675  * ice_get_pca9575_handle
676  * @hw: pointer to the hw struct
677  * @pca9575_handle: GPIO controller's handle
678  *
679  * Find and return the GPIO controller's handle in the netlist.
680  * When found - the value will be cached in the hw structure and following calls
681  * will return cached value
682  */
683 static int
684 ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
685 {
686 	struct ice_aqc_get_link_topo *cmd;
687 	struct ice_aq_desc desc;
688 	int status;
689 	u8 idx;
690 
691 	/* If handle was read previously return cached value */
692 	if (hw->io_expander_handle) {
693 		*pca9575_handle = hw->io_expander_handle;
694 		return 0;
695 	}
696 
697 	/* If handle was not detected read it from the netlist */
698 	cmd = &desc.params.get_link_topo;
699 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
700 
701 	/* Set node type to GPIO controller */
702 	cmd->addr.topo_params.node_type_ctx =
703 		(ICE_AQC_LINK_TOPO_NODE_TYPE_M &
704 		 ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
705 
706 #define SW_PCA9575_SFP_TOPO_IDX		2
707 #define SW_PCA9575_QSFP_TOPO_IDX	1
708 
709 	/* Check if the SW IO expander controlling SMA exists in the netlist. */
710 	if (hw->device_id == ICE_DEV_ID_E810C_SFP)
711 		idx = SW_PCA9575_SFP_TOPO_IDX;
712 	else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
713 		idx = SW_PCA9575_QSFP_TOPO_IDX;
714 	else
715 		return -EOPNOTSUPP;
716 
717 	cmd->addr.topo_params.index = idx;
718 
719 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
720 	if (status)
721 		return -EOPNOTSUPP;
722 
723 	/* Verify if we found the right IO expander type */
724 	if (desc.params.get_link_topo.node_part_num !=
725 		ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
726 		return -EOPNOTSUPP;
727 
728 	/* If present save the handle and return it */
729 	hw->io_expander_handle =
730 		le16_to_cpu(desc.params.get_link_topo.addr.handle);
731 	*pca9575_handle = hw->io_expander_handle;
732 
733 	return 0;
734 }
735 
736 /**
737  * ice_read_sma_ctrl_e810t
738  * @hw: pointer to the hw struct
739  * @data: pointer to data to be read from the GPIO controller
740  *
741  * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
742  * PCA9575 expander, so only bits 3-7 in data are valid.
743  */
744 int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
745 {
746 	int status;
747 	u16 handle;
748 	u8 i;
749 
750 	status = ice_get_pca9575_handle(hw, &handle);
751 	if (status)
752 		return status;
753 
754 	*data = 0;
755 
756 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
757 		bool pin;
758 
759 		status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
760 					 &pin, NULL);
761 		if (status)
762 			break;
763 		*data |= (u8)(!pin) << i;
764 	}
765 
766 	return status;
767 }
768 
769 /**
770  * ice_write_sma_ctrl_e810t
771  * @hw: pointer to the hw struct
772  * @data: data to be written to the GPIO controller
773  *
774  * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
775  * of the PCA9575 expander, so only bits 3-7 in data are valid.
776  */
777 int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
778 {
779 	int status;
780 	u16 handle;
781 	u8 i;
782 
783 	status = ice_get_pca9575_handle(hw, &handle);
784 	if (status)
785 		return status;
786 
787 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
788 		bool pin;
789 
790 		pin = !(data & (1 << i));
791 		status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
792 					 pin, NULL);
793 		if (status)
794 			break;
795 	}
796 
797 	return status;
798 }
799 
800 /**
801  * ice_is_pca9575_present
802  * @hw: pointer to the hw struct
803  *
804  * Check if the SW IO expander is present in the netlist
805  */
806 bool ice_is_pca9575_present(struct ice_hw *hw)
807 {
808 	u16 handle = 0;
809 	int status;
810 
811 	if (!ice_is_e810t(hw))
812 		return false;
813 
814 	status = ice_get_pca9575_handle(hw, &handle);
815 
816 	return !status && handle;
817 }
818 
819 /**
820  * ice_ptp_init_phc - Initialize PTP hardware clock
821  * @hw: pointer to the HW struct
822  *
823  * Perform the steps required to initialize the PTP hardware clock.
824  */
825 int ice_ptp_init_phc(struct ice_hw *hw)
826 {
827 	u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
828 
829 	/* Enable source clocks */
830 	wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
831 
832 	/* Clear event err indications for auxiliary pins */
833 	(void)rd32(hw, GLTSYN_STAT(src_idx));
834 
835 	return ice_ptp_init_phc_e810(hw);
836 }
837