103cb4473SJacob Keller // SPDX-License-Identifier: GPL-2.0
203cb4473SJacob Keller /* Copyright (C) 2021, Intel Corporation. */
303cb4473SJacob Keller 
403cb4473SJacob Keller #include "ice_common.h"
503cb4473SJacob Keller #include "ice_ptp_hw.h"
6*3a749623SJacob Keller #include "ice_ptp_consts.h"
703cb4473SJacob Keller 
803cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used
903cb4473SJacob Keller  * for the Precision Time Protocol.
1003cb4473SJacob Keller  *
1103cb4473SJacob Keller  * The ice hardware represents the current time using three registers:
1203cb4473SJacob Keller  *
1303cb4473SJacob Keller  *    GLTSYN_TIME_H     GLTSYN_TIME_L     GLTSYN_TIME_R
1403cb4473SJacob Keller  *  +---------------+ +---------------+ +---------------+
1503cb4473SJacob Keller  *  |    32 bits    | |    32 bits    | |    32 bits    |
1603cb4473SJacob Keller  *  +---------------+ +---------------+ +---------------+
1703cb4473SJacob Keller  *
1803cb4473SJacob Keller  * The registers are incremented every clock tick using a 40bit increment
1903cb4473SJacob Keller  * value defined over two registers:
2003cb4473SJacob Keller  *
2103cb4473SJacob Keller  *                     GLTSYN_INCVAL_H   GLTSYN_INCVAL_L
2203cb4473SJacob Keller  *                    +---------------+ +---------------+
2303cb4473SJacob Keller  *                    |    8 bit s    | |    32 bits    |
2403cb4473SJacob Keller  *                    +---------------+ +---------------+
2503cb4473SJacob Keller  *
2603cb4473SJacob Keller  * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
2703cb4473SJacob Keller  * registers every clock source tick. Depending on the specific device
2803cb4473SJacob Keller  * configuration, the clock source frequency could be one of a number of
2903cb4473SJacob Keller  * values.
3003cb4473SJacob Keller  *
3103cb4473SJacob Keller  * For E810 devices, the increment frequency is 812.5 MHz
3203cb4473SJacob Keller  *
33*3a749623SJacob Keller  * For E822 devices the clock can be derived from different sources, and the
34*3a749623SJacob Keller  * increment has an effective frequency of one of the following:
35*3a749623SJacob Keller  * - 823.4375 MHz
36*3a749623SJacob Keller  * - 783.36 MHz
37*3a749623SJacob Keller  * - 796.875 MHz
38*3a749623SJacob Keller  * - 816 MHz
39*3a749623SJacob Keller  * - 830.078125 MHz
40*3a749623SJacob Keller  * - 783.36 MHz
41*3a749623SJacob Keller  *
4203cb4473SJacob Keller  * The hardware captures timestamps in the PHY for incoming packets, and for
4303cb4473SJacob Keller  * outgoing packets on request. To support this, the PHY maintains a timer
4403cb4473SJacob Keller  * that matches the lower 64 bits of the global source timer.
4503cb4473SJacob Keller  *
4603cb4473SJacob Keller  * In order to ensure that the PHY timers and the source timer are equivalent,
4703cb4473SJacob Keller  * shadow registers are used to prepare the desired initial values. A special
4803cb4473SJacob Keller  * sync command is issued to trigger copying from the shadow registers into
4903cb4473SJacob Keller  * the appropriate source and PHY registers simultaneously.
50*3a749623SJacob Keller  *
51*3a749623SJacob Keller  * The driver supports devices which have different PHYs with subtly different
52*3a749623SJacob Keller  * mechanisms to program and control the timers. We divide the devices into
53*3a749623SJacob Keller  * families named after the first major device, E810 and similar devices, and
54*3a749623SJacob Keller  * E822 and similar devices.
55*3a749623SJacob Keller  *
56*3a749623SJacob Keller  * - E822 based devices have additional support for fine grained Vernier
57*3a749623SJacob Keller  *   calibration which requires significant setup
58*3a749623SJacob Keller  * - The layout of timestamp data in the PHY register blocks is different
59*3a749623SJacob Keller  * - The way timer synchronization commands are issued is different.
60*3a749623SJacob Keller  *
61*3a749623SJacob Keller  * To support this, very low level functions have an e810 or e822 suffix
62*3a749623SJacob Keller  * indicating what type of device they work on. Higher level abstractions for
63*3a749623SJacob Keller  * tasks that can be done on both devices do not have the suffix and will
64*3a749623SJacob Keller  * correctly look up the appropriate low level function when running.
65*3a749623SJacob Keller  *
66*3a749623SJacob Keller  * Functions which only make sense on a single device family may not have
67*3a749623SJacob Keller  * a suitable generic implementation
6803cb4473SJacob Keller  */
6903cb4473SJacob Keller 
7003cb4473SJacob Keller /**
7103cb4473SJacob Keller  * ice_get_ptp_src_clock_index - determine source clock index
7203cb4473SJacob Keller  * @hw: pointer to HW struct
7303cb4473SJacob Keller  *
7403cb4473SJacob Keller  * Determine the source clock index currently in use, based on device
7503cb4473SJacob Keller  * capabilities reported during initialization.
7603cb4473SJacob Keller  */
7703cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
7803cb4473SJacob Keller {
7903cb4473SJacob Keller 	return hw->func_caps.ts_func_info.tmr_index_assoc;
8003cb4473SJacob Keller }
8103cb4473SJacob Keller 
82*3a749623SJacob Keller /**
83*3a749623SJacob Keller  * ice_ptp_read_src_incval - Read source timer increment value
84*3a749623SJacob Keller  * @hw: pointer to HW struct
85*3a749623SJacob Keller  *
86*3a749623SJacob Keller  * Read the increment value of the source timer and return it.
87*3a749623SJacob Keller  */
88*3a749623SJacob Keller static u64 ice_ptp_read_src_incval(struct ice_hw *hw)
89*3a749623SJacob Keller {
90*3a749623SJacob Keller 	u32 lo, hi;
91*3a749623SJacob Keller 	u8 tmr_idx;
92*3a749623SJacob Keller 
93*3a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
94*3a749623SJacob Keller 
95*3a749623SJacob Keller 	lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
96*3a749623SJacob Keller 	hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
97*3a749623SJacob Keller 
98*3a749623SJacob Keller 	return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;
99*3a749623SJacob Keller }
100*3a749623SJacob Keller 
101*3a749623SJacob Keller /**
102*3a749623SJacob Keller  * ice_ptp_src_cmd - Prepare source timer for a timer command
103*3a749623SJacob Keller  * @hw: pointer to HW structure
104*3a749623SJacob Keller  * @cmd: Timer command
105*3a749623SJacob Keller  *
106*3a749623SJacob Keller  * Prepare the source timer for an upcoming timer sync command.
107*3a749623SJacob Keller  */
108*3a749623SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
109*3a749623SJacob Keller {
110*3a749623SJacob Keller 	u32 cmd_val;
111*3a749623SJacob Keller 	u8 tmr_idx;
112*3a749623SJacob Keller 
113*3a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
114*3a749623SJacob Keller 	cmd_val = tmr_idx << SEL_CPK_SRC;
115*3a749623SJacob Keller 
116*3a749623SJacob Keller 	switch (cmd) {
117*3a749623SJacob Keller 	case INIT_TIME:
118*3a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_INIT_TIME;
119*3a749623SJacob Keller 		break;
120*3a749623SJacob Keller 	case INIT_INCVAL:
121*3a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_INIT_INCVAL;
122*3a749623SJacob Keller 		break;
123*3a749623SJacob Keller 	case ADJ_TIME:
124*3a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_ADJ_TIME;
125*3a749623SJacob Keller 		break;
126*3a749623SJacob Keller 	case ADJ_TIME_AT_TIME:
127*3a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
128*3a749623SJacob Keller 		break;
129*3a749623SJacob Keller 	case READ_TIME:
130*3a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_READ_TIME;
131*3a749623SJacob Keller 		break;
132*3a749623SJacob Keller 	}
133*3a749623SJacob Keller 
134*3a749623SJacob Keller 	wr32(hw, GLTSYN_CMD, cmd_val);
135*3a749623SJacob Keller }
136*3a749623SJacob Keller 
137*3a749623SJacob Keller /**
138*3a749623SJacob Keller  * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands
139*3a749623SJacob Keller  * @hw: pointer to HW struct
140*3a749623SJacob Keller  *
141*3a749623SJacob Keller  * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the
142*3a749623SJacob Keller  * write immediately. This triggers the hardware to begin executing all of the
143*3a749623SJacob Keller  * source and PHY timer commands synchronously.
144*3a749623SJacob Keller  */
145*3a749623SJacob Keller static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
146*3a749623SJacob Keller {
147*3a749623SJacob Keller 	wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
148*3a749623SJacob Keller 	ice_flush(hw);
149*3a749623SJacob Keller }
150*3a749623SJacob Keller 
151*3a749623SJacob Keller /* E822 family functions
152*3a749623SJacob Keller  *
153*3a749623SJacob Keller  * The following functions operate on the E822 family of devices.
154*3a749623SJacob Keller  */
155*3a749623SJacob Keller 
156*3a749623SJacob Keller /**
157*3a749623SJacob Keller  * ice_fill_phy_msg_e822 - Fill message data for a PHY register access
158*3a749623SJacob Keller  * @msg: the PHY message buffer to fill in
159*3a749623SJacob Keller  * @port: the port to access
160*3a749623SJacob Keller  * @offset: the register offset
161*3a749623SJacob Keller  */
162*3a749623SJacob Keller static void
163*3a749623SJacob Keller ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
164*3a749623SJacob Keller {
165*3a749623SJacob Keller 	int phy_port, phy, quadtype;
166*3a749623SJacob Keller 
167*3a749623SJacob Keller 	phy_port = port % ICE_PORTS_PER_PHY;
168*3a749623SJacob Keller 	phy = port / ICE_PORTS_PER_PHY;
169*3a749623SJacob Keller 	quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE;
170*3a749623SJacob Keller 
171*3a749623SJacob Keller 	if (quadtype == 0) {
172*3a749623SJacob Keller 		msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
173*3a749623SJacob Keller 		msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port);
174*3a749623SJacob Keller 	} else {
175*3a749623SJacob Keller 		msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port);
176*3a749623SJacob Keller 		msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port);
177*3a749623SJacob Keller 	}
178*3a749623SJacob Keller 
179*3a749623SJacob Keller 	if (phy == 0)
180*3a749623SJacob Keller 		msg->dest_dev = rmn_0;
181*3a749623SJacob Keller 	else if (phy == 1)
182*3a749623SJacob Keller 		msg->dest_dev = rmn_1;
183*3a749623SJacob Keller 	else
184*3a749623SJacob Keller 		msg->dest_dev = rmn_2;
185*3a749623SJacob Keller }
186*3a749623SJacob Keller 
187*3a749623SJacob Keller /**
188*3a749623SJacob Keller  * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register
189*3a749623SJacob Keller  * @low_addr: the low address to check
190*3a749623SJacob Keller  * @high_addr: on return, contains the high address of the 64bit register
191*3a749623SJacob Keller  *
192*3a749623SJacob Keller  * Checks if the provided low address is one of the known 64bit PHY values
193*3a749623SJacob Keller  * represented as two 32bit registers. If it is, return the appropriate high
194*3a749623SJacob Keller  * register offset to use.
195*3a749623SJacob Keller  */
196*3a749623SJacob Keller static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
197*3a749623SJacob Keller {
198*3a749623SJacob Keller 	switch (low_addr) {
199*3a749623SJacob Keller 	case P_REG_PAR_PCS_TX_OFFSET_L:
200*3a749623SJacob Keller 		*high_addr = P_REG_PAR_PCS_TX_OFFSET_U;
201*3a749623SJacob Keller 		return true;
202*3a749623SJacob Keller 	case P_REG_PAR_PCS_RX_OFFSET_L:
203*3a749623SJacob Keller 		*high_addr = P_REG_PAR_PCS_RX_OFFSET_U;
204*3a749623SJacob Keller 		return true;
205*3a749623SJacob Keller 	case P_REG_PAR_TX_TIME_L:
206*3a749623SJacob Keller 		*high_addr = P_REG_PAR_TX_TIME_U;
207*3a749623SJacob Keller 		return true;
208*3a749623SJacob Keller 	case P_REG_PAR_RX_TIME_L:
209*3a749623SJacob Keller 		*high_addr = P_REG_PAR_RX_TIME_U;
210*3a749623SJacob Keller 		return true;
211*3a749623SJacob Keller 	case P_REG_TOTAL_TX_OFFSET_L:
212*3a749623SJacob Keller 		*high_addr = P_REG_TOTAL_TX_OFFSET_U;
213*3a749623SJacob Keller 		return true;
214*3a749623SJacob Keller 	case P_REG_TOTAL_RX_OFFSET_L:
215*3a749623SJacob Keller 		*high_addr = P_REG_TOTAL_RX_OFFSET_U;
216*3a749623SJacob Keller 		return true;
217*3a749623SJacob Keller 	case P_REG_UIX66_10G_40G_L:
218*3a749623SJacob Keller 		*high_addr = P_REG_UIX66_10G_40G_U;
219*3a749623SJacob Keller 		return true;
220*3a749623SJacob Keller 	case P_REG_UIX66_25G_100G_L:
221*3a749623SJacob Keller 		*high_addr = P_REG_UIX66_25G_100G_U;
222*3a749623SJacob Keller 		return true;
223*3a749623SJacob Keller 	case P_REG_TX_CAPTURE_L:
224*3a749623SJacob Keller 		*high_addr = P_REG_TX_CAPTURE_U;
225*3a749623SJacob Keller 		return true;
226*3a749623SJacob Keller 	case P_REG_RX_CAPTURE_L:
227*3a749623SJacob Keller 		*high_addr = P_REG_RX_CAPTURE_U;
228*3a749623SJacob Keller 		return true;
229*3a749623SJacob Keller 	case P_REG_TX_TIMER_INC_PRE_L:
230*3a749623SJacob Keller 		*high_addr = P_REG_TX_TIMER_INC_PRE_U;
231*3a749623SJacob Keller 		return true;
232*3a749623SJacob Keller 	case P_REG_RX_TIMER_INC_PRE_L:
233*3a749623SJacob Keller 		*high_addr = P_REG_RX_TIMER_INC_PRE_U;
234*3a749623SJacob Keller 		return true;
235*3a749623SJacob Keller 	default:
236*3a749623SJacob Keller 		return false;
237*3a749623SJacob Keller 	}
238*3a749623SJacob Keller }
239*3a749623SJacob Keller 
240*3a749623SJacob Keller /**
241*3a749623SJacob Keller  * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register
242*3a749623SJacob Keller  * @low_addr: the low address to check
243*3a749623SJacob Keller  * @high_addr: on return, contains the high address of the 40bit value
244*3a749623SJacob Keller  *
245*3a749623SJacob Keller  * Checks if the provided low address is one of the known 40bit PHY values
246*3a749623SJacob Keller  * split into two registers with the lower 8 bits in the low register and the
247*3a749623SJacob Keller  * upper 32 bits in the high register. If it is, return the appropriate high
248*3a749623SJacob Keller  * register offset to use.
249*3a749623SJacob Keller  */
250*3a749623SJacob Keller static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
251*3a749623SJacob Keller {
252*3a749623SJacob Keller 	switch (low_addr) {
253*3a749623SJacob Keller 	case P_REG_TIMETUS_L:
254*3a749623SJacob Keller 		*high_addr = P_REG_TIMETUS_U;
255*3a749623SJacob Keller 		return true;
256*3a749623SJacob Keller 	case P_REG_PAR_RX_TUS_L:
257*3a749623SJacob Keller 		*high_addr = P_REG_PAR_RX_TUS_U;
258*3a749623SJacob Keller 		return true;
259*3a749623SJacob Keller 	case P_REG_PAR_TX_TUS_L:
260*3a749623SJacob Keller 		*high_addr = P_REG_PAR_TX_TUS_U;
261*3a749623SJacob Keller 		return true;
262*3a749623SJacob Keller 	case P_REG_PCS_RX_TUS_L:
263*3a749623SJacob Keller 		*high_addr = P_REG_PCS_RX_TUS_U;
264*3a749623SJacob Keller 		return true;
265*3a749623SJacob Keller 	case P_REG_PCS_TX_TUS_L:
266*3a749623SJacob Keller 		*high_addr = P_REG_PCS_TX_TUS_U;
267*3a749623SJacob Keller 		return true;
268*3a749623SJacob Keller 	case P_REG_DESK_PAR_RX_TUS_L:
269*3a749623SJacob Keller 		*high_addr = P_REG_DESK_PAR_RX_TUS_U;
270*3a749623SJacob Keller 		return true;
271*3a749623SJacob Keller 	case P_REG_DESK_PAR_TX_TUS_L:
272*3a749623SJacob Keller 		*high_addr = P_REG_DESK_PAR_TX_TUS_U;
273*3a749623SJacob Keller 		return true;
274*3a749623SJacob Keller 	case P_REG_DESK_PCS_RX_TUS_L:
275*3a749623SJacob Keller 		*high_addr = P_REG_DESK_PCS_RX_TUS_U;
276*3a749623SJacob Keller 		return true;
277*3a749623SJacob Keller 	case P_REG_DESK_PCS_TX_TUS_L:
278*3a749623SJacob Keller 		*high_addr = P_REG_DESK_PCS_TX_TUS_U;
279*3a749623SJacob Keller 		return true;
280*3a749623SJacob Keller 	default:
281*3a749623SJacob Keller 		return false;
282*3a749623SJacob Keller 	}
283*3a749623SJacob Keller }
284*3a749623SJacob Keller 
285*3a749623SJacob Keller /**
286*3a749623SJacob Keller  * ice_read_phy_reg_e822 - Read a PHY register
287*3a749623SJacob Keller  * @hw: pointer to the HW struct
288*3a749623SJacob Keller  * @port: PHY port to read from
289*3a749623SJacob Keller  * @offset: PHY register offset to read
290*3a749623SJacob Keller  * @val: on return, the contents read from the PHY
291*3a749623SJacob Keller  *
292*3a749623SJacob Keller  * Read a PHY register for the given port over the device sideband queue.
293*3a749623SJacob Keller  */
294*3a749623SJacob Keller int
295*3a749623SJacob Keller ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
296*3a749623SJacob Keller {
297*3a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
298*3a749623SJacob Keller 	int err;
299*3a749623SJacob Keller 
300*3a749623SJacob Keller 	ice_fill_phy_msg_e822(&msg, port, offset);
301*3a749623SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
302*3a749623SJacob Keller 
303*3a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
304*3a749623SJacob Keller 	if (err) {
305*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
306*3a749623SJacob Keller 			  err);
307*3a749623SJacob Keller 		return err;
308*3a749623SJacob Keller 	}
309*3a749623SJacob Keller 
310*3a749623SJacob Keller 	*val = msg.data;
311*3a749623SJacob Keller 
312*3a749623SJacob Keller 	return 0;
313*3a749623SJacob Keller }
314*3a749623SJacob Keller 
315*3a749623SJacob Keller /**
316*3a749623SJacob Keller  * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers
317*3a749623SJacob Keller  * @hw: pointer to the HW struct
318*3a749623SJacob Keller  * @port: PHY port to read from
319*3a749623SJacob Keller  * @low_addr: offset of the lower register to read from
320*3a749623SJacob Keller  * @val: on return, the contents of the 64bit value from the PHY registers
321*3a749623SJacob Keller  *
322*3a749623SJacob Keller  * Reads the two registers associated with a 64bit value and returns it in the
323*3a749623SJacob Keller  * val pointer. The offset always specifies the lower register offset to use.
324*3a749623SJacob Keller  * The high offset is looked up. This function only operates on registers
325*3a749623SJacob Keller  * known to be two parts of a 64bit value.
326*3a749623SJacob Keller  */
327*3a749623SJacob Keller static int
328*3a749623SJacob Keller ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
329*3a749623SJacob Keller {
330*3a749623SJacob Keller 	u32 low, high;
331*3a749623SJacob Keller 	u16 high_addr;
332*3a749623SJacob Keller 	int err;
333*3a749623SJacob Keller 
334*3a749623SJacob Keller 	/* Only operate on registers known to be split into two 32bit
335*3a749623SJacob Keller 	 * registers.
336*3a749623SJacob Keller 	 */
337*3a749623SJacob Keller 	if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
338*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
339*3a749623SJacob Keller 			  low_addr);
340*3a749623SJacob Keller 		return -EINVAL;
341*3a749623SJacob Keller 	}
342*3a749623SJacob Keller 
343*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, low_addr, &low);
344*3a749623SJacob Keller 	if (err) {
345*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d",
346*3a749623SJacob Keller 			  low_addr, err);
347*3a749623SJacob Keller 		return err;
348*3a749623SJacob Keller 	}
349*3a749623SJacob Keller 
350*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, high_addr, &high);
351*3a749623SJacob Keller 	if (err) {
352*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d",
353*3a749623SJacob Keller 			  high_addr, err);
354*3a749623SJacob Keller 		return err;
355*3a749623SJacob Keller 	}
356*3a749623SJacob Keller 
357*3a749623SJacob Keller 	*val = (u64)high << 32 | low;
358*3a749623SJacob Keller 
359*3a749623SJacob Keller 	return 0;
360*3a749623SJacob Keller }
361*3a749623SJacob Keller 
362*3a749623SJacob Keller /**
363*3a749623SJacob Keller  * ice_write_phy_reg_e822 - Write a PHY register
364*3a749623SJacob Keller  * @hw: pointer to the HW struct
365*3a749623SJacob Keller  * @port: PHY port to write to
366*3a749623SJacob Keller  * @offset: PHY register offset to write
367*3a749623SJacob Keller  * @val: The value to write to the register
368*3a749623SJacob Keller  *
369*3a749623SJacob Keller  * Write a PHY register for the given port over the device sideband queue.
370*3a749623SJacob Keller  */
371*3a749623SJacob Keller int
372*3a749623SJacob Keller ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
373*3a749623SJacob Keller {
374*3a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
375*3a749623SJacob Keller 	int err;
376*3a749623SJacob Keller 
377*3a749623SJacob Keller 	ice_fill_phy_msg_e822(&msg, port, offset);
378*3a749623SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
379*3a749623SJacob Keller 	msg.data = val;
380*3a749623SJacob Keller 
381*3a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
382*3a749623SJacob Keller 	if (err) {
383*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
384*3a749623SJacob Keller 			  err);
385*3a749623SJacob Keller 		return err;
386*3a749623SJacob Keller 	}
387*3a749623SJacob Keller 
388*3a749623SJacob Keller 	return 0;
389*3a749623SJacob Keller }
390*3a749623SJacob Keller 
391*3a749623SJacob Keller /**
392*3a749623SJacob Keller  * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY
393*3a749623SJacob Keller  * @hw: pointer to the HW struct
394*3a749623SJacob Keller  * @port: port to write to
395*3a749623SJacob Keller  * @low_addr: offset of the low register
396*3a749623SJacob Keller  * @val: 40b value to write
397*3a749623SJacob Keller  *
398*3a749623SJacob Keller  * Write the provided 40b value to the two associated registers by splitting
399*3a749623SJacob Keller  * it up into two chunks, the lower 8 bits and the upper 32 bits.
400*3a749623SJacob Keller  */
401*3a749623SJacob Keller static int
402*3a749623SJacob Keller ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
403*3a749623SJacob Keller {
404*3a749623SJacob Keller 	u32 low, high;
405*3a749623SJacob Keller 	u16 high_addr;
406*3a749623SJacob Keller 	int err;
407*3a749623SJacob Keller 
408*3a749623SJacob Keller 	/* Only operate on registers known to be split into a lower 8 bit
409*3a749623SJacob Keller 	 * register and an upper 32 bit register.
410*3a749623SJacob Keller 	 */
411*3a749623SJacob Keller 	if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
412*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n",
413*3a749623SJacob Keller 			  low_addr);
414*3a749623SJacob Keller 		return -EINVAL;
415*3a749623SJacob Keller 	}
416*3a749623SJacob Keller 
417*3a749623SJacob Keller 	low = (u32)(val & P_REG_40B_LOW_M);
418*3a749623SJacob Keller 	high = (u32)(val >> P_REG_40B_HIGH_S);
419*3a749623SJacob Keller 
420*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, low_addr, low);
421*3a749623SJacob Keller 	if (err) {
422*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
423*3a749623SJacob Keller 			  low_addr, err);
424*3a749623SJacob Keller 		return err;
425*3a749623SJacob Keller 	}
426*3a749623SJacob Keller 
427*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, high_addr, high);
428*3a749623SJacob Keller 	if (err) {
429*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
430*3a749623SJacob Keller 			  high_addr, err);
431*3a749623SJacob Keller 		return err;
432*3a749623SJacob Keller 	}
433*3a749623SJacob Keller 
434*3a749623SJacob Keller 	return 0;
435*3a749623SJacob Keller }
436*3a749623SJacob Keller 
437*3a749623SJacob Keller /**
438*3a749623SJacob Keller  * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers
439*3a749623SJacob Keller  * @hw: pointer to the HW struct
440*3a749623SJacob Keller  * @port: PHY port to read from
441*3a749623SJacob Keller  * @low_addr: offset of the lower register to read from
442*3a749623SJacob Keller  * @val: the contents of the 64bit value to write to PHY
443*3a749623SJacob Keller  *
444*3a749623SJacob Keller  * Write the 64bit value to the two associated 32bit PHY registers. The offset
445*3a749623SJacob Keller  * is always specified as the lower register, and the high address is looked
446*3a749623SJacob Keller  * up. This function only operates on registers known to be two parts of
447*3a749623SJacob Keller  * a 64bit value.
448*3a749623SJacob Keller  */
449*3a749623SJacob Keller static int
450*3a749623SJacob Keller ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
451*3a749623SJacob Keller {
452*3a749623SJacob Keller 	u32 low, high;
453*3a749623SJacob Keller 	u16 high_addr;
454*3a749623SJacob Keller 	int err;
455*3a749623SJacob Keller 
456*3a749623SJacob Keller 	/* Only operate on registers known to be split into two 32bit
457*3a749623SJacob Keller 	 * registers.
458*3a749623SJacob Keller 	 */
459*3a749623SJacob Keller 	if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
460*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
461*3a749623SJacob Keller 			  low_addr);
462*3a749623SJacob Keller 		return -EINVAL;
463*3a749623SJacob Keller 	}
464*3a749623SJacob Keller 
465*3a749623SJacob Keller 	low = lower_32_bits(val);
466*3a749623SJacob Keller 	high = upper_32_bits(val);
467*3a749623SJacob Keller 
468*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, low_addr, low);
469*3a749623SJacob Keller 	if (err) {
470*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
471*3a749623SJacob Keller 			  low_addr, err);
472*3a749623SJacob Keller 		return err;
473*3a749623SJacob Keller 	}
474*3a749623SJacob Keller 
475*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, high_addr, high);
476*3a749623SJacob Keller 	if (err) {
477*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
478*3a749623SJacob Keller 			  high_addr, err);
479*3a749623SJacob Keller 		return err;
480*3a749623SJacob Keller 	}
481*3a749623SJacob Keller 
482*3a749623SJacob Keller 	return 0;
483*3a749623SJacob Keller }
484*3a749623SJacob Keller 
485*3a749623SJacob Keller /**
486*3a749623SJacob Keller  * ice_fill_quad_msg_e822 - Fill message data for quad register access
487*3a749623SJacob Keller  * @msg: the PHY message buffer to fill in
488*3a749623SJacob Keller  * @quad: the quad to access
489*3a749623SJacob Keller  * @offset: the register offset
490*3a749623SJacob Keller  *
491*3a749623SJacob Keller  * Fill a message buffer for accessing a register in a quad shared between
492*3a749623SJacob Keller  * multiple PHYs.
493*3a749623SJacob Keller  */
494*3a749623SJacob Keller static void
495*3a749623SJacob Keller ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
496*3a749623SJacob Keller {
497*3a749623SJacob Keller 	u32 addr;
498*3a749623SJacob Keller 
499*3a749623SJacob Keller 	msg->dest_dev = rmn_0;
500*3a749623SJacob Keller 
501*3a749623SJacob Keller 	if ((quad % ICE_NUM_QUAD_TYPE) == 0)
502*3a749623SJacob Keller 		addr = Q_0_BASE + offset;
503*3a749623SJacob Keller 	else
504*3a749623SJacob Keller 		addr = Q_1_BASE + offset;
505*3a749623SJacob Keller 
506*3a749623SJacob Keller 	msg->msg_addr_low = lower_16_bits(addr);
507*3a749623SJacob Keller 	msg->msg_addr_high = upper_16_bits(addr);
508*3a749623SJacob Keller }
509*3a749623SJacob Keller 
510*3a749623SJacob Keller /**
511*3a749623SJacob Keller  * ice_read_quad_reg_e822 - Read a PHY quad register
512*3a749623SJacob Keller  * @hw: pointer to the HW struct
513*3a749623SJacob Keller  * @quad: quad to read from
514*3a749623SJacob Keller  * @offset: quad register offset to read
515*3a749623SJacob Keller  * @val: on return, the contents read from the quad
516*3a749623SJacob Keller  *
517*3a749623SJacob Keller  * Read a quad register over the device sideband queue. Quad registers are
518*3a749623SJacob Keller  * shared between multiple PHYs.
519*3a749623SJacob Keller  */
520*3a749623SJacob Keller int
521*3a749623SJacob Keller ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
522*3a749623SJacob Keller {
523*3a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
524*3a749623SJacob Keller 	int err;
525*3a749623SJacob Keller 
526*3a749623SJacob Keller 	if (quad >= ICE_MAX_QUAD)
527*3a749623SJacob Keller 		return -EINVAL;
528*3a749623SJacob Keller 
529*3a749623SJacob Keller 	ice_fill_quad_msg_e822(&msg, quad, offset);
530*3a749623SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
531*3a749623SJacob Keller 
532*3a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
533*3a749623SJacob Keller 	if (err) {
534*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
535*3a749623SJacob Keller 			  err);
536*3a749623SJacob Keller 		return err;
537*3a749623SJacob Keller 	}
538*3a749623SJacob Keller 
539*3a749623SJacob Keller 	*val = msg.data;
540*3a749623SJacob Keller 
541*3a749623SJacob Keller 	return 0;
542*3a749623SJacob Keller }
543*3a749623SJacob Keller 
544*3a749623SJacob Keller /**
545*3a749623SJacob Keller  * ice_write_quad_reg_e822 - Write a PHY quad register
546*3a749623SJacob Keller  * @hw: pointer to the HW struct
547*3a749623SJacob Keller  * @quad: quad to write to
548*3a749623SJacob Keller  * @offset: quad register offset to write
549*3a749623SJacob Keller  * @val: The value to write to the register
550*3a749623SJacob Keller  *
551*3a749623SJacob Keller  * Write a quad register over the device sideband queue. Quad registers are
552*3a749623SJacob Keller  * shared between multiple PHYs.
553*3a749623SJacob Keller  */
554*3a749623SJacob Keller int
555*3a749623SJacob Keller ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
556*3a749623SJacob Keller {
557*3a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
558*3a749623SJacob Keller 	int err;
559*3a749623SJacob Keller 
560*3a749623SJacob Keller 	if (quad >= ICE_MAX_QUAD)
561*3a749623SJacob Keller 		return -EINVAL;
562*3a749623SJacob Keller 
563*3a749623SJacob Keller 	ice_fill_quad_msg_e822(&msg, quad, offset);
564*3a749623SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
565*3a749623SJacob Keller 	msg.data = val;
566*3a749623SJacob Keller 
567*3a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
568*3a749623SJacob Keller 	if (err) {
569*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
570*3a749623SJacob Keller 			  err);
571*3a749623SJacob Keller 		return err;
572*3a749623SJacob Keller 	}
573*3a749623SJacob Keller 
574*3a749623SJacob Keller 	return 0;
575*3a749623SJacob Keller }
576*3a749623SJacob Keller 
577*3a749623SJacob Keller /**
578*3a749623SJacob Keller  * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block
579*3a749623SJacob Keller  * @hw: pointer to the HW struct
580*3a749623SJacob Keller  * @quad: the quad to read from
581*3a749623SJacob Keller  * @idx: the timestamp index to read
582*3a749623SJacob Keller  * @tstamp: on return, the 40bit timestamp value
583*3a749623SJacob Keller  *
584*3a749623SJacob Keller  * Read a 40bit timestamp value out of the two associated registers in the
585*3a749623SJacob Keller  * quad memory block that is shared between the internal PHYs of the E822
586*3a749623SJacob Keller  * family of devices.
587*3a749623SJacob Keller  */
588*3a749623SJacob Keller static int
589*3a749623SJacob Keller ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
590*3a749623SJacob Keller {
591*3a749623SJacob Keller 	u16 lo_addr, hi_addr;
592*3a749623SJacob Keller 	u32 lo, hi;
593*3a749623SJacob Keller 	int err;
594*3a749623SJacob Keller 
595*3a749623SJacob Keller 	lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
596*3a749623SJacob Keller 	hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
597*3a749623SJacob Keller 
598*3a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);
599*3a749623SJacob Keller 	if (err) {
600*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
601*3a749623SJacob Keller 			  err);
602*3a749623SJacob Keller 		return err;
603*3a749623SJacob Keller 	}
604*3a749623SJacob Keller 
605*3a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);
606*3a749623SJacob Keller 	if (err) {
607*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
608*3a749623SJacob Keller 			  err);
609*3a749623SJacob Keller 		return err;
610*3a749623SJacob Keller 	}
611*3a749623SJacob Keller 
612*3a749623SJacob Keller 	/* For E822 based internal PHYs, the timestamp is reported with the
613*3a749623SJacob Keller 	 * lower 8 bits in the low register, and the upper 32 bits in the high
614*3a749623SJacob Keller 	 * register.
615*3a749623SJacob Keller 	 */
616*3a749623SJacob Keller 	*tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
617*3a749623SJacob Keller 
618*3a749623SJacob Keller 	return 0;
619*3a749623SJacob Keller }
620*3a749623SJacob Keller 
621*3a749623SJacob Keller /**
622*3a749623SJacob Keller  * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block
623*3a749623SJacob Keller  * @hw: pointer to the HW struct
624*3a749623SJacob Keller  * @quad: the quad to read from
625*3a749623SJacob Keller  * @idx: the timestamp index to reset
626*3a749623SJacob Keller  *
627*3a749623SJacob Keller  * Clear a timestamp, resetting its valid bit, from the PHY quad block that is
628*3a749623SJacob Keller  * shared between the internal PHYs on the E822 devices.
629*3a749623SJacob Keller  */
630*3a749623SJacob Keller static int
631*3a749623SJacob Keller ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
632*3a749623SJacob Keller {
633*3a749623SJacob Keller 	u16 lo_addr, hi_addr;
634*3a749623SJacob Keller 	int err;
635*3a749623SJacob Keller 
636*3a749623SJacob Keller 	lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
637*3a749623SJacob Keller 	hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
638*3a749623SJacob Keller 
639*3a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);
640*3a749623SJacob Keller 	if (err) {
641*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
642*3a749623SJacob Keller 			  err);
643*3a749623SJacob Keller 		return err;
644*3a749623SJacob Keller 	}
645*3a749623SJacob Keller 
646*3a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);
647*3a749623SJacob Keller 	if (err) {
648*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
649*3a749623SJacob Keller 			  err);
650*3a749623SJacob Keller 		return err;
651*3a749623SJacob Keller 	}
652*3a749623SJacob Keller 
653*3a749623SJacob Keller 	return 0;
654*3a749623SJacob Keller }
655*3a749623SJacob Keller 
656*3a749623SJacob Keller /**
657*3a749623SJacob Keller  * ice_ptp_set_vernier_wl - Set the window length for vernier calibration
658*3a749623SJacob Keller  * @hw: pointer to the HW struct
659*3a749623SJacob Keller  *
660*3a749623SJacob Keller  * Set the window length used for the vernier port calibration process.
661*3a749623SJacob Keller  */
662*3a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw)
663*3a749623SJacob Keller {
664*3a749623SJacob Keller 	u8 port;
665*3a749623SJacob Keller 
666*3a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
667*3a749623SJacob Keller 		int err;
668*3a749623SJacob Keller 
669*3a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_WL,
670*3a749623SJacob Keller 					     PTP_VERNIER_WL);
671*3a749623SJacob Keller 		if (err) {
672*3a749623SJacob Keller 			ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n",
673*3a749623SJacob Keller 				  port, err);
674*3a749623SJacob Keller 			return err;
675*3a749623SJacob Keller 		}
676*3a749623SJacob Keller 	}
677*3a749623SJacob Keller 
678*3a749623SJacob Keller 	return 0;
679*3a749623SJacob Keller }
680*3a749623SJacob Keller 
681*3a749623SJacob Keller /**
682*3a749623SJacob Keller  * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization
683*3a749623SJacob Keller  * @hw: pointer to HW struct
684*3a749623SJacob Keller  *
685*3a749623SJacob Keller  * Perform PHC initialization steps specific to E822 devices.
686*3a749623SJacob Keller  */
687*3a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw)
688*3a749623SJacob Keller {
689*3a749623SJacob Keller 	u32 regval;
690*3a749623SJacob Keller 
691*3a749623SJacob Keller 	/* Enable reading switch and PHY registers over the sideband queue */
692*3a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
693*3a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
694*3a749623SJacob Keller 	regval = rd32(hw, PF_SB_REM_DEV_CTL);
695*3a749623SJacob Keller 	regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
696*3a749623SJacob Keller 		   PF_SB_REM_DEV_CTL_PHY0);
697*3a749623SJacob Keller 	wr32(hw, PF_SB_REM_DEV_CTL, regval);
698*3a749623SJacob Keller 
699*3a749623SJacob Keller 	/* Set window length for all the ports */
700*3a749623SJacob Keller 	return ice_ptp_set_vernier_wl(hw);
701*3a749623SJacob Keller }
702*3a749623SJacob Keller 
703*3a749623SJacob Keller /**
704*3a749623SJacob Keller  * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time
705*3a749623SJacob Keller  * @hw: pointer to the HW struct
706*3a749623SJacob Keller  * @time: Time to initialize the PHY port clocks to
707*3a749623SJacob Keller  *
708*3a749623SJacob Keller  * Program the PHY port registers with a new initial time value. The port
709*3a749623SJacob Keller  * clock will be initialized once the driver issues an INIT_TIME sync
710*3a749623SJacob Keller  * command. The time value is the upper 32 bits of the PHY timer, usually in
711*3a749623SJacob Keller  * units of nominal nanoseconds.
712*3a749623SJacob Keller  */
713*3a749623SJacob Keller static int
714*3a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
715*3a749623SJacob Keller {
716*3a749623SJacob Keller 	u64 phy_time;
717*3a749623SJacob Keller 	u8 port;
718*3a749623SJacob Keller 	int err;
719*3a749623SJacob Keller 
720*3a749623SJacob Keller 	/* The time represents the upper 32 bits of the PHY timer, so we need
721*3a749623SJacob Keller 	 * to shift to account for this when programming.
722*3a749623SJacob Keller 	 */
723*3a749623SJacob Keller 	phy_time = (u64)time << 32;
724*3a749623SJacob Keller 
725*3a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
726*3a749623SJacob Keller 		/* Tx case */
727*3a749623SJacob Keller 		err = ice_write_64b_phy_reg_e822(hw, port,
728*3a749623SJacob Keller 						 P_REG_TX_TIMER_INC_PRE_L,
729*3a749623SJacob Keller 						 phy_time);
730*3a749623SJacob Keller 		if (err)
731*3a749623SJacob Keller 			goto exit_err;
732*3a749623SJacob Keller 
733*3a749623SJacob Keller 		/* Rx case */
734*3a749623SJacob Keller 		err = ice_write_64b_phy_reg_e822(hw, port,
735*3a749623SJacob Keller 						 P_REG_RX_TIMER_INC_PRE_L,
736*3a749623SJacob Keller 						 phy_time);
737*3a749623SJacob Keller 		if (err)
738*3a749623SJacob Keller 			goto exit_err;
739*3a749623SJacob Keller 	}
740*3a749623SJacob Keller 
741*3a749623SJacob Keller 	return 0;
742*3a749623SJacob Keller 
743*3a749623SJacob Keller exit_err:
744*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n",
745*3a749623SJacob Keller 		  port, err);
746*3a749623SJacob Keller 
747*3a749623SJacob Keller 	return err;
748*3a749623SJacob Keller }
749*3a749623SJacob Keller 
750*3a749623SJacob Keller /**
751*3a749623SJacob Keller  * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust
752*3a749623SJacob Keller  * @hw: pointer to HW struct
753*3a749623SJacob Keller  * @port: Port number to be programmed
754*3a749623SJacob Keller  * @time: time in cycles to adjust the port Tx and Rx clocks
755*3a749623SJacob Keller  *
756*3a749623SJacob Keller  * Program the port for an atomic adjustment by writing the Tx and Rx timer
757*3a749623SJacob Keller  * registers. The atomic adjustment won't be completed until the driver issues
758*3a749623SJacob Keller  * an ADJ_TIME command.
759*3a749623SJacob Keller  *
760*3a749623SJacob Keller  * Note that time is not in units of nanoseconds. It is in clock time
761*3a749623SJacob Keller  * including the lower sub-nanosecond portion of the port timer.
762*3a749623SJacob Keller  *
763*3a749623SJacob Keller  * Negative adjustments are supported using 2s complement arithmetic.
764*3a749623SJacob Keller  */
765*3a749623SJacob Keller int
766*3a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time)
767*3a749623SJacob Keller {
768*3a749623SJacob Keller 	u32 l_time, u_time;
769*3a749623SJacob Keller 	int err;
770*3a749623SJacob Keller 
771*3a749623SJacob Keller 	l_time = lower_32_bits(time);
772*3a749623SJacob Keller 	u_time = upper_32_bits(time);
773*3a749623SJacob Keller 
774*3a749623SJacob Keller 	/* Tx case */
775*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L,
776*3a749623SJacob Keller 				     l_time);
777*3a749623SJacob Keller 	if (err)
778*3a749623SJacob Keller 		goto exit_err;
779*3a749623SJacob Keller 
780*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U,
781*3a749623SJacob Keller 				     u_time);
782*3a749623SJacob Keller 	if (err)
783*3a749623SJacob Keller 		goto exit_err;
784*3a749623SJacob Keller 
785*3a749623SJacob Keller 	/* Rx case */
786*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L,
787*3a749623SJacob Keller 				     l_time);
788*3a749623SJacob Keller 	if (err)
789*3a749623SJacob Keller 		goto exit_err;
790*3a749623SJacob Keller 
791*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U,
792*3a749623SJacob Keller 				     u_time);
793*3a749623SJacob Keller 	if (err)
794*3a749623SJacob Keller 		goto exit_err;
795*3a749623SJacob Keller 
796*3a749623SJacob Keller 	return 0;
797*3a749623SJacob Keller 
798*3a749623SJacob Keller exit_err:
799*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n",
800*3a749623SJacob Keller 		  port, err);
801*3a749623SJacob Keller 	return err;
802*3a749623SJacob Keller }
803*3a749623SJacob Keller 
804*3a749623SJacob Keller /**
805*3a749623SJacob Keller  * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment
806*3a749623SJacob Keller  * @hw: pointer to HW struct
807*3a749623SJacob Keller  * @adj: adjustment in nanoseconds
808*3a749623SJacob Keller  *
809*3a749623SJacob Keller  * Prepare the PHY ports for an atomic time adjustment by programming the PHY
810*3a749623SJacob Keller  * Tx and Rx port registers. The actual adjustment is completed by issuing an
811*3a749623SJacob Keller  * ADJ_TIME or ADJ_TIME_AT_TIME sync command.
812*3a749623SJacob Keller  */
813*3a749623SJacob Keller static int
814*3a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
815*3a749623SJacob Keller {
816*3a749623SJacob Keller 	s64 cycles;
817*3a749623SJacob Keller 	u8 port;
818*3a749623SJacob Keller 
819*3a749623SJacob Keller 	/* The port clock supports adjustment of the sub-nanosecond portion of
820*3a749623SJacob Keller 	 * the clock. We shift the provided adjustment in nanoseconds to
821*3a749623SJacob Keller 	 * calculate the appropriate adjustment to program into the PHY ports.
822*3a749623SJacob Keller 	 */
823*3a749623SJacob Keller 	if (adj > 0)
824*3a749623SJacob Keller 		cycles = (s64)adj << 32;
825*3a749623SJacob Keller 	else
826*3a749623SJacob Keller 		cycles = -(((s64)-adj) << 32);
827*3a749623SJacob Keller 
828*3a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
829*3a749623SJacob Keller 		int err;
830*3a749623SJacob Keller 
831*3a749623SJacob Keller 		err = ice_ptp_prep_port_adj_e822(hw, port, cycles);
832*3a749623SJacob Keller 		if (err)
833*3a749623SJacob Keller 			return err;
834*3a749623SJacob Keller 	}
835*3a749623SJacob Keller 
836*3a749623SJacob Keller 	return 0;
837*3a749623SJacob Keller }
838*3a749623SJacob Keller 
839*3a749623SJacob Keller /**
840*3a749623SJacob Keller  * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment
841*3a749623SJacob Keller  * @hw: pointer to HW struct
842*3a749623SJacob Keller  * @incval: new increment value to prepare
843*3a749623SJacob Keller  *
844*3a749623SJacob Keller  * Prepare each of the PHY ports for a new increment value by programming the
845*3a749623SJacob Keller  * port's TIMETUS registers. The new increment value will be updated after
846*3a749623SJacob Keller  * issuing an INIT_INCVAL command.
847*3a749623SJacob Keller  */
848*3a749623SJacob Keller static int
849*3a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
850*3a749623SJacob Keller {
851*3a749623SJacob Keller 	int err;
852*3a749623SJacob Keller 	u8 port;
853*3a749623SJacob Keller 
854*3a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
855*3a749623SJacob Keller 		err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,
856*3a749623SJacob Keller 						 incval);
857*3a749623SJacob Keller 		if (err)
858*3a749623SJacob Keller 			goto exit_err;
859*3a749623SJacob Keller 	}
860*3a749623SJacob Keller 
861*3a749623SJacob Keller 	return 0;
862*3a749623SJacob Keller 
863*3a749623SJacob Keller exit_err:
864*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n",
865*3a749623SJacob Keller 		  port, err);
866*3a749623SJacob Keller 
867*3a749623SJacob Keller 	return err;
868*3a749623SJacob Keller }
869*3a749623SJacob Keller 
870*3a749623SJacob Keller /**
871*3a749623SJacob Keller  * ice_ptp_read_port_capture - Read a port's local time capture
872*3a749623SJacob Keller  * @hw: pointer to HW struct
873*3a749623SJacob Keller  * @port: Port number to read
874*3a749623SJacob Keller  * @tx_ts: on return, the Tx port time capture
875*3a749623SJacob Keller  * @rx_ts: on return, the Rx port time capture
876*3a749623SJacob Keller  *
877*3a749623SJacob Keller  * Read the port's Tx and Rx local time capture values.
878*3a749623SJacob Keller  *
879*3a749623SJacob Keller  * Note this has no equivalent for the E810 devices.
880*3a749623SJacob Keller  */
881*3a749623SJacob Keller static int
882*3a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
883*3a749623SJacob Keller {
884*3a749623SJacob Keller 	int err;
885*3a749623SJacob Keller 
886*3a749623SJacob Keller 	/* Tx case */
887*3a749623SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
888*3a749623SJacob Keller 	if (err) {
889*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n",
890*3a749623SJacob Keller 			  err);
891*3a749623SJacob Keller 		return err;
892*3a749623SJacob Keller 	}
893*3a749623SJacob Keller 
894*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n",
895*3a749623SJacob Keller 		  (unsigned long long)*tx_ts);
896*3a749623SJacob Keller 
897*3a749623SJacob Keller 	/* Rx case */
898*3a749623SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
899*3a749623SJacob Keller 	if (err) {
900*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n",
901*3a749623SJacob Keller 			  err);
902*3a749623SJacob Keller 		return err;
903*3a749623SJacob Keller 	}
904*3a749623SJacob Keller 
905*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n",
906*3a749623SJacob Keller 		  (unsigned long long)*rx_ts);
907*3a749623SJacob Keller 
908*3a749623SJacob Keller 	return 0;
909*3a749623SJacob Keller }
910*3a749623SJacob Keller 
911*3a749623SJacob Keller /**
912*3a749623SJacob Keller  * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command
913*3a749623SJacob Keller  * @hw: pointer to HW struct
914*3a749623SJacob Keller  * @port: Port to which cmd has to be sent
915*3a749623SJacob Keller  * @cmd: Command to be sent to the port
916*3a749623SJacob Keller  *
917*3a749623SJacob Keller  * Prepare the requested port for an upcoming timer sync command.
918*3a749623SJacob Keller  *
919*3a749623SJacob Keller  * Note there is no equivalent of this operation on E810, as that device
920*3a749623SJacob Keller  * always handles all external PHYs internally.
921*3a749623SJacob Keller  */
922*3a749623SJacob Keller static int
923*3a749623SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
924*3a749623SJacob Keller {
925*3a749623SJacob Keller 	u32 cmd_val, val;
926*3a749623SJacob Keller 	u8 tmr_idx;
927*3a749623SJacob Keller 	int err;
928*3a749623SJacob Keller 
929*3a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
930*3a749623SJacob Keller 	cmd_val = tmr_idx << SEL_PHY_SRC;
931*3a749623SJacob Keller 	switch (cmd) {
932*3a749623SJacob Keller 	case INIT_TIME:
933*3a749623SJacob Keller 		cmd_val |= PHY_CMD_INIT_TIME;
934*3a749623SJacob Keller 		break;
935*3a749623SJacob Keller 	case INIT_INCVAL:
936*3a749623SJacob Keller 		cmd_val |= PHY_CMD_INIT_INCVAL;
937*3a749623SJacob Keller 		break;
938*3a749623SJacob Keller 	case ADJ_TIME:
939*3a749623SJacob Keller 		cmd_val |= PHY_CMD_ADJ_TIME;
940*3a749623SJacob Keller 		break;
941*3a749623SJacob Keller 	case READ_TIME:
942*3a749623SJacob Keller 		cmd_val |= PHY_CMD_READ_TIME;
943*3a749623SJacob Keller 		break;
944*3a749623SJacob Keller 	case ADJ_TIME_AT_TIME:
945*3a749623SJacob Keller 		cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
946*3a749623SJacob Keller 		break;
947*3a749623SJacob Keller 	}
948*3a749623SJacob Keller 
949*3a749623SJacob Keller 	/* Tx case */
950*3a749623SJacob Keller 	/* Read, modify, write */
951*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val);
952*3a749623SJacob Keller 	if (err) {
953*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n",
954*3a749623SJacob Keller 			  err);
955*3a749623SJacob Keller 		return err;
956*3a749623SJacob Keller 	}
957*3a749623SJacob Keller 
958*3a749623SJacob Keller 	/* Modify necessary bits only and perform write */
959*3a749623SJacob Keller 	val &= ~TS_CMD_MASK;
960*3a749623SJacob Keller 	val |= cmd_val;
961*3a749623SJacob Keller 
962*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val);
963*3a749623SJacob Keller 	if (err) {
964*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n",
965*3a749623SJacob Keller 			  err);
966*3a749623SJacob Keller 		return err;
967*3a749623SJacob Keller 	}
968*3a749623SJacob Keller 
969*3a749623SJacob Keller 	/* Rx case */
970*3a749623SJacob Keller 	/* Read, modify, write */
971*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val);
972*3a749623SJacob Keller 	if (err) {
973*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n",
974*3a749623SJacob Keller 			  err);
975*3a749623SJacob Keller 		return err;
976*3a749623SJacob Keller 	}
977*3a749623SJacob Keller 
978*3a749623SJacob Keller 	/* Modify necessary bits only and perform write */
979*3a749623SJacob Keller 	val &= ~TS_CMD_MASK;
980*3a749623SJacob Keller 	val |= cmd_val;
981*3a749623SJacob Keller 
982*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val);
983*3a749623SJacob Keller 	if (err) {
984*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n",
985*3a749623SJacob Keller 			  err);
986*3a749623SJacob Keller 		return err;
987*3a749623SJacob Keller 	}
988*3a749623SJacob Keller 
989*3a749623SJacob Keller 	return 0;
990*3a749623SJacob Keller }
991*3a749623SJacob Keller 
992*3a749623SJacob Keller /**
993*3a749623SJacob Keller  * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
994*3a749623SJacob Keller  * @hw: pointer to the HW struct
995*3a749623SJacob Keller  * @cmd: timer command to prepare
996*3a749623SJacob Keller  *
997*3a749623SJacob Keller  * Prepare all ports connected to this device for an upcoming timer sync
998*3a749623SJacob Keller  * command.
999*3a749623SJacob Keller  */
1000*3a749623SJacob Keller static int
1001*3a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
1002*3a749623SJacob Keller {
1003*3a749623SJacob Keller 	u8 port;
1004*3a749623SJacob Keller 
1005*3a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1006*3a749623SJacob Keller 		int err;
1007*3a749623SJacob Keller 
1008*3a749623SJacob Keller 		err = ice_ptp_one_port_cmd(hw, port, cmd);
1009*3a749623SJacob Keller 		if (err)
1010*3a749623SJacob Keller 			return err;
1011*3a749623SJacob Keller 	}
1012*3a749623SJacob Keller 
1013*3a749623SJacob Keller 	return 0;
1014*3a749623SJacob Keller }
1015*3a749623SJacob Keller 
1016*3a749623SJacob Keller /* E822 Vernier calibration functions
1017*3a749623SJacob Keller  *
1018*3a749623SJacob Keller  * The following functions are used as part of the vernier calibration of
1019*3a749623SJacob Keller  * a port. This calibration increases the precision of the timestamps on the
1020*3a749623SJacob Keller  * port.
1021*3a749623SJacob Keller  */
1022*3a749623SJacob Keller 
1023*3a749623SJacob Keller /**
1024*3a749623SJacob Keller  * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode
1025*3a749623SJacob Keller  * @hw: pointer to HW struct
1026*3a749623SJacob Keller  * @port: the port to read from
1027*3a749623SJacob Keller  * @link_out: if non-NULL, holds link speed on success
1028*3a749623SJacob Keller  * @fec_out: if non-NULL, holds FEC algorithm on success
1029*3a749623SJacob Keller  *
1030*3a749623SJacob Keller  * Read the serdes data for the PHY port and extract the link speed and FEC
1031*3a749623SJacob Keller  * algorithm.
1032*3a749623SJacob Keller  */
1033*3a749623SJacob Keller static int
1034*3a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
1035*3a749623SJacob Keller 			       enum ice_ptp_link_spd *link_out,
1036*3a749623SJacob Keller 			       enum ice_ptp_fec_mode *fec_out)
1037*3a749623SJacob Keller {
1038*3a749623SJacob Keller 	enum ice_ptp_link_spd link;
1039*3a749623SJacob Keller 	enum ice_ptp_fec_mode fec;
1040*3a749623SJacob Keller 	u32 serdes;
1041*3a749623SJacob Keller 	int err;
1042*3a749623SJacob Keller 
1043*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);
1044*3a749623SJacob Keller 	if (err) {
1045*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n");
1046*3a749623SJacob Keller 		return err;
1047*3a749623SJacob Keller 	}
1048*3a749623SJacob Keller 
1049*3a749623SJacob Keller 	/* Determine the FEC algorithm */
1050*3a749623SJacob Keller 	fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes);
1051*3a749623SJacob Keller 
1052*3a749623SJacob Keller 	serdes &= P_REG_LINK_SPEED_SERDES_M;
1053*3a749623SJacob Keller 
1054*3a749623SJacob Keller 	/* Determine the link speed */
1055*3a749623SJacob Keller 	if (fec == ICE_PTP_FEC_MODE_RS_FEC) {
1056*3a749623SJacob Keller 		switch (serdes) {
1057*3a749623SJacob Keller 		case ICE_PTP_SERDES_25G:
1058*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_25G_RS;
1059*3a749623SJacob Keller 			break;
1060*3a749623SJacob Keller 		case ICE_PTP_SERDES_50G:
1061*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_50G_RS;
1062*3a749623SJacob Keller 			break;
1063*3a749623SJacob Keller 		case ICE_PTP_SERDES_100G:
1064*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_100G_RS;
1065*3a749623SJacob Keller 			break;
1066*3a749623SJacob Keller 		default:
1067*3a749623SJacob Keller 			return -EIO;
1068*3a749623SJacob Keller 		}
1069*3a749623SJacob Keller 	} else {
1070*3a749623SJacob Keller 		switch (serdes) {
1071*3a749623SJacob Keller 		case ICE_PTP_SERDES_1G:
1072*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_1G;
1073*3a749623SJacob Keller 			break;
1074*3a749623SJacob Keller 		case ICE_PTP_SERDES_10G:
1075*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_10G;
1076*3a749623SJacob Keller 			break;
1077*3a749623SJacob Keller 		case ICE_PTP_SERDES_25G:
1078*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_25G;
1079*3a749623SJacob Keller 			break;
1080*3a749623SJacob Keller 		case ICE_PTP_SERDES_40G:
1081*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_40G;
1082*3a749623SJacob Keller 			break;
1083*3a749623SJacob Keller 		case ICE_PTP_SERDES_50G:
1084*3a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_50G;
1085*3a749623SJacob Keller 			break;
1086*3a749623SJacob Keller 		default:
1087*3a749623SJacob Keller 			return -EIO;
1088*3a749623SJacob Keller 		}
1089*3a749623SJacob Keller 	}
1090*3a749623SJacob Keller 
1091*3a749623SJacob Keller 	if (link_out)
1092*3a749623SJacob Keller 		*link_out = link;
1093*3a749623SJacob Keller 	if (fec_out)
1094*3a749623SJacob Keller 		*fec_out = fec;
1095*3a749623SJacob Keller 
1096*3a749623SJacob Keller 	return 0;
1097*3a749623SJacob Keller }
1098*3a749623SJacob Keller 
1099*3a749623SJacob Keller /**
1100*3a749623SJacob Keller  * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp
1101*3a749623SJacob Keller  * @hw: pointer to HW struct
1102*3a749623SJacob Keller  * @port: to configure the quad for
1103*3a749623SJacob Keller  */
1104*3a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
1105*3a749623SJacob Keller {
1106*3a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
1107*3a749623SJacob Keller 	int err;
1108*3a749623SJacob Keller 	u32 val;
1109*3a749623SJacob Keller 	u8 quad;
1110*3a749623SJacob Keller 
1111*3a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);
1112*3a749623SJacob Keller 	if (err) {
1113*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n",
1114*3a749623SJacob Keller 			  err);
1115*3a749623SJacob Keller 		return;
1116*3a749623SJacob Keller 	}
1117*3a749623SJacob Keller 
1118*3a749623SJacob Keller 	quad = port / ICE_PORTS_PER_QUAD;
1119*3a749623SJacob Keller 
1120*3a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
1121*3a749623SJacob Keller 	if (err) {
1122*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n",
1123*3a749623SJacob Keller 			  err);
1124*3a749623SJacob Keller 		return;
1125*3a749623SJacob Keller 	}
1126*3a749623SJacob Keller 
1127*3a749623SJacob Keller 	if (link_spd >= ICE_PTP_LNK_SPD_40G)
1128*3a749623SJacob Keller 		val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
1129*3a749623SJacob Keller 	else
1130*3a749623SJacob Keller 		val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
1131*3a749623SJacob Keller 
1132*3a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
1133*3a749623SJacob Keller 	if (err) {
1134*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n",
1135*3a749623SJacob Keller 			  err);
1136*3a749623SJacob Keller 		return;
1137*3a749623SJacob Keller 	}
1138*3a749623SJacob Keller }
1139*3a749623SJacob Keller 
1140*3a749623SJacob Keller /**
1141*3a749623SJacob Keller  * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822
1142*3a749623SJacob Keller  * @hw: pointer to the HW structure
1143*3a749623SJacob Keller  * @port: the port to configure
1144*3a749623SJacob Keller  *
1145*3a749623SJacob Keller  * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC
1146*3a749623SJacob Keller  * hardware clock time units (TUs). That is, determine the number of TUs per
1147*3a749623SJacob Keller  * serdes unit interval, and program the UIX registers with this conversion.
1148*3a749623SJacob Keller  *
1149*3a749623SJacob Keller  * This conversion is used as part of the calibration process when determining
1150*3a749623SJacob Keller  * the additional error of a timestamp vs the real time of transmission or
1151*3a749623SJacob Keller  * receipt of the packet.
1152*3a749623SJacob Keller  *
1153*3a749623SJacob Keller  * Hardware uses the number of TUs per 66 UIs, written to the UIX registers
1154*3a749623SJacob Keller  * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks.
1155*3a749623SJacob Keller  *
1156*3a749623SJacob Keller  * To calculate the conversion ratio, we use the following facts:
1157*3a749623SJacob Keller  *
1158*3a749623SJacob Keller  * a) the clock frequency in Hz (cycles per second)
1159*3a749623SJacob Keller  * b) the number of TUs per cycle (the increment value of the clock)
1160*3a749623SJacob Keller  * c) 1 second per 1 billion nanoseconds
1161*3a749623SJacob Keller  * d) the duration of 66 UIs in nanoseconds
1162*3a749623SJacob Keller  *
1163*3a749623SJacob Keller  * Given these facts, we can use the following table to work out what ratios
1164*3a749623SJacob Keller  * to multiply in order to get the number of TUs per 66 UIs:
1165*3a749623SJacob Keller  *
1166*3a749623SJacob Keller  * cycles |   1 second   | incval (TUs) | nanoseconds
1167*3a749623SJacob Keller  * -------+--------------+--------------+-------------
1168*3a749623SJacob Keller  * second | 1 billion ns |    cycle     |   66 UIs
1169*3a749623SJacob Keller  *
1170*3a749623SJacob Keller  * To perform the multiplication using integers without too much loss of
1171*3a749623SJacob Keller  * precision, we can take use the following equation:
1172*3a749623SJacob Keller  *
1173*3a749623SJacob Keller  * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion)
1174*3a749623SJacob Keller  *
1175*3a749623SJacob Keller  * We scale up to using 6600 UI instead of 66 in order to avoid fractional
1176*3a749623SJacob Keller  * nanosecond UIs (66 UI at 10G/40G is 6.4 ns)
1177*3a749623SJacob Keller  *
1178*3a749623SJacob Keller  * The increment value has a maximum expected range of about 34 bits, while
1179*3a749623SJacob Keller  * the frequency value is about 29 bits. Multiplying these values shouldn't
1180*3a749623SJacob Keller  * overflow the 64 bits. However, we must then further multiply them again by
1181*3a749623SJacob Keller  * the Serdes unit interval duration. To avoid overflow here, we split the
1182*3a749623SJacob Keller  * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and
1183*3a749623SJacob Keller  * a divide by 390,625,000. This does lose some precision, but avoids
1184*3a749623SJacob Keller  * miscalculation due to arithmetic overflow.
1185*3a749623SJacob Keller  */
1186*3a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
1187*3a749623SJacob Keller {
1188*3a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, uix;
1189*3a749623SJacob Keller 	int err;
1190*3a749623SJacob Keller 
1191*3a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1192*3a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
1193*3a749623SJacob Keller 
1194*3a749623SJacob Keller 	/* Calculate TUs per second divided by 256 */
1195*3a749623SJacob Keller 	tu_per_sec = (cur_freq * clk_incval) >> 8;
1196*3a749623SJacob Keller 
1197*3a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */
1198*3a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */
1199*3a749623SJacob Keller 
1200*3a749623SJacob Keller 	/* Program the 10Gb/40Gb conversion ratio */
1201*3a749623SJacob Keller 	uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000);
1202*3a749623SJacob Keller 
1203*3a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
1204*3a749623SJacob Keller 					 uix);
1205*3a749623SJacob Keller 	if (err) {
1206*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n",
1207*3a749623SJacob Keller 			  err);
1208*3a749623SJacob Keller 		return err;
1209*3a749623SJacob Keller 	}
1210*3a749623SJacob Keller 
1211*3a749623SJacob Keller 	/* Program the 25Gb/100Gb conversion ratio */
1212*3a749623SJacob Keller 	uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000);
1213*3a749623SJacob Keller 
1214*3a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
1215*3a749623SJacob Keller 					 uix);
1216*3a749623SJacob Keller 	if (err) {
1217*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n",
1218*3a749623SJacob Keller 			  err);
1219*3a749623SJacob Keller 		return err;
1220*3a749623SJacob Keller 	}
1221*3a749623SJacob Keller 
1222*3a749623SJacob Keller 	return 0;
1223*3a749623SJacob Keller }
1224*3a749623SJacob Keller 
1225*3a749623SJacob Keller /**
1226*3a749623SJacob Keller  * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle
1227*3a749623SJacob Keller  * @hw: pointer to the HW struct
1228*3a749623SJacob Keller  * @port: port to configure
1229*3a749623SJacob Keller  *
1230*3a749623SJacob Keller  * Configure the number of TUs for the PAR and PCS clocks used as part of the
1231*3a749623SJacob Keller  * timestamp calibration process. This depends on the link speed, as the PHY
1232*3a749623SJacob Keller  * uses different markers depending on the speed.
1233*3a749623SJacob Keller  *
1234*3a749623SJacob Keller  * 1Gb/10Gb/25Gb:
1235*3a749623SJacob Keller  * - Tx/Rx PAR/PCS markers
1236*3a749623SJacob Keller  *
1237*3a749623SJacob Keller  * 25Gb RS:
1238*3a749623SJacob Keller  * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
1239*3a749623SJacob Keller  *
1240*3a749623SJacob Keller  * 40Gb/50Gb:
1241*3a749623SJacob Keller  * - Tx/Rx PAR/PCS markers
1242*3a749623SJacob Keller  * - Rx Deskew PAR/PCS markers
1243*3a749623SJacob Keller  *
1244*3a749623SJacob Keller  * 50G RS and 100GB RS:
1245*3a749623SJacob Keller  * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
1246*3a749623SJacob Keller  * - Rx Deskew PAR/PCS markers
1247*3a749623SJacob Keller  * - Tx PAR/PCS markers
1248*3a749623SJacob Keller  *
1249*3a749623SJacob Keller  * To calculate the conversion, we use the PHC clock frequency (cycles per
1250*3a749623SJacob Keller  * second), the increment value (TUs per cycle), and the related PHY clock
1251*3a749623SJacob Keller  * frequency to calculate the TUs per unit of the PHY link clock. The
1252*3a749623SJacob Keller  * following table shows how the units convert:
1253*3a749623SJacob Keller  *
1254*3a749623SJacob Keller  * cycles |  TUs  | second
1255*3a749623SJacob Keller  * -------+-------+--------
1256*3a749623SJacob Keller  * second | cycle | cycles
1257*3a749623SJacob Keller  *
1258*3a749623SJacob Keller  * For each conversion register, look up the appropriate frequency from the
1259*3a749623SJacob Keller  * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program
1260*3a749623SJacob Keller  * this to the appropriate register, preparing hardware to perform timestamp
1261*3a749623SJacob Keller  * calibration to calculate the total Tx or Rx offset to adjust the timestamp
1262*3a749623SJacob Keller  * in order to calibrate for the internal PHY delays.
1263*3a749623SJacob Keller  *
1264*3a749623SJacob Keller  * Note that the increment value ranges up to ~34 bits, and the clock
1265*3a749623SJacob Keller  * frequency is ~29 bits, so multiplying them together should fit within the
1266*3a749623SJacob Keller  * 64 bit arithmetic.
1267*3a749623SJacob Keller  */
1268*3a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
1269*3a749623SJacob Keller {
1270*3a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, phy_tus;
1271*3a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
1272*3a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
1273*3a749623SJacob Keller 	int err;
1274*3a749623SJacob Keller 
1275*3a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1276*3a749623SJacob Keller 	if (err)
1277*3a749623SJacob Keller 		return err;
1278*3a749623SJacob Keller 
1279*3a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1280*3a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
1281*3a749623SJacob Keller 
1282*3a749623SJacob Keller 	/* Calculate TUs per cycle of the PHC clock */
1283*3a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
1284*3a749623SJacob Keller 
1285*3a749623SJacob Keller 	/* For each PHY conversion register, look up the appropriate link
1286*3a749623SJacob Keller 	 * speed frequency and determine the TUs per that clock's cycle time.
1287*3a749623SJacob Keller 	 * Split this into a high and low value and then program the
1288*3a749623SJacob Keller 	 * appropriate register. If that link speed does not use the
1289*3a749623SJacob Keller 	 * associated register, write zeros to clear it instead.
1290*3a749623SJacob Keller 	 */
1291*3a749623SJacob Keller 
1292*3a749623SJacob Keller 	/* P_REG_PAR_TX_TUS */
1293*3a749623SJacob Keller 	if (e822_vernier[link_spd].tx_par_clk)
1294*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1295*3a749623SJacob Keller 				  e822_vernier[link_spd].tx_par_clk);
1296*3a749623SJacob Keller 	else
1297*3a749623SJacob Keller 		phy_tus = 0;
1298*3a749623SJacob Keller 
1299*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,
1300*3a749623SJacob Keller 					 phy_tus);
1301*3a749623SJacob Keller 	if (err)
1302*3a749623SJacob Keller 		return err;
1303*3a749623SJacob Keller 
1304*3a749623SJacob Keller 	/* P_REG_PAR_RX_TUS */
1305*3a749623SJacob Keller 	if (e822_vernier[link_spd].rx_par_clk)
1306*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1307*3a749623SJacob Keller 				  e822_vernier[link_spd].rx_par_clk);
1308*3a749623SJacob Keller 	else
1309*3a749623SJacob Keller 		phy_tus = 0;
1310*3a749623SJacob Keller 
1311*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,
1312*3a749623SJacob Keller 					 phy_tus);
1313*3a749623SJacob Keller 	if (err)
1314*3a749623SJacob Keller 		return err;
1315*3a749623SJacob Keller 
1316*3a749623SJacob Keller 	/* P_REG_PCS_TX_TUS */
1317*3a749623SJacob Keller 	if (e822_vernier[link_spd].tx_pcs_clk)
1318*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1319*3a749623SJacob Keller 				  e822_vernier[link_spd].tx_pcs_clk);
1320*3a749623SJacob Keller 	else
1321*3a749623SJacob Keller 		phy_tus = 0;
1322*3a749623SJacob Keller 
1323*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,
1324*3a749623SJacob Keller 					 phy_tus);
1325*3a749623SJacob Keller 	if (err)
1326*3a749623SJacob Keller 		return err;
1327*3a749623SJacob Keller 
1328*3a749623SJacob Keller 	/* P_REG_PCS_RX_TUS */
1329*3a749623SJacob Keller 	if (e822_vernier[link_spd].rx_pcs_clk)
1330*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1331*3a749623SJacob Keller 				  e822_vernier[link_spd].rx_pcs_clk);
1332*3a749623SJacob Keller 	else
1333*3a749623SJacob Keller 		phy_tus = 0;
1334*3a749623SJacob Keller 
1335*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,
1336*3a749623SJacob Keller 					 phy_tus);
1337*3a749623SJacob Keller 	if (err)
1338*3a749623SJacob Keller 		return err;
1339*3a749623SJacob Keller 
1340*3a749623SJacob Keller 	/* P_REG_DESK_PAR_TX_TUS */
1341*3a749623SJacob Keller 	if (e822_vernier[link_spd].tx_desk_rsgb_par)
1342*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1343*3a749623SJacob Keller 				  e822_vernier[link_spd].tx_desk_rsgb_par);
1344*3a749623SJacob Keller 	else
1345*3a749623SJacob Keller 		phy_tus = 0;
1346*3a749623SJacob Keller 
1347*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,
1348*3a749623SJacob Keller 					 phy_tus);
1349*3a749623SJacob Keller 	if (err)
1350*3a749623SJacob Keller 		return err;
1351*3a749623SJacob Keller 
1352*3a749623SJacob Keller 	/* P_REG_DESK_PAR_RX_TUS */
1353*3a749623SJacob Keller 	if (e822_vernier[link_spd].rx_desk_rsgb_par)
1354*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1355*3a749623SJacob Keller 				  e822_vernier[link_spd].rx_desk_rsgb_par);
1356*3a749623SJacob Keller 	else
1357*3a749623SJacob Keller 		phy_tus = 0;
1358*3a749623SJacob Keller 
1359*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,
1360*3a749623SJacob Keller 					 phy_tus);
1361*3a749623SJacob Keller 	if (err)
1362*3a749623SJacob Keller 		return err;
1363*3a749623SJacob Keller 
1364*3a749623SJacob Keller 	/* P_REG_DESK_PCS_TX_TUS */
1365*3a749623SJacob Keller 	if (e822_vernier[link_spd].tx_desk_rsgb_pcs)
1366*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1367*3a749623SJacob Keller 				  e822_vernier[link_spd].tx_desk_rsgb_pcs);
1368*3a749623SJacob Keller 	else
1369*3a749623SJacob Keller 		phy_tus = 0;
1370*3a749623SJacob Keller 
1371*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,
1372*3a749623SJacob Keller 					 phy_tus);
1373*3a749623SJacob Keller 	if (err)
1374*3a749623SJacob Keller 		return err;
1375*3a749623SJacob Keller 
1376*3a749623SJacob Keller 	/* P_REG_DESK_PCS_RX_TUS */
1377*3a749623SJacob Keller 	if (e822_vernier[link_spd].rx_desk_rsgb_pcs)
1378*3a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
1379*3a749623SJacob Keller 				  e822_vernier[link_spd].rx_desk_rsgb_pcs);
1380*3a749623SJacob Keller 	else
1381*3a749623SJacob Keller 		phy_tus = 0;
1382*3a749623SJacob Keller 
1383*3a749623SJacob Keller 	return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,
1384*3a749623SJacob Keller 					  phy_tus);
1385*3a749623SJacob Keller }
1386*3a749623SJacob Keller 
1387*3a749623SJacob Keller /**
1388*3a749623SJacob Keller  * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port
1389*3a749623SJacob Keller  * @hw: pointer to the HW struct
1390*3a749623SJacob Keller  * @link_spd: the Link speed to calculate for
1391*3a749623SJacob Keller  *
1392*3a749623SJacob Keller  * Calculate the fixed offset due to known static latency data.
1393*3a749623SJacob Keller  */
1394*3a749623SJacob Keller static u64
1395*3a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
1396*3a749623SJacob Keller {
1397*3a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
1398*3a749623SJacob Keller 
1399*3a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1400*3a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
1401*3a749623SJacob Keller 
1402*3a749623SJacob Keller 	/* Calculate TUs per second */
1403*3a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
1404*3a749623SJacob Keller 
1405*3a749623SJacob Keller 	/* Calculate number of TUs to add for the fixed Tx latency. Since the
1406*3a749623SJacob Keller 	 * latency measurement is in 1/100th of a nanosecond, we need to
1407*3a749623SJacob Keller 	 * multiply by tu_per_sec and then divide by 1e11. This calculation
1408*3a749623SJacob Keller 	 * overflows 64 bit integer arithmetic, so break it up into two
1409*3a749623SJacob Keller 	 * divisions by 1e4 first then by 1e7.
1410*3a749623SJacob Keller 	 */
1411*3a749623SJacob Keller 	fixed_offset = div_u64(tu_per_sec, 10000);
1412*3a749623SJacob Keller 	fixed_offset *= e822_vernier[link_spd].tx_fixed_delay;
1413*3a749623SJacob Keller 	fixed_offset = div_u64(fixed_offset, 10000000);
1414*3a749623SJacob Keller 
1415*3a749623SJacob Keller 	return fixed_offset;
1416*3a749623SJacob Keller }
1417*3a749623SJacob Keller 
1418*3a749623SJacob Keller /**
1419*3a749623SJacob Keller  * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode
1420*3a749623SJacob Keller  * @hw: pointer to the HW struct
1421*3a749623SJacob Keller  * @port: the PHY port to configure
1422*3a749623SJacob Keller  *
1423*3a749623SJacob Keller  * Calculate and program the fixed Tx offset, and indicate that the offset is
1424*3a749623SJacob Keller  * ready. This can be used when operating in bypass mode.
1425*3a749623SJacob Keller  */
1426*3a749623SJacob Keller static int
1427*3a749623SJacob Keller ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port)
1428*3a749623SJacob Keller {
1429*3a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
1430*3a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
1431*3a749623SJacob Keller 	u64 total_offset;
1432*3a749623SJacob Keller 	int err;
1433*3a749623SJacob Keller 
1434*3a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1435*3a749623SJacob Keller 	if (err)
1436*3a749623SJacob Keller 		return err;
1437*3a749623SJacob Keller 
1438*3a749623SJacob Keller 	total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
1439*3a749623SJacob Keller 
1440*3a749623SJacob Keller 	/* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L
1441*3a749623SJacob Keller 	 * register, then indicate that the Tx offset is ready. After this,
1442*3a749623SJacob Keller 	 * timestamps will be enabled.
1443*3a749623SJacob Keller 	 *
1444*3a749623SJacob Keller 	 * Note that this skips including the more precise offsets generated
1445*3a749623SJacob Keller 	 * by the Vernier calibration.
1446*3a749623SJacob Keller 	 */
1447*3a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
1448*3a749623SJacob Keller 					 total_offset);
1449*3a749623SJacob Keller 	if (err)
1450*3a749623SJacob Keller 		return err;
1451*3a749623SJacob Keller 
1452*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
1453*3a749623SJacob Keller 	if (err)
1454*3a749623SJacob Keller 		return err;
1455*3a749623SJacob Keller 
1456*3a749623SJacob Keller 	return 0;
1457*3a749623SJacob Keller }
1458*3a749623SJacob Keller 
1459*3a749623SJacob Keller /**
1460*3a749623SJacob Keller  * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port
1461*3a749623SJacob Keller  * @hw: pointer to HW struct
1462*3a749623SJacob Keller  * @link_spd: The Link speed to calculate for
1463*3a749623SJacob Keller  *
1464*3a749623SJacob Keller  * Determine the fixed Rx latency for a given link speed.
1465*3a749623SJacob Keller  */
1466*3a749623SJacob Keller static u64
1467*3a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
1468*3a749623SJacob Keller {
1469*3a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
1470*3a749623SJacob Keller 
1471*3a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1472*3a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
1473*3a749623SJacob Keller 
1474*3a749623SJacob Keller 	/* Calculate TUs per second */
1475*3a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
1476*3a749623SJacob Keller 
1477*3a749623SJacob Keller 	/* Calculate number of TUs to add for the fixed Rx latency. Since the
1478*3a749623SJacob Keller 	 * latency measurement is in 1/100th of a nanosecond, we need to
1479*3a749623SJacob Keller 	 * multiply by tu_per_sec and then divide by 1e11. This calculation
1480*3a749623SJacob Keller 	 * overflows 64 bit integer arithmetic, so break it up into two
1481*3a749623SJacob Keller 	 * divisions by 1e4 first then by 1e7.
1482*3a749623SJacob Keller 	 */
1483*3a749623SJacob Keller 	fixed_offset = div_u64(tu_per_sec, 10000);
1484*3a749623SJacob Keller 	fixed_offset *= e822_vernier[link_spd].rx_fixed_delay;
1485*3a749623SJacob Keller 	fixed_offset = div_u64(fixed_offset, 10000000);
1486*3a749623SJacob Keller 
1487*3a749623SJacob Keller 	return fixed_offset;
1488*3a749623SJacob Keller }
1489*3a749623SJacob Keller 
1490*3a749623SJacob Keller /**
1491*3a749623SJacob Keller  * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode
1492*3a749623SJacob Keller  * @hw: pointer to the HW struct
1493*3a749623SJacob Keller  * @port: the PHY port to configure
1494*3a749623SJacob Keller  *
1495*3a749623SJacob Keller  * Calculate and program the fixed Rx offset, and indicate that the offset is
1496*3a749623SJacob Keller  * ready. This can be used when operating in bypass mode.
1497*3a749623SJacob Keller  */
1498*3a749623SJacob Keller static int
1499*3a749623SJacob Keller ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port)
1500*3a749623SJacob Keller {
1501*3a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
1502*3a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
1503*3a749623SJacob Keller 	u64 total_offset;
1504*3a749623SJacob Keller 	int err;
1505*3a749623SJacob Keller 
1506*3a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1507*3a749623SJacob Keller 	if (err)
1508*3a749623SJacob Keller 		return err;
1509*3a749623SJacob Keller 
1510*3a749623SJacob Keller 	total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
1511*3a749623SJacob Keller 
1512*3a749623SJacob Keller 	/* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L
1513*3a749623SJacob Keller 	 * register, then indicate that the Rx offset is ready. After this,
1514*3a749623SJacob Keller 	 * timestamps will be enabled.
1515*3a749623SJacob Keller 	 *
1516*3a749623SJacob Keller 	 * Note that this skips including the more precise offsets generated
1517*3a749623SJacob Keller 	 * by Vernier calibration.
1518*3a749623SJacob Keller 	 */
1519*3a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
1520*3a749623SJacob Keller 					 total_offset);
1521*3a749623SJacob Keller 	if (err)
1522*3a749623SJacob Keller 		return err;
1523*3a749623SJacob Keller 
1524*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
1525*3a749623SJacob Keller 	if (err)
1526*3a749623SJacob Keller 		return err;
1527*3a749623SJacob Keller 
1528*3a749623SJacob Keller 	return 0;
1529*3a749623SJacob Keller }
1530*3a749623SJacob Keller 
1531*3a749623SJacob Keller /**
1532*3a749623SJacob Keller  * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time
1533*3a749623SJacob Keller  * @hw: pointer to the HW struct
1534*3a749623SJacob Keller  * @port: the PHY port to read
1535*3a749623SJacob Keller  * @phy_time: on return, the 64bit PHY timer value
1536*3a749623SJacob Keller  * @phc_time: on return, the lower 64bits of PHC time
1537*3a749623SJacob Keller  *
1538*3a749623SJacob Keller  * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC
1539*3a749623SJacob Keller  * timer values.
1540*3a749623SJacob Keller  */
1541*3a749623SJacob Keller static int
1542*3a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
1543*3a749623SJacob Keller 			       u64 *phc_time)
1544*3a749623SJacob Keller {
1545*3a749623SJacob Keller 	u64 tx_time, rx_time;
1546*3a749623SJacob Keller 	u32 zo, lo;
1547*3a749623SJacob Keller 	u8 tmr_idx;
1548*3a749623SJacob Keller 	int err;
1549*3a749623SJacob Keller 
1550*3a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
1551*3a749623SJacob Keller 
1552*3a749623SJacob Keller 	/* Prepare the PHC timer for a READ_TIME capture command */
1553*3a749623SJacob Keller 	ice_ptp_src_cmd(hw, READ_TIME);
1554*3a749623SJacob Keller 
1555*3a749623SJacob Keller 	/* Prepare the PHY timer for a READ_TIME capture command */
1556*3a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, READ_TIME);
1557*3a749623SJacob Keller 	if (err)
1558*3a749623SJacob Keller 		return err;
1559*3a749623SJacob Keller 
1560*3a749623SJacob Keller 	/* Issue the sync to start the READ_TIME capture */
1561*3a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
1562*3a749623SJacob Keller 
1563*3a749623SJacob Keller 	/* Read the captured PHC time from the shadow time registers */
1564*3a749623SJacob Keller 	zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
1565*3a749623SJacob Keller 	lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
1566*3a749623SJacob Keller 	*phc_time = (u64)lo << 32 | zo;
1567*3a749623SJacob Keller 
1568*3a749623SJacob Keller 	/* Read the captured PHY time from the PHY shadow registers */
1569*3a749623SJacob Keller 	err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time);
1570*3a749623SJacob Keller 	if (err)
1571*3a749623SJacob Keller 		return err;
1572*3a749623SJacob Keller 
1573*3a749623SJacob Keller 	/* If the PHY Tx and Rx timers don't match, log a warning message.
1574*3a749623SJacob Keller 	 * Note that this should not happen in normal circumstances since the
1575*3a749623SJacob Keller 	 * driver always programs them together.
1576*3a749623SJacob Keller 	 */
1577*3a749623SJacob Keller 	if (tx_time != rx_time)
1578*3a749623SJacob Keller 		dev_warn(ice_hw_to_dev(hw),
1579*3a749623SJacob Keller 			 "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n",
1580*3a749623SJacob Keller 			 port, (unsigned long long)tx_time,
1581*3a749623SJacob Keller 			 (unsigned long long)rx_time);
1582*3a749623SJacob Keller 
1583*3a749623SJacob Keller 	*phy_time = tx_time;
1584*3a749623SJacob Keller 
1585*3a749623SJacob Keller 	return 0;
1586*3a749623SJacob Keller }
1587*3a749623SJacob Keller 
1588*3a749623SJacob Keller /**
1589*3a749623SJacob Keller  * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer
1590*3a749623SJacob Keller  * @hw: pointer to the HW struct
1591*3a749623SJacob Keller  * @port: the PHY port to synchronize
1592*3a749623SJacob Keller  *
1593*3a749623SJacob Keller  * Perform an adjustment to ensure that the PHY and PHC timers are in sync.
1594*3a749623SJacob Keller  * This is done by issuing a READ_TIME command which triggers a simultaneous
1595*3a749623SJacob Keller  * read of the PHY timer and PHC timer. Then we use the difference to
1596*3a749623SJacob Keller  * calculate an appropriate 2s complement addition to add to the PHY timer in
1597*3a749623SJacob Keller  * order to ensure it reads the same value as the primary PHC timer.
1598*3a749623SJacob Keller  */
1599*3a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
1600*3a749623SJacob Keller {
1601*3a749623SJacob Keller 	u64 phc_time, phy_time, difference;
1602*3a749623SJacob Keller 	int err;
1603*3a749623SJacob Keller 
1604*3a749623SJacob Keller 	if (!ice_ptp_lock(hw)) {
1605*3a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n");
1606*3a749623SJacob Keller 		return -EBUSY;
1607*3a749623SJacob Keller 	}
1608*3a749623SJacob Keller 
1609*3a749623SJacob Keller 	err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
1610*3a749623SJacob Keller 	if (err)
1611*3a749623SJacob Keller 		goto err_unlock;
1612*3a749623SJacob Keller 
1613*3a749623SJacob Keller 	/* Calculate the amount required to add to the port time in order for
1614*3a749623SJacob Keller 	 * it to match the PHC time.
1615*3a749623SJacob Keller 	 *
1616*3a749623SJacob Keller 	 * Note that the port adjustment is done using 2s complement
1617*3a749623SJacob Keller 	 * arithmetic. This is convenient since it means that we can simply
1618*3a749623SJacob Keller 	 * calculate the difference between the PHC time and the port time,
1619*3a749623SJacob Keller 	 * and it will be interpreted correctly.
1620*3a749623SJacob Keller 	 */
1621*3a749623SJacob Keller 	difference = phc_time - phy_time;
1622*3a749623SJacob Keller 
1623*3a749623SJacob Keller 	err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference);
1624*3a749623SJacob Keller 	if (err)
1625*3a749623SJacob Keller 		goto err_unlock;
1626*3a749623SJacob Keller 
1627*3a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME);
1628*3a749623SJacob Keller 	if (err)
1629*3a749623SJacob Keller 		goto err_unlock;
1630*3a749623SJacob Keller 
1631*3a749623SJacob Keller 	/* Issue the sync to activate the time adjustment */
1632*3a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
1633*3a749623SJacob Keller 
1634*3a749623SJacob Keller 	/* Re-capture the timer values to flush the command registers and
1635*3a749623SJacob Keller 	 * verify that the time was properly adjusted.
1636*3a749623SJacob Keller 	 */
1637*3a749623SJacob Keller 	err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
1638*3a749623SJacob Keller 	if (err)
1639*3a749623SJacob Keller 		goto err_unlock;
1640*3a749623SJacob Keller 
1641*3a749623SJacob Keller 	dev_info(ice_hw_to_dev(hw),
1642*3a749623SJacob Keller 		 "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n",
1643*3a749623SJacob Keller 		 port, (unsigned long long)phy_time,
1644*3a749623SJacob Keller 		 (unsigned long long)phc_time);
1645*3a749623SJacob Keller 
1646*3a749623SJacob Keller 	ice_ptp_unlock(hw);
1647*3a749623SJacob Keller 
1648*3a749623SJacob Keller 	return 0;
1649*3a749623SJacob Keller 
1650*3a749623SJacob Keller err_unlock:
1651*3a749623SJacob Keller 	ice_ptp_unlock(hw);
1652*3a749623SJacob Keller 	return err;
1653*3a749623SJacob Keller }
1654*3a749623SJacob Keller 
1655*3a749623SJacob Keller /**
1656*3a749623SJacob Keller  * ice_stop_phy_timer_e822 - Stop the PHY clock timer
1657*3a749623SJacob Keller  * @hw: pointer to the HW struct
1658*3a749623SJacob Keller  * @port: the PHY port to stop
1659*3a749623SJacob Keller  * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS
1660*3a749623SJacob Keller  *
1661*3a749623SJacob Keller  * Stop the clock of a PHY port. This must be done as part of the flow to
1662*3a749623SJacob Keller  * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
1663*3a749623SJacob Keller  * initialized or when link speed changes.
1664*3a749623SJacob Keller  */
1665*3a749623SJacob Keller int
1666*3a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
1667*3a749623SJacob Keller {
1668*3a749623SJacob Keller 	int err;
1669*3a749623SJacob Keller 	u32 val;
1670*3a749623SJacob Keller 
1671*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);
1672*3a749623SJacob Keller 	if (err)
1673*3a749623SJacob Keller 		return err;
1674*3a749623SJacob Keller 
1675*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);
1676*3a749623SJacob Keller 	if (err)
1677*3a749623SJacob Keller 		return err;
1678*3a749623SJacob Keller 
1679*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
1680*3a749623SJacob Keller 	if (err)
1681*3a749623SJacob Keller 		return err;
1682*3a749623SJacob Keller 
1683*3a749623SJacob Keller 	val &= ~P_REG_PS_START_M;
1684*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1685*3a749623SJacob Keller 	if (err)
1686*3a749623SJacob Keller 		return err;
1687*3a749623SJacob Keller 
1688*3a749623SJacob Keller 	val &= ~P_REG_PS_ENA_CLK_M;
1689*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1690*3a749623SJacob Keller 	if (err)
1691*3a749623SJacob Keller 		return err;
1692*3a749623SJacob Keller 
1693*3a749623SJacob Keller 	if (soft_reset) {
1694*3a749623SJacob Keller 		val |= P_REG_PS_SFT_RESET_M;
1695*3a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1696*3a749623SJacob Keller 		if (err)
1697*3a749623SJacob Keller 			return err;
1698*3a749623SJacob Keller 	}
1699*3a749623SJacob Keller 
1700*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port);
1701*3a749623SJacob Keller 
1702*3a749623SJacob Keller 	return 0;
1703*3a749623SJacob Keller }
1704*3a749623SJacob Keller 
1705*3a749623SJacob Keller /**
1706*3a749623SJacob Keller  * ice_start_phy_timer_e822 - Start the PHY clock timer
1707*3a749623SJacob Keller  * @hw: pointer to the HW struct
1708*3a749623SJacob Keller  * @port: the PHY port to start
1709*3a749623SJacob Keller  * @bypass: if true, start the PHY in bypass mode
1710*3a749623SJacob Keller  *
1711*3a749623SJacob Keller  * Start the clock of a PHY port. This must be done as part of the flow to
1712*3a749623SJacob Keller  * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
1713*3a749623SJacob Keller  * initialized or when link speed changes.
1714*3a749623SJacob Keller  *
1715*3a749623SJacob Keller  * Bypass mode enables timestamps immediately without waiting for Vernier
1716*3a749623SJacob Keller  * calibration to complete. Hardware will still continue taking Vernier
1717*3a749623SJacob Keller  * measurements on Tx or Rx of packets, but they will not be applied to
1718*3a749623SJacob Keller  * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware
1719*3a749623SJacob Keller  * has completed offset calculation.
1720*3a749623SJacob Keller  */
1721*3a749623SJacob Keller int
1722*3a749623SJacob Keller ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass)
1723*3a749623SJacob Keller {
1724*3a749623SJacob Keller 	u32 lo, hi, val;
1725*3a749623SJacob Keller 	u64 incval;
1726*3a749623SJacob Keller 	u8 tmr_idx;
1727*3a749623SJacob Keller 	int err;
1728*3a749623SJacob Keller 
1729*3a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
1730*3a749623SJacob Keller 
1731*3a749623SJacob Keller 	err = ice_stop_phy_timer_e822(hw, port, false);
1732*3a749623SJacob Keller 	if (err)
1733*3a749623SJacob Keller 		return err;
1734*3a749623SJacob Keller 
1735*3a749623SJacob Keller 	ice_phy_cfg_lane_e822(hw, port);
1736*3a749623SJacob Keller 
1737*3a749623SJacob Keller 	err = ice_phy_cfg_uix_e822(hw, port);
1738*3a749623SJacob Keller 	if (err)
1739*3a749623SJacob Keller 		return err;
1740*3a749623SJacob Keller 
1741*3a749623SJacob Keller 	err = ice_phy_cfg_parpcs_e822(hw, port);
1742*3a749623SJacob Keller 	if (err)
1743*3a749623SJacob Keller 		return err;
1744*3a749623SJacob Keller 
1745*3a749623SJacob Keller 	lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
1746*3a749623SJacob Keller 	hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
1747*3a749623SJacob Keller 	incval = (u64)hi << 32 | lo;
1748*3a749623SJacob Keller 
1749*3a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
1750*3a749623SJacob Keller 	if (err)
1751*3a749623SJacob Keller 		return err;
1752*3a749623SJacob Keller 
1753*3a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
1754*3a749623SJacob Keller 	if (err)
1755*3a749623SJacob Keller 		return err;
1756*3a749623SJacob Keller 
1757*3a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
1758*3a749623SJacob Keller 
1759*3a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
1760*3a749623SJacob Keller 	if (err)
1761*3a749623SJacob Keller 		return err;
1762*3a749623SJacob Keller 
1763*3a749623SJacob Keller 	val |= P_REG_PS_SFT_RESET_M;
1764*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1765*3a749623SJacob Keller 	if (err)
1766*3a749623SJacob Keller 		return err;
1767*3a749623SJacob Keller 
1768*3a749623SJacob Keller 	val |= P_REG_PS_START_M;
1769*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1770*3a749623SJacob Keller 	if (err)
1771*3a749623SJacob Keller 		return err;
1772*3a749623SJacob Keller 
1773*3a749623SJacob Keller 	val &= ~P_REG_PS_SFT_RESET_M;
1774*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1775*3a749623SJacob Keller 	if (err)
1776*3a749623SJacob Keller 		return err;
1777*3a749623SJacob Keller 
1778*3a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
1779*3a749623SJacob Keller 	if (err)
1780*3a749623SJacob Keller 		return err;
1781*3a749623SJacob Keller 
1782*3a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
1783*3a749623SJacob Keller 
1784*3a749623SJacob Keller 	val |= P_REG_PS_ENA_CLK_M;
1785*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1786*3a749623SJacob Keller 	if (err)
1787*3a749623SJacob Keller 		return err;
1788*3a749623SJacob Keller 
1789*3a749623SJacob Keller 	val |= P_REG_PS_LOAD_OFFSET_M;
1790*3a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1791*3a749623SJacob Keller 	if (err)
1792*3a749623SJacob Keller 		return err;
1793*3a749623SJacob Keller 
1794*3a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
1795*3a749623SJacob Keller 
1796*3a749623SJacob Keller 	err = ice_sync_phy_timer_e822(hw, port);
1797*3a749623SJacob Keller 	if (err)
1798*3a749623SJacob Keller 		return err;
1799*3a749623SJacob Keller 
1800*3a749623SJacob Keller 	if (bypass) {
1801*3a749623SJacob Keller 		val |= P_REG_PS_BYPASS_MODE_M;
1802*3a749623SJacob Keller 		/* Enter BYPASS mode, enabling timestamps immediately. */
1803*3a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
1804*3a749623SJacob Keller 		if (err)
1805*3a749623SJacob Keller 			return err;
1806*3a749623SJacob Keller 
1807*3a749623SJacob Keller 		/* Program the fixed Tx offset */
1808*3a749623SJacob Keller 		err = ice_phy_cfg_fixed_tx_offset_e822(hw, port);
1809*3a749623SJacob Keller 		if (err)
1810*3a749623SJacob Keller 			return err;
1811*3a749623SJacob Keller 
1812*3a749623SJacob Keller 		/* Program the fixed Rx offset */
1813*3a749623SJacob Keller 		err = ice_phy_cfg_fixed_rx_offset_e822(hw, port);
1814*3a749623SJacob Keller 		if (err)
1815*3a749623SJacob Keller 			return err;
1816*3a749623SJacob Keller 	}
1817*3a749623SJacob Keller 
1818*3a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
1819*3a749623SJacob Keller 
1820*3a749623SJacob Keller 	return 0;
1821*3a749623SJacob Keller }
1822*3a749623SJacob Keller 
182303cb4473SJacob Keller /* E810 functions
182403cb4473SJacob Keller  *
182503cb4473SJacob Keller  * The following functions operate on the E810 series devices which use
182603cb4473SJacob Keller  * a separate external PHY.
182703cb4473SJacob Keller  */
182803cb4473SJacob Keller 
182903cb4473SJacob Keller /**
183003cb4473SJacob Keller  * ice_read_phy_reg_e810 - Read register from external PHY on E810
183103cb4473SJacob Keller  * @hw: pointer to the HW struct
183203cb4473SJacob Keller  * @addr: the address to read from
183303cb4473SJacob Keller  * @val: On return, the value read from the PHY
183403cb4473SJacob Keller  *
183503cb4473SJacob Keller  * Read a register from the external PHY on the E810 device.
183603cb4473SJacob Keller  */
183703cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
183803cb4473SJacob Keller {
183903cb4473SJacob Keller 	struct ice_sbq_msg_input msg = {0};
184039b28106SJacob Keller 	int err;
184103cb4473SJacob Keller 
184203cb4473SJacob Keller 	msg.msg_addr_low = lower_16_bits(addr);
184303cb4473SJacob Keller 	msg.msg_addr_high = upper_16_bits(addr);
184403cb4473SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
184503cb4473SJacob Keller 	msg.dest_dev = rmn_0;
184603cb4473SJacob Keller 
184739b28106SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
184839b28106SJacob Keller 	if (err) {
184939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
185039b28106SJacob Keller 			  err);
185139b28106SJacob Keller 		return err;
185203cb4473SJacob Keller 	}
185303cb4473SJacob Keller 
185403cb4473SJacob Keller 	*val = msg.data;
185503cb4473SJacob Keller 
185603cb4473SJacob Keller 	return 0;
185703cb4473SJacob Keller }
185803cb4473SJacob Keller 
185903cb4473SJacob Keller /**
186003cb4473SJacob Keller  * ice_write_phy_reg_e810 - Write register on external PHY on E810
186103cb4473SJacob Keller  * @hw: pointer to the HW struct
186203cb4473SJacob Keller  * @addr: the address to writem to
186303cb4473SJacob Keller  * @val: the value to write to the PHY
186403cb4473SJacob Keller  *
186503cb4473SJacob Keller  * Write a value to a register of the external PHY on the E810 device.
186603cb4473SJacob Keller  */
186703cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
186803cb4473SJacob Keller {
186903cb4473SJacob Keller 	struct ice_sbq_msg_input msg = {0};
187039b28106SJacob Keller 	int err;
187103cb4473SJacob Keller 
187203cb4473SJacob Keller 	msg.msg_addr_low = lower_16_bits(addr);
187303cb4473SJacob Keller 	msg.msg_addr_high = upper_16_bits(addr);
187403cb4473SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
187503cb4473SJacob Keller 	msg.dest_dev = rmn_0;
187603cb4473SJacob Keller 	msg.data = val;
187703cb4473SJacob Keller 
187839b28106SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
187939b28106SJacob Keller 	if (err) {
188039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
188139b28106SJacob Keller 			  err);
188239b28106SJacob Keller 		return err;
188303cb4473SJacob Keller 	}
188403cb4473SJacob Keller 
188503cb4473SJacob Keller 	return 0;
188603cb4473SJacob Keller }
188703cb4473SJacob Keller 
188803cb4473SJacob Keller /**
188903cb4473SJacob Keller  * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
189003cb4473SJacob Keller  * @hw: pointer to the HW struct
189103cb4473SJacob Keller  * @lport: the lport to read from
189203cb4473SJacob Keller  * @idx: the timestamp index to read
189303cb4473SJacob Keller  * @tstamp: on return, the 40bit timestamp value
189403cb4473SJacob Keller  *
189503cb4473SJacob Keller  * Read a 40bit timestamp value out of the timestamp block of the external PHY
189603cb4473SJacob Keller  * on the E810 device.
189703cb4473SJacob Keller  */
189803cb4473SJacob Keller static int
189903cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
190003cb4473SJacob Keller {
190103cb4473SJacob Keller 	u32 lo_addr, hi_addr, lo, hi;
190239b28106SJacob Keller 	int err;
190303cb4473SJacob Keller 
190403cb4473SJacob Keller 	lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
190503cb4473SJacob Keller 	hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
190603cb4473SJacob Keller 
190739b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, lo_addr, &lo);
190839b28106SJacob Keller 	if (err) {
190939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
191039b28106SJacob Keller 			  err);
191139b28106SJacob Keller 		return err;
191203cb4473SJacob Keller 	}
191303cb4473SJacob Keller 
191439b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, hi_addr, &hi);
191539b28106SJacob Keller 	if (err) {
191639b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
191739b28106SJacob Keller 			  err);
191839b28106SJacob Keller 		return err;
191903cb4473SJacob Keller 	}
192003cb4473SJacob Keller 
192103cb4473SJacob Keller 	/* For E810 devices, the timestamp is reported with the lower 32 bits
192203cb4473SJacob Keller 	 * in the low register, and the upper 8 bits in the high register.
192303cb4473SJacob Keller 	 */
192403cb4473SJacob Keller 	*tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
192503cb4473SJacob Keller 
192603cb4473SJacob Keller 	return 0;
192703cb4473SJacob Keller }
192803cb4473SJacob Keller 
192903cb4473SJacob Keller /**
193003cb4473SJacob Keller  * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
193103cb4473SJacob Keller  * @hw: pointer to the HW struct
193203cb4473SJacob Keller  * @lport: the lport to read from
193303cb4473SJacob Keller  * @idx: the timestamp index to reset
193403cb4473SJacob Keller  *
193503cb4473SJacob Keller  * Clear a timestamp, resetting its valid bit, from the timestamp block of the
193603cb4473SJacob Keller  * external PHY on the E810 device.
193703cb4473SJacob Keller  */
193803cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
193903cb4473SJacob Keller {
194003cb4473SJacob Keller 	u32 lo_addr, hi_addr;
194139b28106SJacob Keller 	int err;
194203cb4473SJacob Keller 
194303cb4473SJacob Keller 	lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
194403cb4473SJacob Keller 	hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
194503cb4473SJacob Keller 
194639b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, lo_addr, 0);
194739b28106SJacob Keller 	if (err) {
194839b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
194939b28106SJacob Keller 			  err);
195039b28106SJacob Keller 		return err;
195103cb4473SJacob Keller 	}
195203cb4473SJacob Keller 
195339b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, hi_addr, 0);
195439b28106SJacob Keller 	if (err) {
195539b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
195639b28106SJacob Keller 			  err);
195739b28106SJacob Keller 		return err;
195803cb4473SJacob Keller 	}
195903cb4473SJacob Keller 
196003cb4473SJacob Keller 	return 0;
196103cb4473SJacob Keller }
196203cb4473SJacob Keller 
196303cb4473SJacob Keller /**
196403cb4473SJacob Keller  * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
196503cb4473SJacob Keller  * @hw: pointer to HW struct
196603cb4473SJacob Keller  *
196703cb4473SJacob Keller  * Enable the timesync PTP functionality for the external PHY connected to
196803cb4473SJacob Keller  * this function.
196903cb4473SJacob Keller  */
197003cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw)
197103cb4473SJacob Keller {
197203cb4473SJacob Keller 	u8 tmr_idx;
197339b28106SJacob Keller 	int err;
197403cb4473SJacob Keller 
197503cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
197639b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
197703cb4473SJacob Keller 				     GLTSYN_ENA_TSYN_ENA_M);
197839b28106SJacob Keller 	if (err)
197903cb4473SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
198039b28106SJacob Keller 			  err);
198103cb4473SJacob Keller 
198239b28106SJacob Keller 	return err;
198303cb4473SJacob Keller }
198403cb4473SJacob Keller 
198503cb4473SJacob Keller /**
1986b2ee7256SJacob Keller  * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization
1987b2ee7256SJacob Keller  * @hw: pointer to HW struct
1988b2ee7256SJacob Keller  *
1989b2ee7256SJacob Keller  * Perform E810-specific PTP hardware clock initialization steps.
1990b2ee7256SJacob Keller  */
1991b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw)
1992b2ee7256SJacob Keller {
1993b2ee7256SJacob Keller 	/* Ensure synchronization delay is zero */
1994b2ee7256SJacob Keller 	wr32(hw, GLTSYN_SYNC_DLAY, 0);
1995b2ee7256SJacob Keller 
1996b2ee7256SJacob Keller 	/* Initialize the PHY */
1997b2ee7256SJacob Keller 	return ice_ptp_init_phy_e810(hw);
1998b2ee7256SJacob Keller }
1999b2ee7256SJacob Keller 
2000b2ee7256SJacob Keller /**
200103cb4473SJacob Keller  * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
200203cb4473SJacob Keller  * @hw: Board private structure
200303cb4473SJacob Keller  * @time: Time to initialize the PHY port clock to
200403cb4473SJacob Keller  *
200503cb4473SJacob Keller  * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
200603cb4473SJacob Keller  * initial clock time. The time will not actually be programmed until the
200703cb4473SJacob Keller  * driver issues an INIT_TIME command.
200803cb4473SJacob Keller  *
200903cb4473SJacob Keller  * The time value is the upper 32 bits of the PHY timer, usually in units of
201003cb4473SJacob Keller  * nominal nanoseconds.
201103cb4473SJacob Keller  */
201203cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
201303cb4473SJacob Keller {
201403cb4473SJacob Keller 	u8 tmr_idx;
201539b28106SJacob Keller 	int err;
201603cb4473SJacob Keller 
201703cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
201839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
201939b28106SJacob Keller 	if (err) {
202039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n",
202139b28106SJacob Keller 			  err);
202239b28106SJacob Keller 		return err;
202303cb4473SJacob Keller 	}
202403cb4473SJacob Keller 
202539b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
202639b28106SJacob Keller 	if (err) {
202739b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n",
202839b28106SJacob Keller 			  err);
202939b28106SJacob Keller 		return err;
203003cb4473SJacob Keller 	}
203103cb4473SJacob Keller 
203203cb4473SJacob Keller 	return 0;
203303cb4473SJacob Keller }
203403cb4473SJacob Keller 
203503cb4473SJacob Keller /**
203603cb4473SJacob Keller  * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
203703cb4473SJacob Keller  * @hw: pointer to HW struct
203803cb4473SJacob Keller  * @adj: adjustment value to program
203903cb4473SJacob Keller  *
204003cb4473SJacob Keller  * Prepare the PHY port for an atomic adjustment by programming the PHY
204103cb4473SJacob Keller  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
204203cb4473SJacob Keller  * is completed by issuing an ADJ_TIME sync command.
204303cb4473SJacob Keller  *
204403cb4473SJacob Keller  * The adjustment value only contains the portion used for the upper 32bits of
204503cb4473SJacob Keller  * the PHY timer, usually in units of nominal nanoseconds. Negative
204603cb4473SJacob Keller  * adjustments are supported using 2s complement arithmetic.
204703cb4473SJacob Keller  */
204803cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
204903cb4473SJacob Keller {
205003cb4473SJacob Keller 	u8 tmr_idx;
205139b28106SJacob Keller 	int err;
205203cb4473SJacob Keller 
205303cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
205403cb4473SJacob Keller 
205503cb4473SJacob Keller 	/* Adjustments are represented as signed 2's complement values in
205603cb4473SJacob Keller 	 * nanoseconds. Sub-nanosecond adjustment is not supported.
205703cb4473SJacob Keller 	 */
205839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0);
205939b28106SJacob Keller 	if (err) {
206039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n",
206139b28106SJacob Keller 			  err);
206239b28106SJacob Keller 		return err;
206303cb4473SJacob Keller 	}
206403cb4473SJacob Keller 
206539b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj);
206639b28106SJacob Keller 	if (err) {
206739b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n",
206839b28106SJacob Keller 			  err);
206939b28106SJacob Keller 		return err;
207003cb4473SJacob Keller 	}
207103cb4473SJacob Keller 
207203cb4473SJacob Keller 	return 0;
207303cb4473SJacob Keller }
207403cb4473SJacob Keller 
207503cb4473SJacob Keller /**
207603cb4473SJacob Keller  * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
207703cb4473SJacob Keller  * @hw: pointer to HW struct
207803cb4473SJacob Keller  * @incval: The new 40bit increment value to prepare
207903cb4473SJacob Keller  *
208003cb4473SJacob Keller  * Prepare the PHY port for a new increment value by programming the PHY
208103cb4473SJacob Keller  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
208203cb4473SJacob Keller  * completed by issuing an INIT_INCVAL command.
208303cb4473SJacob Keller  */
208403cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
208503cb4473SJacob Keller {
208603cb4473SJacob Keller 	u32 high, low;
208703cb4473SJacob Keller 	u8 tmr_idx;
208839b28106SJacob Keller 	int err;
208903cb4473SJacob Keller 
209003cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
209103cb4473SJacob Keller 	low = lower_32_bits(incval);
209203cb4473SJacob Keller 	high = upper_32_bits(incval);
209303cb4473SJacob Keller 
209439b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
209539b28106SJacob Keller 	if (err) {
209639b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n",
209739b28106SJacob Keller 			  err);
209839b28106SJacob Keller 		return err;
209903cb4473SJacob Keller 	}
210003cb4473SJacob Keller 
210139b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
210239b28106SJacob Keller 	if (err) {
210339b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n",
210439b28106SJacob Keller 			  err);
210539b28106SJacob Keller 		return err;
210603cb4473SJacob Keller 	}
210703cb4473SJacob Keller 
210803cb4473SJacob Keller 	return 0;
210903cb4473SJacob Keller }
211003cb4473SJacob Keller 
211103cb4473SJacob Keller /**
211203cb4473SJacob Keller  * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
211303cb4473SJacob Keller  * @hw: pointer to HW struct
211403cb4473SJacob Keller  * @cmd: Command to be sent to the port
211503cb4473SJacob Keller  *
211603cb4473SJacob Keller  * Prepare the external PHYs connected to this device for a timer sync
211703cb4473SJacob Keller  * command.
211803cb4473SJacob Keller  */
211903cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
212003cb4473SJacob Keller {
212103cb4473SJacob Keller 	u32 cmd_val, val;
212239b28106SJacob Keller 	int err;
212303cb4473SJacob Keller 
212403cb4473SJacob Keller 	switch (cmd) {
212503cb4473SJacob Keller 	case INIT_TIME:
212603cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_INIT_TIME;
212703cb4473SJacob Keller 		break;
212803cb4473SJacob Keller 	case INIT_INCVAL:
212903cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_INIT_INCVAL;
213003cb4473SJacob Keller 		break;
213103cb4473SJacob Keller 	case ADJ_TIME:
213203cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_ADJ_TIME;
213303cb4473SJacob Keller 		break;
213403cb4473SJacob Keller 	case READ_TIME:
213503cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_READ_TIME;
213603cb4473SJacob Keller 		break;
213703cb4473SJacob Keller 	case ADJ_TIME_AT_TIME:
213803cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
213903cb4473SJacob Keller 		break;
214003cb4473SJacob Keller 	}
214103cb4473SJacob Keller 
214203cb4473SJacob Keller 	/* Read, modify, write */
214339b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val);
214439b28106SJacob Keller 	if (err) {
214539b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err);
214639b28106SJacob Keller 		return err;
214703cb4473SJacob Keller 	}
214803cb4473SJacob Keller 
214903cb4473SJacob Keller 	/* Modify necessary bits only and perform write */
215003cb4473SJacob Keller 	val &= ~TS_CMD_MASK_E810;
215103cb4473SJacob Keller 	val |= cmd_val;
215203cb4473SJacob Keller 
215339b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val);
215439b28106SJacob Keller 	if (err) {
215539b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err);
215639b28106SJacob Keller 		return err;
215703cb4473SJacob Keller 	}
215803cb4473SJacob Keller 
215903cb4473SJacob Keller 	return 0;
216003cb4473SJacob Keller }
216103cb4473SJacob Keller 
216203cb4473SJacob Keller /* Device agnostic functions
216303cb4473SJacob Keller  *
2164*3a749623SJacob Keller  * The following functions implement shared behavior common to both E822 and
2165*3a749623SJacob Keller  * E810 devices, possibly calling a device specific implementation where
2166*3a749623SJacob Keller  * necessary.
216703cb4473SJacob Keller  */
216803cb4473SJacob Keller 
216903cb4473SJacob Keller /**
217003cb4473SJacob Keller  * ice_ptp_lock - Acquire PTP global semaphore register lock
217103cb4473SJacob Keller  * @hw: pointer to the HW struct
217203cb4473SJacob Keller  *
217303cb4473SJacob Keller  * Acquire the global PTP hardware semaphore lock. Returns true if the lock
217403cb4473SJacob Keller  * was acquired, false otherwise.
217503cb4473SJacob Keller  *
217603cb4473SJacob Keller  * The PFTSYN_SEM register sets the busy bit on read, returning the previous
217703cb4473SJacob Keller  * value. If software sees the busy bit cleared, this means that this function
217803cb4473SJacob Keller  * acquired the lock (and the busy bit is now set). If software sees the busy
217903cb4473SJacob Keller  * bit set, it means that another function acquired the lock.
218003cb4473SJacob Keller  *
218103cb4473SJacob Keller  * Software must clear the busy bit with a write to release the lock for other
218203cb4473SJacob Keller  * functions when done.
218303cb4473SJacob Keller  */
218403cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw)
218503cb4473SJacob Keller {
218603cb4473SJacob Keller 	u32 hw_lock;
218703cb4473SJacob Keller 	int i;
218803cb4473SJacob Keller 
218903cb4473SJacob Keller #define MAX_TRIES 5
219003cb4473SJacob Keller 
219103cb4473SJacob Keller 	for (i = 0; i < MAX_TRIES; i++) {
219203cb4473SJacob Keller 		hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
219303cb4473SJacob Keller 		hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
2194587b839dSColin Ian King 		if (!hw_lock)
2195587b839dSColin Ian King 			break;
2196587b839dSColin Ian King 
219703cb4473SJacob Keller 		/* Somebody is holding the lock */
219803cb4473SJacob Keller 		usleep_range(10000, 20000);
219903cb4473SJacob Keller 	}
220003cb4473SJacob Keller 
220103cb4473SJacob Keller 	return !hw_lock;
220203cb4473SJacob Keller }
220303cb4473SJacob Keller 
220403cb4473SJacob Keller /**
220503cb4473SJacob Keller  * ice_ptp_unlock - Release PTP global semaphore register lock
220603cb4473SJacob Keller  * @hw: pointer to the HW struct
220703cb4473SJacob Keller  *
220803cb4473SJacob Keller  * Release the global PTP hardware semaphore lock. This is done by writing to
220903cb4473SJacob Keller  * the PFTSYN_SEM register.
221003cb4473SJacob Keller  */
221103cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw)
221203cb4473SJacob Keller {
221303cb4473SJacob Keller 	wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
221403cb4473SJacob Keller }
221503cb4473SJacob Keller 
221603cb4473SJacob Keller /**
221703cb4473SJacob Keller  * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
221803cb4473SJacob Keller  * @hw: pointer to HW struct
221903cb4473SJacob Keller  * @cmd: the command to issue
222003cb4473SJacob Keller  *
222103cb4473SJacob Keller  * Prepare the source timer and PHY timers and then trigger the requested
222203cb4473SJacob Keller  * command. This causes the shadow registers previously written in preparation
222303cb4473SJacob Keller  * for the command to be synchronously applied to both the source and PHY
222403cb4473SJacob Keller  * timers.
222503cb4473SJacob Keller  */
222603cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
222703cb4473SJacob Keller {
222839b28106SJacob Keller 	int err;
222903cb4473SJacob Keller 
223003cb4473SJacob Keller 	/* First, prepare the source timer */
223103cb4473SJacob Keller 	ice_ptp_src_cmd(hw, cmd);
223203cb4473SJacob Keller 
223303cb4473SJacob Keller 	/* Next, prepare the ports */
2234*3a749623SJacob Keller 	if (ice_is_e810(hw))
223539b28106SJacob Keller 		err = ice_ptp_port_cmd_e810(hw, cmd);
2236*3a749623SJacob Keller 	else
2237*3a749623SJacob Keller 		err = ice_ptp_port_cmd_e822(hw, cmd);
223839b28106SJacob Keller 	if (err) {
223939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n",
224039b28106SJacob Keller 			  cmd, err);
224139b28106SJacob Keller 		return err;
224203cb4473SJacob Keller 	}
224303cb4473SJacob Keller 
2244*3a749623SJacob Keller 	/* Write the sync command register to drive both source and PHY timer
2245*3a749623SJacob Keller 	 * commands synchronously
224603cb4473SJacob Keller 	 */
2247*3a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
224803cb4473SJacob Keller 
224903cb4473SJacob Keller 	return 0;
225003cb4473SJacob Keller }
225103cb4473SJacob Keller 
225203cb4473SJacob Keller /**
225303cb4473SJacob Keller  * ice_ptp_init_time - Initialize device time to provided value
225403cb4473SJacob Keller  * @hw: pointer to HW struct
225503cb4473SJacob Keller  * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
225603cb4473SJacob Keller  *
225703cb4473SJacob Keller  * Initialize the device to the specified time provided. This requires a three
225803cb4473SJacob Keller  * step process:
225903cb4473SJacob Keller  *
226003cb4473SJacob Keller  * 1) write the new init time to the source timer shadow registers
226103cb4473SJacob Keller  * 2) write the new init time to the PHY timer shadow registers
226203cb4473SJacob Keller  * 3) issue an init_time timer command to synchronously switch both the source
226303cb4473SJacob Keller  *    and port timers to the new init time value at the next clock cycle.
226403cb4473SJacob Keller  */
226503cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time)
226603cb4473SJacob Keller {
226703cb4473SJacob Keller 	u8 tmr_idx;
226839b28106SJacob Keller 	int err;
226903cb4473SJacob Keller 
227003cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
227103cb4473SJacob Keller 
227203cb4473SJacob Keller 	/* Source timers */
227303cb4473SJacob Keller 	wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time));
227403cb4473SJacob Keller 	wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time));
227503cb4473SJacob Keller 	wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
227603cb4473SJacob Keller 
227703cb4473SJacob Keller 	/* PHY timers */
227803cb4473SJacob Keller 	/* Fill Rx and Tx ports and send msg to PHY */
2279*3a749623SJacob Keller 	if (ice_is_e810(hw))
228039b28106SJacob Keller 		err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
2281*3a749623SJacob Keller 	else
2282*3a749623SJacob Keller 		err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
228339b28106SJacob Keller 	if (err)
228439b28106SJacob Keller 		return err;
228503cb4473SJacob Keller 
228603cb4473SJacob Keller 	return ice_ptp_tmr_cmd(hw, INIT_TIME);
228703cb4473SJacob Keller }
228803cb4473SJacob Keller 
228903cb4473SJacob Keller /**
229003cb4473SJacob Keller  * ice_ptp_write_incval - Program PHC with new increment value
229103cb4473SJacob Keller  * @hw: pointer to HW struct
229203cb4473SJacob Keller  * @incval: Source timer increment value per clock cycle
229303cb4473SJacob Keller  *
229403cb4473SJacob Keller  * Program the PHC with a new increment value. This requires a three-step
229503cb4473SJacob Keller  * process:
229603cb4473SJacob Keller  *
229703cb4473SJacob Keller  * 1) Write the increment value to the source timer shadow registers
229803cb4473SJacob Keller  * 2) Write the increment value to the PHY timer shadow registers
229903cb4473SJacob Keller  * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
230003cb4473SJacob Keller  *    source and port timers to the new increment value at the next clock
230103cb4473SJacob Keller  *    cycle.
230203cb4473SJacob Keller  */
230303cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
230403cb4473SJacob Keller {
230503cb4473SJacob Keller 	u8 tmr_idx;
230639b28106SJacob Keller 	int err;
230703cb4473SJacob Keller 
230803cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
230903cb4473SJacob Keller 
231003cb4473SJacob Keller 	/* Shadow Adjust */
231103cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
231203cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
231303cb4473SJacob Keller 
2314*3a749623SJacob Keller 	if (ice_is_e810(hw))
231539b28106SJacob Keller 		err = ice_ptp_prep_phy_incval_e810(hw, incval);
2316*3a749623SJacob Keller 	else
2317*3a749623SJacob Keller 		err = ice_ptp_prep_phy_incval_e822(hw, incval);
231839b28106SJacob Keller 	if (err)
231939b28106SJacob Keller 		return err;
232003cb4473SJacob Keller 
232103cb4473SJacob Keller 	return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
232203cb4473SJacob Keller }
232303cb4473SJacob Keller 
232403cb4473SJacob Keller /**
232503cb4473SJacob Keller  * ice_ptp_write_incval_locked - Program new incval while holding semaphore
232603cb4473SJacob Keller  * @hw: pointer to HW struct
232703cb4473SJacob Keller  * @incval: Source timer increment value per clock cycle
232803cb4473SJacob Keller  *
232903cb4473SJacob Keller  * Program a new PHC incval while holding the PTP semaphore.
233003cb4473SJacob Keller  */
233103cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
233203cb4473SJacob Keller {
233339b28106SJacob Keller 	int err;
233403cb4473SJacob Keller 
233503cb4473SJacob Keller 	if (!ice_ptp_lock(hw))
233603cb4473SJacob Keller 		return -EBUSY;
233703cb4473SJacob Keller 
233839b28106SJacob Keller 	err = ice_ptp_write_incval(hw, incval);
233903cb4473SJacob Keller 
234003cb4473SJacob Keller 	ice_ptp_unlock(hw);
234103cb4473SJacob Keller 
234239b28106SJacob Keller 	return err;
234303cb4473SJacob Keller }
234403cb4473SJacob Keller 
234503cb4473SJacob Keller /**
234603cb4473SJacob Keller  * ice_ptp_adj_clock - Adjust PHC clock time atomically
234703cb4473SJacob Keller  * @hw: pointer to HW struct
234803cb4473SJacob Keller  * @adj: Adjustment in nanoseconds
234903cb4473SJacob Keller  *
235003cb4473SJacob Keller  * Perform an atomic adjustment of the PHC time by the specified number of
235103cb4473SJacob Keller  * nanoseconds. This requires a three-step process:
235203cb4473SJacob Keller  *
235303cb4473SJacob Keller  * 1) Write the adjustment to the source timer shadow registers
235403cb4473SJacob Keller  * 2) Write the adjustment to the PHY timer shadow registers
235503cb4473SJacob Keller  * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
235603cb4473SJacob Keller  *    both the source and port timers at the next clock cycle.
235703cb4473SJacob Keller  */
235803cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
235903cb4473SJacob Keller {
236003cb4473SJacob Keller 	u8 tmr_idx;
236139b28106SJacob Keller 	int err;
236203cb4473SJacob Keller 
236303cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
236403cb4473SJacob Keller 
236503cb4473SJacob Keller 	/* Write the desired clock adjustment into the GLTSYN_SHADJ register.
236603cb4473SJacob Keller 	 * For an ADJ_TIME command, this set of registers represents the value
236703cb4473SJacob Keller 	 * to add to the clock time. It supports subtraction by interpreting
236803cb4473SJacob Keller 	 * the value as a 2's complement integer.
236903cb4473SJacob Keller 	 */
237003cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
237103cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
237203cb4473SJacob Keller 
2373*3a749623SJacob Keller 	if (ice_is_e810(hw))
237439b28106SJacob Keller 		err = ice_ptp_prep_phy_adj_e810(hw, adj);
2375*3a749623SJacob Keller 	else
2376*3a749623SJacob Keller 		err = ice_ptp_prep_phy_adj_e822(hw, adj);
237739b28106SJacob Keller 	if (err)
237839b28106SJacob Keller 		return err;
237903cb4473SJacob Keller 
238003cb4473SJacob Keller 	return ice_ptp_tmr_cmd(hw, ADJ_TIME);
238103cb4473SJacob Keller }
238203cb4473SJacob Keller 
238303cb4473SJacob Keller /**
238403cb4473SJacob Keller  * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
238503cb4473SJacob Keller  * @hw: pointer to the HW struct
238603cb4473SJacob Keller  * @block: the block to read from
238703cb4473SJacob Keller  * @idx: the timestamp index to read
238803cb4473SJacob Keller  * @tstamp: on return, the 40bit timestamp value
238903cb4473SJacob Keller  *
2390*3a749623SJacob Keller  * Read a 40bit timestamp value out of the timestamp block. For E822 devices,
2391*3a749623SJacob Keller  * the block is the quad to read from. For E810 devices, the block is the
2392*3a749623SJacob Keller  * logical port to read from.
239303cb4473SJacob Keller  */
239403cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
239503cb4473SJacob Keller {
2396*3a749623SJacob Keller 	if (ice_is_e810(hw))
239703cb4473SJacob Keller 		return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
2398*3a749623SJacob Keller 	else
2399*3a749623SJacob Keller 		return ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
240003cb4473SJacob Keller }
240103cb4473SJacob Keller 
240203cb4473SJacob Keller /**
240303cb4473SJacob Keller  * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
240403cb4473SJacob Keller  * @hw: pointer to the HW struct
240503cb4473SJacob Keller  * @block: the block to read from
240603cb4473SJacob Keller  * @idx: the timestamp index to reset
240703cb4473SJacob Keller  *
2408*3a749623SJacob Keller  * Clear a timestamp, resetting its valid bit, from the timestamp block. For
2409*3a749623SJacob Keller  * E822 devices, the block is the quad to clear from. For E810 devices, the
2410*3a749623SJacob Keller  * block is the logical port to clear from.
241103cb4473SJacob Keller  */
241203cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
241303cb4473SJacob Keller {
2414*3a749623SJacob Keller 	if (ice_is_e810(hw))
241503cb4473SJacob Keller 		return ice_clear_phy_tstamp_e810(hw, block, idx);
2416*3a749623SJacob Keller 	else
2417*3a749623SJacob Keller 		return ice_clear_phy_tstamp_e822(hw, block, idx);
241803cb4473SJacob Keller }
2419885fe693SMaciej Machnikowski 
2420885fe693SMaciej Machnikowski /* E810T SMA functions
2421885fe693SMaciej Machnikowski  *
2422885fe693SMaciej Machnikowski  * The following functions operate specifically on E810T hardware and are used
2423885fe693SMaciej Machnikowski  * to access the extended GPIOs available.
2424885fe693SMaciej Machnikowski  */
2425885fe693SMaciej Machnikowski 
2426885fe693SMaciej Machnikowski /**
2427885fe693SMaciej Machnikowski  * ice_get_pca9575_handle
2428885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2429885fe693SMaciej Machnikowski  * @pca9575_handle: GPIO controller's handle
2430885fe693SMaciej Machnikowski  *
2431885fe693SMaciej Machnikowski  * Find and return the GPIO controller's handle in the netlist.
2432885fe693SMaciej Machnikowski  * When found - the value will be cached in the hw structure and following calls
2433885fe693SMaciej Machnikowski  * will return cached value
2434885fe693SMaciej Machnikowski  */
2435885fe693SMaciej Machnikowski static int
2436885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
2437885fe693SMaciej Machnikowski {
2438885fe693SMaciej Machnikowski 	struct ice_aqc_get_link_topo *cmd;
2439885fe693SMaciej Machnikowski 	struct ice_aq_desc desc;
2440885fe693SMaciej Machnikowski 	int status;
2441885fe693SMaciej Machnikowski 	u8 idx;
2442885fe693SMaciej Machnikowski 
2443885fe693SMaciej Machnikowski 	/* If handle was read previously return cached value */
2444885fe693SMaciej Machnikowski 	if (hw->io_expander_handle) {
2445885fe693SMaciej Machnikowski 		*pca9575_handle = hw->io_expander_handle;
2446885fe693SMaciej Machnikowski 		return 0;
2447885fe693SMaciej Machnikowski 	}
2448885fe693SMaciej Machnikowski 
2449885fe693SMaciej Machnikowski 	/* If handle was not detected read it from the netlist */
2450885fe693SMaciej Machnikowski 	cmd = &desc.params.get_link_topo;
2451885fe693SMaciej Machnikowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
2452885fe693SMaciej Machnikowski 
2453885fe693SMaciej Machnikowski 	/* Set node type to GPIO controller */
2454885fe693SMaciej Machnikowski 	cmd->addr.topo_params.node_type_ctx =
2455885fe693SMaciej Machnikowski 		(ICE_AQC_LINK_TOPO_NODE_TYPE_M &
2456885fe693SMaciej Machnikowski 		 ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
2457885fe693SMaciej Machnikowski 
2458885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX		2
2459885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX	1
2460885fe693SMaciej Machnikowski 
2461885fe693SMaciej Machnikowski 	/* Check if the SW IO expander controlling SMA exists in the netlist. */
2462885fe693SMaciej Machnikowski 	if (hw->device_id == ICE_DEV_ID_E810C_SFP)
2463885fe693SMaciej Machnikowski 		idx = SW_PCA9575_SFP_TOPO_IDX;
2464885fe693SMaciej Machnikowski 	else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
2465885fe693SMaciej Machnikowski 		idx = SW_PCA9575_QSFP_TOPO_IDX;
2466885fe693SMaciej Machnikowski 	else
2467885fe693SMaciej Machnikowski 		return -EOPNOTSUPP;
2468885fe693SMaciej Machnikowski 
2469885fe693SMaciej Machnikowski 	cmd->addr.topo_params.index = idx;
2470885fe693SMaciej Machnikowski 
2471885fe693SMaciej Machnikowski 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
2472885fe693SMaciej Machnikowski 	if (status)
2473885fe693SMaciej Machnikowski 		return -EOPNOTSUPP;
2474885fe693SMaciej Machnikowski 
2475885fe693SMaciej Machnikowski 	/* Verify if we found the right IO expander type */
2476885fe693SMaciej Machnikowski 	if (desc.params.get_link_topo.node_part_num !=
2477885fe693SMaciej Machnikowski 		ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
2478885fe693SMaciej Machnikowski 		return -EOPNOTSUPP;
2479885fe693SMaciej Machnikowski 
2480885fe693SMaciej Machnikowski 	/* If present save the handle and return it */
2481885fe693SMaciej Machnikowski 	hw->io_expander_handle =
2482885fe693SMaciej Machnikowski 		le16_to_cpu(desc.params.get_link_topo.addr.handle);
2483885fe693SMaciej Machnikowski 	*pca9575_handle = hw->io_expander_handle;
2484885fe693SMaciej Machnikowski 
2485885fe693SMaciej Machnikowski 	return 0;
2486885fe693SMaciej Machnikowski }
2487885fe693SMaciej Machnikowski 
2488885fe693SMaciej Machnikowski /**
2489885fe693SMaciej Machnikowski  * ice_read_sma_ctrl_e810t
2490885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2491885fe693SMaciej Machnikowski  * @data: pointer to data to be read from the GPIO controller
2492885fe693SMaciej Machnikowski  *
2493885fe693SMaciej Machnikowski  * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
2494885fe693SMaciej Machnikowski  * PCA9575 expander, so only bits 3-7 in data are valid.
2495885fe693SMaciej Machnikowski  */
2496885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
2497885fe693SMaciej Machnikowski {
2498885fe693SMaciej Machnikowski 	int status;
2499885fe693SMaciej Machnikowski 	u16 handle;
2500885fe693SMaciej Machnikowski 	u8 i;
2501885fe693SMaciej Machnikowski 
2502885fe693SMaciej Machnikowski 	status = ice_get_pca9575_handle(hw, &handle);
2503885fe693SMaciej Machnikowski 	if (status)
2504885fe693SMaciej Machnikowski 		return status;
2505885fe693SMaciej Machnikowski 
2506885fe693SMaciej Machnikowski 	*data = 0;
2507885fe693SMaciej Machnikowski 
2508885fe693SMaciej Machnikowski 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
2509885fe693SMaciej Machnikowski 		bool pin;
2510885fe693SMaciej Machnikowski 
2511885fe693SMaciej Machnikowski 		status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
2512885fe693SMaciej Machnikowski 					 &pin, NULL);
2513885fe693SMaciej Machnikowski 		if (status)
2514885fe693SMaciej Machnikowski 			break;
2515885fe693SMaciej Machnikowski 		*data |= (u8)(!pin) << i;
2516885fe693SMaciej Machnikowski 	}
2517885fe693SMaciej Machnikowski 
2518885fe693SMaciej Machnikowski 	return status;
2519885fe693SMaciej Machnikowski }
2520885fe693SMaciej Machnikowski 
2521885fe693SMaciej Machnikowski /**
2522885fe693SMaciej Machnikowski  * ice_write_sma_ctrl_e810t
2523885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2524885fe693SMaciej Machnikowski  * @data: data to be written to the GPIO controller
2525885fe693SMaciej Machnikowski  *
2526885fe693SMaciej Machnikowski  * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
2527885fe693SMaciej Machnikowski  * of the PCA9575 expander, so only bits 3-7 in data are valid.
2528885fe693SMaciej Machnikowski  */
2529885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
2530885fe693SMaciej Machnikowski {
2531885fe693SMaciej Machnikowski 	int status;
2532885fe693SMaciej Machnikowski 	u16 handle;
2533885fe693SMaciej Machnikowski 	u8 i;
2534885fe693SMaciej Machnikowski 
2535885fe693SMaciej Machnikowski 	status = ice_get_pca9575_handle(hw, &handle);
2536885fe693SMaciej Machnikowski 	if (status)
2537885fe693SMaciej Machnikowski 		return status;
2538885fe693SMaciej Machnikowski 
2539885fe693SMaciej Machnikowski 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
2540885fe693SMaciej Machnikowski 		bool pin;
2541885fe693SMaciej Machnikowski 
2542885fe693SMaciej Machnikowski 		pin = !(data & (1 << i));
2543885fe693SMaciej Machnikowski 		status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
2544885fe693SMaciej Machnikowski 					 pin, NULL);
2545885fe693SMaciej Machnikowski 		if (status)
2546885fe693SMaciej Machnikowski 			break;
2547885fe693SMaciej Machnikowski 	}
2548885fe693SMaciej Machnikowski 
2549885fe693SMaciej Machnikowski 	return status;
2550885fe693SMaciej Machnikowski }
2551885fe693SMaciej Machnikowski 
2552885fe693SMaciej Machnikowski /**
2553885fe693SMaciej Machnikowski  * ice_is_pca9575_present
2554885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2555885fe693SMaciej Machnikowski  *
2556885fe693SMaciej Machnikowski  * Check if the SW IO expander is present in the netlist
2557885fe693SMaciej Machnikowski  */
2558885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw)
2559885fe693SMaciej Machnikowski {
2560885fe693SMaciej Machnikowski 	u16 handle = 0;
2561885fe693SMaciej Machnikowski 	int status;
2562885fe693SMaciej Machnikowski 
2563885fe693SMaciej Machnikowski 	if (!ice_is_e810t(hw))
2564885fe693SMaciej Machnikowski 		return false;
2565885fe693SMaciej Machnikowski 
2566885fe693SMaciej Machnikowski 	status = ice_get_pca9575_handle(hw, &handle);
2567885fe693SMaciej Machnikowski 
2568885fe693SMaciej Machnikowski 	return !status && handle;
2569885fe693SMaciej Machnikowski }
2570b2ee7256SJacob Keller 
2571b2ee7256SJacob Keller /**
2572b2ee7256SJacob Keller  * ice_ptp_init_phc - Initialize PTP hardware clock
2573b2ee7256SJacob Keller  * @hw: pointer to the HW struct
2574b2ee7256SJacob Keller  *
2575b2ee7256SJacob Keller  * Perform the steps required to initialize the PTP hardware clock.
2576b2ee7256SJacob Keller  */
2577b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw)
2578b2ee7256SJacob Keller {
2579b2ee7256SJacob Keller 	u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
2580b2ee7256SJacob Keller 
2581b2ee7256SJacob Keller 	/* Enable source clocks */
2582b2ee7256SJacob Keller 	wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
2583b2ee7256SJacob Keller 
2584b2ee7256SJacob Keller 	/* Clear event err indications for auxiliary pins */
2585b2ee7256SJacob Keller 	(void)rd32(hw, GLTSYN_STAT(src_idx));
2586b2ee7256SJacob Keller 
2587*3a749623SJacob Keller 	if (ice_is_e810(hw))
2588b2ee7256SJacob Keller 		return ice_ptp_init_phc_e810(hw);
2589*3a749623SJacob Keller 	else
2590*3a749623SJacob Keller 		return ice_ptp_init_phc_e822(hw);
2591b2ee7256SJacob Keller }
2592