103cb4473SJacob Keller // SPDX-License-Identifier: GPL-2.0
203cb4473SJacob Keller /* Copyright (C) 2021, Intel Corporation. */
303cb4473SJacob Keller 
41229b339SKarol Kolacinski #include <linux/delay.h>
503cb4473SJacob Keller #include "ice_common.h"
603cb4473SJacob Keller #include "ice_ptp_hw.h"
73a749623SJacob Keller #include "ice_ptp_consts.h"
8b111ab5aSJacob Keller #include "ice_cgu_regs.h"
903cb4473SJacob Keller 
1003cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used
1103cb4473SJacob Keller  * for the Precision Time Protocol.
1203cb4473SJacob Keller  *
1303cb4473SJacob Keller  * The ice hardware represents the current time using three registers:
1403cb4473SJacob Keller  *
1503cb4473SJacob Keller  *    GLTSYN_TIME_H     GLTSYN_TIME_L     GLTSYN_TIME_R
1603cb4473SJacob Keller  *  +---------------+ +---------------+ +---------------+
1703cb4473SJacob Keller  *  |    32 bits    | |    32 bits    | |    32 bits    |
1803cb4473SJacob Keller  *  +---------------+ +---------------+ +---------------+
1903cb4473SJacob Keller  *
2003cb4473SJacob Keller  * The registers are incremented every clock tick using a 40bit increment
2103cb4473SJacob Keller  * value defined over two registers:
2203cb4473SJacob Keller  *
2303cb4473SJacob Keller  *                     GLTSYN_INCVAL_H   GLTSYN_INCVAL_L
2403cb4473SJacob Keller  *                    +---------------+ +---------------+
2503cb4473SJacob Keller  *                    |    8 bit s    | |    32 bits    |
2603cb4473SJacob Keller  *                    +---------------+ +---------------+
2703cb4473SJacob Keller  *
2803cb4473SJacob Keller  * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
2903cb4473SJacob Keller  * registers every clock source tick. Depending on the specific device
3003cb4473SJacob Keller  * configuration, the clock source frequency could be one of a number of
3103cb4473SJacob Keller  * values.
3203cb4473SJacob Keller  *
3303cb4473SJacob Keller  * For E810 devices, the increment frequency is 812.5 MHz
3403cb4473SJacob Keller  *
353a749623SJacob Keller  * For E822 devices the clock can be derived from different sources, and the
363a749623SJacob Keller  * increment has an effective frequency of one of the following:
373a749623SJacob Keller  * - 823.4375 MHz
383a749623SJacob Keller  * - 783.36 MHz
393a749623SJacob Keller  * - 796.875 MHz
403a749623SJacob Keller  * - 816 MHz
413a749623SJacob Keller  * - 830.078125 MHz
423a749623SJacob Keller  * - 783.36 MHz
433a749623SJacob Keller  *
4403cb4473SJacob Keller  * The hardware captures timestamps in the PHY for incoming packets, and for
4503cb4473SJacob Keller  * outgoing packets on request. To support this, the PHY maintains a timer
4603cb4473SJacob Keller  * that matches the lower 64 bits of the global source timer.
4703cb4473SJacob Keller  *
4803cb4473SJacob Keller  * In order to ensure that the PHY timers and the source timer are equivalent,
4903cb4473SJacob Keller  * shadow registers are used to prepare the desired initial values. A special
5003cb4473SJacob Keller  * sync command is issued to trigger copying from the shadow registers into
5103cb4473SJacob Keller  * the appropriate source and PHY registers simultaneously.
523a749623SJacob Keller  *
533a749623SJacob Keller  * The driver supports devices which have different PHYs with subtly different
543a749623SJacob Keller  * mechanisms to program and control the timers. We divide the devices into
553a749623SJacob Keller  * families named after the first major device, E810 and similar devices, and
563a749623SJacob Keller  * E822 and similar devices.
573a749623SJacob Keller  *
583a749623SJacob Keller  * - E822 based devices have additional support for fine grained Vernier
593a749623SJacob Keller  *   calibration which requires significant setup
603a749623SJacob Keller  * - The layout of timestamp data in the PHY register blocks is different
613a749623SJacob Keller  * - The way timer synchronization commands are issued is different.
623a749623SJacob Keller  *
633a749623SJacob Keller  * To support this, very low level functions have an e810 or e822 suffix
643a749623SJacob Keller  * indicating what type of device they work on. Higher level abstractions for
653a749623SJacob Keller  * tasks that can be done on both devices do not have the suffix and will
663a749623SJacob Keller  * correctly look up the appropriate low level function when running.
673a749623SJacob Keller  *
683a749623SJacob Keller  * Functions which only make sense on a single device family may not have
693a749623SJacob Keller  * a suitable generic implementation
7003cb4473SJacob Keller  */
7103cb4473SJacob Keller 
7203cb4473SJacob Keller /**
7303cb4473SJacob Keller  * ice_get_ptp_src_clock_index - determine source clock index
7403cb4473SJacob Keller  * @hw: pointer to HW struct
7503cb4473SJacob Keller  *
7603cb4473SJacob Keller  * Determine the source clock index currently in use, based on device
7703cb4473SJacob Keller  * capabilities reported during initialization.
7803cb4473SJacob Keller  */
ice_get_ptp_src_clock_index(struct ice_hw * hw)7903cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
8003cb4473SJacob Keller {
8103cb4473SJacob Keller 	return hw->func_caps.ts_func_info.tmr_index_assoc;
8203cb4473SJacob Keller }
8303cb4473SJacob Keller 
843a749623SJacob Keller /**
853a749623SJacob Keller  * ice_ptp_read_src_incval - Read source timer increment value
863a749623SJacob Keller  * @hw: pointer to HW struct
873a749623SJacob Keller  *
883a749623SJacob Keller  * Read the increment value of the source timer and return it.
893a749623SJacob Keller  */
ice_ptp_read_src_incval(struct ice_hw * hw)903a749623SJacob Keller static u64 ice_ptp_read_src_incval(struct ice_hw *hw)
913a749623SJacob Keller {
923a749623SJacob Keller 	u32 lo, hi;
933a749623SJacob Keller 	u8 tmr_idx;
943a749623SJacob Keller 
953a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
963a749623SJacob Keller 
973a749623SJacob Keller 	lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
983a749623SJacob Keller 	hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
993a749623SJacob Keller 
1003a749623SJacob Keller 	return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;
1013a749623SJacob Keller }
1023a749623SJacob Keller 
1033a749623SJacob Keller /**
1043a749623SJacob Keller  * ice_ptp_src_cmd - Prepare source timer for a timer command
1053a749623SJacob Keller  * @hw: pointer to HW structure
1063a749623SJacob Keller  * @cmd: Timer command
1073a749623SJacob Keller  *
1083a749623SJacob Keller  * Prepare the source timer for an upcoming timer sync command.
1093a749623SJacob Keller  */
ice_ptp_src_cmd(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)1103a749623SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
1113a749623SJacob Keller {
1123a749623SJacob Keller 	u32 cmd_val;
1133a749623SJacob Keller 	u8 tmr_idx;
1143a749623SJacob Keller 
1153a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
1163a749623SJacob Keller 	cmd_val = tmr_idx << SEL_CPK_SRC;
1173a749623SJacob Keller 
1183a749623SJacob Keller 	switch (cmd) {
1193a749623SJacob Keller 	case INIT_TIME:
1203a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_INIT_TIME;
1213a749623SJacob Keller 		break;
1223a749623SJacob Keller 	case INIT_INCVAL:
1233a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_INIT_INCVAL;
1243a749623SJacob Keller 		break;
1253a749623SJacob Keller 	case ADJ_TIME:
1263a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_ADJ_TIME;
1273a749623SJacob Keller 		break;
1283a749623SJacob Keller 	case ADJ_TIME_AT_TIME:
1293a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
1303a749623SJacob Keller 		break;
1313a749623SJacob Keller 	case READ_TIME:
1323a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_READ_TIME;
1333a749623SJacob Keller 		break;
134*0aacec49SJacob Keller 	case ICE_PTP_NOP:
135*0aacec49SJacob Keller 		break;
1363a749623SJacob Keller 	}
1373a749623SJacob Keller 
1383a749623SJacob Keller 	wr32(hw, GLTSYN_CMD, cmd_val);
1393a749623SJacob Keller }
1403a749623SJacob Keller 
1413a749623SJacob Keller /**
1423a749623SJacob Keller  * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands
1433a749623SJacob Keller  * @hw: pointer to HW struct
1443a749623SJacob Keller  *
1453a749623SJacob Keller  * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the
1463a749623SJacob Keller  * write immediately. This triggers the hardware to begin executing all of the
1473a749623SJacob Keller  * source and PHY timer commands synchronously.
1483a749623SJacob Keller  */
ice_ptp_exec_tmr_cmd(struct ice_hw * hw)1493a749623SJacob Keller static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
1503a749623SJacob Keller {
1513a749623SJacob Keller 	wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
1523a749623SJacob Keller 	ice_flush(hw);
1533a749623SJacob Keller }
1543a749623SJacob Keller 
1553a749623SJacob Keller /* E822 family functions
1563a749623SJacob Keller  *
1573a749623SJacob Keller  * The following functions operate on the E822 family of devices.
1583a749623SJacob Keller  */
1593a749623SJacob Keller 
1603a749623SJacob Keller /**
1613a749623SJacob Keller  * ice_fill_phy_msg_e822 - Fill message data for a PHY register access
1623a749623SJacob Keller  * @msg: the PHY message buffer to fill in
1633a749623SJacob Keller  * @port: the port to access
1643a749623SJacob Keller  * @offset: the register offset
1653a749623SJacob Keller  */
1663a749623SJacob Keller static void
ice_fill_phy_msg_e822(struct ice_sbq_msg_input * msg,u8 port,u16 offset)1673a749623SJacob Keller ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
1683a749623SJacob Keller {
1693a749623SJacob Keller 	int phy_port, phy, quadtype;
1703a749623SJacob Keller 
1713a749623SJacob Keller 	phy_port = port % ICE_PORTS_PER_PHY;
1723a749623SJacob Keller 	phy = port / ICE_PORTS_PER_PHY;
1733a749623SJacob Keller 	quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE;
1743a749623SJacob Keller 
1753a749623SJacob Keller 	if (quadtype == 0) {
1763a749623SJacob Keller 		msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
1773a749623SJacob Keller 		msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port);
1783a749623SJacob Keller 	} else {
1793a749623SJacob Keller 		msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port);
1803a749623SJacob Keller 		msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port);
1813a749623SJacob Keller 	}
1823a749623SJacob Keller 
1833a749623SJacob Keller 	if (phy == 0)
1843a749623SJacob Keller 		msg->dest_dev = rmn_0;
1853a749623SJacob Keller 	else if (phy == 1)
1863a749623SJacob Keller 		msg->dest_dev = rmn_1;
1873a749623SJacob Keller 	else
1883a749623SJacob Keller 		msg->dest_dev = rmn_2;
1893a749623SJacob Keller }
1903a749623SJacob Keller 
1913a749623SJacob Keller /**
1923a749623SJacob Keller  * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register
1933a749623SJacob Keller  * @low_addr: the low address to check
1943a749623SJacob Keller  * @high_addr: on return, contains the high address of the 64bit register
1953a749623SJacob Keller  *
1963a749623SJacob Keller  * Checks if the provided low address is one of the known 64bit PHY values
1973a749623SJacob Keller  * represented as two 32bit registers. If it is, return the appropriate high
1983a749623SJacob Keller  * register offset to use.
1993a749623SJacob Keller  */
ice_is_64b_phy_reg_e822(u16 low_addr,u16 * high_addr)2003a749623SJacob Keller static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
2013a749623SJacob Keller {
2023a749623SJacob Keller 	switch (low_addr) {
2033a749623SJacob Keller 	case P_REG_PAR_PCS_TX_OFFSET_L:
2043a749623SJacob Keller 		*high_addr = P_REG_PAR_PCS_TX_OFFSET_U;
2053a749623SJacob Keller 		return true;
2063a749623SJacob Keller 	case P_REG_PAR_PCS_RX_OFFSET_L:
2073a749623SJacob Keller 		*high_addr = P_REG_PAR_PCS_RX_OFFSET_U;
2083a749623SJacob Keller 		return true;
2093a749623SJacob Keller 	case P_REG_PAR_TX_TIME_L:
2103a749623SJacob Keller 		*high_addr = P_REG_PAR_TX_TIME_U;
2113a749623SJacob Keller 		return true;
2123a749623SJacob Keller 	case P_REG_PAR_RX_TIME_L:
2133a749623SJacob Keller 		*high_addr = P_REG_PAR_RX_TIME_U;
2143a749623SJacob Keller 		return true;
2153a749623SJacob Keller 	case P_REG_TOTAL_TX_OFFSET_L:
2163a749623SJacob Keller 		*high_addr = P_REG_TOTAL_TX_OFFSET_U;
2173a749623SJacob Keller 		return true;
2183a749623SJacob Keller 	case P_REG_TOTAL_RX_OFFSET_L:
2193a749623SJacob Keller 		*high_addr = P_REG_TOTAL_RX_OFFSET_U;
2203a749623SJacob Keller 		return true;
2213a749623SJacob Keller 	case P_REG_UIX66_10G_40G_L:
2223a749623SJacob Keller 		*high_addr = P_REG_UIX66_10G_40G_U;
2233a749623SJacob Keller 		return true;
2243a749623SJacob Keller 	case P_REG_UIX66_25G_100G_L:
2253a749623SJacob Keller 		*high_addr = P_REG_UIX66_25G_100G_U;
2263a749623SJacob Keller 		return true;
2273a749623SJacob Keller 	case P_REG_TX_CAPTURE_L:
2283a749623SJacob Keller 		*high_addr = P_REG_TX_CAPTURE_U;
2293a749623SJacob Keller 		return true;
2303a749623SJacob Keller 	case P_REG_RX_CAPTURE_L:
2313a749623SJacob Keller 		*high_addr = P_REG_RX_CAPTURE_U;
2323a749623SJacob Keller 		return true;
2333a749623SJacob Keller 	case P_REG_TX_TIMER_INC_PRE_L:
2343a749623SJacob Keller 		*high_addr = P_REG_TX_TIMER_INC_PRE_U;
2353a749623SJacob Keller 		return true;
2363a749623SJacob Keller 	case P_REG_RX_TIMER_INC_PRE_L:
2373a749623SJacob Keller 		*high_addr = P_REG_RX_TIMER_INC_PRE_U;
2383a749623SJacob Keller 		return true;
2393a749623SJacob Keller 	default:
2403a749623SJacob Keller 		return false;
2413a749623SJacob Keller 	}
2423a749623SJacob Keller }
2433a749623SJacob Keller 
2443a749623SJacob Keller /**
2453a749623SJacob Keller  * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register
2463a749623SJacob Keller  * @low_addr: the low address to check
2473a749623SJacob Keller  * @high_addr: on return, contains the high address of the 40bit value
2483a749623SJacob Keller  *
2493a749623SJacob Keller  * Checks if the provided low address is one of the known 40bit PHY values
2503a749623SJacob Keller  * split into two registers with the lower 8 bits in the low register and the
2513a749623SJacob Keller  * upper 32 bits in the high register. If it is, return the appropriate high
2523a749623SJacob Keller  * register offset to use.
2533a749623SJacob Keller  */
ice_is_40b_phy_reg_e822(u16 low_addr,u16 * high_addr)2543a749623SJacob Keller static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
2553a749623SJacob Keller {
2563a749623SJacob Keller 	switch (low_addr) {
2573a749623SJacob Keller 	case P_REG_TIMETUS_L:
2583a749623SJacob Keller 		*high_addr = P_REG_TIMETUS_U;
2593a749623SJacob Keller 		return true;
2603a749623SJacob Keller 	case P_REG_PAR_RX_TUS_L:
2613a749623SJacob Keller 		*high_addr = P_REG_PAR_RX_TUS_U;
2623a749623SJacob Keller 		return true;
2633a749623SJacob Keller 	case P_REG_PAR_TX_TUS_L:
2643a749623SJacob Keller 		*high_addr = P_REG_PAR_TX_TUS_U;
2653a749623SJacob Keller 		return true;
2663a749623SJacob Keller 	case P_REG_PCS_RX_TUS_L:
2673a749623SJacob Keller 		*high_addr = P_REG_PCS_RX_TUS_U;
2683a749623SJacob Keller 		return true;
2693a749623SJacob Keller 	case P_REG_PCS_TX_TUS_L:
2703a749623SJacob Keller 		*high_addr = P_REG_PCS_TX_TUS_U;
2713a749623SJacob Keller 		return true;
2723a749623SJacob Keller 	case P_REG_DESK_PAR_RX_TUS_L:
2733a749623SJacob Keller 		*high_addr = P_REG_DESK_PAR_RX_TUS_U;
2743a749623SJacob Keller 		return true;
2753a749623SJacob Keller 	case P_REG_DESK_PAR_TX_TUS_L:
2763a749623SJacob Keller 		*high_addr = P_REG_DESK_PAR_TX_TUS_U;
2773a749623SJacob Keller 		return true;
2783a749623SJacob Keller 	case P_REG_DESK_PCS_RX_TUS_L:
2793a749623SJacob Keller 		*high_addr = P_REG_DESK_PCS_RX_TUS_U;
2803a749623SJacob Keller 		return true;
2813a749623SJacob Keller 	case P_REG_DESK_PCS_TX_TUS_L:
2823a749623SJacob Keller 		*high_addr = P_REG_DESK_PCS_TX_TUS_U;
2833a749623SJacob Keller 		return true;
2843a749623SJacob Keller 	default:
2853a749623SJacob Keller 		return false;
2863a749623SJacob Keller 	}
2873a749623SJacob Keller }
2883a749623SJacob Keller 
2893a749623SJacob Keller /**
2903a749623SJacob Keller  * ice_read_phy_reg_e822 - Read a PHY register
2913a749623SJacob Keller  * @hw: pointer to the HW struct
2923a749623SJacob Keller  * @port: PHY port to read from
2933a749623SJacob Keller  * @offset: PHY register offset to read
2943a749623SJacob Keller  * @val: on return, the contents read from the PHY
2953a749623SJacob Keller  *
2963a749623SJacob Keller  * Read a PHY register for the given port over the device sideband queue.
2973a749623SJacob Keller  */
2983a749623SJacob Keller static int
ice_read_phy_reg_e822(struct ice_hw * hw,u8 port,u16 offset,u32 * val)2993a749623SJacob Keller ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
3003a749623SJacob Keller {
3013a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
3023a749623SJacob Keller 	int err;
3033a749623SJacob Keller 
3043a749623SJacob Keller 	ice_fill_phy_msg_e822(&msg, port, offset);
3053a749623SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
3063a749623SJacob Keller 
3073a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
3083a749623SJacob Keller 	if (err) {
3093a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
3103a749623SJacob Keller 			  err);
3113a749623SJacob Keller 		return err;
3123a749623SJacob Keller 	}
3133a749623SJacob Keller 
3143a749623SJacob Keller 	*val = msg.data;
3153a749623SJacob Keller 
3163a749623SJacob Keller 	return 0;
3173a749623SJacob Keller }
3183a749623SJacob Keller 
3193a749623SJacob Keller /**
3203a749623SJacob Keller  * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers
3213a749623SJacob Keller  * @hw: pointer to the HW struct
3223a749623SJacob Keller  * @port: PHY port to read from
3233a749623SJacob Keller  * @low_addr: offset of the lower register to read from
3243a749623SJacob Keller  * @val: on return, the contents of the 64bit value from the PHY registers
3253a749623SJacob Keller  *
3263a749623SJacob Keller  * Reads the two registers associated with a 64bit value and returns it in the
3273a749623SJacob Keller  * val pointer. The offset always specifies the lower register offset to use.
3283a749623SJacob Keller  * The high offset is looked up. This function only operates on registers
3293a749623SJacob Keller  * known to be two parts of a 64bit value.
3303a749623SJacob Keller  */
3313a749623SJacob Keller static int
ice_read_64b_phy_reg_e822(struct ice_hw * hw,u8 port,u16 low_addr,u64 * val)3323a749623SJacob Keller ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
3333a749623SJacob Keller {
3343a749623SJacob Keller 	u32 low, high;
3353a749623SJacob Keller 	u16 high_addr;
3363a749623SJacob Keller 	int err;
3373a749623SJacob Keller 
3383a749623SJacob Keller 	/* Only operate on registers known to be split into two 32bit
3393a749623SJacob Keller 	 * registers.
3403a749623SJacob Keller 	 */
3413a749623SJacob Keller 	if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
3423a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
3433a749623SJacob Keller 			  low_addr);
3443a749623SJacob Keller 		return -EINVAL;
3453a749623SJacob Keller 	}
3463a749623SJacob Keller 
3473a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, low_addr, &low);
3483a749623SJacob Keller 	if (err) {
3493a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d",
3503a749623SJacob Keller 			  low_addr, err);
3513a749623SJacob Keller 		return err;
3523a749623SJacob Keller 	}
3533a749623SJacob Keller 
3543a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, high_addr, &high);
3553a749623SJacob Keller 	if (err) {
3563a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d",
3573a749623SJacob Keller 			  high_addr, err);
3583a749623SJacob Keller 		return err;
3593a749623SJacob Keller 	}
3603a749623SJacob Keller 
3613a749623SJacob Keller 	*val = (u64)high << 32 | low;
3623a749623SJacob Keller 
3633a749623SJacob Keller 	return 0;
3643a749623SJacob Keller }
3653a749623SJacob Keller 
3663a749623SJacob Keller /**
3673a749623SJacob Keller  * ice_write_phy_reg_e822 - Write a PHY register
3683a749623SJacob Keller  * @hw: pointer to the HW struct
3693a749623SJacob Keller  * @port: PHY port to write to
3703a749623SJacob Keller  * @offset: PHY register offset to write
3713a749623SJacob Keller  * @val: The value to write to the register
3723a749623SJacob Keller  *
3733a749623SJacob Keller  * Write a PHY register for the given port over the device sideband queue.
3743a749623SJacob Keller  */
3753a749623SJacob Keller static int
ice_write_phy_reg_e822(struct ice_hw * hw,u8 port,u16 offset,u32 val)3763a749623SJacob Keller ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
3773a749623SJacob Keller {
3783a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
3793a749623SJacob Keller 	int err;
3803a749623SJacob Keller 
3813a749623SJacob Keller 	ice_fill_phy_msg_e822(&msg, port, offset);
3823a749623SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
3833a749623SJacob Keller 	msg.data = val;
3843a749623SJacob Keller 
3853a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
3863a749623SJacob Keller 	if (err) {
3873a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
3883a749623SJacob Keller 			  err);
3893a749623SJacob Keller 		return err;
3903a749623SJacob Keller 	}
3913a749623SJacob Keller 
3923a749623SJacob Keller 	return 0;
3933a749623SJacob Keller }
3943a749623SJacob Keller 
3953a749623SJacob Keller /**
3963a749623SJacob Keller  * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY
3973a749623SJacob Keller  * @hw: pointer to the HW struct
3983a749623SJacob Keller  * @port: port to write to
3993a749623SJacob Keller  * @low_addr: offset of the low register
4003a749623SJacob Keller  * @val: 40b value to write
4013a749623SJacob Keller  *
4023a749623SJacob Keller  * Write the provided 40b value to the two associated registers by splitting
4033a749623SJacob Keller  * it up into two chunks, the lower 8 bits and the upper 32 bits.
4043a749623SJacob Keller  */
4053a749623SJacob Keller static int
ice_write_40b_phy_reg_e822(struct ice_hw * hw,u8 port,u16 low_addr,u64 val)4063a749623SJacob Keller ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
4073a749623SJacob Keller {
4083a749623SJacob Keller 	u32 low, high;
4093a749623SJacob Keller 	u16 high_addr;
4103a749623SJacob Keller 	int err;
4113a749623SJacob Keller 
4123a749623SJacob Keller 	/* Only operate on registers known to be split into a lower 8 bit
4133a749623SJacob Keller 	 * register and an upper 32 bit register.
4143a749623SJacob Keller 	 */
4153a749623SJacob Keller 	if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
4163a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n",
4173a749623SJacob Keller 			  low_addr);
4183a749623SJacob Keller 		return -EINVAL;
4193a749623SJacob Keller 	}
4203a749623SJacob Keller 
4213a749623SJacob Keller 	low = (u32)(val & P_REG_40B_LOW_M);
4223a749623SJacob Keller 	high = (u32)(val >> P_REG_40B_HIGH_S);
4233a749623SJacob Keller 
4243a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, low_addr, low);
4253a749623SJacob Keller 	if (err) {
4263a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
4273a749623SJacob Keller 			  low_addr, err);
4283a749623SJacob Keller 		return err;
4293a749623SJacob Keller 	}
4303a749623SJacob Keller 
4313a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, high_addr, high);
4323a749623SJacob Keller 	if (err) {
4333a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
4343a749623SJacob Keller 			  high_addr, err);
4353a749623SJacob Keller 		return err;
4363a749623SJacob Keller 	}
4373a749623SJacob Keller 
4383a749623SJacob Keller 	return 0;
4393a749623SJacob Keller }
4403a749623SJacob Keller 
4413a749623SJacob Keller /**
4423a749623SJacob Keller  * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers
4433a749623SJacob Keller  * @hw: pointer to the HW struct
4443a749623SJacob Keller  * @port: PHY port to read from
4453a749623SJacob Keller  * @low_addr: offset of the lower register to read from
4463a749623SJacob Keller  * @val: the contents of the 64bit value to write to PHY
4473a749623SJacob Keller  *
4483a749623SJacob Keller  * Write the 64bit value to the two associated 32bit PHY registers. The offset
4493a749623SJacob Keller  * is always specified as the lower register, and the high address is looked
4503a749623SJacob Keller  * up. This function only operates on registers known to be two parts of
4513a749623SJacob Keller  * a 64bit value.
4523a749623SJacob Keller  */
4533a749623SJacob Keller static int
ice_write_64b_phy_reg_e822(struct ice_hw * hw,u8 port,u16 low_addr,u64 val)4543a749623SJacob Keller ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
4553a749623SJacob Keller {
4563a749623SJacob Keller 	u32 low, high;
4573a749623SJacob Keller 	u16 high_addr;
4583a749623SJacob Keller 	int err;
4593a749623SJacob Keller 
4603a749623SJacob Keller 	/* Only operate on registers known to be split into two 32bit
4613a749623SJacob Keller 	 * registers.
4623a749623SJacob Keller 	 */
4633a749623SJacob Keller 	if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
4643a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
4653a749623SJacob Keller 			  low_addr);
4663a749623SJacob Keller 		return -EINVAL;
4673a749623SJacob Keller 	}
4683a749623SJacob Keller 
4693a749623SJacob Keller 	low = lower_32_bits(val);
4703a749623SJacob Keller 	high = upper_32_bits(val);
4713a749623SJacob Keller 
4723a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, low_addr, low);
4733a749623SJacob Keller 	if (err) {
4743a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
4753a749623SJacob Keller 			  low_addr, err);
4763a749623SJacob Keller 		return err;
4773a749623SJacob Keller 	}
4783a749623SJacob Keller 
4793a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, high_addr, high);
4803a749623SJacob Keller 	if (err) {
4813a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
4823a749623SJacob Keller 			  high_addr, err);
4833a749623SJacob Keller 		return err;
4843a749623SJacob Keller 	}
4853a749623SJacob Keller 
4863a749623SJacob Keller 	return 0;
4873a749623SJacob Keller }
4883a749623SJacob Keller 
4893a749623SJacob Keller /**
4903a749623SJacob Keller  * ice_fill_quad_msg_e822 - Fill message data for quad register access
4913a749623SJacob Keller  * @msg: the PHY message buffer to fill in
4923a749623SJacob Keller  * @quad: the quad to access
4933a749623SJacob Keller  * @offset: the register offset
4943a749623SJacob Keller  *
4953a749623SJacob Keller  * Fill a message buffer for accessing a register in a quad shared between
4963a749623SJacob Keller  * multiple PHYs.
4973a749623SJacob Keller  */
4983a749623SJacob Keller static void
ice_fill_quad_msg_e822(struct ice_sbq_msg_input * msg,u8 quad,u16 offset)4993a749623SJacob Keller ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
5003a749623SJacob Keller {
5013a749623SJacob Keller 	u32 addr;
5023a749623SJacob Keller 
5033a749623SJacob Keller 	msg->dest_dev = rmn_0;
5043a749623SJacob Keller 
5053a749623SJacob Keller 	if ((quad % ICE_NUM_QUAD_TYPE) == 0)
5063a749623SJacob Keller 		addr = Q_0_BASE + offset;
5073a749623SJacob Keller 	else
5083a749623SJacob Keller 		addr = Q_1_BASE + offset;
5093a749623SJacob Keller 
5103a749623SJacob Keller 	msg->msg_addr_low = lower_16_bits(addr);
5113a749623SJacob Keller 	msg->msg_addr_high = upper_16_bits(addr);
5123a749623SJacob Keller }
5133a749623SJacob Keller 
5143a749623SJacob Keller /**
5153a749623SJacob Keller  * ice_read_quad_reg_e822 - Read a PHY quad register
5163a749623SJacob Keller  * @hw: pointer to the HW struct
5173a749623SJacob Keller  * @quad: quad to read from
5183a749623SJacob Keller  * @offset: quad register offset to read
5193a749623SJacob Keller  * @val: on return, the contents read from the quad
5203a749623SJacob Keller  *
5213a749623SJacob Keller  * Read a quad register over the device sideband queue. Quad registers are
5223a749623SJacob Keller  * shared between multiple PHYs.
5233a749623SJacob Keller  */
5243a749623SJacob Keller int
ice_read_quad_reg_e822(struct ice_hw * hw,u8 quad,u16 offset,u32 * val)5253a749623SJacob Keller ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
5263a749623SJacob Keller {
5273a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
5283a749623SJacob Keller 	int err;
5293a749623SJacob Keller 
5303a749623SJacob Keller 	if (quad >= ICE_MAX_QUAD)
5313a749623SJacob Keller 		return -EINVAL;
5323a749623SJacob Keller 
5333a749623SJacob Keller 	ice_fill_quad_msg_e822(&msg, quad, offset);
5343a749623SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
5353a749623SJacob Keller 
5363a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
5373a749623SJacob Keller 	if (err) {
5383a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
5393a749623SJacob Keller 			  err);
5403a749623SJacob Keller 		return err;
5413a749623SJacob Keller 	}
5423a749623SJacob Keller 
5433a749623SJacob Keller 	*val = msg.data;
5443a749623SJacob Keller 
5453a749623SJacob Keller 	return 0;
5463a749623SJacob Keller }
5473a749623SJacob Keller 
5483a749623SJacob Keller /**
5493a749623SJacob Keller  * ice_write_quad_reg_e822 - Write a PHY quad register
5503a749623SJacob Keller  * @hw: pointer to the HW struct
5513a749623SJacob Keller  * @quad: quad to write to
5523a749623SJacob Keller  * @offset: quad register offset to write
5533a749623SJacob Keller  * @val: The value to write to the register
5543a749623SJacob Keller  *
5553a749623SJacob Keller  * Write a quad register over the device sideband queue. Quad registers are
5563a749623SJacob Keller  * shared between multiple PHYs.
5573a749623SJacob Keller  */
5583a749623SJacob Keller int
ice_write_quad_reg_e822(struct ice_hw * hw,u8 quad,u16 offset,u32 val)5593a749623SJacob Keller ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
5603a749623SJacob Keller {
5613a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
5623a749623SJacob Keller 	int err;
5633a749623SJacob Keller 
5643a749623SJacob Keller 	if (quad >= ICE_MAX_QUAD)
5653a749623SJacob Keller 		return -EINVAL;
5663a749623SJacob Keller 
5673a749623SJacob Keller 	ice_fill_quad_msg_e822(&msg, quad, offset);
5683a749623SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
5693a749623SJacob Keller 	msg.data = val;
5703a749623SJacob Keller 
5713a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
5723a749623SJacob Keller 	if (err) {
5733a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
5743a749623SJacob Keller 			  err);
5753a749623SJacob Keller 		return err;
5763a749623SJacob Keller 	}
5773a749623SJacob Keller 
5783a749623SJacob Keller 	return 0;
5793a749623SJacob Keller }
5803a749623SJacob Keller 
5813a749623SJacob Keller /**
5823a749623SJacob Keller  * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block
5833a749623SJacob Keller  * @hw: pointer to the HW struct
5843a749623SJacob Keller  * @quad: the quad to read from
5853a749623SJacob Keller  * @idx: the timestamp index to read
5863a749623SJacob Keller  * @tstamp: on return, the 40bit timestamp value
5873a749623SJacob Keller  *
5883a749623SJacob Keller  * Read a 40bit timestamp value out of the two associated registers in the
5893a749623SJacob Keller  * quad memory block that is shared between the internal PHYs of the E822
5903a749623SJacob Keller  * family of devices.
5913a749623SJacob Keller  */
5923a749623SJacob Keller static int
ice_read_phy_tstamp_e822(struct ice_hw * hw,u8 quad,u8 idx,u64 * tstamp)5933a749623SJacob Keller ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
5943a749623SJacob Keller {
5953a749623SJacob Keller 	u16 lo_addr, hi_addr;
5963a749623SJacob Keller 	u32 lo, hi;
5973a749623SJacob Keller 	int err;
5983a749623SJacob Keller 
5993a749623SJacob Keller 	lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
6003a749623SJacob Keller 	hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
6013a749623SJacob Keller 
6023a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);
6033a749623SJacob Keller 	if (err) {
6043a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
6053a749623SJacob Keller 			  err);
6063a749623SJacob Keller 		return err;
6073a749623SJacob Keller 	}
6083a749623SJacob Keller 
6093a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);
6103a749623SJacob Keller 	if (err) {
6113a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
6123a749623SJacob Keller 			  err);
6133a749623SJacob Keller 		return err;
6143a749623SJacob Keller 	}
6153a749623SJacob Keller 
6163a749623SJacob Keller 	/* For E822 based internal PHYs, the timestamp is reported with the
6173a749623SJacob Keller 	 * lower 8 bits in the low register, and the upper 32 bits in the high
6183a749623SJacob Keller 	 * register.
6193a749623SJacob Keller 	 */
6203a749623SJacob Keller 	*tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
6213a749623SJacob Keller 
6223a749623SJacob Keller 	return 0;
6233a749623SJacob Keller }
6243a749623SJacob Keller 
6253a749623SJacob Keller /**
6263a749623SJacob Keller  * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block
6273a749623SJacob Keller  * @hw: pointer to the HW struct
6283a749623SJacob Keller  * @quad: the quad to read from
6293a749623SJacob Keller  * @idx: the timestamp index to reset
6303a749623SJacob Keller  *
6313a749623SJacob Keller  * Clear a timestamp, resetting its valid bit, from the PHY quad block that is
6323a749623SJacob Keller  * shared between the internal PHYs on the E822 devices.
6333a749623SJacob Keller  */
6343a749623SJacob Keller static int
ice_clear_phy_tstamp_e822(struct ice_hw * hw,u8 quad,u8 idx)6353a749623SJacob Keller ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
6363a749623SJacob Keller {
6373a749623SJacob Keller 	u16 lo_addr, hi_addr;
6383a749623SJacob Keller 	int err;
6393a749623SJacob Keller 
6403a749623SJacob Keller 	lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
6413a749623SJacob Keller 	hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
6423a749623SJacob Keller 
6433a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);
6443a749623SJacob Keller 	if (err) {
6453a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
6463a749623SJacob Keller 			  err);
6473a749623SJacob Keller 		return err;
6483a749623SJacob Keller 	}
6493a749623SJacob Keller 
6503a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);
6513a749623SJacob Keller 	if (err) {
6523a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
6533a749623SJacob Keller 			  err);
6543a749623SJacob Keller 		return err;
6553a749623SJacob Keller 	}
6563a749623SJacob Keller 
6573a749623SJacob Keller 	return 0;
6583a749623SJacob Keller }
6593a749623SJacob Keller 
6603a749623SJacob Keller /**
661407b66c0SKarol Kolacinski  * ice_ptp_reset_ts_memory_quad_e822 - Clear all timestamps from the quad block
662407b66c0SKarol Kolacinski  * @hw: pointer to the HW struct
663407b66c0SKarol Kolacinski  * @quad: the quad to read from
664407b66c0SKarol Kolacinski  *
665407b66c0SKarol Kolacinski  * Clear all timestamps from the PHY quad block that is shared between the
666407b66c0SKarol Kolacinski  * internal PHYs on the E822 devices.
667407b66c0SKarol Kolacinski  */
ice_ptp_reset_ts_memory_quad_e822(struct ice_hw * hw,u8 quad)668407b66c0SKarol Kolacinski void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad)
669407b66c0SKarol Kolacinski {
670407b66c0SKarol Kolacinski 	ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M);
671407b66c0SKarol Kolacinski 	ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M);
672407b66c0SKarol Kolacinski }
673407b66c0SKarol Kolacinski 
674407b66c0SKarol Kolacinski /**
675407b66c0SKarol Kolacinski  * ice_ptp_reset_ts_memory_e822 - Clear all timestamps from all quad blocks
676407b66c0SKarol Kolacinski  * @hw: pointer to the HW struct
677407b66c0SKarol Kolacinski  */
ice_ptp_reset_ts_memory_e822(struct ice_hw * hw)678407b66c0SKarol Kolacinski static void ice_ptp_reset_ts_memory_e822(struct ice_hw *hw)
679407b66c0SKarol Kolacinski {
680407b66c0SKarol Kolacinski 	unsigned int quad;
681407b66c0SKarol Kolacinski 
682407b66c0SKarol Kolacinski 	for (quad = 0; quad < ICE_MAX_QUAD; quad++)
683407b66c0SKarol Kolacinski 		ice_ptp_reset_ts_memory_quad_e822(hw, quad);
684407b66c0SKarol Kolacinski }
685407b66c0SKarol Kolacinski 
686407b66c0SKarol Kolacinski /**
687b111ab5aSJacob Keller  * ice_read_cgu_reg_e822 - Read a CGU register
688b111ab5aSJacob Keller  * @hw: pointer to the HW struct
689b111ab5aSJacob Keller  * @addr: Register address to read
690b111ab5aSJacob Keller  * @val: storage for register value read
691b111ab5aSJacob Keller  *
692b111ab5aSJacob Keller  * Read the contents of a register of the Clock Generation Unit. Only
693b111ab5aSJacob Keller  * applicable to E822 devices.
694b111ab5aSJacob Keller  */
695b111ab5aSJacob Keller static int
ice_read_cgu_reg_e822(struct ice_hw * hw,u32 addr,u32 * val)696b111ab5aSJacob Keller ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
697b111ab5aSJacob Keller {
698b111ab5aSJacob Keller 	struct ice_sbq_msg_input cgu_msg;
699b111ab5aSJacob Keller 	int err;
700b111ab5aSJacob Keller 
701b111ab5aSJacob Keller 	cgu_msg.opcode = ice_sbq_msg_rd;
702b111ab5aSJacob Keller 	cgu_msg.dest_dev = cgu;
703b111ab5aSJacob Keller 	cgu_msg.msg_addr_low = addr;
704b111ab5aSJacob Keller 	cgu_msg.msg_addr_high = 0x0;
705b111ab5aSJacob Keller 
706b111ab5aSJacob Keller 	err = ice_sbq_rw_reg(hw, &cgu_msg);
707b111ab5aSJacob Keller 	if (err) {
708b111ab5aSJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n",
709b111ab5aSJacob Keller 			  addr, err);
710b111ab5aSJacob Keller 		return err;
711b111ab5aSJacob Keller 	}
712b111ab5aSJacob Keller 
713b111ab5aSJacob Keller 	*val = cgu_msg.data;
714b111ab5aSJacob Keller 
715b111ab5aSJacob Keller 	return err;
716b111ab5aSJacob Keller }
717b111ab5aSJacob Keller 
718b111ab5aSJacob Keller /**
719b111ab5aSJacob Keller  * ice_write_cgu_reg_e822 - Write a CGU register
720b111ab5aSJacob Keller  * @hw: pointer to the HW struct
721b111ab5aSJacob Keller  * @addr: Register address to write
722b111ab5aSJacob Keller  * @val: value to write into the register
723b111ab5aSJacob Keller  *
724b111ab5aSJacob Keller  * Write the specified value to a register of the Clock Generation Unit. Only
725b111ab5aSJacob Keller  * applicable to E822 devices.
726b111ab5aSJacob Keller  */
727b111ab5aSJacob Keller static int
ice_write_cgu_reg_e822(struct ice_hw * hw,u32 addr,u32 val)728b111ab5aSJacob Keller ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val)
729b111ab5aSJacob Keller {
730b111ab5aSJacob Keller 	struct ice_sbq_msg_input cgu_msg;
731b111ab5aSJacob Keller 	int err;
732b111ab5aSJacob Keller 
733b111ab5aSJacob Keller 	cgu_msg.opcode = ice_sbq_msg_wr;
734b111ab5aSJacob Keller 	cgu_msg.dest_dev = cgu;
735b111ab5aSJacob Keller 	cgu_msg.msg_addr_low = addr;
736b111ab5aSJacob Keller 	cgu_msg.msg_addr_high = 0x0;
737b111ab5aSJacob Keller 	cgu_msg.data = val;
738b111ab5aSJacob Keller 
739b111ab5aSJacob Keller 	err = ice_sbq_rw_reg(hw, &cgu_msg);
740b111ab5aSJacob Keller 	if (err) {
741b111ab5aSJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n",
742b111ab5aSJacob Keller 			  addr, err);
743b111ab5aSJacob Keller 		return err;
744b111ab5aSJacob Keller 	}
745b111ab5aSJacob Keller 
746b111ab5aSJacob Keller 	return err;
747b111ab5aSJacob Keller }
748b111ab5aSJacob Keller 
749b111ab5aSJacob Keller /**
750b111ab5aSJacob Keller  * ice_clk_freq_str - Convert time_ref_freq to string
751b111ab5aSJacob Keller  * @clk_freq: Clock frequency
752b111ab5aSJacob Keller  *
753b111ab5aSJacob Keller  * Convert the specified TIME_REF clock frequency to a string.
754b111ab5aSJacob Keller  */
ice_clk_freq_str(u8 clk_freq)755b111ab5aSJacob Keller static const char *ice_clk_freq_str(u8 clk_freq)
756b111ab5aSJacob Keller {
757b111ab5aSJacob Keller 	switch ((enum ice_time_ref_freq)clk_freq) {
758b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_25_000:
759b111ab5aSJacob Keller 		return "25 MHz";
760b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_122_880:
761b111ab5aSJacob Keller 		return "122.88 MHz";
762b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_125_000:
763b111ab5aSJacob Keller 		return "125 MHz";
764b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_153_600:
765b111ab5aSJacob Keller 		return "153.6 MHz";
766b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_156_250:
767b111ab5aSJacob Keller 		return "156.25 MHz";
768b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_245_760:
769b111ab5aSJacob Keller 		return "245.76 MHz";
770b111ab5aSJacob Keller 	default:
771b111ab5aSJacob Keller 		return "Unknown";
772b111ab5aSJacob Keller 	}
773b111ab5aSJacob Keller }
774b111ab5aSJacob Keller 
775b111ab5aSJacob Keller /**
776b111ab5aSJacob Keller  * ice_clk_src_str - Convert time_ref_src to string
777b111ab5aSJacob Keller  * @clk_src: Clock source
778b111ab5aSJacob Keller  *
779b111ab5aSJacob Keller  * Convert the specified clock source to its string name.
780b111ab5aSJacob Keller  */
ice_clk_src_str(u8 clk_src)781b111ab5aSJacob Keller static const char *ice_clk_src_str(u8 clk_src)
782b111ab5aSJacob Keller {
783b111ab5aSJacob Keller 	switch ((enum ice_clk_src)clk_src) {
784b111ab5aSJacob Keller 	case ICE_CLK_SRC_TCX0:
785b111ab5aSJacob Keller 		return "TCX0";
786b111ab5aSJacob Keller 	case ICE_CLK_SRC_TIME_REF:
787b111ab5aSJacob Keller 		return "TIME_REF";
788b111ab5aSJacob Keller 	default:
789b111ab5aSJacob Keller 		return "Unknown";
790b111ab5aSJacob Keller 	}
791b111ab5aSJacob Keller }
792b111ab5aSJacob Keller 
793b111ab5aSJacob Keller /**
794b111ab5aSJacob Keller  * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit
795b111ab5aSJacob Keller  * @hw: pointer to the HW struct
796b111ab5aSJacob Keller  * @clk_freq: Clock frequency to program
797b111ab5aSJacob Keller  * @clk_src: Clock source to select (TIME_REF, or TCX0)
798b111ab5aSJacob Keller  *
799b111ab5aSJacob Keller  * Configure the Clock Generation Unit with the desired clock frequency and
800b111ab5aSJacob Keller  * time reference, enabling the PLL which drives the PTP hardware clock.
801b111ab5aSJacob Keller  */
802b111ab5aSJacob Keller static int
ice_cfg_cgu_pll_e822(struct ice_hw * hw,enum ice_time_ref_freq clk_freq,enum ice_clk_src clk_src)803b111ab5aSJacob Keller ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
804b111ab5aSJacob Keller 		     enum ice_clk_src clk_src)
805b111ab5aSJacob Keller {
806b111ab5aSJacob Keller 	union tspll_ro_bwm_lf bwm_lf;
807b111ab5aSJacob Keller 	union nac_cgu_dword19 dw19;
808b111ab5aSJacob Keller 	union nac_cgu_dword22 dw22;
809b111ab5aSJacob Keller 	union nac_cgu_dword24 dw24;
810b111ab5aSJacob Keller 	union nac_cgu_dword9 dw9;
811b111ab5aSJacob Keller 	int err;
812b111ab5aSJacob Keller 
813b111ab5aSJacob Keller 	if (clk_freq >= NUM_ICE_TIME_REF_FREQ) {
814b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n",
815b111ab5aSJacob Keller 			 clk_freq);
816b111ab5aSJacob Keller 		return -EINVAL;
817b111ab5aSJacob Keller 	}
818b111ab5aSJacob Keller 
819b111ab5aSJacob Keller 	if (clk_src >= NUM_ICE_CLK_SRC) {
820b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n",
821b111ab5aSJacob Keller 			 clk_src);
822b111ab5aSJacob Keller 		return -EINVAL;
823b111ab5aSJacob Keller 	}
824b111ab5aSJacob Keller 
825b111ab5aSJacob Keller 	if (clk_src == ICE_CLK_SRC_TCX0 &&
826b111ab5aSJacob Keller 	    clk_freq != ICE_TIME_REF_FREQ_25_000) {
827b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw),
828b111ab5aSJacob Keller 			 "TCX0 only supports 25 MHz frequency\n");
829b111ab5aSJacob Keller 		return -EINVAL;
830b111ab5aSJacob Keller 	}
831b111ab5aSJacob Keller 
832b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val);
833b111ab5aSJacob Keller 	if (err)
834b111ab5aSJacob Keller 		return err;
835b111ab5aSJacob Keller 
836b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
837b111ab5aSJacob Keller 	if (err)
838b111ab5aSJacob Keller 		return err;
839b111ab5aSJacob Keller 
840b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
841b111ab5aSJacob Keller 	if (err)
842b111ab5aSJacob Keller 		return err;
843b111ab5aSJacob Keller 
844b111ab5aSJacob Keller 	/* Log the current clock configuration */
845b111ab5aSJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
846b111ab5aSJacob Keller 		  dw24.field.ts_pll_enable ? "enabled" : "disabled",
847b111ab5aSJacob Keller 		  ice_clk_src_str(dw24.field.time_ref_sel),
848b111ab5aSJacob Keller 		  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
849b111ab5aSJacob Keller 		  bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
850b111ab5aSJacob Keller 
851b111ab5aSJacob Keller 	/* Disable the PLL before changing the clock source or frequency */
852b111ab5aSJacob Keller 	if (dw24.field.ts_pll_enable) {
853b111ab5aSJacob Keller 		dw24.field.ts_pll_enable = 0;
854b111ab5aSJacob Keller 
855b111ab5aSJacob Keller 		err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
856b111ab5aSJacob Keller 		if (err)
857b111ab5aSJacob Keller 			return err;
858b111ab5aSJacob Keller 	}
859b111ab5aSJacob Keller 
860b111ab5aSJacob Keller 	/* Set the frequency */
861b111ab5aSJacob Keller 	dw9.field.time_ref_freq_sel = clk_freq;
862b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val);
863b111ab5aSJacob Keller 	if (err)
864b111ab5aSJacob Keller 		return err;
865b111ab5aSJacob Keller 
866b111ab5aSJacob Keller 	/* Configure the TS PLL feedback divisor */
867b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val);
868b111ab5aSJacob Keller 	if (err)
869b111ab5aSJacob Keller 		return err;
870b111ab5aSJacob Keller 
871b111ab5aSJacob Keller 	dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
872b111ab5aSJacob Keller 	dw19.field.tspll_ndivratio = 1;
873b111ab5aSJacob Keller 
874b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val);
875b111ab5aSJacob Keller 	if (err)
876b111ab5aSJacob Keller 		return err;
877b111ab5aSJacob Keller 
878b111ab5aSJacob Keller 	/* Configure the TS PLL post divisor */
879b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val);
880b111ab5aSJacob Keller 	if (err)
881b111ab5aSJacob Keller 		return err;
882b111ab5aSJacob Keller 
883b111ab5aSJacob Keller 	dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
884b111ab5aSJacob Keller 	dw22.field.time1588clk_sel_div2 = 0;
885b111ab5aSJacob Keller 
886b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val);
887b111ab5aSJacob Keller 	if (err)
888b111ab5aSJacob Keller 		return err;
889b111ab5aSJacob Keller 
890b111ab5aSJacob Keller 	/* Configure the TS PLL pre divisor and clock source */
891b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
892b111ab5aSJacob Keller 	if (err)
893b111ab5aSJacob Keller 		return err;
894b111ab5aSJacob Keller 
895b111ab5aSJacob Keller 	dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div;
896b111ab5aSJacob Keller 	dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
897b111ab5aSJacob Keller 	dw24.field.time_ref_sel = clk_src;
898b111ab5aSJacob Keller 
899b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
900b111ab5aSJacob Keller 	if (err)
901b111ab5aSJacob Keller 		return err;
902b111ab5aSJacob Keller 
903b111ab5aSJacob Keller 	/* Finally, enable the PLL */
904b111ab5aSJacob Keller 	dw24.field.ts_pll_enable = 1;
905b111ab5aSJacob Keller 
906b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
907b111ab5aSJacob Keller 	if (err)
908b111ab5aSJacob Keller 		return err;
909b111ab5aSJacob Keller 
910b111ab5aSJacob Keller 	/* Wait to verify if the PLL locks */
911b111ab5aSJacob Keller 	usleep_range(1000, 5000);
912b111ab5aSJacob Keller 
913b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
914b111ab5aSJacob Keller 	if (err)
915b111ab5aSJacob Keller 		return err;
916b111ab5aSJacob Keller 
917b111ab5aSJacob Keller 	if (!bwm_lf.field.plllock_true_lock_cri) {
918b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n");
919b111ab5aSJacob Keller 		return -EBUSY;
920b111ab5aSJacob Keller 	}
921b111ab5aSJacob Keller 
922b111ab5aSJacob Keller 	/* Log the current clock configuration */
923b111ab5aSJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
924b111ab5aSJacob Keller 		  dw24.field.ts_pll_enable ? "enabled" : "disabled",
925b111ab5aSJacob Keller 		  ice_clk_src_str(dw24.field.time_ref_sel),
926b111ab5aSJacob Keller 		  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
927b111ab5aSJacob Keller 		  bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
928b111ab5aSJacob Keller 
929b111ab5aSJacob Keller 	return 0;
930b111ab5aSJacob Keller }
931b111ab5aSJacob Keller 
932b111ab5aSJacob Keller /**
933b111ab5aSJacob Keller  * ice_init_cgu_e822 - Initialize CGU with settings from firmware
934b111ab5aSJacob Keller  * @hw: pointer to the HW structure
935b111ab5aSJacob Keller  *
936b111ab5aSJacob Keller  * Initialize the Clock Generation Unit of the E822 device.
937b111ab5aSJacob Keller  */
ice_init_cgu_e822(struct ice_hw * hw)938b111ab5aSJacob Keller static int ice_init_cgu_e822(struct ice_hw *hw)
939b111ab5aSJacob Keller {
940b111ab5aSJacob Keller 	struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
941b111ab5aSJacob Keller 	union tspll_cntr_bist_settings cntr_bist;
942b111ab5aSJacob Keller 	int err;
943b111ab5aSJacob Keller 
944b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
945b111ab5aSJacob Keller 				    &cntr_bist.val);
946b111ab5aSJacob Keller 	if (err)
947b111ab5aSJacob Keller 		return err;
948b111ab5aSJacob Keller 
949b111ab5aSJacob Keller 	/* Disable sticky lock detection so lock err reported is accurate */
950b111ab5aSJacob Keller 	cntr_bist.field.i_plllock_sel_0 = 0;
951b111ab5aSJacob Keller 	cntr_bist.field.i_plllock_sel_1 = 0;
952b111ab5aSJacob Keller 
953b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
954b111ab5aSJacob Keller 				     cntr_bist.val);
955b111ab5aSJacob Keller 	if (err)
956b111ab5aSJacob Keller 		return err;
957b111ab5aSJacob Keller 
958b111ab5aSJacob Keller 	/* Configure the CGU PLL using the parameters from the function
959b111ab5aSJacob Keller 	 * capabilities.
960b111ab5aSJacob Keller 	 */
961b111ab5aSJacob Keller 	err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref,
962b111ab5aSJacob Keller 				   (enum ice_clk_src)ts_info->clk_src);
963b111ab5aSJacob Keller 	if (err)
964b111ab5aSJacob Keller 		return err;
965b111ab5aSJacob Keller 
966b111ab5aSJacob Keller 	return 0;
967b111ab5aSJacob Keller }
968b111ab5aSJacob Keller 
969b111ab5aSJacob Keller /**
9703a749623SJacob Keller  * ice_ptp_set_vernier_wl - Set the window length for vernier calibration
9713a749623SJacob Keller  * @hw: pointer to the HW struct
9723a749623SJacob Keller  *
9733a749623SJacob Keller  * Set the window length used for the vernier port calibration process.
9743a749623SJacob Keller  */
ice_ptp_set_vernier_wl(struct ice_hw * hw)9753a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw)
9763a749623SJacob Keller {
9773a749623SJacob Keller 	u8 port;
9783a749623SJacob Keller 
9793a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
9803a749623SJacob Keller 		int err;
9813a749623SJacob Keller 
9823a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_WL,
9833a749623SJacob Keller 					     PTP_VERNIER_WL);
9843a749623SJacob Keller 		if (err) {
9853a749623SJacob Keller 			ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n",
9863a749623SJacob Keller 				  port, err);
9873a749623SJacob Keller 			return err;
9883a749623SJacob Keller 		}
9893a749623SJacob Keller 	}
9903a749623SJacob Keller 
9913a749623SJacob Keller 	return 0;
9923a749623SJacob Keller }
9933a749623SJacob Keller 
9943a749623SJacob Keller /**
9953a749623SJacob Keller  * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization
9963a749623SJacob Keller  * @hw: pointer to HW struct
9973a749623SJacob Keller  *
9983a749623SJacob Keller  * Perform PHC initialization steps specific to E822 devices.
9993a749623SJacob Keller  */
ice_ptp_init_phc_e822(struct ice_hw * hw)10003a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw)
10013a749623SJacob Keller {
1002b111ab5aSJacob Keller 	int err;
10033a749623SJacob Keller 	u32 regval;
10043a749623SJacob Keller 
10053a749623SJacob Keller 	/* Enable reading switch and PHY registers over the sideband queue */
10063a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
10073a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
10083a749623SJacob Keller 	regval = rd32(hw, PF_SB_REM_DEV_CTL);
10093a749623SJacob Keller 	regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
10103a749623SJacob Keller 		   PF_SB_REM_DEV_CTL_PHY0);
10113a749623SJacob Keller 	wr32(hw, PF_SB_REM_DEV_CTL, regval);
10123a749623SJacob Keller 
1013b111ab5aSJacob Keller 	/* Initialize the Clock Generation Unit */
1014b111ab5aSJacob Keller 	err = ice_init_cgu_e822(hw);
1015b111ab5aSJacob Keller 	if (err)
1016b111ab5aSJacob Keller 		return err;
1017b111ab5aSJacob Keller 
10183a749623SJacob Keller 	/* Set window length for all the ports */
10193a749623SJacob Keller 	return ice_ptp_set_vernier_wl(hw);
10203a749623SJacob Keller }
10213a749623SJacob Keller 
10223a749623SJacob Keller /**
10233a749623SJacob Keller  * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time
10243a749623SJacob Keller  * @hw: pointer to the HW struct
10253a749623SJacob Keller  * @time: Time to initialize the PHY port clocks to
10263a749623SJacob Keller  *
10273a749623SJacob Keller  * Program the PHY port registers with a new initial time value. The port
10283a749623SJacob Keller  * clock will be initialized once the driver issues an INIT_TIME sync
10293a749623SJacob Keller  * command. The time value is the upper 32 bits of the PHY timer, usually in
10303a749623SJacob Keller  * units of nominal nanoseconds.
10313a749623SJacob Keller  */
10323a749623SJacob Keller static int
ice_ptp_prep_phy_time_e822(struct ice_hw * hw,u32 time)10333a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
10343a749623SJacob Keller {
10353a749623SJacob Keller 	u64 phy_time;
10363a749623SJacob Keller 	u8 port;
10373a749623SJacob Keller 	int err;
10383a749623SJacob Keller 
10393a749623SJacob Keller 	/* The time represents the upper 32 bits of the PHY timer, so we need
10403a749623SJacob Keller 	 * to shift to account for this when programming.
10413a749623SJacob Keller 	 */
10423a749623SJacob Keller 	phy_time = (u64)time << 32;
10433a749623SJacob Keller 
10443a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
10453a749623SJacob Keller 		/* Tx case */
10463a749623SJacob Keller 		err = ice_write_64b_phy_reg_e822(hw, port,
10473a749623SJacob Keller 						 P_REG_TX_TIMER_INC_PRE_L,
10483a749623SJacob Keller 						 phy_time);
10493a749623SJacob Keller 		if (err)
10503a749623SJacob Keller 			goto exit_err;
10513a749623SJacob Keller 
10523a749623SJacob Keller 		/* Rx case */
10533a749623SJacob Keller 		err = ice_write_64b_phy_reg_e822(hw, port,
10543a749623SJacob Keller 						 P_REG_RX_TIMER_INC_PRE_L,
10553a749623SJacob Keller 						 phy_time);
10563a749623SJacob Keller 		if (err)
10573a749623SJacob Keller 			goto exit_err;
10583a749623SJacob Keller 	}
10593a749623SJacob Keller 
10603a749623SJacob Keller 	return 0;
10613a749623SJacob Keller 
10623a749623SJacob Keller exit_err:
10633a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n",
10643a749623SJacob Keller 		  port, err);
10653a749623SJacob Keller 
10663a749623SJacob Keller 	return err;
10673a749623SJacob Keller }
10683a749623SJacob Keller 
10693a749623SJacob Keller /**
10703a749623SJacob Keller  * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust
10713a749623SJacob Keller  * @hw: pointer to HW struct
10723a749623SJacob Keller  * @port: Port number to be programmed
10733a749623SJacob Keller  * @time: time in cycles to adjust the port Tx and Rx clocks
10743a749623SJacob Keller  *
10753a749623SJacob Keller  * Program the port for an atomic adjustment by writing the Tx and Rx timer
10763a749623SJacob Keller  * registers. The atomic adjustment won't be completed until the driver issues
10773a749623SJacob Keller  * an ADJ_TIME command.
10783a749623SJacob Keller  *
10793a749623SJacob Keller  * Note that time is not in units of nanoseconds. It is in clock time
10803a749623SJacob Keller  * including the lower sub-nanosecond portion of the port timer.
10813a749623SJacob Keller  *
10823a749623SJacob Keller  * Negative adjustments are supported using 2s complement arithmetic.
10833a749623SJacob Keller  */
10843a749623SJacob Keller static int
ice_ptp_prep_port_adj_e822(struct ice_hw * hw,u8 port,s64 time)10853a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time)
10863a749623SJacob Keller {
10873a749623SJacob Keller 	u32 l_time, u_time;
10883a749623SJacob Keller 	int err;
10893a749623SJacob Keller 
10903a749623SJacob Keller 	l_time = lower_32_bits(time);
10913a749623SJacob Keller 	u_time = upper_32_bits(time);
10923a749623SJacob Keller 
10933a749623SJacob Keller 	/* Tx case */
10943a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L,
10953a749623SJacob Keller 				     l_time);
10963a749623SJacob Keller 	if (err)
10973a749623SJacob Keller 		goto exit_err;
10983a749623SJacob Keller 
10993a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U,
11003a749623SJacob Keller 				     u_time);
11013a749623SJacob Keller 	if (err)
11023a749623SJacob Keller 		goto exit_err;
11033a749623SJacob Keller 
11043a749623SJacob Keller 	/* Rx case */
11053a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L,
11063a749623SJacob Keller 				     l_time);
11073a749623SJacob Keller 	if (err)
11083a749623SJacob Keller 		goto exit_err;
11093a749623SJacob Keller 
11103a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U,
11113a749623SJacob Keller 				     u_time);
11123a749623SJacob Keller 	if (err)
11133a749623SJacob Keller 		goto exit_err;
11143a749623SJacob Keller 
11153a749623SJacob Keller 	return 0;
11163a749623SJacob Keller 
11173a749623SJacob Keller exit_err:
11183a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n",
11193a749623SJacob Keller 		  port, err);
11203a749623SJacob Keller 	return err;
11213a749623SJacob Keller }
11223a749623SJacob Keller 
11233a749623SJacob Keller /**
11243a749623SJacob Keller  * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment
11253a749623SJacob Keller  * @hw: pointer to HW struct
11263a749623SJacob Keller  * @adj: adjustment in nanoseconds
11273a749623SJacob Keller  *
11283a749623SJacob Keller  * Prepare the PHY ports for an atomic time adjustment by programming the PHY
11293a749623SJacob Keller  * Tx and Rx port registers. The actual adjustment is completed by issuing an
11303a749623SJacob Keller  * ADJ_TIME or ADJ_TIME_AT_TIME sync command.
11313a749623SJacob Keller  */
11323a749623SJacob Keller static int
ice_ptp_prep_phy_adj_e822(struct ice_hw * hw,s32 adj)11333a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
11343a749623SJacob Keller {
11353a749623SJacob Keller 	s64 cycles;
11363a749623SJacob Keller 	u8 port;
11373a749623SJacob Keller 
11383a749623SJacob Keller 	/* The port clock supports adjustment of the sub-nanosecond portion of
11393a749623SJacob Keller 	 * the clock. We shift the provided adjustment in nanoseconds to
11403a749623SJacob Keller 	 * calculate the appropriate adjustment to program into the PHY ports.
11413a749623SJacob Keller 	 */
11423a749623SJacob Keller 	if (adj > 0)
11433a749623SJacob Keller 		cycles = (s64)adj << 32;
11443a749623SJacob Keller 	else
11453a749623SJacob Keller 		cycles = -(((s64)-adj) << 32);
11463a749623SJacob Keller 
11473a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
11483a749623SJacob Keller 		int err;
11493a749623SJacob Keller 
11503a749623SJacob Keller 		err = ice_ptp_prep_port_adj_e822(hw, port, cycles);
11513a749623SJacob Keller 		if (err)
11523a749623SJacob Keller 			return err;
11533a749623SJacob Keller 	}
11543a749623SJacob Keller 
11553a749623SJacob Keller 	return 0;
11563a749623SJacob Keller }
11573a749623SJacob Keller 
11583a749623SJacob Keller /**
11593a749623SJacob Keller  * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment
11603a749623SJacob Keller  * @hw: pointer to HW struct
11613a749623SJacob Keller  * @incval: new increment value to prepare
11623a749623SJacob Keller  *
11633a749623SJacob Keller  * Prepare each of the PHY ports for a new increment value by programming the
11643a749623SJacob Keller  * port's TIMETUS registers. The new increment value will be updated after
11653a749623SJacob Keller  * issuing an INIT_INCVAL command.
11663a749623SJacob Keller  */
11673a749623SJacob Keller static int
ice_ptp_prep_phy_incval_e822(struct ice_hw * hw,u64 incval)11683a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
11693a749623SJacob Keller {
11703a749623SJacob Keller 	int err;
11713a749623SJacob Keller 	u8 port;
11723a749623SJacob Keller 
11733a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
11743a749623SJacob Keller 		err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,
11753a749623SJacob Keller 						 incval);
11763a749623SJacob Keller 		if (err)
11773a749623SJacob Keller 			goto exit_err;
11783a749623SJacob Keller 	}
11793a749623SJacob Keller 
11803a749623SJacob Keller 	return 0;
11813a749623SJacob Keller 
11823a749623SJacob Keller exit_err:
11833a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n",
11843a749623SJacob Keller 		  port, err);
11853a749623SJacob Keller 
11863a749623SJacob Keller 	return err;
11873a749623SJacob Keller }
11883a749623SJacob Keller 
11893a749623SJacob Keller /**
11903a749623SJacob Keller  * ice_ptp_read_port_capture - Read a port's local time capture
11913a749623SJacob Keller  * @hw: pointer to HW struct
11923a749623SJacob Keller  * @port: Port number to read
11933a749623SJacob Keller  * @tx_ts: on return, the Tx port time capture
11943a749623SJacob Keller  * @rx_ts: on return, the Rx port time capture
11953a749623SJacob Keller  *
11963a749623SJacob Keller  * Read the port's Tx and Rx local time capture values.
11973a749623SJacob Keller  *
11983a749623SJacob Keller  * Note this has no equivalent for the E810 devices.
11993a749623SJacob Keller  */
12003a749623SJacob Keller static int
ice_ptp_read_port_capture(struct ice_hw * hw,u8 port,u64 * tx_ts,u64 * rx_ts)12013a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
12023a749623SJacob Keller {
12033a749623SJacob Keller 	int err;
12043a749623SJacob Keller 
12053a749623SJacob Keller 	/* Tx case */
12063a749623SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
12073a749623SJacob Keller 	if (err) {
12083a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n",
12093a749623SJacob Keller 			  err);
12103a749623SJacob Keller 		return err;
12113a749623SJacob Keller 	}
12123a749623SJacob Keller 
12133a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n",
12143a749623SJacob Keller 		  (unsigned long long)*tx_ts);
12153a749623SJacob Keller 
12163a749623SJacob Keller 	/* Rx case */
12173a749623SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
12183a749623SJacob Keller 	if (err) {
12193a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n",
12203a749623SJacob Keller 			  err);
12213a749623SJacob Keller 		return err;
12223a749623SJacob Keller 	}
12233a749623SJacob Keller 
12243a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n",
12253a749623SJacob Keller 		  (unsigned long long)*rx_ts);
12263a749623SJacob Keller 
12273a749623SJacob Keller 	return 0;
12283a749623SJacob Keller }
12293a749623SJacob Keller 
12303a749623SJacob Keller /**
1231*0aacec49SJacob Keller  * ice_ptp_write_port_cmd_e822 - Prepare a single PHY port for a timer command
12323a749623SJacob Keller  * @hw: pointer to HW struct
12333a749623SJacob Keller  * @port: Port to which cmd has to be sent
12343a749623SJacob Keller  * @cmd: Command to be sent to the port
12353a749623SJacob Keller  *
12363a749623SJacob Keller  * Prepare the requested port for an upcoming timer sync command.
12373a749623SJacob Keller  *
1238*0aacec49SJacob Keller  * Do not use this function directly. If you want to configure exactly one
1239*0aacec49SJacob Keller  * port, use ice_ptp_one_port_cmd() instead.
12403a749623SJacob Keller  */
12413a749623SJacob Keller static int
ice_ptp_write_port_cmd_e822(struct ice_hw * hw,u8 port,enum ice_ptp_tmr_cmd cmd)1242*0aacec49SJacob Keller ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
12433a749623SJacob Keller {
12443a749623SJacob Keller 	u32 cmd_val, val;
12453a749623SJacob Keller 	u8 tmr_idx;
12463a749623SJacob Keller 	int err;
12473a749623SJacob Keller 
12483a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
12493a749623SJacob Keller 	cmd_val = tmr_idx << SEL_PHY_SRC;
12503a749623SJacob Keller 	switch (cmd) {
12513a749623SJacob Keller 	case INIT_TIME:
12523a749623SJacob Keller 		cmd_val |= PHY_CMD_INIT_TIME;
12533a749623SJacob Keller 		break;
12543a749623SJacob Keller 	case INIT_INCVAL:
12553a749623SJacob Keller 		cmd_val |= PHY_CMD_INIT_INCVAL;
12563a749623SJacob Keller 		break;
12573a749623SJacob Keller 	case ADJ_TIME:
12583a749623SJacob Keller 		cmd_val |= PHY_CMD_ADJ_TIME;
12593a749623SJacob Keller 		break;
12603a749623SJacob Keller 	case READ_TIME:
12613a749623SJacob Keller 		cmd_val |= PHY_CMD_READ_TIME;
12623a749623SJacob Keller 		break;
12633a749623SJacob Keller 	case ADJ_TIME_AT_TIME:
12643a749623SJacob Keller 		cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
12653a749623SJacob Keller 		break;
1266*0aacec49SJacob Keller 	case ICE_PTP_NOP:
1267*0aacec49SJacob Keller 		break;
12683a749623SJacob Keller 	}
12693a749623SJacob Keller 
12703a749623SJacob Keller 	/* Tx case */
12713a749623SJacob Keller 	/* Read, modify, write */
12723a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val);
12733a749623SJacob Keller 	if (err) {
12743a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n",
12753a749623SJacob Keller 			  err);
12763a749623SJacob Keller 		return err;
12773a749623SJacob Keller 	}
12783a749623SJacob Keller 
12793a749623SJacob Keller 	/* Modify necessary bits only and perform write */
12803a749623SJacob Keller 	val &= ~TS_CMD_MASK;
12813a749623SJacob Keller 	val |= cmd_val;
12823a749623SJacob Keller 
12833a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val);
12843a749623SJacob Keller 	if (err) {
12853a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n",
12863a749623SJacob Keller 			  err);
12873a749623SJacob Keller 		return err;
12883a749623SJacob Keller 	}
12893a749623SJacob Keller 
12903a749623SJacob Keller 	/* Rx case */
12913a749623SJacob Keller 	/* Read, modify, write */
12923a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val);
12933a749623SJacob Keller 	if (err) {
12943a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n",
12953a749623SJacob Keller 			  err);
12963a749623SJacob Keller 		return err;
12973a749623SJacob Keller 	}
12983a749623SJacob Keller 
12993a749623SJacob Keller 	/* Modify necessary bits only and perform write */
13003a749623SJacob Keller 	val &= ~TS_CMD_MASK;
13013a749623SJacob Keller 	val |= cmd_val;
13023a749623SJacob Keller 
13033a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val);
13043a749623SJacob Keller 	if (err) {
13053a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n",
13063a749623SJacob Keller 			  err);
13073a749623SJacob Keller 		return err;
13083a749623SJacob Keller 	}
13093a749623SJacob Keller 
13103a749623SJacob Keller 	return 0;
13113a749623SJacob Keller }
13123a749623SJacob Keller 
13133a749623SJacob Keller /**
1314*0aacec49SJacob Keller  * ice_ptp_one_port_cmd - Prepare one port for a timer command
1315*0aacec49SJacob Keller  * @hw: pointer to the HW struct
1316*0aacec49SJacob Keller  * @configured_port: the port to configure with configured_cmd
1317*0aacec49SJacob Keller  * @configured_cmd: timer command to prepare on the configured_port
1318*0aacec49SJacob Keller  *
1319*0aacec49SJacob Keller  * Prepare the configured_port for the configured_cmd, and prepare all other
1320*0aacec49SJacob Keller  * ports for ICE_PTP_NOP. This causes the configured_port to execute the
1321*0aacec49SJacob Keller  * desired command while all other ports perform no operation.
1322*0aacec49SJacob Keller  */
1323*0aacec49SJacob Keller static int
ice_ptp_one_port_cmd(struct ice_hw * hw,u8 configured_port,enum ice_ptp_tmr_cmd configured_cmd)1324*0aacec49SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
1325*0aacec49SJacob Keller 		     enum ice_ptp_tmr_cmd configured_cmd)
1326*0aacec49SJacob Keller {
1327*0aacec49SJacob Keller 	u8 port;
1328*0aacec49SJacob Keller 
1329*0aacec49SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
1330*0aacec49SJacob Keller 		enum ice_ptp_tmr_cmd cmd;
1331*0aacec49SJacob Keller 		int err;
1332*0aacec49SJacob Keller 
1333*0aacec49SJacob Keller 		if (port == configured_port)
1334*0aacec49SJacob Keller 			cmd = configured_cmd;
1335*0aacec49SJacob Keller 		else
1336*0aacec49SJacob Keller 			cmd = ICE_PTP_NOP;
1337*0aacec49SJacob Keller 
1338*0aacec49SJacob Keller 		err = ice_ptp_write_port_cmd_e822(hw, port, cmd);
1339*0aacec49SJacob Keller 		if (err)
1340*0aacec49SJacob Keller 			return err;
1341*0aacec49SJacob Keller 	}
1342*0aacec49SJacob Keller 
1343*0aacec49SJacob Keller 	return 0;
1344*0aacec49SJacob Keller }
1345*0aacec49SJacob Keller 
1346*0aacec49SJacob Keller /**
13473a749623SJacob Keller  * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
13483a749623SJacob Keller  * @hw: pointer to the HW struct
13493a749623SJacob Keller  * @cmd: timer command to prepare
13503a749623SJacob Keller  *
13513a749623SJacob Keller  * Prepare all ports connected to this device for an upcoming timer sync
13523a749623SJacob Keller  * command.
13533a749623SJacob Keller  */
13543a749623SJacob Keller static int
ice_ptp_port_cmd_e822(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)13553a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
13563a749623SJacob Keller {
13573a749623SJacob Keller 	u8 port;
13583a749623SJacob Keller 
13593a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
13603a749623SJacob Keller 		int err;
13613a749623SJacob Keller 
1362*0aacec49SJacob Keller 		err = ice_ptp_write_port_cmd_e822(hw, port, cmd);
13633a749623SJacob Keller 		if (err)
13643a749623SJacob Keller 			return err;
13653a749623SJacob Keller 	}
13663a749623SJacob Keller 
13673a749623SJacob Keller 	return 0;
13683a749623SJacob Keller }
13693a749623SJacob Keller 
13703a749623SJacob Keller /* E822 Vernier calibration functions
13713a749623SJacob Keller  *
13723a749623SJacob Keller  * The following functions are used as part of the vernier calibration of
13733a749623SJacob Keller  * a port. This calibration increases the precision of the timestamps on the
13743a749623SJacob Keller  * port.
13753a749623SJacob Keller  */
13763a749623SJacob Keller 
13773a749623SJacob Keller /**
13783a749623SJacob Keller  * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode
13793a749623SJacob Keller  * @hw: pointer to HW struct
13803a749623SJacob Keller  * @port: the port to read from
13813a749623SJacob Keller  * @link_out: if non-NULL, holds link speed on success
13823a749623SJacob Keller  * @fec_out: if non-NULL, holds FEC algorithm on success
13833a749623SJacob Keller  *
13843a749623SJacob Keller  * Read the serdes data for the PHY port and extract the link speed and FEC
13853a749623SJacob Keller  * algorithm.
13863a749623SJacob Keller  */
13873a749623SJacob Keller static int
ice_phy_get_speed_and_fec_e822(struct ice_hw * hw,u8 port,enum ice_ptp_link_spd * link_out,enum ice_ptp_fec_mode * fec_out)13883a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
13893a749623SJacob Keller 			       enum ice_ptp_link_spd *link_out,
13903a749623SJacob Keller 			       enum ice_ptp_fec_mode *fec_out)
13913a749623SJacob Keller {
13923a749623SJacob Keller 	enum ice_ptp_link_spd link;
13933a749623SJacob Keller 	enum ice_ptp_fec_mode fec;
13943a749623SJacob Keller 	u32 serdes;
13953a749623SJacob Keller 	int err;
13963a749623SJacob Keller 
13973a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);
13983a749623SJacob Keller 	if (err) {
13993a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n");
14003a749623SJacob Keller 		return err;
14013a749623SJacob Keller 	}
14023a749623SJacob Keller 
14033a749623SJacob Keller 	/* Determine the FEC algorithm */
14043a749623SJacob Keller 	fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes);
14053a749623SJacob Keller 
14063a749623SJacob Keller 	serdes &= P_REG_LINK_SPEED_SERDES_M;
14073a749623SJacob Keller 
14083a749623SJacob Keller 	/* Determine the link speed */
14093a749623SJacob Keller 	if (fec == ICE_PTP_FEC_MODE_RS_FEC) {
14103a749623SJacob Keller 		switch (serdes) {
14113a749623SJacob Keller 		case ICE_PTP_SERDES_25G:
14123a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_25G_RS;
14133a749623SJacob Keller 			break;
14143a749623SJacob Keller 		case ICE_PTP_SERDES_50G:
14153a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_50G_RS;
14163a749623SJacob Keller 			break;
14173a749623SJacob Keller 		case ICE_PTP_SERDES_100G:
14183a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_100G_RS;
14193a749623SJacob Keller 			break;
14203a749623SJacob Keller 		default:
14213a749623SJacob Keller 			return -EIO;
14223a749623SJacob Keller 		}
14233a749623SJacob Keller 	} else {
14243a749623SJacob Keller 		switch (serdes) {
14253a749623SJacob Keller 		case ICE_PTP_SERDES_1G:
14263a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_1G;
14273a749623SJacob Keller 			break;
14283a749623SJacob Keller 		case ICE_PTP_SERDES_10G:
14293a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_10G;
14303a749623SJacob Keller 			break;
14313a749623SJacob Keller 		case ICE_PTP_SERDES_25G:
14323a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_25G;
14333a749623SJacob Keller 			break;
14343a749623SJacob Keller 		case ICE_PTP_SERDES_40G:
14353a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_40G;
14363a749623SJacob Keller 			break;
14373a749623SJacob Keller 		case ICE_PTP_SERDES_50G:
14383a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_50G;
14393a749623SJacob Keller 			break;
14403a749623SJacob Keller 		default:
14413a749623SJacob Keller 			return -EIO;
14423a749623SJacob Keller 		}
14433a749623SJacob Keller 	}
14443a749623SJacob Keller 
14453a749623SJacob Keller 	if (link_out)
14463a749623SJacob Keller 		*link_out = link;
14473a749623SJacob Keller 	if (fec_out)
14483a749623SJacob Keller 		*fec_out = fec;
14493a749623SJacob Keller 
14503a749623SJacob Keller 	return 0;
14513a749623SJacob Keller }
14523a749623SJacob Keller 
14533a749623SJacob Keller /**
14543a749623SJacob Keller  * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp
14553a749623SJacob Keller  * @hw: pointer to HW struct
14563a749623SJacob Keller  * @port: to configure the quad for
14573a749623SJacob Keller  */
ice_phy_cfg_lane_e822(struct ice_hw * hw,u8 port)14583a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
14593a749623SJacob Keller {
14603a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
14613a749623SJacob Keller 	int err;
14623a749623SJacob Keller 	u32 val;
14633a749623SJacob Keller 	u8 quad;
14643a749623SJacob Keller 
14653a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);
14663a749623SJacob Keller 	if (err) {
14673a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n",
14683a749623SJacob Keller 			  err);
14693a749623SJacob Keller 		return;
14703a749623SJacob Keller 	}
14713a749623SJacob Keller 
14723a749623SJacob Keller 	quad = port / ICE_PORTS_PER_QUAD;
14733a749623SJacob Keller 
14743a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
14753a749623SJacob Keller 	if (err) {
14763a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n",
14773a749623SJacob Keller 			  err);
14783a749623SJacob Keller 		return;
14793a749623SJacob Keller 	}
14803a749623SJacob Keller 
14813a749623SJacob Keller 	if (link_spd >= ICE_PTP_LNK_SPD_40G)
14823a749623SJacob Keller 		val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
14833a749623SJacob Keller 	else
14843a749623SJacob Keller 		val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
14853a749623SJacob Keller 
14863a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
14873a749623SJacob Keller 	if (err) {
14883a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n",
14893a749623SJacob Keller 			  err);
14903a749623SJacob Keller 		return;
14913a749623SJacob Keller 	}
14923a749623SJacob Keller }
14933a749623SJacob Keller 
14943a749623SJacob Keller /**
14953a749623SJacob Keller  * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822
14963a749623SJacob Keller  * @hw: pointer to the HW structure
14973a749623SJacob Keller  * @port: the port to configure
14983a749623SJacob Keller  *
14993a749623SJacob Keller  * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC
15003a749623SJacob Keller  * hardware clock time units (TUs). That is, determine the number of TUs per
15013a749623SJacob Keller  * serdes unit interval, and program the UIX registers with this conversion.
15023a749623SJacob Keller  *
15033a749623SJacob Keller  * This conversion is used as part of the calibration process when determining
15043a749623SJacob Keller  * the additional error of a timestamp vs the real time of transmission or
15053a749623SJacob Keller  * receipt of the packet.
15063a749623SJacob Keller  *
15073a749623SJacob Keller  * Hardware uses the number of TUs per 66 UIs, written to the UIX registers
15083a749623SJacob Keller  * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks.
15093a749623SJacob Keller  *
15103a749623SJacob Keller  * To calculate the conversion ratio, we use the following facts:
15113a749623SJacob Keller  *
15123a749623SJacob Keller  * a) the clock frequency in Hz (cycles per second)
15133a749623SJacob Keller  * b) the number of TUs per cycle (the increment value of the clock)
15143a749623SJacob Keller  * c) 1 second per 1 billion nanoseconds
15153a749623SJacob Keller  * d) the duration of 66 UIs in nanoseconds
15163a749623SJacob Keller  *
15173a749623SJacob Keller  * Given these facts, we can use the following table to work out what ratios
15183a749623SJacob Keller  * to multiply in order to get the number of TUs per 66 UIs:
15193a749623SJacob Keller  *
15203a749623SJacob Keller  * cycles |   1 second   | incval (TUs) | nanoseconds
15213a749623SJacob Keller  * -------+--------------+--------------+-------------
15223a749623SJacob Keller  * second | 1 billion ns |    cycle     |   66 UIs
15233a749623SJacob Keller  *
15243a749623SJacob Keller  * To perform the multiplication using integers without too much loss of
15253a749623SJacob Keller  * precision, we can take use the following equation:
15263a749623SJacob Keller  *
15273a749623SJacob Keller  * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion)
15283a749623SJacob Keller  *
15293a749623SJacob Keller  * We scale up to using 6600 UI instead of 66 in order to avoid fractional
15303a749623SJacob Keller  * nanosecond UIs (66 UI at 10G/40G is 6.4 ns)
15313a749623SJacob Keller  *
15323a749623SJacob Keller  * The increment value has a maximum expected range of about 34 bits, while
15333a749623SJacob Keller  * the frequency value is about 29 bits. Multiplying these values shouldn't
15343a749623SJacob Keller  * overflow the 64 bits. However, we must then further multiply them again by
15353a749623SJacob Keller  * the Serdes unit interval duration. To avoid overflow here, we split the
15363a749623SJacob Keller  * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and
15373a749623SJacob Keller  * a divide by 390,625,000. This does lose some precision, but avoids
15383a749623SJacob Keller  * miscalculation due to arithmetic overflow.
15393a749623SJacob Keller  */
ice_phy_cfg_uix_e822(struct ice_hw * hw,u8 port)15403a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
15413a749623SJacob Keller {
15423a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, uix;
15433a749623SJacob Keller 	int err;
15443a749623SJacob Keller 
15453a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
15463a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
15473a749623SJacob Keller 
15483a749623SJacob Keller 	/* Calculate TUs per second divided by 256 */
15493a749623SJacob Keller 	tu_per_sec = (cur_freq * clk_incval) >> 8;
15503a749623SJacob Keller 
15513a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */
15523a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */
15533a749623SJacob Keller 
15543a749623SJacob Keller 	/* Program the 10Gb/40Gb conversion ratio */
15553a749623SJacob Keller 	uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000);
15563a749623SJacob Keller 
15573a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
15583a749623SJacob Keller 					 uix);
15593a749623SJacob Keller 	if (err) {
15603a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n",
15613a749623SJacob Keller 			  err);
15623a749623SJacob Keller 		return err;
15633a749623SJacob Keller 	}
15643a749623SJacob Keller 
15653a749623SJacob Keller 	/* Program the 25Gb/100Gb conversion ratio */
15663a749623SJacob Keller 	uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000);
15673a749623SJacob Keller 
15683a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
15693a749623SJacob Keller 					 uix);
15703a749623SJacob Keller 	if (err) {
15713a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n",
15723a749623SJacob Keller 			  err);
15733a749623SJacob Keller 		return err;
15743a749623SJacob Keller 	}
15753a749623SJacob Keller 
15763a749623SJacob Keller 	return 0;
15773a749623SJacob Keller }
15783a749623SJacob Keller 
15793a749623SJacob Keller /**
15803a749623SJacob Keller  * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle
15813a749623SJacob Keller  * @hw: pointer to the HW struct
15823a749623SJacob Keller  * @port: port to configure
15833a749623SJacob Keller  *
15843a749623SJacob Keller  * Configure the number of TUs for the PAR and PCS clocks used as part of the
15853a749623SJacob Keller  * timestamp calibration process. This depends on the link speed, as the PHY
15863a749623SJacob Keller  * uses different markers depending on the speed.
15873a749623SJacob Keller  *
15883a749623SJacob Keller  * 1Gb/10Gb/25Gb:
15893a749623SJacob Keller  * - Tx/Rx PAR/PCS markers
15903a749623SJacob Keller  *
15913a749623SJacob Keller  * 25Gb RS:
15923a749623SJacob Keller  * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
15933a749623SJacob Keller  *
15943a749623SJacob Keller  * 40Gb/50Gb:
15953a749623SJacob Keller  * - Tx/Rx PAR/PCS markers
15963a749623SJacob Keller  * - Rx Deskew PAR/PCS markers
15973a749623SJacob Keller  *
15983a749623SJacob Keller  * 50G RS and 100GB RS:
15993a749623SJacob Keller  * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
16003a749623SJacob Keller  * - Rx Deskew PAR/PCS markers
16013a749623SJacob Keller  * - Tx PAR/PCS markers
16023a749623SJacob Keller  *
16033a749623SJacob Keller  * To calculate the conversion, we use the PHC clock frequency (cycles per
16043a749623SJacob Keller  * second), the increment value (TUs per cycle), and the related PHY clock
16053a749623SJacob Keller  * frequency to calculate the TUs per unit of the PHY link clock. The
16063a749623SJacob Keller  * following table shows how the units convert:
16073a749623SJacob Keller  *
16083a749623SJacob Keller  * cycles |  TUs  | second
16093a749623SJacob Keller  * -------+-------+--------
16103a749623SJacob Keller  * second | cycle | cycles
16113a749623SJacob Keller  *
16123a749623SJacob Keller  * For each conversion register, look up the appropriate frequency from the
16133a749623SJacob Keller  * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program
16143a749623SJacob Keller  * this to the appropriate register, preparing hardware to perform timestamp
16153a749623SJacob Keller  * calibration to calculate the total Tx or Rx offset to adjust the timestamp
16163a749623SJacob Keller  * in order to calibrate for the internal PHY delays.
16173a749623SJacob Keller  *
16183a749623SJacob Keller  * Note that the increment value ranges up to ~34 bits, and the clock
16193a749623SJacob Keller  * frequency is ~29 bits, so multiplying them together should fit within the
16203a749623SJacob Keller  * 64 bit arithmetic.
16213a749623SJacob Keller  */
ice_phy_cfg_parpcs_e822(struct ice_hw * hw,u8 port)16223a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
16233a749623SJacob Keller {
16243a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, phy_tus;
16253a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
16263a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
16273a749623SJacob Keller 	int err;
16283a749623SJacob Keller 
16293a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
16303a749623SJacob Keller 	if (err)
16313a749623SJacob Keller 		return err;
16323a749623SJacob Keller 
16333a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
16343a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
16353a749623SJacob Keller 
16363a749623SJacob Keller 	/* Calculate TUs per cycle of the PHC clock */
16373a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
16383a749623SJacob Keller 
16393a749623SJacob Keller 	/* For each PHY conversion register, look up the appropriate link
16403a749623SJacob Keller 	 * speed frequency and determine the TUs per that clock's cycle time.
16413a749623SJacob Keller 	 * Split this into a high and low value and then program the
16423a749623SJacob Keller 	 * appropriate register. If that link speed does not use the
16433a749623SJacob Keller 	 * associated register, write zeros to clear it instead.
16443a749623SJacob Keller 	 */
16453a749623SJacob Keller 
16463a749623SJacob Keller 	/* P_REG_PAR_TX_TUS */
16473a749623SJacob Keller 	if (e822_vernier[link_spd].tx_par_clk)
16483a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16493a749623SJacob Keller 				  e822_vernier[link_spd].tx_par_clk);
16503a749623SJacob Keller 	else
16513a749623SJacob Keller 		phy_tus = 0;
16523a749623SJacob Keller 
16533a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,
16543a749623SJacob Keller 					 phy_tus);
16553a749623SJacob Keller 	if (err)
16563a749623SJacob Keller 		return err;
16573a749623SJacob Keller 
16583a749623SJacob Keller 	/* P_REG_PAR_RX_TUS */
16593a749623SJacob Keller 	if (e822_vernier[link_spd].rx_par_clk)
16603a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16613a749623SJacob Keller 				  e822_vernier[link_spd].rx_par_clk);
16623a749623SJacob Keller 	else
16633a749623SJacob Keller 		phy_tus = 0;
16643a749623SJacob Keller 
16653a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,
16663a749623SJacob Keller 					 phy_tus);
16673a749623SJacob Keller 	if (err)
16683a749623SJacob Keller 		return err;
16693a749623SJacob Keller 
16703a749623SJacob Keller 	/* P_REG_PCS_TX_TUS */
16713a749623SJacob Keller 	if (e822_vernier[link_spd].tx_pcs_clk)
16723a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16733a749623SJacob Keller 				  e822_vernier[link_spd].tx_pcs_clk);
16743a749623SJacob Keller 	else
16753a749623SJacob Keller 		phy_tus = 0;
16763a749623SJacob Keller 
16773a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,
16783a749623SJacob Keller 					 phy_tus);
16793a749623SJacob Keller 	if (err)
16803a749623SJacob Keller 		return err;
16813a749623SJacob Keller 
16823a749623SJacob Keller 	/* P_REG_PCS_RX_TUS */
16833a749623SJacob Keller 	if (e822_vernier[link_spd].rx_pcs_clk)
16843a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16853a749623SJacob Keller 				  e822_vernier[link_spd].rx_pcs_clk);
16863a749623SJacob Keller 	else
16873a749623SJacob Keller 		phy_tus = 0;
16883a749623SJacob Keller 
16893a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,
16903a749623SJacob Keller 					 phy_tus);
16913a749623SJacob Keller 	if (err)
16923a749623SJacob Keller 		return err;
16933a749623SJacob Keller 
16943a749623SJacob Keller 	/* P_REG_DESK_PAR_TX_TUS */
16953a749623SJacob Keller 	if (e822_vernier[link_spd].tx_desk_rsgb_par)
16963a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16973a749623SJacob Keller 				  e822_vernier[link_spd].tx_desk_rsgb_par);
16983a749623SJacob Keller 	else
16993a749623SJacob Keller 		phy_tus = 0;
17003a749623SJacob Keller 
17013a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,
17023a749623SJacob Keller 					 phy_tus);
17033a749623SJacob Keller 	if (err)
17043a749623SJacob Keller 		return err;
17053a749623SJacob Keller 
17063a749623SJacob Keller 	/* P_REG_DESK_PAR_RX_TUS */
17073a749623SJacob Keller 	if (e822_vernier[link_spd].rx_desk_rsgb_par)
17083a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
17093a749623SJacob Keller 				  e822_vernier[link_spd].rx_desk_rsgb_par);
17103a749623SJacob Keller 	else
17113a749623SJacob Keller 		phy_tus = 0;
17123a749623SJacob Keller 
17133a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,
17143a749623SJacob Keller 					 phy_tus);
17153a749623SJacob Keller 	if (err)
17163a749623SJacob Keller 		return err;
17173a749623SJacob Keller 
17183a749623SJacob Keller 	/* P_REG_DESK_PCS_TX_TUS */
17193a749623SJacob Keller 	if (e822_vernier[link_spd].tx_desk_rsgb_pcs)
17203a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
17213a749623SJacob Keller 				  e822_vernier[link_spd].tx_desk_rsgb_pcs);
17223a749623SJacob Keller 	else
17233a749623SJacob Keller 		phy_tus = 0;
17243a749623SJacob Keller 
17253a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,
17263a749623SJacob Keller 					 phy_tus);
17273a749623SJacob Keller 	if (err)
17283a749623SJacob Keller 		return err;
17293a749623SJacob Keller 
17303a749623SJacob Keller 	/* P_REG_DESK_PCS_RX_TUS */
17313a749623SJacob Keller 	if (e822_vernier[link_spd].rx_desk_rsgb_pcs)
17323a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
17333a749623SJacob Keller 				  e822_vernier[link_spd].rx_desk_rsgb_pcs);
17343a749623SJacob Keller 	else
17353a749623SJacob Keller 		phy_tus = 0;
17363a749623SJacob Keller 
17373a749623SJacob Keller 	return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,
17383a749623SJacob Keller 					  phy_tus);
17393a749623SJacob Keller }
17403a749623SJacob Keller 
17413a749623SJacob Keller /**
17423a749623SJacob Keller  * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port
17433a749623SJacob Keller  * @hw: pointer to the HW struct
17443a749623SJacob Keller  * @link_spd: the Link speed to calculate for
17453a749623SJacob Keller  *
17463a749623SJacob Keller  * Calculate the fixed offset due to known static latency data.
17473a749623SJacob Keller  */
17483a749623SJacob Keller static u64
ice_calc_fixed_tx_offset_e822(struct ice_hw * hw,enum ice_ptp_link_spd link_spd)17493a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
17503a749623SJacob Keller {
17513a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
17523a749623SJacob Keller 
17533a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
17543a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
17553a749623SJacob Keller 
17563a749623SJacob Keller 	/* Calculate TUs per second */
17573a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
17583a749623SJacob Keller 
17593a749623SJacob Keller 	/* Calculate number of TUs to add for the fixed Tx latency. Since the
17603a749623SJacob Keller 	 * latency measurement is in 1/100th of a nanosecond, we need to
17613a749623SJacob Keller 	 * multiply by tu_per_sec and then divide by 1e11. This calculation
17623a749623SJacob Keller 	 * overflows 64 bit integer arithmetic, so break it up into two
17633a749623SJacob Keller 	 * divisions by 1e4 first then by 1e7.
17643a749623SJacob Keller 	 */
17653a749623SJacob Keller 	fixed_offset = div_u64(tu_per_sec, 10000);
17663a749623SJacob Keller 	fixed_offset *= e822_vernier[link_spd].tx_fixed_delay;
17673a749623SJacob Keller 	fixed_offset = div_u64(fixed_offset, 10000000);
17683a749623SJacob Keller 
17693a749623SJacob Keller 	return fixed_offset;
17703a749623SJacob Keller }
17713a749623SJacob Keller 
17723a749623SJacob Keller /**
1773a69f1cb6SJacob Keller  * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset
1774a69f1cb6SJacob Keller  * @hw: pointer to the HW struct
1775a69f1cb6SJacob Keller  * @port: the PHY port to configure
1776a69f1cb6SJacob Keller  *
1777a69f1cb6SJacob Keller  * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to
1778a69f1cb6SJacob Keller  * adjust Tx timestamps by. This is calculated by combining some known static
1779a69f1cb6SJacob Keller  * latency along with the Vernier offset computations done by hardware.
1780a69f1cb6SJacob Keller  *
1781f029a343SSiddaraju DH  * This function will not return successfully until the Tx offset calculations
1782f029a343SSiddaraju DH  * have been completed, which requires waiting until at least one packet has
1783f029a343SSiddaraju DH  * been transmitted by the device. It is safe to call this function
1784f029a343SSiddaraju DH  * periodically until calibration succeeds, as it will only program the offset
1785f029a343SSiddaraju DH  * once.
1786a69f1cb6SJacob Keller  *
1787a69f1cb6SJacob Keller  * To avoid overflow, when calculating the offset based on the known static
1788a69f1cb6SJacob Keller  * latency values, we use measurements in 1/100th of a nanosecond, and divide
1789a69f1cb6SJacob Keller  * the TUs per second up front. This avoids overflow while allowing
1790a69f1cb6SJacob Keller  * calculation of the adjustment using integer arithmetic.
1791f029a343SSiddaraju DH  *
1792f029a343SSiddaraju DH  * Returns zero on success, -EBUSY if the hardware vernier offset
1793f029a343SSiddaraju DH  * calibration has not completed, or another error code on failure.
1794a69f1cb6SJacob Keller  */
ice_phy_cfg_tx_offset_e822(struct ice_hw * hw,u8 port)1795f029a343SSiddaraju DH int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
1796a69f1cb6SJacob Keller {
1797a69f1cb6SJacob Keller 	enum ice_ptp_link_spd link_spd;
1798a69f1cb6SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
1799a69f1cb6SJacob Keller 	u64 total_offset, val;
1800a69f1cb6SJacob Keller 	int err;
1801f029a343SSiddaraju DH 	u32 reg;
1802f029a343SSiddaraju DH 
1803f029a343SSiddaraju DH 	/* Nothing to do if we've already programmed the offset */
1804f029a343SSiddaraju DH 	err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OR, &reg);
1805f029a343SSiddaraju DH 	if (err) {
1806f029a343SSiddaraju DH 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OR for port %u, err %d\n",
1807f029a343SSiddaraju DH 			  port, err);
1808f029a343SSiddaraju DH 		return err;
1809f029a343SSiddaraju DH 	}
1810f029a343SSiddaraju DH 
1811f029a343SSiddaraju DH 	if (reg)
1812f029a343SSiddaraju DH 		return 0;
1813f029a343SSiddaraju DH 
1814f029a343SSiddaraju DH 	err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &reg);
1815f029a343SSiddaraju DH 	if (err) {
1816f029a343SSiddaraju DH 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n",
1817f029a343SSiddaraju DH 			  port, err);
1818f029a343SSiddaraju DH 		return err;
1819f029a343SSiddaraju DH 	}
1820f029a343SSiddaraju DH 
1821f029a343SSiddaraju DH 	if (!(reg & P_REG_TX_OV_STATUS_OV_M))
1822f029a343SSiddaraju DH 		return -EBUSY;
1823a69f1cb6SJacob Keller 
1824a69f1cb6SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
1825a69f1cb6SJacob Keller 	if (err)
1826a69f1cb6SJacob Keller 		return err;
1827a69f1cb6SJacob Keller 
1828a69f1cb6SJacob Keller 	total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
1829a69f1cb6SJacob Keller 
1830a69f1cb6SJacob Keller 	/* Read the first Vernier offset from the PHY register and add it to
1831a69f1cb6SJacob Keller 	 * the total offset.
1832a69f1cb6SJacob Keller 	 */
1833a69f1cb6SJacob Keller 	if (link_spd == ICE_PTP_LNK_SPD_1G ||
1834a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_10G ||
1835a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_25G ||
1836a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_25G_RS ||
1837a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_40G ||
1838a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_50G) {
1839a69f1cb6SJacob Keller 		err = ice_read_64b_phy_reg_e822(hw, port,
1840a69f1cb6SJacob Keller 						P_REG_PAR_PCS_TX_OFFSET_L,
1841a69f1cb6SJacob Keller 						&val);
1842a69f1cb6SJacob Keller 		if (err)
1843a69f1cb6SJacob Keller 			return err;
1844a69f1cb6SJacob Keller 
1845a69f1cb6SJacob Keller 		total_offset += val;
1846a69f1cb6SJacob Keller 	}
1847a69f1cb6SJacob Keller 
1848a69f1cb6SJacob Keller 	/* For Tx, we only need to use the second Vernier offset for
1849a69f1cb6SJacob Keller 	 * multi-lane link speeds with RS-FEC. The lanes will always be
1850a69f1cb6SJacob Keller 	 * aligned.
1851a69f1cb6SJacob Keller 	 */
1852a69f1cb6SJacob Keller 	if (link_spd == ICE_PTP_LNK_SPD_50G_RS ||
1853a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_100G_RS) {
1854a69f1cb6SJacob Keller 		err = ice_read_64b_phy_reg_e822(hw, port,
1855a69f1cb6SJacob Keller 						P_REG_PAR_TX_TIME_L,
1856a69f1cb6SJacob Keller 						&val);
1857a69f1cb6SJacob Keller 		if (err)
1858a69f1cb6SJacob Keller 			return err;
1859a69f1cb6SJacob Keller 
1860a69f1cb6SJacob Keller 		total_offset += val;
1861a69f1cb6SJacob Keller 	}
1862a69f1cb6SJacob Keller 
1863a69f1cb6SJacob Keller 	/* Now that the total offset has been calculated, program it to the
1864a69f1cb6SJacob Keller 	 * PHY and indicate that the Tx offset is ready. After this,
1865a69f1cb6SJacob Keller 	 * timestamps will be enabled.
1866a69f1cb6SJacob Keller 	 */
1867a69f1cb6SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
1868a69f1cb6SJacob Keller 					 total_offset);
1869a69f1cb6SJacob Keller 	if (err)
1870a69f1cb6SJacob Keller 		return err;
1871a69f1cb6SJacob Keller 
1872a69f1cb6SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
1873a69f1cb6SJacob Keller 	if (err)
1874a69f1cb6SJacob Keller 		return err;
1875a69f1cb6SJacob Keller 
1876f029a343SSiddaraju DH 	dev_info(ice_hw_to_dev(hw), "Port=%d Tx vernier offset calibration complete\n",
1877f029a343SSiddaraju DH 		 port);
1878f029a343SSiddaraju DH 
1879a69f1cb6SJacob Keller 	return 0;
1880a69f1cb6SJacob Keller }
1881a69f1cb6SJacob Keller 
1882a69f1cb6SJacob Keller /**
1883a69f1cb6SJacob Keller  * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx
1884a69f1cb6SJacob Keller  * @hw: pointer to the HW struct
1885a69f1cb6SJacob Keller  * @port: the PHY port to adjust for
1886a69f1cb6SJacob Keller  * @link_spd: the current link speed of the PHY
1887a69f1cb6SJacob Keller  * @fec_mode: the current FEC mode of the PHY
1888a69f1cb6SJacob Keller  * @pmd_adj: on return, the amount to adjust the Rx total offset by
1889a69f1cb6SJacob Keller  *
1890a69f1cb6SJacob Keller  * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY.
1891a69f1cb6SJacob Keller  * This varies by link speed and FEC mode. The value calculated accounts for
1892a69f1cb6SJacob Keller  * various delays caused when receiving a packet.
1893a69f1cb6SJacob Keller  */
1894a69f1cb6SJacob Keller static int
ice_phy_calc_pmd_adj_e822(struct ice_hw * hw,u8 port,enum ice_ptp_link_spd link_spd,enum ice_ptp_fec_mode fec_mode,u64 * pmd_adj)1895a69f1cb6SJacob Keller ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
1896a69f1cb6SJacob Keller 			  enum ice_ptp_link_spd link_spd,
1897a69f1cb6SJacob Keller 			  enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj)
1898a69f1cb6SJacob Keller {
1899a69f1cb6SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, mult, adj;
1900a69f1cb6SJacob Keller 	u8 pmd_align;
1901a69f1cb6SJacob Keller 	u32 val;
1902a69f1cb6SJacob Keller 	int err;
1903a69f1cb6SJacob Keller 
1904a69f1cb6SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val);
1905a69f1cb6SJacob Keller 	if (err) {
1906a69f1cb6SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n",
1907a69f1cb6SJacob Keller 			  err);
1908a69f1cb6SJacob Keller 		return err;
1909a69f1cb6SJacob Keller 	}
1910a69f1cb6SJacob Keller 
1911a69f1cb6SJacob Keller 	pmd_align = (u8)val;
1912a69f1cb6SJacob Keller 
1913a69f1cb6SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
1914a69f1cb6SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
1915a69f1cb6SJacob Keller 
1916a69f1cb6SJacob Keller 	/* Calculate TUs per second */
1917a69f1cb6SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
1918a69f1cb6SJacob Keller 
1919a69f1cb6SJacob Keller 	/* The PMD alignment adjustment measurement depends on the link speed,
1920a69f1cb6SJacob Keller 	 * and whether FEC is enabled. For each link speed, the alignment
1921a69f1cb6SJacob Keller 	 * adjustment is calculated by dividing a value by the length of
1922a69f1cb6SJacob Keller 	 * a Time Unit in nanoseconds.
1923a69f1cb6SJacob Keller 	 *
1924a69f1cb6SJacob Keller 	 * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8
1925a69f1cb6SJacob Keller 	 * 10G: align == 65 ? 0 : (align * 0.1 * 32/33)
1926a69f1cb6SJacob Keller 	 * 10G w/FEC: align * 0.1 * 32/33
1927a69f1cb6SJacob Keller 	 * 25G: align == 65 ? 0 : (align * 0.4 * 32/33)
1928a69f1cb6SJacob Keller 	 * 25G w/FEC: align * 0.4 * 32/33
1929a69f1cb6SJacob Keller 	 * 40G: align == 65 ? 0 : (align * 0.1 * 32/33)
1930a69f1cb6SJacob Keller 	 * 40G w/FEC: align * 0.1 * 32/33
1931a69f1cb6SJacob Keller 	 * 50G: align == 65 ? 0 : (align * 0.4 * 32/33)
1932a69f1cb6SJacob Keller 	 * 50G w/FEC: align * 0.8 * 32/33
1933a69f1cb6SJacob Keller 	 *
1934a69f1cb6SJacob Keller 	 * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33.
1935a69f1cb6SJacob Keller 	 *
1936a69f1cb6SJacob Keller 	 * To allow for calculating this value using integer arithmetic, we
1937a69f1cb6SJacob Keller 	 * instead start with the number of TUs per second, (inverse of the
1938a69f1cb6SJacob Keller 	 * length of a Time Unit in nanoseconds), multiply by a value based
1939a69f1cb6SJacob Keller 	 * on the PMD alignment register, and then divide by the right value
1940a69f1cb6SJacob Keller 	 * calculated based on the table above. To avoid integer overflow this
1941a69f1cb6SJacob Keller 	 * division is broken up into a step of dividing by 125 first.
1942a69f1cb6SJacob Keller 	 */
1943a69f1cb6SJacob Keller 	if (link_spd == ICE_PTP_LNK_SPD_1G) {
1944a69f1cb6SJacob Keller 		if (pmd_align == 4)
1945a69f1cb6SJacob Keller 			mult = 10;
1946a69f1cb6SJacob Keller 		else
1947a69f1cb6SJacob Keller 			mult = (pmd_align + 6) % 10;
1948a69f1cb6SJacob Keller 	} else if (link_spd == ICE_PTP_LNK_SPD_10G ||
1949a69f1cb6SJacob Keller 		   link_spd == ICE_PTP_LNK_SPD_25G ||
1950a69f1cb6SJacob Keller 		   link_spd == ICE_PTP_LNK_SPD_40G ||
1951a69f1cb6SJacob Keller 		   link_spd == ICE_PTP_LNK_SPD_50G) {
1952a69f1cb6SJacob Keller 		/* If Clause 74 FEC, always calculate PMD adjust */
1953a69f1cb6SJacob Keller 		if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74)
1954a69f1cb6SJacob Keller 			mult = pmd_align;
1955a69f1cb6SJacob Keller 		else
1956a69f1cb6SJacob Keller 			mult = 0;
1957a69f1cb6SJacob Keller 	} else if (link_spd == ICE_PTP_LNK_SPD_25G_RS ||
1958a69f1cb6SJacob Keller 		   link_spd == ICE_PTP_LNK_SPD_50G_RS ||
1959a69f1cb6SJacob Keller 		   link_spd == ICE_PTP_LNK_SPD_100G_RS) {
1960a69f1cb6SJacob Keller 		if (pmd_align < 17)
1961a69f1cb6SJacob Keller 			mult = pmd_align + 40;
1962a69f1cb6SJacob Keller 		else
1963a69f1cb6SJacob Keller 			mult = pmd_align;
1964a69f1cb6SJacob Keller 	} else {
1965a69f1cb6SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n",
1966a69f1cb6SJacob Keller 			  link_spd);
1967a69f1cb6SJacob Keller 		mult = 0;
1968a69f1cb6SJacob Keller 	}
1969a69f1cb6SJacob Keller 
1970a69f1cb6SJacob Keller 	/* In some cases, there's no need to adjust for the PMD alignment */
1971a69f1cb6SJacob Keller 	if (!mult) {
1972a69f1cb6SJacob Keller 		*pmd_adj = 0;
1973a69f1cb6SJacob Keller 		return 0;
1974a69f1cb6SJacob Keller 	}
1975a69f1cb6SJacob Keller 
1976a69f1cb6SJacob Keller 	/* Calculate the adjustment by multiplying TUs per second by the
1977a69f1cb6SJacob Keller 	 * appropriate multiplier and divisor. To avoid overflow, we first
1978a69f1cb6SJacob Keller 	 * divide by 125, and then handle remaining divisor based on the link
1979a69f1cb6SJacob Keller 	 * speed pmd_adj_divisor value.
1980a69f1cb6SJacob Keller 	 */
1981a69f1cb6SJacob Keller 	adj = div_u64(tu_per_sec, 125);
1982a69f1cb6SJacob Keller 	adj *= mult;
1983a69f1cb6SJacob Keller 	adj = div_u64(adj, e822_vernier[link_spd].pmd_adj_divisor);
1984a69f1cb6SJacob Keller 
1985a69f1cb6SJacob Keller 	/* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx
1986a69f1cb6SJacob Keller 	 * cycle count is necessary.
1987a69f1cb6SJacob Keller 	 */
1988a69f1cb6SJacob Keller 	if (link_spd == ICE_PTP_LNK_SPD_25G_RS) {
1989a69f1cb6SJacob Keller 		u64 cycle_adj;
1990a69f1cb6SJacob Keller 		u8 rx_cycle;
1991a69f1cb6SJacob Keller 
1992a69f1cb6SJacob Keller 		err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT,
1993a69f1cb6SJacob Keller 					    &val);
1994a69f1cb6SJacob Keller 		if (err) {
1995a69f1cb6SJacob Keller 			ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n",
1996a69f1cb6SJacob Keller 				  err);
1997a69f1cb6SJacob Keller 			return err;
1998a69f1cb6SJacob Keller 		}
1999a69f1cb6SJacob Keller 
2000a69f1cb6SJacob Keller 		rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M;
2001a69f1cb6SJacob Keller 		if (rx_cycle) {
2002a69f1cb6SJacob Keller 			mult = (4 - rx_cycle) * 40;
2003a69f1cb6SJacob Keller 
2004a69f1cb6SJacob Keller 			cycle_adj = div_u64(tu_per_sec, 125);
2005a69f1cb6SJacob Keller 			cycle_adj *= mult;
2006a69f1cb6SJacob Keller 			cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor);
2007a69f1cb6SJacob Keller 
2008a69f1cb6SJacob Keller 			adj += cycle_adj;
2009a69f1cb6SJacob Keller 		}
2010a69f1cb6SJacob Keller 	} else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) {
2011a69f1cb6SJacob Keller 		u64 cycle_adj;
2012a69f1cb6SJacob Keller 		u8 rx_cycle;
2013a69f1cb6SJacob Keller 
2014a69f1cb6SJacob Keller 		err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT,
2015a69f1cb6SJacob Keller 					    &val);
2016a69f1cb6SJacob Keller 		if (err) {
2017a69f1cb6SJacob Keller 			ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n",
2018a69f1cb6SJacob Keller 				  err);
2019a69f1cb6SJacob Keller 			return err;
2020a69f1cb6SJacob Keller 		}
2021a69f1cb6SJacob Keller 
2022a69f1cb6SJacob Keller 		rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M;
2023a69f1cb6SJacob Keller 		if (rx_cycle) {
2024a69f1cb6SJacob Keller 			mult = rx_cycle * 40;
2025a69f1cb6SJacob Keller 
2026a69f1cb6SJacob Keller 			cycle_adj = div_u64(tu_per_sec, 125);
2027a69f1cb6SJacob Keller 			cycle_adj *= mult;
2028a69f1cb6SJacob Keller 			cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor);
2029a69f1cb6SJacob Keller 
2030a69f1cb6SJacob Keller 			adj += cycle_adj;
2031a69f1cb6SJacob Keller 		}
2032a69f1cb6SJacob Keller 	}
2033a69f1cb6SJacob Keller 
2034a69f1cb6SJacob Keller 	/* Return the calculated adjustment */
2035a69f1cb6SJacob Keller 	*pmd_adj = adj;
2036a69f1cb6SJacob Keller 
2037a69f1cb6SJacob Keller 	return 0;
2038a69f1cb6SJacob Keller }
2039a69f1cb6SJacob Keller 
2040a69f1cb6SJacob Keller /**
20413a749623SJacob Keller  * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port
20423a749623SJacob Keller  * @hw: pointer to HW struct
20433a749623SJacob Keller  * @link_spd: The Link speed to calculate for
20443a749623SJacob Keller  *
20453a749623SJacob Keller  * Determine the fixed Rx latency for a given link speed.
20463a749623SJacob Keller  */
20473a749623SJacob Keller static u64
ice_calc_fixed_rx_offset_e822(struct ice_hw * hw,enum ice_ptp_link_spd link_spd)20483a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
20493a749623SJacob Keller {
20503a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
20513a749623SJacob Keller 
20523a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
20533a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
20543a749623SJacob Keller 
20553a749623SJacob Keller 	/* Calculate TUs per second */
20563a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
20573a749623SJacob Keller 
20583a749623SJacob Keller 	/* Calculate number of TUs to add for the fixed Rx latency. Since the
20593a749623SJacob Keller 	 * latency measurement is in 1/100th of a nanosecond, we need to
20603a749623SJacob Keller 	 * multiply by tu_per_sec and then divide by 1e11. This calculation
20613a749623SJacob Keller 	 * overflows 64 bit integer arithmetic, so break it up into two
20623a749623SJacob Keller 	 * divisions by 1e4 first then by 1e7.
20633a749623SJacob Keller 	 */
20643a749623SJacob Keller 	fixed_offset = div_u64(tu_per_sec, 10000);
20653a749623SJacob Keller 	fixed_offset *= e822_vernier[link_spd].rx_fixed_delay;
20663a749623SJacob Keller 	fixed_offset = div_u64(fixed_offset, 10000000);
20673a749623SJacob Keller 
20683a749623SJacob Keller 	return fixed_offset;
20693a749623SJacob Keller }
20703a749623SJacob Keller 
20713a749623SJacob Keller /**
2072a69f1cb6SJacob Keller  * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset
2073a69f1cb6SJacob Keller  * @hw: pointer to the HW struct
2074a69f1cb6SJacob Keller  * @port: the PHY port to configure
2075a69f1cb6SJacob Keller  *
2076a69f1cb6SJacob Keller  * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to
2077a69f1cb6SJacob Keller  * adjust Rx timestamps by. This combines calculations from the Vernier offset
2078a69f1cb6SJacob Keller  * measurements taken in hardware with some data about known fixed delay as
2079a69f1cb6SJacob Keller  * well as adjusting for multi-lane alignment delay.
2080a69f1cb6SJacob Keller  *
2081f029a343SSiddaraju DH  * This function will not return successfully until the Rx offset calculations
2082f029a343SSiddaraju DH  * have been completed, which requires waiting until at least one packet has
2083f029a343SSiddaraju DH  * been received by the device. It is safe to call this function periodically
2084f029a343SSiddaraju DH  * until calibration succeeds, as it will only program the offset once.
2085f029a343SSiddaraju DH  *
2086a69f1cb6SJacob Keller  * This function must be called only after the offset registers are valid,
2087a69f1cb6SJacob Keller  * i.e. after the Vernier calibration wait has passed, to ensure that the PHY
2088a69f1cb6SJacob Keller  * has measured the offset.
2089a69f1cb6SJacob Keller  *
2090a69f1cb6SJacob Keller  * To avoid overflow, when calculating the offset based on the known static
2091a69f1cb6SJacob Keller  * latency values, we use measurements in 1/100th of a nanosecond, and divide
2092a69f1cb6SJacob Keller  * the TUs per second up front. This avoids overflow while allowing
2093a69f1cb6SJacob Keller  * calculation of the adjustment using integer arithmetic.
2094f029a343SSiddaraju DH  *
2095f029a343SSiddaraju DH  * Returns zero on success, -EBUSY if the hardware vernier offset
2096f029a343SSiddaraju DH  * calibration has not completed, or another error code on failure.
2097a69f1cb6SJacob Keller  */
ice_phy_cfg_rx_offset_e822(struct ice_hw * hw,u8 port)2098f029a343SSiddaraju DH int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
2099a69f1cb6SJacob Keller {
2100a69f1cb6SJacob Keller 	enum ice_ptp_link_spd link_spd;
2101a69f1cb6SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
2102a69f1cb6SJacob Keller 	u64 total_offset, pmd, val;
2103a69f1cb6SJacob Keller 	int err;
2104f029a343SSiddaraju DH 	u32 reg;
2105f029a343SSiddaraju DH 
2106f029a343SSiddaraju DH 	/* Nothing to do if we've already programmed the offset */
2107f029a343SSiddaraju DH 	err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OR, &reg);
2108f029a343SSiddaraju DH 	if (err) {
2109f029a343SSiddaraju DH 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OR for port %u, err %d\n",
2110f029a343SSiddaraju DH 			  port, err);
2111f029a343SSiddaraju DH 		return err;
2112f029a343SSiddaraju DH 	}
2113f029a343SSiddaraju DH 
2114f029a343SSiddaraju DH 	if (reg)
2115f029a343SSiddaraju DH 		return 0;
2116f029a343SSiddaraju DH 
2117f029a343SSiddaraju DH 	err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &reg);
2118f029a343SSiddaraju DH 	if (err) {
2119f029a343SSiddaraju DH 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n",
2120f029a343SSiddaraju DH 			  port, err);
2121f029a343SSiddaraju DH 		return err;
2122f029a343SSiddaraju DH 	}
2123f029a343SSiddaraju DH 
2124f029a343SSiddaraju DH 	if (!(reg & P_REG_RX_OV_STATUS_OV_M))
2125f029a343SSiddaraju DH 		return -EBUSY;
2126a69f1cb6SJacob Keller 
2127a69f1cb6SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
2128a69f1cb6SJacob Keller 	if (err)
2129a69f1cb6SJacob Keller 		return err;
2130a69f1cb6SJacob Keller 
2131a69f1cb6SJacob Keller 	total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
2132a69f1cb6SJacob Keller 
2133a69f1cb6SJacob Keller 	/* Read the first Vernier offset from the PHY register and add it to
2134a69f1cb6SJacob Keller 	 * the total offset.
2135a69f1cb6SJacob Keller 	 */
2136a69f1cb6SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port,
2137a69f1cb6SJacob Keller 					P_REG_PAR_PCS_RX_OFFSET_L,
2138a69f1cb6SJacob Keller 					&val);
2139a69f1cb6SJacob Keller 	if (err)
2140a69f1cb6SJacob Keller 		return err;
2141a69f1cb6SJacob Keller 
2142a69f1cb6SJacob Keller 	total_offset += val;
2143a69f1cb6SJacob Keller 
2144a69f1cb6SJacob Keller 	/* For Rx, all multi-lane link speeds include a second Vernier
2145a69f1cb6SJacob Keller 	 * calibration, because the lanes might not be aligned.
2146a69f1cb6SJacob Keller 	 */
2147a69f1cb6SJacob Keller 	if (link_spd == ICE_PTP_LNK_SPD_40G ||
2148a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_50G ||
2149a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_50G_RS ||
2150a69f1cb6SJacob Keller 	    link_spd == ICE_PTP_LNK_SPD_100G_RS) {
2151a69f1cb6SJacob Keller 		err = ice_read_64b_phy_reg_e822(hw, port,
2152a69f1cb6SJacob Keller 						P_REG_PAR_RX_TIME_L,
2153a69f1cb6SJacob Keller 						&val);
2154a69f1cb6SJacob Keller 		if (err)
2155a69f1cb6SJacob Keller 			return err;
2156a69f1cb6SJacob Keller 
2157a69f1cb6SJacob Keller 		total_offset += val;
2158a69f1cb6SJacob Keller 	}
2159a69f1cb6SJacob Keller 
2160a69f1cb6SJacob Keller 	/* In addition, Rx must account for the PMD alignment */
2161a69f1cb6SJacob Keller 	err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd);
2162a69f1cb6SJacob Keller 	if (err)
2163a69f1cb6SJacob Keller 		return err;
2164a69f1cb6SJacob Keller 
2165a69f1cb6SJacob Keller 	/* For RS-FEC, this adjustment adds delay, but for other modes, it
2166a69f1cb6SJacob Keller 	 * subtracts delay.
2167a69f1cb6SJacob Keller 	 */
2168a69f1cb6SJacob Keller 	if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC)
2169a69f1cb6SJacob Keller 		total_offset += pmd;
2170a69f1cb6SJacob Keller 	else
2171a69f1cb6SJacob Keller 		total_offset -= pmd;
2172a69f1cb6SJacob Keller 
2173a69f1cb6SJacob Keller 	/* Now that the total offset has been calculated, program it to the
2174a69f1cb6SJacob Keller 	 * PHY and indicate that the Rx offset is ready. After this,
2175a69f1cb6SJacob Keller 	 * timestamps will be enabled.
2176a69f1cb6SJacob Keller 	 */
2177a69f1cb6SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
2178a69f1cb6SJacob Keller 					 total_offset);
2179a69f1cb6SJacob Keller 	if (err)
2180a69f1cb6SJacob Keller 		return err;
2181a69f1cb6SJacob Keller 
2182a69f1cb6SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
2183a69f1cb6SJacob Keller 	if (err)
2184a69f1cb6SJacob Keller 		return err;
2185a69f1cb6SJacob Keller 
2186f029a343SSiddaraju DH 	dev_info(ice_hw_to_dev(hw), "Port=%d Rx vernier offset calibration complete\n",
2187f029a343SSiddaraju DH 		 port);
2188f029a343SSiddaraju DH 
2189a69f1cb6SJacob Keller 	return 0;
2190a69f1cb6SJacob Keller }
2191a69f1cb6SJacob Keller 
2192a69f1cb6SJacob Keller /**
21933a749623SJacob Keller  * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time
21943a749623SJacob Keller  * @hw: pointer to the HW struct
21953a749623SJacob Keller  * @port: the PHY port to read
21963a749623SJacob Keller  * @phy_time: on return, the 64bit PHY timer value
21973a749623SJacob Keller  * @phc_time: on return, the lower 64bits of PHC time
21983a749623SJacob Keller  *
21993a749623SJacob Keller  * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC
22003a749623SJacob Keller  * timer values.
22013a749623SJacob Keller  */
22023a749623SJacob Keller static int
ice_read_phy_and_phc_time_e822(struct ice_hw * hw,u8 port,u64 * phy_time,u64 * phc_time)22033a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
22043a749623SJacob Keller 			       u64 *phc_time)
22053a749623SJacob Keller {
22063a749623SJacob Keller 	u64 tx_time, rx_time;
22073a749623SJacob Keller 	u32 zo, lo;
22083a749623SJacob Keller 	u8 tmr_idx;
22093a749623SJacob Keller 	int err;
22103a749623SJacob Keller 
22113a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
22123a749623SJacob Keller 
22133a749623SJacob Keller 	/* Prepare the PHC timer for a READ_TIME capture command */
22143a749623SJacob Keller 	ice_ptp_src_cmd(hw, READ_TIME);
22153a749623SJacob Keller 
22163a749623SJacob Keller 	/* Prepare the PHY timer for a READ_TIME capture command */
22173a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, READ_TIME);
22183a749623SJacob Keller 	if (err)
22193a749623SJacob Keller 		return err;
22203a749623SJacob Keller 
22213a749623SJacob Keller 	/* Issue the sync to start the READ_TIME capture */
22223a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
22233a749623SJacob Keller 
22243a749623SJacob Keller 	/* Read the captured PHC time from the shadow time registers */
22253a749623SJacob Keller 	zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
22263a749623SJacob Keller 	lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
22273a749623SJacob Keller 	*phc_time = (u64)lo << 32 | zo;
22283a749623SJacob Keller 
22293a749623SJacob Keller 	/* Read the captured PHY time from the PHY shadow registers */
22303a749623SJacob Keller 	err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time);
22313a749623SJacob Keller 	if (err)
22323a749623SJacob Keller 		return err;
22333a749623SJacob Keller 
22343a749623SJacob Keller 	/* If the PHY Tx and Rx timers don't match, log a warning message.
22353a749623SJacob Keller 	 * Note that this should not happen in normal circumstances since the
22363a749623SJacob Keller 	 * driver always programs them together.
22373a749623SJacob Keller 	 */
22383a749623SJacob Keller 	if (tx_time != rx_time)
22393a749623SJacob Keller 		dev_warn(ice_hw_to_dev(hw),
22403a749623SJacob Keller 			 "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n",
22413a749623SJacob Keller 			 port, (unsigned long long)tx_time,
22423a749623SJacob Keller 			 (unsigned long long)rx_time);
22433a749623SJacob Keller 
22443a749623SJacob Keller 	*phy_time = tx_time;
22453a749623SJacob Keller 
22463a749623SJacob Keller 	return 0;
22473a749623SJacob Keller }
22483a749623SJacob Keller 
22493a749623SJacob Keller /**
22503a749623SJacob Keller  * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer
22513a749623SJacob Keller  * @hw: pointer to the HW struct
22523a749623SJacob Keller  * @port: the PHY port to synchronize
22533a749623SJacob Keller  *
22543a749623SJacob Keller  * Perform an adjustment to ensure that the PHY and PHC timers are in sync.
22553a749623SJacob Keller  * This is done by issuing a READ_TIME command which triggers a simultaneous
22563a749623SJacob Keller  * read of the PHY timer and PHC timer. Then we use the difference to
22573a749623SJacob Keller  * calculate an appropriate 2s complement addition to add to the PHY timer in
22583a749623SJacob Keller  * order to ensure it reads the same value as the primary PHC timer.
22593a749623SJacob Keller  */
ice_sync_phy_timer_e822(struct ice_hw * hw,u8 port)22603a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
22613a749623SJacob Keller {
22623a749623SJacob Keller 	u64 phc_time, phy_time, difference;
22633a749623SJacob Keller 	int err;
22643a749623SJacob Keller 
22653a749623SJacob Keller 	if (!ice_ptp_lock(hw)) {
22663a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n");
22673a749623SJacob Keller 		return -EBUSY;
22683a749623SJacob Keller 	}
22693a749623SJacob Keller 
22703a749623SJacob Keller 	err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
22713a749623SJacob Keller 	if (err)
22723a749623SJacob Keller 		goto err_unlock;
22733a749623SJacob Keller 
22743a749623SJacob Keller 	/* Calculate the amount required to add to the port time in order for
22753a749623SJacob Keller 	 * it to match the PHC time.
22763a749623SJacob Keller 	 *
22773a749623SJacob Keller 	 * Note that the port adjustment is done using 2s complement
22783a749623SJacob Keller 	 * arithmetic. This is convenient since it means that we can simply
22793a749623SJacob Keller 	 * calculate the difference between the PHC time and the port time,
22803a749623SJacob Keller 	 * and it will be interpreted correctly.
22813a749623SJacob Keller 	 */
22823a749623SJacob Keller 	difference = phc_time - phy_time;
22833a749623SJacob Keller 
22843a749623SJacob Keller 	err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference);
22853a749623SJacob Keller 	if (err)
22863a749623SJacob Keller 		goto err_unlock;
22873a749623SJacob Keller 
22883a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME);
22893a749623SJacob Keller 	if (err)
22903a749623SJacob Keller 		goto err_unlock;
22913a749623SJacob Keller 
2292*0aacec49SJacob Keller 	/* Do not perform any action on the main timer */
2293*0aacec49SJacob Keller 	ice_ptp_src_cmd(hw, ICE_PTP_NOP);
2294*0aacec49SJacob Keller 
22953a749623SJacob Keller 	/* Issue the sync to activate the time adjustment */
22963a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
22973a749623SJacob Keller 
22983a749623SJacob Keller 	/* Re-capture the timer values to flush the command registers and
22993a749623SJacob Keller 	 * verify that the time was properly adjusted.
23003a749623SJacob Keller 	 */
23013a749623SJacob Keller 	err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
23023a749623SJacob Keller 	if (err)
23033a749623SJacob Keller 		goto err_unlock;
23043a749623SJacob Keller 
23053a749623SJacob Keller 	dev_info(ice_hw_to_dev(hw),
23063a749623SJacob Keller 		 "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n",
23073a749623SJacob Keller 		 port, (unsigned long long)phy_time,
23083a749623SJacob Keller 		 (unsigned long long)phc_time);
23093a749623SJacob Keller 
23103a749623SJacob Keller 	ice_ptp_unlock(hw);
23113a749623SJacob Keller 
23123a749623SJacob Keller 	return 0;
23133a749623SJacob Keller 
23143a749623SJacob Keller err_unlock:
23153a749623SJacob Keller 	ice_ptp_unlock(hw);
23163a749623SJacob Keller 	return err;
23173a749623SJacob Keller }
23183a749623SJacob Keller 
23193a749623SJacob Keller /**
23203a749623SJacob Keller  * ice_stop_phy_timer_e822 - Stop the PHY clock timer
23213a749623SJacob Keller  * @hw: pointer to the HW struct
23223a749623SJacob Keller  * @port: the PHY port to stop
23233a749623SJacob Keller  * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS
23243a749623SJacob Keller  *
23253a749623SJacob Keller  * Stop the clock of a PHY port. This must be done as part of the flow to
23263a749623SJacob Keller  * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
23273a749623SJacob Keller  * initialized or when link speed changes.
23283a749623SJacob Keller  */
23293a749623SJacob Keller int
ice_stop_phy_timer_e822(struct ice_hw * hw,u8 port,bool soft_reset)23303a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
23313a749623SJacob Keller {
23323a749623SJacob Keller 	int err;
23333a749623SJacob Keller 	u32 val;
23343a749623SJacob Keller 
23353a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);
23363a749623SJacob Keller 	if (err)
23373a749623SJacob Keller 		return err;
23383a749623SJacob Keller 
23393a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);
23403a749623SJacob Keller 	if (err)
23413a749623SJacob Keller 		return err;
23423a749623SJacob Keller 
23433a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
23443a749623SJacob Keller 	if (err)
23453a749623SJacob Keller 		return err;
23463a749623SJacob Keller 
23473a749623SJacob Keller 	val &= ~P_REG_PS_START_M;
23483a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
23493a749623SJacob Keller 	if (err)
23503a749623SJacob Keller 		return err;
23513a749623SJacob Keller 
23523a749623SJacob Keller 	val &= ~P_REG_PS_ENA_CLK_M;
23533a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
23543a749623SJacob Keller 	if (err)
23553a749623SJacob Keller 		return err;
23563a749623SJacob Keller 
23573a749623SJacob Keller 	if (soft_reset) {
23583a749623SJacob Keller 		val |= P_REG_PS_SFT_RESET_M;
23593a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
23603a749623SJacob Keller 		if (err)
23613a749623SJacob Keller 			return err;
23623a749623SJacob Keller 	}
23633a749623SJacob Keller 
23643a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port);
23653a749623SJacob Keller 
23663a749623SJacob Keller 	return 0;
23673a749623SJacob Keller }
23683a749623SJacob Keller 
23693a749623SJacob Keller /**
23703a749623SJacob Keller  * ice_start_phy_timer_e822 - Start the PHY clock timer
23713a749623SJacob Keller  * @hw: pointer to the HW struct
23723a749623SJacob Keller  * @port: the PHY port to start
23733a749623SJacob Keller  *
23743a749623SJacob Keller  * Start the clock of a PHY port. This must be done as part of the flow to
23753a749623SJacob Keller  * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
23763a749623SJacob Keller  * initialized or when link speed changes.
23773a749623SJacob Keller  *
23780357d5caSMilena Olech  * Hardware will take Vernier measurements on Tx or Rx of packets.
23793a749623SJacob Keller  */
ice_start_phy_timer_e822(struct ice_hw * hw,u8 port)23800357d5caSMilena Olech int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
23813a749623SJacob Keller {
23823a749623SJacob Keller 	u32 lo, hi, val;
23833a749623SJacob Keller 	u64 incval;
23843a749623SJacob Keller 	u8 tmr_idx;
23853a749623SJacob Keller 	int err;
23863a749623SJacob Keller 
23873a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
23883a749623SJacob Keller 
23893a749623SJacob Keller 	err = ice_stop_phy_timer_e822(hw, port, false);
23903a749623SJacob Keller 	if (err)
23913a749623SJacob Keller 		return err;
23923a749623SJacob Keller 
23933a749623SJacob Keller 	ice_phy_cfg_lane_e822(hw, port);
23943a749623SJacob Keller 
23953a749623SJacob Keller 	err = ice_phy_cfg_uix_e822(hw, port);
23963a749623SJacob Keller 	if (err)
23973a749623SJacob Keller 		return err;
23983a749623SJacob Keller 
23993a749623SJacob Keller 	err = ice_phy_cfg_parpcs_e822(hw, port);
24003a749623SJacob Keller 	if (err)
24013a749623SJacob Keller 		return err;
24023a749623SJacob Keller 
24033a749623SJacob Keller 	lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
24043a749623SJacob Keller 	hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
24053a749623SJacob Keller 	incval = (u64)hi << 32 | lo;
24063a749623SJacob Keller 
24073a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
24083a749623SJacob Keller 	if (err)
24093a749623SJacob Keller 		return err;
24103a749623SJacob Keller 
24113a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
24123a749623SJacob Keller 	if (err)
24133a749623SJacob Keller 		return err;
24143a749623SJacob Keller 
2415*0aacec49SJacob Keller 	/* Do not perform any action on the main timer */
2416*0aacec49SJacob Keller 	ice_ptp_src_cmd(hw, ICE_PTP_NOP);
2417*0aacec49SJacob Keller 
24183a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
24193a749623SJacob Keller 
24203a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
24213a749623SJacob Keller 	if (err)
24223a749623SJacob Keller 		return err;
24233a749623SJacob Keller 
24243a749623SJacob Keller 	val |= P_REG_PS_SFT_RESET_M;
24253a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
24263a749623SJacob Keller 	if (err)
24273a749623SJacob Keller 		return err;
24283a749623SJacob Keller 
24293a749623SJacob Keller 	val |= P_REG_PS_START_M;
24303a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
24313a749623SJacob Keller 	if (err)
24323a749623SJacob Keller 		return err;
24333a749623SJacob Keller 
24343a749623SJacob Keller 	val &= ~P_REG_PS_SFT_RESET_M;
24353a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
24363a749623SJacob Keller 	if (err)
24373a749623SJacob Keller 		return err;
24383a749623SJacob Keller 
24393a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
24403a749623SJacob Keller 	if (err)
24413a749623SJacob Keller 		return err;
24423a749623SJacob Keller 
24433a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
24443a749623SJacob Keller 
24453a749623SJacob Keller 	val |= P_REG_PS_ENA_CLK_M;
24463a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
24473a749623SJacob Keller 	if (err)
24483a749623SJacob Keller 		return err;
24493a749623SJacob Keller 
24503a749623SJacob Keller 	val |= P_REG_PS_LOAD_OFFSET_M;
24513a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
24523a749623SJacob Keller 	if (err)
24533a749623SJacob Keller 		return err;
24543a749623SJacob Keller 
24553a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
24563a749623SJacob Keller 
24573a749623SJacob Keller 	err = ice_sync_phy_timer_e822(hw, port);
24583a749623SJacob Keller 	if (err)
24593a749623SJacob Keller 		return err;
24603a749623SJacob Keller 
24613a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
24623a749623SJacob Keller 
24633a749623SJacob Keller 	return 0;
24643a749623SJacob Keller }
24653a749623SJacob Keller 
2466a69f1cb6SJacob Keller /**
246710e4b4a3SJacob Keller  * ice_get_phy_tx_tstamp_ready_e822 - Read Tx memory status register
246810e4b4a3SJacob Keller  * @hw: pointer to the HW struct
246910e4b4a3SJacob Keller  * @quad: the timestamp quad to read from
247010e4b4a3SJacob Keller  * @tstamp_ready: contents of the Tx memory status register
247110e4b4a3SJacob Keller  *
247210e4b4a3SJacob Keller  * Read the Q_REG_TX_MEMORY_STATUS register indicating which timestamps in
247310e4b4a3SJacob Keller  * the PHY are ready. A set bit means the corresponding timestamp is valid and
247410e4b4a3SJacob Keller  * ready to be captured from the PHY timestamp block.
247510e4b4a3SJacob Keller  */
247610e4b4a3SJacob Keller static int
ice_get_phy_tx_tstamp_ready_e822(struct ice_hw * hw,u8 quad,u64 * tstamp_ready)247710e4b4a3SJacob Keller ice_get_phy_tx_tstamp_ready_e822(struct ice_hw *hw, u8 quad, u64 *tstamp_ready)
247810e4b4a3SJacob Keller {
247910e4b4a3SJacob Keller 	u32 hi, lo;
248010e4b4a3SJacob Keller 	int err;
248110e4b4a3SJacob Keller 
248210e4b4a3SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi);
248310e4b4a3SJacob Keller 	if (err) {
248410e4b4a3SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_U for quad %u, err %d\n",
248510e4b4a3SJacob Keller 			  quad, err);
248610e4b4a3SJacob Keller 		return err;
248710e4b4a3SJacob Keller 	}
248810e4b4a3SJacob Keller 
248910e4b4a3SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo);
249010e4b4a3SJacob Keller 	if (err) {
249110e4b4a3SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_L for quad %u, err %d\n",
249210e4b4a3SJacob Keller 			  quad, err);
249310e4b4a3SJacob Keller 		return err;
249410e4b4a3SJacob Keller 	}
249510e4b4a3SJacob Keller 
249610e4b4a3SJacob Keller 	*tstamp_ready = (u64)hi << 32 | (u64)lo;
249710e4b4a3SJacob Keller 
249810e4b4a3SJacob Keller 	return 0;
249910e4b4a3SJacob Keller }
250010e4b4a3SJacob Keller 
250103cb4473SJacob Keller /* E810 functions
250203cb4473SJacob Keller  *
250303cb4473SJacob Keller  * The following functions operate on the E810 series devices which use
250403cb4473SJacob Keller  * a separate external PHY.
250503cb4473SJacob Keller  */
250603cb4473SJacob Keller 
250703cb4473SJacob Keller /**
250803cb4473SJacob Keller  * ice_read_phy_reg_e810 - Read register from external PHY on E810
250903cb4473SJacob Keller  * @hw: pointer to the HW struct
251003cb4473SJacob Keller  * @addr: the address to read from
251103cb4473SJacob Keller  * @val: On return, the value read from the PHY
251203cb4473SJacob Keller  *
251303cb4473SJacob Keller  * Read a register from the external PHY on the E810 device.
251403cb4473SJacob Keller  */
ice_read_phy_reg_e810(struct ice_hw * hw,u32 addr,u32 * val)251503cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
251603cb4473SJacob Keller {
251703cb4473SJacob Keller 	struct ice_sbq_msg_input msg = {0};
251839b28106SJacob Keller 	int err;
251903cb4473SJacob Keller 
252003cb4473SJacob Keller 	msg.msg_addr_low = lower_16_bits(addr);
252103cb4473SJacob Keller 	msg.msg_addr_high = upper_16_bits(addr);
252203cb4473SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
252303cb4473SJacob Keller 	msg.dest_dev = rmn_0;
252403cb4473SJacob Keller 
252539b28106SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
252639b28106SJacob Keller 	if (err) {
252739b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
252839b28106SJacob Keller 			  err);
252939b28106SJacob Keller 		return err;
253003cb4473SJacob Keller 	}
253103cb4473SJacob Keller 
253203cb4473SJacob Keller 	*val = msg.data;
253303cb4473SJacob Keller 
253403cb4473SJacob Keller 	return 0;
253503cb4473SJacob Keller }
253603cb4473SJacob Keller 
253703cb4473SJacob Keller /**
253803cb4473SJacob Keller  * ice_write_phy_reg_e810 - Write register on external PHY on E810
253903cb4473SJacob Keller  * @hw: pointer to the HW struct
254003cb4473SJacob Keller  * @addr: the address to writem to
254103cb4473SJacob Keller  * @val: the value to write to the PHY
254203cb4473SJacob Keller  *
254303cb4473SJacob Keller  * Write a value to a register of the external PHY on the E810 device.
254403cb4473SJacob Keller  */
ice_write_phy_reg_e810(struct ice_hw * hw,u32 addr,u32 val)254503cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
254603cb4473SJacob Keller {
254703cb4473SJacob Keller 	struct ice_sbq_msg_input msg = {0};
254839b28106SJacob Keller 	int err;
254903cb4473SJacob Keller 
255003cb4473SJacob Keller 	msg.msg_addr_low = lower_16_bits(addr);
255103cb4473SJacob Keller 	msg.msg_addr_high = upper_16_bits(addr);
255203cb4473SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
255303cb4473SJacob Keller 	msg.dest_dev = rmn_0;
255403cb4473SJacob Keller 	msg.data = val;
255503cb4473SJacob Keller 
255639b28106SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
255739b28106SJacob Keller 	if (err) {
255839b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
255939b28106SJacob Keller 			  err);
256039b28106SJacob Keller 		return err;
256103cb4473SJacob Keller 	}
256203cb4473SJacob Keller 
256303cb4473SJacob Keller 	return 0;
256403cb4473SJacob Keller }
256503cb4473SJacob Keller 
256603cb4473SJacob Keller /**
25671229b339SKarol Kolacinski  * ice_read_phy_tstamp_ll_e810 - Read a PHY timestamp registers through the FW
25681229b339SKarol Kolacinski  * @hw: pointer to the HW struct
25691229b339SKarol Kolacinski  * @idx: the timestamp index to read
25701229b339SKarol Kolacinski  * @hi: 8 bit timestamp high value
25711229b339SKarol Kolacinski  * @lo: 32 bit timestamp low value
25721229b339SKarol Kolacinski  *
25731229b339SKarol Kolacinski  * Read a 8bit timestamp high value and 32 bit timestamp low value out of the
25741229b339SKarol Kolacinski  * timestamp block of the external PHY on the E810 device using the low latency
25751229b339SKarol Kolacinski  * timestamp read.
25761229b339SKarol Kolacinski  */
25771229b339SKarol Kolacinski static int
ice_read_phy_tstamp_ll_e810(struct ice_hw * hw,u8 idx,u8 * hi,u32 * lo)25781229b339SKarol Kolacinski ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
25791229b339SKarol Kolacinski {
25801229b339SKarol Kolacinski 	u32 val;
25811229b339SKarol Kolacinski 	u8 i;
25821229b339SKarol Kolacinski 
25831229b339SKarol Kolacinski 	/* Write TS index to read to the PF register so the FW can read it */
25841229b339SKarol Kolacinski 	val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS;
25851229b339SKarol Kolacinski 	wr32(hw, PF_SB_ATQBAL, val);
25861229b339SKarol Kolacinski 
25871229b339SKarol Kolacinski 	/* Read the register repeatedly until the FW provides us the TS */
25881229b339SKarol Kolacinski 	for (i = TS_LL_READ_RETRIES; i > 0; i--) {
25891229b339SKarol Kolacinski 		val = rd32(hw, PF_SB_ATQBAL);
25901229b339SKarol Kolacinski 
25911229b339SKarol Kolacinski 		/* When the bit is cleared, the TS is ready in the register */
25921229b339SKarol Kolacinski 		if (!(FIELD_GET(TS_LL_READ_TS, val))) {
25931229b339SKarol Kolacinski 			/* High 8 bit value of the TS is on the bits 16:23 */
25941229b339SKarol Kolacinski 			*hi = FIELD_GET(TS_LL_READ_TS_HIGH, val);
25951229b339SKarol Kolacinski 
25961229b339SKarol Kolacinski 			/* Read the low 32 bit value and set the TS valid bit */
25971229b339SKarol Kolacinski 			*lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID;
25981229b339SKarol Kolacinski 			return 0;
25991229b339SKarol Kolacinski 		}
26001229b339SKarol Kolacinski 
26011229b339SKarol Kolacinski 		udelay(10);
26021229b339SKarol Kolacinski 	}
26031229b339SKarol Kolacinski 
26041229b339SKarol Kolacinski 	/* FW failed to provide the TS in time */
26051229b339SKarol Kolacinski 	ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n");
26061229b339SKarol Kolacinski 	return -EINVAL;
26071229b339SKarol Kolacinski }
26081229b339SKarol Kolacinski 
26091229b339SKarol Kolacinski /**
26101229b339SKarol Kolacinski  * ice_read_phy_tstamp_sbq_e810 - Read a PHY timestamp registers through the sbq
26111229b339SKarol Kolacinski  * @hw: pointer to the HW struct
26121229b339SKarol Kolacinski  * @lport: the lport to read from
26131229b339SKarol Kolacinski  * @idx: the timestamp index to read
26141229b339SKarol Kolacinski  * @hi: 8 bit timestamp high value
26151229b339SKarol Kolacinski  * @lo: 32 bit timestamp low value
26161229b339SKarol Kolacinski  *
26171229b339SKarol Kolacinski  * Read a 8bit timestamp high value and 32 bit timestamp low value out of the
26181229b339SKarol Kolacinski  * timestamp block of the external PHY on the E810 device using sideband queue.
26191229b339SKarol Kolacinski  */
26201229b339SKarol Kolacinski static int
ice_read_phy_tstamp_sbq_e810(struct ice_hw * hw,u8 lport,u8 idx,u8 * hi,u32 * lo)26211229b339SKarol Kolacinski ice_read_phy_tstamp_sbq_e810(struct ice_hw *hw, u8 lport, u8 idx, u8 *hi,
26221229b339SKarol Kolacinski 			     u32 *lo)
26231229b339SKarol Kolacinski {
26241229b339SKarol Kolacinski 	u32 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
26251229b339SKarol Kolacinski 	u32 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
26261229b339SKarol Kolacinski 	u32 lo_val, hi_val;
26271229b339SKarol Kolacinski 	int err;
26281229b339SKarol Kolacinski 
26291229b339SKarol Kolacinski 	err = ice_read_phy_reg_e810(hw, lo_addr, &lo_val);
26301229b339SKarol Kolacinski 	if (err) {
26311229b339SKarol Kolacinski 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
26321229b339SKarol Kolacinski 			  err);
26331229b339SKarol Kolacinski 		return err;
26341229b339SKarol Kolacinski 	}
26351229b339SKarol Kolacinski 
26361229b339SKarol Kolacinski 	err = ice_read_phy_reg_e810(hw, hi_addr, &hi_val);
26371229b339SKarol Kolacinski 	if (err) {
26381229b339SKarol Kolacinski 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
26391229b339SKarol Kolacinski 			  err);
26401229b339SKarol Kolacinski 		return err;
26411229b339SKarol Kolacinski 	}
26421229b339SKarol Kolacinski 
26431229b339SKarol Kolacinski 	*lo = lo_val;
26441229b339SKarol Kolacinski 	*hi = (u8)hi_val;
26451229b339SKarol Kolacinski 
26461229b339SKarol Kolacinski 	return 0;
26471229b339SKarol Kolacinski }
26481229b339SKarol Kolacinski 
26491229b339SKarol Kolacinski /**
265003cb4473SJacob Keller  * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
265103cb4473SJacob Keller  * @hw: pointer to the HW struct
265203cb4473SJacob Keller  * @lport: the lport to read from
265303cb4473SJacob Keller  * @idx: the timestamp index to read
265403cb4473SJacob Keller  * @tstamp: on return, the 40bit timestamp value
265503cb4473SJacob Keller  *
265603cb4473SJacob Keller  * Read a 40bit timestamp value out of the timestamp block of the external PHY
265703cb4473SJacob Keller  * on the E810 device.
265803cb4473SJacob Keller  */
265903cb4473SJacob Keller static int
ice_read_phy_tstamp_e810(struct ice_hw * hw,u8 lport,u8 idx,u64 * tstamp)266003cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
266103cb4473SJacob Keller {
26621229b339SKarol Kolacinski 	u32 lo = 0;
26631229b339SKarol Kolacinski 	u8 hi = 0;
266439b28106SJacob Keller 	int err;
266503cb4473SJacob Keller 
26661229b339SKarol Kolacinski 	if (hw->dev_caps.ts_dev_info.ts_ll_read)
26671229b339SKarol Kolacinski 		err = ice_read_phy_tstamp_ll_e810(hw, idx, &hi, &lo);
26681229b339SKarol Kolacinski 	else
26691229b339SKarol Kolacinski 		err = ice_read_phy_tstamp_sbq_e810(hw, lport, idx, &hi, &lo);
267003cb4473SJacob Keller 
26711229b339SKarol Kolacinski 	if (err)
267239b28106SJacob Keller 		return err;
267303cb4473SJacob Keller 
267403cb4473SJacob Keller 	/* For E810 devices, the timestamp is reported with the lower 32 bits
267503cb4473SJacob Keller 	 * in the low register, and the upper 8 bits in the high register.
267603cb4473SJacob Keller 	 */
267703cb4473SJacob Keller 	*tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
267803cb4473SJacob Keller 
267903cb4473SJacob Keller 	return 0;
268003cb4473SJacob Keller }
268103cb4473SJacob Keller 
268203cb4473SJacob Keller /**
268303cb4473SJacob Keller  * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
268403cb4473SJacob Keller  * @hw: pointer to the HW struct
268503cb4473SJacob Keller  * @lport: the lport to read from
268603cb4473SJacob Keller  * @idx: the timestamp index to reset
268703cb4473SJacob Keller  *
268803cb4473SJacob Keller  * Clear a timestamp, resetting its valid bit, from the timestamp block of the
268903cb4473SJacob Keller  * external PHY on the E810 device.
269003cb4473SJacob Keller  */
ice_clear_phy_tstamp_e810(struct ice_hw * hw,u8 lport,u8 idx)269103cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
269203cb4473SJacob Keller {
269303cb4473SJacob Keller 	u32 lo_addr, hi_addr;
269439b28106SJacob Keller 	int err;
269503cb4473SJacob Keller 
269603cb4473SJacob Keller 	lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
269703cb4473SJacob Keller 	hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
269803cb4473SJacob Keller 
269939b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, lo_addr, 0);
270039b28106SJacob Keller 	if (err) {
270139b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
270239b28106SJacob Keller 			  err);
270339b28106SJacob Keller 		return err;
270403cb4473SJacob Keller 	}
270503cb4473SJacob Keller 
270639b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, hi_addr, 0);
270739b28106SJacob Keller 	if (err) {
270839b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
270939b28106SJacob Keller 			  err);
271039b28106SJacob Keller 		return err;
271103cb4473SJacob Keller 	}
271203cb4473SJacob Keller 
271303cb4473SJacob Keller 	return 0;
271403cb4473SJacob Keller }
271503cb4473SJacob Keller 
271603cb4473SJacob Keller /**
271703cb4473SJacob Keller  * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
271803cb4473SJacob Keller  * @hw: pointer to HW struct
271903cb4473SJacob Keller  *
272003cb4473SJacob Keller  * Enable the timesync PTP functionality for the external PHY connected to
272103cb4473SJacob Keller  * this function.
272203cb4473SJacob Keller  */
ice_ptp_init_phy_e810(struct ice_hw * hw)272303cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw)
272403cb4473SJacob Keller {
272503cb4473SJacob Keller 	u8 tmr_idx;
272639b28106SJacob Keller 	int err;
272703cb4473SJacob Keller 
272803cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
272939b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
273003cb4473SJacob Keller 				     GLTSYN_ENA_TSYN_ENA_M);
273139b28106SJacob Keller 	if (err)
273203cb4473SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
273339b28106SJacob Keller 			  err);
273403cb4473SJacob Keller 
273539b28106SJacob Keller 	return err;
273603cb4473SJacob Keller }
273703cb4473SJacob Keller 
273803cb4473SJacob Keller /**
2739b2ee7256SJacob Keller  * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization
2740b2ee7256SJacob Keller  * @hw: pointer to HW struct
2741b2ee7256SJacob Keller  *
2742b2ee7256SJacob Keller  * Perform E810-specific PTP hardware clock initialization steps.
2743b2ee7256SJacob Keller  */
ice_ptp_init_phc_e810(struct ice_hw * hw)2744b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw)
2745b2ee7256SJacob Keller {
2746b2ee7256SJacob Keller 	/* Ensure synchronization delay is zero */
2747b2ee7256SJacob Keller 	wr32(hw, GLTSYN_SYNC_DLAY, 0);
2748b2ee7256SJacob Keller 
2749b2ee7256SJacob Keller 	/* Initialize the PHY */
2750b2ee7256SJacob Keller 	return ice_ptp_init_phy_e810(hw);
2751b2ee7256SJacob Keller }
2752b2ee7256SJacob Keller 
2753b2ee7256SJacob Keller /**
275403cb4473SJacob Keller  * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
275503cb4473SJacob Keller  * @hw: Board private structure
275603cb4473SJacob Keller  * @time: Time to initialize the PHY port clock to
275703cb4473SJacob Keller  *
275803cb4473SJacob Keller  * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
275903cb4473SJacob Keller  * initial clock time. The time will not actually be programmed until the
276003cb4473SJacob Keller  * driver issues an INIT_TIME command.
276103cb4473SJacob Keller  *
276203cb4473SJacob Keller  * The time value is the upper 32 bits of the PHY timer, usually in units of
276303cb4473SJacob Keller  * nominal nanoseconds.
276403cb4473SJacob Keller  */
ice_ptp_prep_phy_time_e810(struct ice_hw * hw,u32 time)276503cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
276603cb4473SJacob Keller {
276703cb4473SJacob Keller 	u8 tmr_idx;
276839b28106SJacob Keller 	int err;
276903cb4473SJacob Keller 
277003cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
277139b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
277239b28106SJacob Keller 	if (err) {
277339b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n",
277439b28106SJacob Keller 			  err);
277539b28106SJacob Keller 		return err;
277603cb4473SJacob Keller 	}
277703cb4473SJacob Keller 
277839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
277939b28106SJacob Keller 	if (err) {
278039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n",
278139b28106SJacob Keller 			  err);
278239b28106SJacob Keller 		return err;
278303cb4473SJacob Keller 	}
278403cb4473SJacob Keller 
278503cb4473SJacob Keller 	return 0;
278603cb4473SJacob Keller }
278703cb4473SJacob Keller 
278803cb4473SJacob Keller /**
278903cb4473SJacob Keller  * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
279003cb4473SJacob Keller  * @hw: pointer to HW struct
279103cb4473SJacob Keller  * @adj: adjustment value to program
279203cb4473SJacob Keller  *
279303cb4473SJacob Keller  * Prepare the PHY port for an atomic adjustment by programming the PHY
279403cb4473SJacob Keller  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
279503cb4473SJacob Keller  * is completed by issuing an ADJ_TIME sync command.
279603cb4473SJacob Keller  *
279703cb4473SJacob Keller  * The adjustment value only contains the portion used for the upper 32bits of
279803cb4473SJacob Keller  * the PHY timer, usually in units of nominal nanoseconds. Negative
279903cb4473SJacob Keller  * adjustments are supported using 2s complement arithmetic.
280003cb4473SJacob Keller  */
ice_ptp_prep_phy_adj_e810(struct ice_hw * hw,s32 adj)280103cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
280203cb4473SJacob Keller {
280303cb4473SJacob Keller 	u8 tmr_idx;
280439b28106SJacob Keller 	int err;
280503cb4473SJacob Keller 
280603cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
280703cb4473SJacob Keller 
280803cb4473SJacob Keller 	/* Adjustments are represented as signed 2's complement values in
280903cb4473SJacob Keller 	 * nanoseconds. Sub-nanosecond adjustment is not supported.
281003cb4473SJacob Keller 	 */
281139b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0);
281239b28106SJacob Keller 	if (err) {
281339b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n",
281439b28106SJacob Keller 			  err);
281539b28106SJacob Keller 		return err;
281603cb4473SJacob Keller 	}
281703cb4473SJacob Keller 
281839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj);
281939b28106SJacob Keller 	if (err) {
282039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n",
282139b28106SJacob Keller 			  err);
282239b28106SJacob Keller 		return err;
282303cb4473SJacob Keller 	}
282403cb4473SJacob Keller 
282503cb4473SJacob Keller 	return 0;
282603cb4473SJacob Keller }
282703cb4473SJacob Keller 
282803cb4473SJacob Keller /**
282903cb4473SJacob Keller  * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
283003cb4473SJacob Keller  * @hw: pointer to HW struct
283103cb4473SJacob Keller  * @incval: The new 40bit increment value to prepare
283203cb4473SJacob Keller  *
283303cb4473SJacob Keller  * Prepare the PHY port for a new increment value by programming the PHY
283403cb4473SJacob Keller  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
283503cb4473SJacob Keller  * completed by issuing an INIT_INCVAL command.
283603cb4473SJacob Keller  */
ice_ptp_prep_phy_incval_e810(struct ice_hw * hw,u64 incval)283703cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
283803cb4473SJacob Keller {
283903cb4473SJacob Keller 	u32 high, low;
284003cb4473SJacob Keller 	u8 tmr_idx;
284139b28106SJacob Keller 	int err;
284203cb4473SJacob Keller 
284303cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
284403cb4473SJacob Keller 	low = lower_32_bits(incval);
284503cb4473SJacob Keller 	high = upper_32_bits(incval);
284603cb4473SJacob Keller 
284739b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
284839b28106SJacob Keller 	if (err) {
284939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n",
285039b28106SJacob Keller 			  err);
285139b28106SJacob Keller 		return err;
285203cb4473SJacob Keller 	}
285303cb4473SJacob Keller 
285439b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
285539b28106SJacob Keller 	if (err) {
285639b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n",
285739b28106SJacob Keller 			  err);
285839b28106SJacob Keller 		return err;
285903cb4473SJacob Keller 	}
286003cb4473SJacob Keller 
286103cb4473SJacob Keller 	return 0;
286203cb4473SJacob Keller }
286303cb4473SJacob Keller 
286403cb4473SJacob Keller /**
286503cb4473SJacob Keller  * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
286603cb4473SJacob Keller  * @hw: pointer to HW struct
286703cb4473SJacob Keller  * @cmd: Command to be sent to the port
286803cb4473SJacob Keller  *
286903cb4473SJacob Keller  * Prepare the external PHYs connected to this device for a timer sync
287003cb4473SJacob Keller  * command.
287103cb4473SJacob Keller  */
ice_ptp_port_cmd_e810(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)287203cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
287303cb4473SJacob Keller {
287403cb4473SJacob Keller 	u32 cmd_val, val;
287539b28106SJacob Keller 	int err;
287603cb4473SJacob Keller 
287703cb4473SJacob Keller 	switch (cmd) {
287803cb4473SJacob Keller 	case INIT_TIME:
287903cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_INIT_TIME;
288003cb4473SJacob Keller 		break;
288103cb4473SJacob Keller 	case INIT_INCVAL:
288203cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_INIT_INCVAL;
288303cb4473SJacob Keller 		break;
288403cb4473SJacob Keller 	case ADJ_TIME:
288503cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_ADJ_TIME;
288603cb4473SJacob Keller 		break;
288703cb4473SJacob Keller 	case READ_TIME:
288803cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_READ_TIME;
288903cb4473SJacob Keller 		break;
289003cb4473SJacob Keller 	case ADJ_TIME_AT_TIME:
289103cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
289203cb4473SJacob Keller 		break;
2893*0aacec49SJacob Keller 	case ICE_PTP_NOP:
2894*0aacec49SJacob Keller 		return 0;
289503cb4473SJacob Keller 	}
289603cb4473SJacob Keller 
289703cb4473SJacob Keller 	/* Read, modify, write */
289839b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val);
289939b28106SJacob Keller 	if (err) {
290039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err);
290139b28106SJacob Keller 		return err;
290203cb4473SJacob Keller 	}
290303cb4473SJacob Keller 
290403cb4473SJacob Keller 	/* Modify necessary bits only and perform write */
290503cb4473SJacob Keller 	val &= ~TS_CMD_MASK_E810;
290603cb4473SJacob Keller 	val |= cmd_val;
290703cb4473SJacob Keller 
290839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val);
290939b28106SJacob Keller 	if (err) {
291039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err);
291139b28106SJacob Keller 		return err;
291203cb4473SJacob Keller 	}
291303cb4473SJacob Keller 
291403cb4473SJacob Keller 	return 0;
291503cb4473SJacob Keller }
291603cb4473SJacob Keller 
291703cb4473SJacob Keller /**
291803cb4473SJacob Keller  * ice_get_phy_tx_tstamp_ready_e810 - Read Tx memory status register
29193a749623SJacob Keller  * @hw: pointer to the HW struct
29203a749623SJacob Keller  * @port: the PHY port to read
29213a749623SJacob Keller  * @tstamp_ready: contents of the Tx memory status register
292203cb4473SJacob Keller  *
292303cb4473SJacob Keller  * E810 devices do not use a Tx memory status register. Instead simply
292403cb4473SJacob Keller  * indicate that all timestamps are currently ready.
292503cb4473SJacob Keller  */
292603cb4473SJacob Keller static int
ice_get_phy_tx_tstamp_ready_e810(struct ice_hw * hw,u8 port,u64 * tstamp_ready)292703cb4473SJacob Keller ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready)
292803cb4473SJacob Keller {
292903cb4473SJacob Keller 	*tstamp_ready = 0xFFFFFFFFFFFFFFFF;
293003cb4473SJacob Keller 	return 0;
293103cb4473SJacob Keller }
293203cb4473SJacob Keller 
293303cb4473SJacob Keller /* E810T SMA functions
293403cb4473SJacob Keller  *
293503cb4473SJacob Keller  * The following functions operate specifically on E810T hardware and are used
293603cb4473SJacob Keller  * to access the extended GPIOs available.
293703cb4473SJacob Keller  */
293803cb4473SJacob Keller 
293903cb4473SJacob Keller /**
294003cb4473SJacob Keller  * ice_get_pca9575_handle
294103cb4473SJacob Keller  * @hw: pointer to the hw struct
294203cb4473SJacob Keller  * @pca9575_handle: GPIO controller's handle
294303cb4473SJacob Keller  *
2944a711a328SKarol Kolacinski  * Find and return the GPIO controller's handle in the netlist.
294503cb4473SJacob Keller  * When found - the value will be cached in the hw structure and following calls
294603cb4473SJacob Keller  * will return cached value
294703cb4473SJacob Keller  */
294803cb4473SJacob Keller static int
ice_get_pca9575_handle(struct ice_hw * hw,u16 * pca9575_handle)2949a711a328SKarol Kolacinski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
295003cb4473SJacob Keller {
2951a711a328SKarol Kolacinski 	struct ice_aqc_get_link_topo *cmd;
2952a711a328SKarol Kolacinski 	struct ice_aq_desc desc;
2953a711a328SKarol Kolacinski 	int status;
2954a711a328SKarol Kolacinski 	u8 idx;
2955a711a328SKarol Kolacinski 
295603cb4473SJacob Keller 	/* If handle was read previously return cached value */
295703cb4473SJacob Keller 	if (hw->io_expander_handle) {
295803cb4473SJacob Keller 		*pca9575_handle = hw->io_expander_handle;
295903cb4473SJacob Keller 		return 0;
296003cb4473SJacob Keller 	}
296103cb4473SJacob Keller 
296203cb4473SJacob Keller 	/* If handle was not detected read it from the netlist */
296303cb4473SJacob Keller 	cmd = &desc.params.get_link_topo;
296403cb4473SJacob Keller 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
296503cb4473SJacob Keller 
296603cb4473SJacob Keller 	/* Set node type to GPIO controller */
296703cb4473SJacob Keller 	cmd->addr.topo_params.node_type_ctx =
296803cb4473SJacob Keller 		(ICE_AQC_LINK_TOPO_NODE_TYPE_M &
296903cb4473SJacob Keller 		 ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
297003cb4473SJacob Keller 
297103cb4473SJacob Keller #define SW_PCA9575_SFP_TOPO_IDX		2
297203cb4473SJacob Keller #define SW_PCA9575_QSFP_TOPO_IDX	1
297303cb4473SJacob Keller 
297403cb4473SJacob Keller 	/* Check if the SW IO expander controlling SMA exists in the netlist. */
297503cb4473SJacob Keller 	if (hw->device_id == ICE_DEV_ID_E810C_SFP)
297603cb4473SJacob Keller 		idx = SW_PCA9575_SFP_TOPO_IDX;
297703cb4473SJacob Keller 	else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
297803cb4473SJacob Keller 		idx = SW_PCA9575_QSFP_TOPO_IDX;
297903cb4473SJacob Keller 	else
298003cb4473SJacob Keller 		return -EOPNOTSUPP;
298103cb4473SJacob Keller 
298203cb4473SJacob Keller 	cmd->addr.topo_params.index = idx;
298303cb4473SJacob Keller 
298403cb4473SJacob Keller 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
298539b28106SJacob Keller 	if (status)
298603cb4473SJacob Keller 		return -EOPNOTSUPP;
298703cb4473SJacob Keller 
298803cb4473SJacob Keller 	/* Verify if we found the right IO expander type */
298903cb4473SJacob Keller 	if (desc.params.get_link_topo.node_part_num !=
299003cb4473SJacob Keller 		ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
29913a749623SJacob Keller 		return -EOPNOTSUPP;
299239b28106SJacob Keller 
29933a749623SJacob Keller 	/* If present save the handle and return it */
29943a749623SJacob Keller 	hw->io_expander_handle =
299539b28106SJacob Keller 		le16_to_cpu(desc.params.get_link_topo.addr.handle);
299639b28106SJacob Keller 	*pca9575_handle = hw->io_expander_handle;
299739b28106SJacob Keller 
299839b28106SJacob Keller 	return 0;
299903cb4473SJacob Keller }
300003cb4473SJacob Keller 
30013a749623SJacob Keller /**
30023a749623SJacob Keller  * ice_read_sma_ctrl_e810t
300303cb4473SJacob Keller  * @hw: pointer to the hw struct
30043a749623SJacob Keller  * @data: pointer to data to be read from the GPIO controller
300503cb4473SJacob Keller  *
300603cb4473SJacob Keller  * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
300703cb4473SJacob Keller  * PCA9575 expander, so only bits 3-7 in data are valid.
300803cb4473SJacob Keller  */
ice_read_sma_ctrl_e810t(struct ice_hw * hw,u8 * data)300903cb4473SJacob Keller int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
301003cb4473SJacob Keller {
301103cb4473SJacob Keller 	int status;
301203cb4473SJacob Keller 	u16 handle;
301303cb4473SJacob Keller 	u8 i;
301403cb4473SJacob Keller 
301503cb4473SJacob Keller 	status = ice_get_pca9575_handle(hw, &handle);
301603cb4473SJacob Keller 	if (status)
301703cb4473SJacob Keller 		return status;
301803cb4473SJacob Keller 
301903cb4473SJacob Keller 	*data = 0;
302003cb4473SJacob Keller 
302103cb4473SJacob Keller 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
302203cb4473SJacob Keller 		bool pin;
302303cb4473SJacob Keller 
302403cb4473SJacob Keller 		status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
302539b28106SJacob Keller 					 &pin, NULL);
302603cb4473SJacob Keller 		if (status)
302703cb4473SJacob Keller 			break;
302803cb4473SJacob Keller 		*data |= (u8)(!pin) << i;
302903cb4473SJacob Keller 	}
303003cb4473SJacob Keller 
303103cb4473SJacob Keller 	return status;
303203cb4473SJacob Keller }
303303cb4473SJacob Keller 
303403cb4473SJacob Keller /**
303503cb4473SJacob Keller  * ice_write_sma_ctrl_e810t
30363a749623SJacob Keller  * @hw: pointer to the hw struct
303739b28106SJacob Keller  * @data: data to be written to the GPIO controller
30383a749623SJacob Keller  *
30393a749623SJacob Keller  * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
304039b28106SJacob Keller  * of the PCA9575 expander, so only bits 3-7 in data are valid.
304139b28106SJacob Keller  */
ice_write_sma_ctrl_e810t(struct ice_hw * hw,u8 data)304203cb4473SJacob Keller int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
304303cb4473SJacob Keller {
304403cb4473SJacob Keller 	int status;
304503cb4473SJacob Keller 	u16 handle;
304603cb4473SJacob Keller 	u8 i;
304703cb4473SJacob Keller 
304803cb4473SJacob Keller 	status = ice_get_pca9575_handle(hw, &handle);
304903cb4473SJacob Keller 	if (status)
305003cb4473SJacob Keller 		return status;
305103cb4473SJacob Keller 
305203cb4473SJacob Keller 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
305303cb4473SJacob Keller 		bool pin;
305403cb4473SJacob Keller 
305503cb4473SJacob Keller 		pin = !(data & (1 << i));
305603cb4473SJacob Keller 		status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
305703cb4473SJacob Keller 					 pin, NULL);
305803cb4473SJacob Keller 		if (status)
305903cb4473SJacob Keller 			break;
306003cb4473SJacob Keller 	}
306103cb4473SJacob Keller 
306203cb4473SJacob Keller 	return status;
306339b28106SJacob Keller }
306403cb4473SJacob Keller 
306503cb4473SJacob Keller /**
306603cb4473SJacob Keller  * ice_read_pca9575_reg_e810t
306703cb4473SJacob Keller  * @hw: pointer to the hw struct
306803cb4473SJacob Keller  * @offset: GPIO controller register offset
306903cb4473SJacob Keller  * @data: pointer to data to be read from the GPIO controller
307003cb4473SJacob Keller  *
30713a749623SJacob Keller  * Read the register from the GPIO controller
307239b28106SJacob Keller  */
ice_read_pca9575_reg_e810t(struct ice_hw * hw,u8 offset,u8 * data)30733a749623SJacob Keller int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data)
30743a749623SJacob Keller {
307539b28106SJacob Keller 	struct ice_aqc_link_topo_addr link_topo;
307639b28106SJacob Keller 	__le16 addr;
307703cb4473SJacob Keller 	u16 handle;
307803cb4473SJacob Keller 	int err;
307903cb4473SJacob Keller 
308003cb4473SJacob Keller 	memset(&link_topo, 0, sizeof(link_topo));
308103cb4473SJacob Keller 
308203cb4473SJacob Keller 	err = ice_get_pca9575_handle(hw, &handle);
308303cb4473SJacob Keller 	if (err)
308403cb4473SJacob Keller 		return err;
308503cb4473SJacob Keller 
308603cb4473SJacob Keller 	link_topo.handle = cpu_to_le16(handle);
308703cb4473SJacob Keller 	link_topo.topo_params.node_type_ctx =
308803cb4473SJacob Keller 		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
308903cb4473SJacob Keller 			   ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED);
309039b28106SJacob Keller 
309103cb4473SJacob Keller 	addr = cpu_to_le16((u16)offset);
309203cb4473SJacob Keller 
309303cb4473SJacob Keller 	return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL);
309403cb4473SJacob Keller }
309539b28106SJacob Keller 
309603cb4473SJacob Keller /* Device agnostic functions
309703cb4473SJacob Keller  *
309803cb4473SJacob Keller  * The following functions implement shared behavior common to both E822 and
309939b28106SJacob Keller  * E810 devices, possibly calling a device specific implementation where
310003cb4473SJacob Keller  * necessary.
310103cb4473SJacob Keller  */
310203cb4473SJacob Keller 
310303cb4473SJacob Keller /**
310403cb4473SJacob Keller  * ice_ptp_lock - Acquire PTP global semaphore register lock
310503cb4473SJacob Keller  * @hw: pointer to the HW struct
310603cb4473SJacob Keller  *
310703cb4473SJacob Keller  * Acquire the global PTP hardware semaphore lock. Returns true if the lock
310803cb4473SJacob Keller  * was acquired, false otherwise.
310903cb4473SJacob Keller  *
311003cb4473SJacob Keller  * The PFTSYN_SEM register sets the busy bit on read, returning the previous
311103cb4473SJacob Keller  * value. If software sees the busy bit cleared, this means that this function
311203cb4473SJacob Keller  * acquired the lock (and the busy bit is now set). If software sees the busy
311303cb4473SJacob Keller  * bit set, it means that another function acquired the lock.
311403cb4473SJacob Keller  *
311503cb4473SJacob Keller  * Software must clear the busy bit with a write to release the lock for other
311603cb4473SJacob Keller  * functions when done.
311703cb4473SJacob Keller  */
ice_ptp_lock(struct ice_hw * hw)311839b28106SJacob Keller bool ice_ptp_lock(struct ice_hw *hw)
311903cb4473SJacob Keller {
312003cb4473SJacob Keller 	u32 hw_lock;
312103cb4473SJacob Keller 	int i;
312203cb4473SJacob Keller 
312303cb4473SJacob Keller #define MAX_TRIES 15
312403cb4473SJacob Keller 
312503cb4473SJacob Keller 	for (i = 0; i < MAX_TRIES; i++) {
312603cb4473SJacob Keller 		hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
312703cb4473SJacob Keller 		hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
312803cb4473SJacob Keller 		if (hw_lock) {
312903cb4473SJacob Keller 			/* Somebody is holding the lock */
31303a749623SJacob Keller 			usleep_range(5000, 6000);
313139b28106SJacob Keller 			continue;
31323a749623SJacob Keller 		}
31333a749623SJacob Keller 
313439b28106SJacob Keller 		break;
313539b28106SJacob Keller 	}
313603cb4473SJacob Keller 
313703cb4473SJacob Keller 	return !hw_lock;
313803cb4473SJacob Keller }
313903cb4473SJacob Keller 
314003cb4473SJacob Keller /**
314103cb4473SJacob Keller  * ice_ptp_unlock - Release PTP global semaphore register lock
314203cb4473SJacob Keller  * @hw: pointer to the HW struct
314303cb4473SJacob Keller  *
314403cb4473SJacob Keller  * Release the global PTP hardware semaphore lock. This is done by writing to
314503cb4473SJacob Keller  * the PFTSYN_SEM register.
314603cb4473SJacob Keller  */
ice_ptp_unlock(struct ice_hw * hw)31473a749623SJacob Keller void ice_ptp_unlock(struct ice_hw *hw)
31483a749623SJacob Keller {
31493a749623SJacob Keller 	wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
315003cb4473SJacob Keller }
315103cb4473SJacob Keller 
315203cb4473SJacob Keller /**
31533a749623SJacob Keller  * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
315403cb4473SJacob Keller  * @hw: pointer to HW struct
31553a749623SJacob Keller  * @cmd: the command to issue
31563a749623SJacob Keller  *
315703cb4473SJacob Keller  * Prepare the source timer and PHY timers and then trigger the requested
315803cb4473SJacob Keller  * command. This causes the shadow registers previously written in preparation
315903cb4473SJacob Keller  * for the command to be synchronously applied to both the source and PHY
316003cb4473SJacob Keller  * timers.
316103cb4473SJacob Keller  */
ice_ptp_tmr_cmd(struct ice_hw * hw,enum ice_ptp_tmr_cmd cmd)316203cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
316303cb4473SJacob Keller {
316403cb4473SJacob Keller 	int err;
31653a749623SJacob Keller 
31663a749623SJacob Keller 	/* First, prepare the source timer */
31673a749623SJacob Keller 	ice_ptp_src_cmd(hw, cmd);
316803cb4473SJacob Keller 
316903cb4473SJacob Keller 	/* Next, prepare the ports */
317003cb4473SJacob Keller 	if (ice_is_e810(hw))
31713a749623SJacob Keller 		err = ice_ptp_port_cmd_e810(hw, cmd);
317203cb4473SJacob Keller 	else
31733a749623SJacob Keller 		err = ice_ptp_port_cmd_e822(hw, cmd);
31743a749623SJacob Keller 	if (err) {
317503cb4473SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n",
3176885fe693SMaciej Machnikowski 			  cmd, err);
317710e4b4a3SJacob Keller 		return err;
317810e4b4a3SJacob Keller 	}
317910e4b4a3SJacob Keller 
318010e4b4a3SJacob Keller 	/* Write the sync command register to drive both source and PHY timer
318110e4b4a3SJacob Keller 	 * commands synchronously
318210e4b4a3SJacob Keller 	 */
318310e4b4a3SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
318410e4b4a3SJacob Keller 
318510e4b4a3SJacob Keller 	return 0;
318610e4b4a3SJacob Keller }
318710e4b4a3SJacob Keller 
318810e4b4a3SJacob Keller /**
318910e4b4a3SJacob Keller  * ice_ptp_init_time - Initialize device time to provided value
319010e4b4a3SJacob Keller  * @hw: pointer to HW struct
319110e4b4a3SJacob Keller  * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
319210e4b4a3SJacob Keller  *
3193885fe693SMaciej Machnikowski  * Initialize the device to the specified time provided. This requires a three
3194885fe693SMaciej Machnikowski  * step process:
3195885fe693SMaciej Machnikowski  *
3196885fe693SMaciej Machnikowski  * 1) write the new init time to the source timer shadow registers
3197885fe693SMaciej Machnikowski  * 2) write the new init time to the PHY timer shadow registers
3198885fe693SMaciej Machnikowski  * 3) issue an init_time timer command to synchronously switch both the source
3199885fe693SMaciej Machnikowski  *    and port timers to the new init time value at the next clock cycle.
3200885fe693SMaciej Machnikowski  */
ice_ptp_init_time(struct ice_hw * hw,u64 time)3201885fe693SMaciej Machnikowski int ice_ptp_init_time(struct ice_hw *hw, u64 time)
3202885fe693SMaciej Machnikowski {
3203885fe693SMaciej Machnikowski 	u8 tmr_idx;
3204885fe693SMaciej Machnikowski 	int err;
3205885fe693SMaciej Machnikowski 
3206885fe693SMaciej Machnikowski 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3207885fe693SMaciej Machnikowski 
3208885fe693SMaciej Machnikowski 	/* Source timers */
3209885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time));
3210885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time));
3211885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
3212885fe693SMaciej Machnikowski 
3213885fe693SMaciej Machnikowski 	/* PHY timers */
3214885fe693SMaciej Machnikowski 	/* Fill Rx and Tx ports and send msg to PHY */
3215885fe693SMaciej Machnikowski 	if (ice_is_e810(hw))
3216885fe693SMaciej Machnikowski 		err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
3217885fe693SMaciej Machnikowski 	else
3218885fe693SMaciej Machnikowski 		err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
3219885fe693SMaciej Machnikowski 	if (err)
3220885fe693SMaciej Machnikowski 		return err;
3221885fe693SMaciej Machnikowski 
3222885fe693SMaciej Machnikowski 	return ice_ptp_tmr_cmd(hw, INIT_TIME);
3223885fe693SMaciej Machnikowski }
3224885fe693SMaciej Machnikowski 
3225885fe693SMaciej Machnikowski /**
3226885fe693SMaciej Machnikowski  * ice_ptp_write_incval - Program PHC with new increment value
3227885fe693SMaciej Machnikowski  * @hw: pointer to HW struct
3228885fe693SMaciej Machnikowski  * @incval: Source timer increment value per clock cycle
3229885fe693SMaciej Machnikowski  *
3230885fe693SMaciej Machnikowski  * Program the PHC with a new increment value. This requires a three-step
3231885fe693SMaciej Machnikowski  * process:
3232885fe693SMaciej Machnikowski  *
3233885fe693SMaciej Machnikowski  * 1) Write the increment value to the source timer shadow registers
3234885fe693SMaciej Machnikowski  * 2) Write the increment value to the PHY timer shadow registers
3235885fe693SMaciej Machnikowski  * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
3236885fe693SMaciej Machnikowski  *    source and port timers to the new increment value at the next clock
3237885fe693SMaciej Machnikowski  *    cycle.
3238885fe693SMaciej Machnikowski  */
ice_ptp_write_incval(struct ice_hw * hw,u64 incval)3239885fe693SMaciej Machnikowski int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
3240885fe693SMaciej Machnikowski {
3241885fe693SMaciej Machnikowski 	u8 tmr_idx;
3242885fe693SMaciej Machnikowski 	int err;
3243885fe693SMaciej Machnikowski 
3244885fe693SMaciej Machnikowski 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3245885fe693SMaciej Machnikowski 
3246885fe693SMaciej Machnikowski 	/* Shadow Adjust */
3247885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
3248885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
3249885fe693SMaciej Machnikowski 
3250885fe693SMaciej Machnikowski 	if (ice_is_e810(hw))
3251885fe693SMaciej Machnikowski 		err = ice_ptp_prep_phy_incval_e810(hw, incval);
3252885fe693SMaciej Machnikowski 	else
3253885fe693SMaciej Machnikowski 		err = ice_ptp_prep_phy_incval_e822(hw, incval);
3254885fe693SMaciej Machnikowski 	if (err)
3255885fe693SMaciej Machnikowski 		return err;
3256885fe693SMaciej Machnikowski 
3257885fe693SMaciej Machnikowski 	return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
3258885fe693SMaciej Machnikowski }
3259885fe693SMaciej Machnikowski 
3260885fe693SMaciej Machnikowski /**
3261885fe693SMaciej Machnikowski  * ice_ptp_write_incval_locked - Program new incval while holding semaphore
3262885fe693SMaciej Machnikowski  * @hw: pointer to HW struct
3263885fe693SMaciej Machnikowski  * @incval: Source timer increment value per clock cycle
3264885fe693SMaciej Machnikowski  *
3265885fe693SMaciej Machnikowski  * Program a new PHC incval while holding the PTP semaphore.
3266885fe693SMaciej Machnikowski  */
ice_ptp_write_incval_locked(struct ice_hw * hw,u64 incval)3267885fe693SMaciej Machnikowski int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
3268885fe693SMaciej Machnikowski {
3269885fe693SMaciej Machnikowski 	int err;
3270885fe693SMaciej Machnikowski 
3271885fe693SMaciej Machnikowski 	if (!ice_ptp_lock(hw))
3272885fe693SMaciej Machnikowski 		return -EBUSY;
3273885fe693SMaciej Machnikowski 
3274885fe693SMaciej Machnikowski 	err = ice_ptp_write_incval(hw, incval);
3275885fe693SMaciej Machnikowski 
3276885fe693SMaciej Machnikowski 	ice_ptp_unlock(hw);
3277885fe693SMaciej Machnikowski 
3278885fe693SMaciej Machnikowski 	return err;
3279885fe693SMaciej Machnikowski }
3280885fe693SMaciej Machnikowski 
3281885fe693SMaciej Machnikowski /**
3282885fe693SMaciej Machnikowski  * ice_ptp_adj_clock - Adjust PHC clock time atomically
3283885fe693SMaciej Machnikowski  * @hw: pointer to HW struct
3284885fe693SMaciej Machnikowski  * @adj: Adjustment in nanoseconds
3285885fe693SMaciej Machnikowski  *
3286885fe693SMaciej Machnikowski  * Perform an atomic adjustment of the PHC time by the specified number of
3287885fe693SMaciej Machnikowski  * nanoseconds. This requires a three-step process:
3288885fe693SMaciej Machnikowski  *
3289885fe693SMaciej Machnikowski  * 1) Write the adjustment to the source timer shadow registers
3290885fe693SMaciej Machnikowski  * 2) Write the adjustment to the PHY timer shadow registers
3291885fe693SMaciej Machnikowski  * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
3292885fe693SMaciej Machnikowski  *    both the source and port timers at the next clock cycle.
3293885fe693SMaciej Machnikowski  */
ice_ptp_adj_clock(struct ice_hw * hw,s32 adj)3294885fe693SMaciej Machnikowski int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
3295885fe693SMaciej Machnikowski {
3296885fe693SMaciej Machnikowski 	u8 tmr_idx;
3297885fe693SMaciej Machnikowski 	int err;
3298885fe693SMaciej Machnikowski 
3299885fe693SMaciej Machnikowski 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3300885fe693SMaciej Machnikowski 
3301885fe693SMaciej Machnikowski 	/* Write the desired clock adjustment into the GLTSYN_SHADJ register.
3302885fe693SMaciej Machnikowski 	 * For an ADJ_TIME command, this set of registers represents the value
3303885fe693SMaciej Machnikowski 	 * to add to the clock time. It supports subtraction by interpreting
3304885fe693SMaciej Machnikowski 	 * the value as a 2's complement integer.
3305885fe693SMaciej Machnikowski 	 */
3306885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
3307885fe693SMaciej Machnikowski 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
3308885fe693SMaciej Machnikowski 
3309885fe693SMaciej Machnikowski 	if (ice_is_e810(hw))
3310885fe693SMaciej Machnikowski 		err = ice_ptp_prep_phy_adj_e810(hw, adj);
3311885fe693SMaciej Machnikowski 	else
3312885fe693SMaciej Machnikowski 		err = ice_ptp_prep_phy_adj_e822(hw, adj);
3313885fe693SMaciej Machnikowski 	if (err)
3314885fe693SMaciej Machnikowski 		return err;
3315885fe693SMaciej Machnikowski 
3316885fe693SMaciej Machnikowski 	return ice_ptp_tmr_cmd(hw, ADJ_TIME);
3317885fe693SMaciej Machnikowski }
3318885fe693SMaciej Machnikowski 
3319885fe693SMaciej Machnikowski /**
3320885fe693SMaciej Machnikowski  * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
3321885fe693SMaciej Machnikowski  * @hw: pointer to the HW struct
3322885fe693SMaciej Machnikowski  * @block: the block to read from
3323885fe693SMaciej Machnikowski  * @idx: the timestamp index to read
3324885fe693SMaciej Machnikowski  * @tstamp: on return, the 40bit timestamp value
3325885fe693SMaciej Machnikowski  *
332643113ff7SKarol Kolacinski  * Read a 40bit timestamp value out of the timestamp block. For E822 devices,
332743113ff7SKarol Kolacinski  * the block is the quad to read from. For E810 devices, the block is the
332843113ff7SKarol Kolacinski  * logical port to read from.
332943113ff7SKarol Kolacinski  */
ice_read_phy_tstamp(struct ice_hw * hw,u8 block,u8 idx,u64 * tstamp)333043113ff7SKarol Kolacinski int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
333143113ff7SKarol Kolacinski {
333243113ff7SKarol Kolacinski 	if (ice_is_e810(hw))
333343113ff7SKarol Kolacinski 		return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
333443113ff7SKarol Kolacinski 	else
333543113ff7SKarol Kolacinski 		return ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
333643113ff7SKarol Kolacinski }
333743113ff7SKarol Kolacinski 
333843113ff7SKarol Kolacinski /**
333943113ff7SKarol Kolacinski  * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
334043113ff7SKarol Kolacinski  * @hw: pointer to the HW struct
334143113ff7SKarol Kolacinski  * @block: the block to read from
334243113ff7SKarol Kolacinski  * @idx: the timestamp index to reset
334343113ff7SKarol Kolacinski  *
334443113ff7SKarol Kolacinski  * Clear a timestamp, resetting its valid bit, from the timestamp block. For
334543113ff7SKarol Kolacinski  * E822 devices, the block is the quad to clear from. For E810 devices, the
334643113ff7SKarol Kolacinski  * block is the logical port to clear from.
334743113ff7SKarol Kolacinski  */
ice_clear_phy_tstamp(struct ice_hw * hw,u8 block,u8 idx)334843113ff7SKarol Kolacinski int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
334943113ff7SKarol Kolacinski {
335043113ff7SKarol Kolacinski 	if (ice_is_e810(hw))
335143113ff7SKarol Kolacinski 		return ice_clear_phy_tstamp_e810(hw, block, idx);
335243113ff7SKarol Kolacinski 	else
335343113ff7SKarol Kolacinski 		return ice_clear_phy_tstamp_e822(hw, block, idx);
335443113ff7SKarol Kolacinski }
335543113ff7SKarol Kolacinski 
335643113ff7SKarol Kolacinski /**
3357885fe693SMaciej Machnikowski  * ice_ptp_reset_ts_memory - Reset timestamp memory for all blocks
3358885fe693SMaciej Machnikowski  * @hw: pointer to the HW struct
3359885fe693SMaciej Machnikowski  */
ice_ptp_reset_ts_memory(struct ice_hw * hw)3360885fe693SMaciej Machnikowski void ice_ptp_reset_ts_memory(struct ice_hw *hw)
3361885fe693SMaciej Machnikowski {
3362885fe693SMaciej Machnikowski 	if (ice_is_e810(hw))
3363885fe693SMaciej Machnikowski 		return;
3364885fe693SMaciej Machnikowski 
3365885fe693SMaciej Machnikowski 	ice_ptp_reset_ts_memory_e822(hw);
3366885fe693SMaciej Machnikowski }
3367885fe693SMaciej Machnikowski 
3368885fe693SMaciej Machnikowski /**
3369885fe693SMaciej Machnikowski  * ice_ptp_init_phc - Initialize PTP hardware clock
3370885fe693SMaciej Machnikowski  * @hw: pointer to the HW struct
3371885fe693SMaciej Machnikowski  *
3372885fe693SMaciej Machnikowski  * Perform the steps required to initialize the PTP hardware clock.
3373885fe693SMaciej Machnikowski  */
ice_ptp_init_phc(struct ice_hw * hw)3374b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw)
3375b2ee7256SJacob Keller {
3376407b66c0SKarol Kolacinski 	u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
3377407b66c0SKarol Kolacinski 
3378407b66c0SKarol Kolacinski 	/* Enable source clocks */
3379407b66c0SKarol Kolacinski 	wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
3380407b66c0SKarol Kolacinski 
3381407b66c0SKarol Kolacinski 	/* Clear event err indications for auxiliary pins */
3382407b66c0SKarol Kolacinski 	(void)rd32(hw, GLTSYN_STAT(src_idx));
3383407b66c0SKarol Kolacinski 
3384407b66c0SKarol Kolacinski 	if (ice_is_e810(hw))
3385407b66c0SKarol Kolacinski 		return ice_ptp_init_phc_e810(hw);
3386407b66c0SKarol Kolacinski 	else
3387407b66c0SKarol Kolacinski 		return ice_ptp_init_phc_e822(hw);
3388b2ee7256SJacob Keller }
3389b2ee7256SJacob Keller 
3390b2ee7256SJacob Keller /**
3391b2ee7256SJacob Keller  * ice_get_phy_tx_tstamp_ready - Read PHY Tx memory status indication
3392b2ee7256SJacob Keller  * @hw: pointer to the HW struct
3393b2ee7256SJacob Keller  * @block: the timestamp block to check
3394b2ee7256SJacob Keller  * @tstamp_ready: storage for the PHY Tx memory status information
3395b2ee7256SJacob Keller  *
3396b2ee7256SJacob Keller  * Check the PHY for Tx timestamp memory status. This reports a 64 bit value
3397b2ee7256SJacob Keller  * which indicates which timestamps in the block may be captured. A set bit
3398b2ee7256SJacob Keller  * means the timestamp can be read. An unset bit means the timestamp is not
3399b2ee7256SJacob Keller  * ready and software should avoid reading the register.
3400b2ee7256SJacob Keller  */
ice_get_phy_tx_tstamp_ready(struct ice_hw * hw,u8 block,u64 * tstamp_ready)3401b2ee7256SJacob Keller int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready)
3402b2ee7256SJacob Keller {
34033a749623SJacob Keller 	if (ice_is_e810(hw))
3404b2ee7256SJacob Keller 		return ice_get_phy_tx_tstamp_ready_e810(hw, block,
34053a749623SJacob Keller 							tstamp_ready);
34063a749623SJacob Keller 	else
3407b2ee7256SJacob Keller 		return ice_get_phy_tx_tstamp_ready_e822(hw, block,
340810e4b4a3SJacob Keller 							tstamp_ready);
340910e4b4a3SJacob Keller }
341010e4b4a3SJacob Keller