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 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  */
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
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
653 /* E810T SMA functions
654  *
655  * The following functions operate specifically on E810T hardware and are used
656  * to access the extended GPIOs available.
657  */
658 
659 /**
660  * ice_get_pca9575_handle
661  * @hw: pointer to the hw struct
662  * @pca9575_handle: GPIO controller's handle
663  *
664  * Find and return the GPIO controller's handle in the netlist.
665  * When found - the value will be cached in the hw structure and following calls
666  * will return cached value
667  */
668 static int
669 ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
670 {
671 	struct ice_aqc_get_link_topo *cmd;
672 	struct ice_aq_desc desc;
673 	int status;
674 	u8 idx;
675 
676 	/* If handle was read previously return cached value */
677 	if (hw->io_expander_handle) {
678 		*pca9575_handle = hw->io_expander_handle;
679 		return 0;
680 	}
681 
682 	/* If handle was not detected read it from the netlist */
683 	cmd = &desc.params.get_link_topo;
684 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
685 
686 	/* Set node type to GPIO controller */
687 	cmd->addr.topo_params.node_type_ctx =
688 		(ICE_AQC_LINK_TOPO_NODE_TYPE_M &
689 		 ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
690 
691 #define SW_PCA9575_SFP_TOPO_IDX		2
692 #define SW_PCA9575_QSFP_TOPO_IDX	1
693 
694 	/* Check if the SW IO expander controlling SMA exists in the netlist. */
695 	if (hw->device_id == ICE_DEV_ID_E810C_SFP)
696 		idx = SW_PCA9575_SFP_TOPO_IDX;
697 	else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
698 		idx = SW_PCA9575_QSFP_TOPO_IDX;
699 	else
700 		return -EOPNOTSUPP;
701 
702 	cmd->addr.topo_params.index = idx;
703 
704 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
705 	if (status)
706 		return -EOPNOTSUPP;
707 
708 	/* Verify if we found the right IO expander type */
709 	if (desc.params.get_link_topo.node_part_num !=
710 		ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
711 		return -EOPNOTSUPP;
712 
713 	/* If present save the handle and return it */
714 	hw->io_expander_handle =
715 		le16_to_cpu(desc.params.get_link_topo.addr.handle);
716 	*pca9575_handle = hw->io_expander_handle;
717 
718 	return 0;
719 }
720 
721 /**
722  * ice_read_sma_ctrl_e810t
723  * @hw: pointer to the hw struct
724  * @data: pointer to data to be read from the GPIO controller
725  *
726  * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
727  * PCA9575 expander, so only bits 3-7 in data are valid.
728  */
729 int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
730 {
731 	int status;
732 	u16 handle;
733 	u8 i;
734 
735 	status = ice_get_pca9575_handle(hw, &handle);
736 	if (status)
737 		return status;
738 
739 	*data = 0;
740 
741 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
742 		bool pin;
743 
744 		status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
745 					 &pin, NULL);
746 		if (status)
747 			break;
748 		*data |= (u8)(!pin) << i;
749 	}
750 
751 	return status;
752 }
753 
754 /**
755  * ice_write_sma_ctrl_e810t
756  * @hw: pointer to the hw struct
757  * @data: data to be written to the GPIO controller
758  *
759  * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
760  * of the PCA9575 expander, so only bits 3-7 in data are valid.
761  */
762 int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
763 {
764 	int status;
765 	u16 handle;
766 	u8 i;
767 
768 	status = ice_get_pca9575_handle(hw, &handle);
769 	if (status)
770 		return status;
771 
772 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
773 		bool pin;
774 
775 		pin = !(data & (1 << i));
776 		status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
777 					 pin, NULL);
778 		if (status)
779 			break;
780 	}
781 
782 	return status;
783 }
784 
785 /**
786  * ice_is_pca9575_present
787  * @hw: pointer to the hw struct
788  *
789  * Check if the SW IO expander is present in the netlist
790  */
791 bool ice_is_pca9575_present(struct ice_hw *hw)
792 {
793 	u16 handle = 0;
794 	int status;
795 
796 	if (!ice_is_e810t(hw))
797 		return false;
798 
799 	status = ice_get_pca9575_handle(hw, &handle);
800 
801 	return !status && handle;
802 }
803