103cb4473SJacob Keller // SPDX-License-Identifier: GPL-2.0
203cb4473SJacob Keller /* Copyright (C) 2021, Intel Corporation. */
303cb4473SJacob Keller 
403cb4473SJacob Keller #include "ice_common.h"
503cb4473SJacob Keller #include "ice_ptp_hw.h"
63a749623SJacob Keller #include "ice_ptp_consts.h"
7*b111ab5aSJacob Keller #include "ice_cgu_regs.h"
803cb4473SJacob Keller 
903cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used
1003cb4473SJacob Keller  * for the Precision Time Protocol.
1103cb4473SJacob Keller  *
1203cb4473SJacob Keller  * The ice hardware represents the current time using three registers:
1303cb4473SJacob Keller  *
1403cb4473SJacob Keller  *    GLTSYN_TIME_H     GLTSYN_TIME_L     GLTSYN_TIME_R
1503cb4473SJacob Keller  *  +---------------+ +---------------+ +---------------+
1603cb4473SJacob Keller  *  |    32 bits    | |    32 bits    | |    32 bits    |
1703cb4473SJacob Keller  *  +---------------+ +---------------+ +---------------+
1803cb4473SJacob Keller  *
1903cb4473SJacob Keller  * The registers are incremented every clock tick using a 40bit increment
2003cb4473SJacob Keller  * value defined over two registers:
2103cb4473SJacob Keller  *
2203cb4473SJacob Keller  *                     GLTSYN_INCVAL_H   GLTSYN_INCVAL_L
2303cb4473SJacob Keller  *                    +---------------+ +---------------+
2403cb4473SJacob Keller  *                    |    8 bit s    | |    32 bits    |
2503cb4473SJacob Keller  *                    +---------------+ +---------------+
2603cb4473SJacob Keller  *
2703cb4473SJacob Keller  * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L
2803cb4473SJacob Keller  * registers every clock source tick. Depending on the specific device
2903cb4473SJacob Keller  * configuration, the clock source frequency could be one of a number of
3003cb4473SJacob Keller  * values.
3103cb4473SJacob Keller  *
3203cb4473SJacob Keller  * For E810 devices, the increment frequency is 812.5 MHz
3303cb4473SJacob Keller  *
343a749623SJacob Keller  * For E822 devices the clock can be derived from different sources, and the
353a749623SJacob Keller  * increment has an effective frequency of one of the following:
363a749623SJacob Keller  * - 823.4375 MHz
373a749623SJacob Keller  * - 783.36 MHz
383a749623SJacob Keller  * - 796.875 MHz
393a749623SJacob Keller  * - 816 MHz
403a749623SJacob Keller  * - 830.078125 MHz
413a749623SJacob Keller  * - 783.36 MHz
423a749623SJacob Keller  *
4303cb4473SJacob Keller  * The hardware captures timestamps in the PHY for incoming packets, and for
4403cb4473SJacob Keller  * outgoing packets on request. To support this, the PHY maintains a timer
4503cb4473SJacob Keller  * that matches the lower 64 bits of the global source timer.
4603cb4473SJacob Keller  *
4703cb4473SJacob Keller  * In order to ensure that the PHY timers and the source timer are equivalent,
4803cb4473SJacob Keller  * shadow registers are used to prepare the desired initial values. A special
4903cb4473SJacob Keller  * sync command is issued to trigger copying from the shadow registers into
5003cb4473SJacob Keller  * the appropriate source and PHY registers simultaneously.
513a749623SJacob Keller  *
523a749623SJacob Keller  * The driver supports devices which have different PHYs with subtly different
533a749623SJacob Keller  * mechanisms to program and control the timers. We divide the devices into
543a749623SJacob Keller  * families named after the first major device, E810 and similar devices, and
553a749623SJacob Keller  * E822 and similar devices.
563a749623SJacob Keller  *
573a749623SJacob Keller  * - E822 based devices have additional support for fine grained Vernier
583a749623SJacob Keller  *   calibration which requires significant setup
593a749623SJacob Keller  * - The layout of timestamp data in the PHY register blocks is different
603a749623SJacob Keller  * - The way timer synchronization commands are issued is different.
613a749623SJacob Keller  *
623a749623SJacob Keller  * To support this, very low level functions have an e810 or e822 suffix
633a749623SJacob Keller  * indicating what type of device they work on. Higher level abstractions for
643a749623SJacob Keller  * tasks that can be done on both devices do not have the suffix and will
653a749623SJacob Keller  * correctly look up the appropriate low level function when running.
663a749623SJacob Keller  *
673a749623SJacob Keller  * Functions which only make sense on a single device family may not have
683a749623SJacob Keller  * a suitable generic implementation
6903cb4473SJacob Keller  */
7003cb4473SJacob Keller 
7103cb4473SJacob Keller /**
7203cb4473SJacob Keller  * ice_get_ptp_src_clock_index - determine source clock index
7303cb4473SJacob Keller  * @hw: pointer to HW struct
7403cb4473SJacob Keller  *
7503cb4473SJacob Keller  * Determine the source clock index currently in use, based on device
7603cb4473SJacob Keller  * capabilities reported during initialization.
7703cb4473SJacob Keller  */
7803cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw)
7903cb4473SJacob Keller {
8003cb4473SJacob Keller 	return hw->func_caps.ts_func_info.tmr_index_assoc;
8103cb4473SJacob Keller }
8203cb4473SJacob Keller 
833a749623SJacob Keller /**
843a749623SJacob Keller  * ice_ptp_read_src_incval - Read source timer increment value
853a749623SJacob Keller  * @hw: pointer to HW struct
863a749623SJacob Keller  *
873a749623SJacob Keller  * Read the increment value of the source timer and return it.
883a749623SJacob Keller  */
893a749623SJacob Keller static u64 ice_ptp_read_src_incval(struct ice_hw *hw)
903a749623SJacob Keller {
913a749623SJacob Keller 	u32 lo, hi;
923a749623SJacob Keller 	u8 tmr_idx;
933a749623SJacob Keller 
943a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
953a749623SJacob Keller 
963a749623SJacob Keller 	lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
973a749623SJacob Keller 	hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
983a749623SJacob Keller 
993a749623SJacob Keller 	return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo;
1003a749623SJacob Keller }
1013a749623SJacob Keller 
1023a749623SJacob Keller /**
1033a749623SJacob Keller  * ice_ptp_src_cmd - Prepare source timer for a timer command
1043a749623SJacob Keller  * @hw: pointer to HW structure
1053a749623SJacob Keller  * @cmd: Timer command
1063a749623SJacob Keller  *
1073a749623SJacob Keller  * Prepare the source timer for an upcoming timer sync command.
1083a749623SJacob Keller  */
1093a749623SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
1103a749623SJacob Keller {
1113a749623SJacob Keller 	u32 cmd_val;
1123a749623SJacob Keller 	u8 tmr_idx;
1133a749623SJacob Keller 
1143a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
1153a749623SJacob Keller 	cmd_val = tmr_idx << SEL_CPK_SRC;
1163a749623SJacob Keller 
1173a749623SJacob Keller 	switch (cmd) {
1183a749623SJacob Keller 	case INIT_TIME:
1193a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_INIT_TIME;
1203a749623SJacob Keller 		break;
1213a749623SJacob Keller 	case INIT_INCVAL:
1223a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_INIT_INCVAL;
1233a749623SJacob Keller 		break;
1243a749623SJacob Keller 	case ADJ_TIME:
1253a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_ADJ_TIME;
1263a749623SJacob Keller 		break;
1273a749623SJacob Keller 	case ADJ_TIME_AT_TIME:
1283a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME;
1293a749623SJacob Keller 		break;
1303a749623SJacob Keller 	case READ_TIME:
1313a749623SJacob Keller 		cmd_val |= GLTSYN_CMD_READ_TIME;
1323a749623SJacob Keller 		break;
1333a749623SJacob Keller 	}
1343a749623SJacob Keller 
1353a749623SJacob Keller 	wr32(hw, GLTSYN_CMD, cmd_val);
1363a749623SJacob Keller }
1373a749623SJacob Keller 
1383a749623SJacob Keller /**
1393a749623SJacob Keller  * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands
1403a749623SJacob Keller  * @hw: pointer to HW struct
1413a749623SJacob Keller  *
1423a749623SJacob Keller  * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the
1433a749623SJacob Keller  * write immediately. This triggers the hardware to begin executing all of the
1443a749623SJacob Keller  * source and PHY timer commands synchronously.
1453a749623SJacob Keller  */
1463a749623SJacob Keller static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
1473a749623SJacob Keller {
1483a749623SJacob Keller 	wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD);
1493a749623SJacob Keller 	ice_flush(hw);
1503a749623SJacob Keller }
1513a749623SJacob Keller 
1523a749623SJacob Keller /* E822 family functions
1533a749623SJacob Keller  *
1543a749623SJacob Keller  * The following functions operate on the E822 family of devices.
1553a749623SJacob Keller  */
1563a749623SJacob Keller 
1573a749623SJacob Keller /**
1583a749623SJacob Keller  * ice_fill_phy_msg_e822 - Fill message data for a PHY register access
1593a749623SJacob Keller  * @msg: the PHY message buffer to fill in
1603a749623SJacob Keller  * @port: the port to access
1613a749623SJacob Keller  * @offset: the register offset
1623a749623SJacob Keller  */
1633a749623SJacob Keller static void
1643a749623SJacob Keller ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
1653a749623SJacob Keller {
1663a749623SJacob Keller 	int phy_port, phy, quadtype;
1673a749623SJacob Keller 
1683a749623SJacob Keller 	phy_port = port % ICE_PORTS_PER_PHY;
1693a749623SJacob Keller 	phy = port / ICE_PORTS_PER_PHY;
1703a749623SJacob Keller 	quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE;
1713a749623SJacob Keller 
1723a749623SJacob Keller 	if (quadtype == 0) {
1733a749623SJacob Keller 		msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
1743a749623SJacob Keller 		msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port);
1753a749623SJacob Keller 	} else {
1763a749623SJacob Keller 		msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port);
1773a749623SJacob Keller 		msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port);
1783a749623SJacob Keller 	}
1793a749623SJacob Keller 
1803a749623SJacob Keller 	if (phy == 0)
1813a749623SJacob Keller 		msg->dest_dev = rmn_0;
1823a749623SJacob Keller 	else if (phy == 1)
1833a749623SJacob Keller 		msg->dest_dev = rmn_1;
1843a749623SJacob Keller 	else
1853a749623SJacob Keller 		msg->dest_dev = rmn_2;
1863a749623SJacob Keller }
1873a749623SJacob Keller 
1883a749623SJacob Keller /**
1893a749623SJacob Keller  * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register
1903a749623SJacob Keller  * @low_addr: the low address to check
1913a749623SJacob Keller  * @high_addr: on return, contains the high address of the 64bit register
1923a749623SJacob Keller  *
1933a749623SJacob Keller  * Checks if the provided low address is one of the known 64bit PHY values
1943a749623SJacob Keller  * represented as two 32bit registers. If it is, return the appropriate high
1953a749623SJacob Keller  * register offset to use.
1963a749623SJacob Keller  */
1973a749623SJacob Keller static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
1983a749623SJacob Keller {
1993a749623SJacob Keller 	switch (low_addr) {
2003a749623SJacob Keller 	case P_REG_PAR_PCS_TX_OFFSET_L:
2013a749623SJacob Keller 		*high_addr = P_REG_PAR_PCS_TX_OFFSET_U;
2023a749623SJacob Keller 		return true;
2033a749623SJacob Keller 	case P_REG_PAR_PCS_RX_OFFSET_L:
2043a749623SJacob Keller 		*high_addr = P_REG_PAR_PCS_RX_OFFSET_U;
2053a749623SJacob Keller 		return true;
2063a749623SJacob Keller 	case P_REG_PAR_TX_TIME_L:
2073a749623SJacob Keller 		*high_addr = P_REG_PAR_TX_TIME_U;
2083a749623SJacob Keller 		return true;
2093a749623SJacob Keller 	case P_REG_PAR_RX_TIME_L:
2103a749623SJacob Keller 		*high_addr = P_REG_PAR_RX_TIME_U;
2113a749623SJacob Keller 		return true;
2123a749623SJacob Keller 	case P_REG_TOTAL_TX_OFFSET_L:
2133a749623SJacob Keller 		*high_addr = P_REG_TOTAL_TX_OFFSET_U;
2143a749623SJacob Keller 		return true;
2153a749623SJacob Keller 	case P_REG_TOTAL_RX_OFFSET_L:
2163a749623SJacob Keller 		*high_addr = P_REG_TOTAL_RX_OFFSET_U;
2173a749623SJacob Keller 		return true;
2183a749623SJacob Keller 	case P_REG_UIX66_10G_40G_L:
2193a749623SJacob Keller 		*high_addr = P_REG_UIX66_10G_40G_U;
2203a749623SJacob Keller 		return true;
2213a749623SJacob Keller 	case P_REG_UIX66_25G_100G_L:
2223a749623SJacob Keller 		*high_addr = P_REG_UIX66_25G_100G_U;
2233a749623SJacob Keller 		return true;
2243a749623SJacob Keller 	case P_REG_TX_CAPTURE_L:
2253a749623SJacob Keller 		*high_addr = P_REG_TX_CAPTURE_U;
2263a749623SJacob Keller 		return true;
2273a749623SJacob Keller 	case P_REG_RX_CAPTURE_L:
2283a749623SJacob Keller 		*high_addr = P_REG_RX_CAPTURE_U;
2293a749623SJacob Keller 		return true;
2303a749623SJacob Keller 	case P_REG_TX_TIMER_INC_PRE_L:
2313a749623SJacob Keller 		*high_addr = P_REG_TX_TIMER_INC_PRE_U;
2323a749623SJacob Keller 		return true;
2333a749623SJacob Keller 	case P_REG_RX_TIMER_INC_PRE_L:
2343a749623SJacob Keller 		*high_addr = P_REG_RX_TIMER_INC_PRE_U;
2353a749623SJacob Keller 		return true;
2363a749623SJacob Keller 	default:
2373a749623SJacob Keller 		return false;
2383a749623SJacob Keller 	}
2393a749623SJacob Keller }
2403a749623SJacob Keller 
2413a749623SJacob Keller /**
2423a749623SJacob Keller  * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register
2433a749623SJacob Keller  * @low_addr: the low address to check
2443a749623SJacob Keller  * @high_addr: on return, contains the high address of the 40bit value
2453a749623SJacob Keller  *
2463a749623SJacob Keller  * Checks if the provided low address is one of the known 40bit PHY values
2473a749623SJacob Keller  * split into two registers with the lower 8 bits in the low register and the
2483a749623SJacob Keller  * upper 32 bits in the high register. If it is, return the appropriate high
2493a749623SJacob Keller  * register offset to use.
2503a749623SJacob Keller  */
2513a749623SJacob Keller static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
2523a749623SJacob Keller {
2533a749623SJacob Keller 	switch (low_addr) {
2543a749623SJacob Keller 	case P_REG_TIMETUS_L:
2553a749623SJacob Keller 		*high_addr = P_REG_TIMETUS_U;
2563a749623SJacob Keller 		return true;
2573a749623SJacob Keller 	case P_REG_PAR_RX_TUS_L:
2583a749623SJacob Keller 		*high_addr = P_REG_PAR_RX_TUS_U;
2593a749623SJacob Keller 		return true;
2603a749623SJacob Keller 	case P_REG_PAR_TX_TUS_L:
2613a749623SJacob Keller 		*high_addr = P_REG_PAR_TX_TUS_U;
2623a749623SJacob Keller 		return true;
2633a749623SJacob Keller 	case P_REG_PCS_RX_TUS_L:
2643a749623SJacob Keller 		*high_addr = P_REG_PCS_RX_TUS_U;
2653a749623SJacob Keller 		return true;
2663a749623SJacob Keller 	case P_REG_PCS_TX_TUS_L:
2673a749623SJacob Keller 		*high_addr = P_REG_PCS_TX_TUS_U;
2683a749623SJacob Keller 		return true;
2693a749623SJacob Keller 	case P_REG_DESK_PAR_RX_TUS_L:
2703a749623SJacob Keller 		*high_addr = P_REG_DESK_PAR_RX_TUS_U;
2713a749623SJacob Keller 		return true;
2723a749623SJacob Keller 	case P_REG_DESK_PAR_TX_TUS_L:
2733a749623SJacob Keller 		*high_addr = P_REG_DESK_PAR_TX_TUS_U;
2743a749623SJacob Keller 		return true;
2753a749623SJacob Keller 	case P_REG_DESK_PCS_RX_TUS_L:
2763a749623SJacob Keller 		*high_addr = P_REG_DESK_PCS_RX_TUS_U;
2773a749623SJacob Keller 		return true;
2783a749623SJacob Keller 	case P_REG_DESK_PCS_TX_TUS_L:
2793a749623SJacob Keller 		*high_addr = P_REG_DESK_PCS_TX_TUS_U;
2803a749623SJacob Keller 		return true;
2813a749623SJacob Keller 	default:
2823a749623SJacob Keller 		return false;
2833a749623SJacob Keller 	}
2843a749623SJacob Keller }
2853a749623SJacob Keller 
2863a749623SJacob Keller /**
2873a749623SJacob Keller  * ice_read_phy_reg_e822 - Read a PHY register
2883a749623SJacob Keller  * @hw: pointer to the HW struct
2893a749623SJacob Keller  * @port: PHY port to read from
2903a749623SJacob Keller  * @offset: PHY register offset to read
2913a749623SJacob Keller  * @val: on return, the contents read from the PHY
2923a749623SJacob Keller  *
2933a749623SJacob Keller  * Read a PHY register for the given port over the device sideband queue.
2943a749623SJacob Keller  */
2953a749623SJacob Keller int
2963a749623SJacob Keller ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
2973a749623SJacob Keller {
2983a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
2993a749623SJacob Keller 	int err;
3003a749623SJacob Keller 
3013a749623SJacob Keller 	ice_fill_phy_msg_e822(&msg, port, offset);
3023a749623SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
3033a749623SJacob Keller 
3043a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
3053a749623SJacob Keller 	if (err) {
3063a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
3073a749623SJacob Keller 			  err);
3083a749623SJacob Keller 		return err;
3093a749623SJacob Keller 	}
3103a749623SJacob Keller 
3113a749623SJacob Keller 	*val = msg.data;
3123a749623SJacob Keller 
3133a749623SJacob Keller 	return 0;
3143a749623SJacob Keller }
3153a749623SJacob Keller 
3163a749623SJacob Keller /**
3173a749623SJacob Keller  * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers
3183a749623SJacob Keller  * @hw: pointer to the HW struct
3193a749623SJacob Keller  * @port: PHY port to read from
3203a749623SJacob Keller  * @low_addr: offset of the lower register to read from
3213a749623SJacob Keller  * @val: on return, the contents of the 64bit value from the PHY registers
3223a749623SJacob Keller  *
3233a749623SJacob Keller  * Reads the two registers associated with a 64bit value and returns it in the
3243a749623SJacob Keller  * val pointer. The offset always specifies the lower register offset to use.
3253a749623SJacob Keller  * The high offset is looked up. This function only operates on registers
3263a749623SJacob Keller  * known to be two parts of a 64bit value.
3273a749623SJacob Keller  */
3283a749623SJacob Keller static int
3293a749623SJacob Keller ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
3303a749623SJacob Keller {
3313a749623SJacob Keller 	u32 low, high;
3323a749623SJacob Keller 	u16 high_addr;
3333a749623SJacob Keller 	int err;
3343a749623SJacob Keller 
3353a749623SJacob Keller 	/* Only operate on registers known to be split into two 32bit
3363a749623SJacob Keller 	 * registers.
3373a749623SJacob Keller 	 */
3383a749623SJacob Keller 	if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
3393a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
3403a749623SJacob Keller 			  low_addr);
3413a749623SJacob Keller 		return -EINVAL;
3423a749623SJacob Keller 	}
3433a749623SJacob Keller 
3443a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, low_addr, &low);
3453a749623SJacob Keller 	if (err) {
3463a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d",
3473a749623SJacob Keller 			  low_addr, err);
3483a749623SJacob Keller 		return err;
3493a749623SJacob Keller 	}
3503a749623SJacob Keller 
3513a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, high_addr, &high);
3523a749623SJacob Keller 	if (err) {
3533a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d",
3543a749623SJacob Keller 			  high_addr, err);
3553a749623SJacob Keller 		return err;
3563a749623SJacob Keller 	}
3573a749623SJacob Keller 
3583a749623SJacob Keller 	*val = (u64)high << 32 | low;
3593a749623SJacob Keller 
3603a749623SJacob Keller 	return 0;
3613a749623SJacob Keller }
3623a749623SJacob Keller 
3633a749623SJacob Keller /**
3643a749623SJacob Keller  * ice_write_phy_reg_e822 - Write a PHY register
3653a749623SJacob Keller  * @hw: pointer to the HW struct
3663a749623SJacob Keller  * @port: PHY port to write to
3673a749623SJacob Keller  * @offset: PHY register offset to write
3683a749623SJacob Keller  * @val: The value to write to the register
3693a749623SJacob Keller  *
3703a749623SJacob Keller  * Write a PHY register for the given port over the device sideband queue.
3713a749623SJacob Keller  */
3723a749623SJacob Keller int
3733a749623SJacob Keller ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
3743a749623SJacob Keller {
3753a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
3763a749623SJacob Keller 	int err;
3773a749623SJacob Keller 
3783a749623SJacob Keller 	ice_fill_phy_msg_e822(&msg, port, offset);
3793a749623SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
3803a749623SJacob Keller 	msg.data = val;
3813a749623SJacob Keller 
3823a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
3833a749623SJacob Keller 	if (err) {
3843a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
3853a749623SJacob Keller 			  err);
3863a749623SJacob Keller 		return err;
3873a749623SJacob Keller 	}
3883a749623SJacob Keller 
3893a749623SJacob Keller 	return 0;
3903a749623SJacob Keller }
3913a749623SJacob Keller 
3923a749623SJacob Keller /**
3933a749623SJacob Keller  * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY
3943a749623SJacob Keller  * @hw: pointer to the HW struct
3953a749623SJacob Keller  * @port: port to write to
3963a749623SJacob Keller  * @low_addr: offset of the low register
3973a749623SJacob Keller  * @val: 40b value to write
3983a749623SJacob Keller  *
3993a749623SJacob Keller  * Write the provided 40b value to the two associated registers by splitting
4003a749623SJacob Keller  * it up into two chunks, the lower 8 bits and the upper 32 bits.
4013a749623SJacob Keller  */
4023a749623SJacob Keller static int
4033a749623SJacob Keller ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
4043a749623SJacob Keller {
4053a749623SJacob Keller 	u32 low, high;
4063a749623SJacob Keller 	u16 high_addr;
4073a749623SJacob Keller 	int err;
4083a749623SJacob Keller 
4093a749623SJacob Keller 	/* Only operate on registers known to be split into a lower 8 bit
4103a749623SJacob Keller 	 * register and an upper 32 bit register.
4113a749623SJacob Keller 	 */
4123a749623SJacob Keller 	if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
4133a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n",
4143a749623SJacob Keller 			  low_addr);
4153a749623SJacob Keller 		return -EINVAL;
4163a749623SJacob Keller 	}
4173a749623SJacob Keller 
4183a749623SJacob Keller 	low = (u32)(val & P_REG_40B_LOW_M);
4193a749623SJacob Keller 	high = (u32)(val >> P_REG_40B_HIGH_S);
4203a749623SJacob Keller 
4213a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, low_addr, low);
4223a749623SJacob Keller 	if (err) {
4233a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
4243a749623SJacob Keller 			  low_addr, err);
4253a749623SJacob Keller 		return err;
4263a749623SJacob Keller 	}
4273a749623SJacob Keller 
4283a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, high_addr, high);
4293a749623SJacob Keller 	if (err) {
4303a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
4313a749623SJacob Keller 			  high_addr, err);
4323a749623SJacob Keller 		return err;
4333a749623SJacob Keller 	}
4343a749623SJacob Keller 
4353a749623SJacob Keller 	return 0;
4363a749623SJacob Keller }
4373a749623SJacob Keller 
4383a749623SJacob Keller /**
4393a749623SJacob Keller  * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers
4403a749623SJacob Keller  * @hw: pointer to the HW struct
4413a749623SJacob Keller  * @port: PHY port to read from
4423a749623SJacob Keller  * @low_addr: offset of the lower register to read from
4433a749623SJacob Keller  * @val: the contents of the 64bit value to write to PHY
4443a749623SJacob Keller  *
4453a749623SJacob Keller  * Write the 64bit value to the two associated 32bit PHY registers. The offset
4463a749623SJacob Keller  * is always specified as the lower register, and the high address is looked
4473a749623SJacob Keller  * up. This function only operates on registers known to be two parts of
4483a749623SJacob Keller  * a 64bit value.
4493a749623SJacob Keller  */
4503a749623SJacob Keller static int
4513a749623SJacob Keller ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
4523a749623SJacob Keller {
4533a749623SJacob Keller 	u32 low, high;
4543a749623SJacob Keller 	u16 high_addr;
4553a749623SJacob Keller 	int err;
4563a749623SJacob Keller 
4573a749623SJacob Keller 	/* Only operate on registers known to be split into two 32bit
4583a749623SJacob Keller 	 * registers.
4593a749623SJacob Keller 	 */
4603a749623SJacob Keller 	if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
4613a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
4623a749623SJacob Keller 			  low_addr);
4633a749623SJacob Keller 		return -EINVAL;
4643a749623SJacob Keller 	}
4653a749623SJacob Keller 
4663a749623SJacob Keller 	low = lower_32_bits(val);
4673a749623SJacob Keller 	high = upper_32_bits(val);
4683a749623SJacob Keller 
4693a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, low_addr, low);
4703a749623SJacob Keller 	if (err) {
4713a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
4723a749623SJacob Keller 			  low_addr, err);
4733a749623SJacob Keller 		return err;
4743a749623SJacob Keller 	}
4753a749623SJacob Keller 
4763a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, high_addr, high);
4773a749623SJacob Keller 	if (err) {
4783a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
4793a749623SJacob Keller 			  high_addr, err);
4803a749623SJacob Keller 		return err;
4813a749623SJacob Keller 	}
4823a749623SJacob Keller 
4833a749623SJacob Keller 	return 0;
4843a749623SJacob Keller }
4853a749623SJacob Keller 
4863a749623SJacob Keller /**
4873a749623SJacob Keller  * ice_fill_quad_msg_e822 - Fill message data for quad register access
4883a749623SJacob Keller  * @msg: the PHY message buffer to fill in
4893a749623SJacob Keller  * @quad: the quad to access
4903a749623SJacob Keller  * @offset: the register offset
4913a749623SJacob Keller  *
4923a749623SJacob Keller  * Fill a message buffer for accessing a register in a quad shared between
4933a749623SJacob Keller  * multiple PHYs.
4943a749623SJacob Keller  */
4953a749623SJacob Keller static void
4963a749623SJacob Keller ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
4973a749623SJacob Keller {
4983a749623SJacob Keller 	u32 addr;
4993a749623SJacob Keller 
5003a749623SJacob Keller 	msg->dest_dev = rmn_0;
5013a749623SJacob Keller 
5023a749623SJacob Keller 	if ((quad % ICE_NUM_QUAD_TYPE) == 0)
5033a749623SJacob Keller 		addr = Q_0_BASE + offset;
5043a749623SJacob Keller 	else
5053a749623SJacob Keller 		addr = Q_1_BASE + offset;
5063a749623SJacob Keller 
5073a749623SJacob Keller 	msg->msg_addr_low = lower_16_bits(addr);
5083a749623SJacob Keller 	msg->msg_addr_high = upper_16_bits(addr);
5093a749623SJacob Keller }
5103a749623SJacob Keller 
5113a749623SJacob Keller /**
5123a749623SJacob Keller  * ice_read_quad_reg_e822 - Read a PHY quad register
5133a749623SJacob Keller  * @hw: pointer to the HW struct
5143a749623SJacob Keller  * @quad: quad to read from
5153a749623SJacob Keller  * @offset: quad register offset to read
5163a749623SJacob Keller  * @val: on return, the contents read from the quad
5173a749623SJacob Keller  *
5183a749623SJacob Keller  * Read a quad register over the device sideband queue. Quad registers are
5193a749623SJacob Keller  * shared between multiple PHYs.
5203a749623SJacob Keller  */
5213a749623SJacob Keller int
5223a749623SJacob Keller ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
5233a749623SJacob Keller {
5243a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
5253a749623SJacob Keller 	int err;
5263a749623SJacob Keller 
5273a749623SJacob Keller 	if (quad >= ICE_MAX_QUAD)
5283a749623SJacob Keller 		return -EINVAL;
5293a749623SJacob Keller 
5303a749623SJacob Keller 	ice_fill_quad_msg_e822(&msg, quad, offset);
5313a749623SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
5323a749623SJacob Keller 
5333a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
5343a749623SJacob Keller 	if (err) {
5353a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
5363a749623SJacob Keller 			  err);
5373a749623SJacob Keller 		return err;
5383a749623SJacob Keller 	}
5393a749623SJacob Keller 
5403a749623SJacob Keller 	*val = msg.data;
5413a749623SJacob Keller 
5423a749623SJacob Keller 	return 0;
5433a749623SJacob Keller }
5443a749623SJacob Keller 
5453a749623SJacob Keller /**
5463a749623SJacob Keller  * ice_write_quad_reg_e822 - Write a PHY quad register
5473a749623SJacob Keller  * @hw: pointer to the HW struct
5483a749623SJacob Keller  * @quad: quad to write to
5493a749623SJacob Keller  * @offset: quad register offset to write
5503a749623SJacob Keller  * @val: The value to write to the register
5513a749623SJacob Keller  *
5523a749623SJacob Keller  * Write a quad register over the device sideband queue. Quad registers are
5533a749623SJacob Keller  * shared between multiple PHYs.
5543a749623SJacob Keller  */
5553a749623SJacob Keller int
5563a749623SJacob Keller ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
5573a749623SJacob Keller {
5583a749623SJacob Keller 	struct ice_sbq_msg_input msg = {0};
5593a749623SJacob Keller 	int err;
5603a749623SJacob Keller 
5613a749623SJacob Keller 	if (quad >= ICE_MAX_QUAD)
5623a749623SJacob Keller 		return -EINVAL;
5633a749623SJacob Keller 
5643a749623SJacob Keller 	ice_fill_quad_msg_e822(&msg, quad, offset);
5653a749623SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
5663a749623SJacob Keller 	msg.data = val;
5673a749623SJacob Keller 
5683a749623SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
5693a749623SJacob Keller 	if (err) {
5703a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
5713a749623SJacob Keller 			  err);
5723a749623SJacob Keller 		return err;
5733a749623SJacob Keller 	}
5743a749623SJacob Keller 
5753a749623SJacob Keller 	return 0;
5763a749623SJacob Keller }
5773a749623SJacob Keller 
5783a749623SJacob Keller /**
5793a749623SJacob Keller  * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block
5803a749623SJacob Keller  * @hw: pointer to the HW struct
5813a749623SJacob Keller  * @quad: the quad to read from
5823a749623SJacob Keller  * @idx: the timestamp index to read
5833a749623SJacob Keller  * @tstamp: on return, the 40bit timestamp value
5843a749623SJacob Keller  *
5853a749623SJacob Keller  * Read a 40bit timestamp value out of the two associated registers in the
5863a749623SJacob Keller  * quad memory block that is shared between the internal PHYs of the E822
5873a749623SJacob Keller  * family of devices.
5883a749623SJacob Keller  */
5893a749623SJacob Keller static int
5903a749623SJacob Keller ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
5913a749623SJacob Keller {
5923a749623SJacob Keller 	u16 lo_addr, hi_addr;
5933a749623SJacob Keller 	u32 lo, hi;
5943a749623SJacob Keller 	int err;
5953a749623SJacob Keller 
5963a749623SJacob Keller 	lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
5973a749623SJacob Keller 	hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
5983a749623SJacob Keller 
5993a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);
6003a749623SJacob Keller 	if (err) {
6013a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
6023a749623SJacob Keller 			  err);
6033a749623SJacob Keller 		return err;
6043a749623SJacob Keller 	}
6053a749623SJacob Keller 
6063a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);
6073a749623SJacob Keller 	if (err) {
6083a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
6093a749623SJacob Keller 			  err);
6103a749623SJacob Keller 		return err;
6113a749623SJacob Keller 	}
6123a749623SJacob Keller 
6133a749623SJacob Keller 	/* For E822 based internal PHYs, the timestamp is reported with the
6143a749623SJacob Keller 	 * lower 8 bits in the low register, and the upper 32 bits in the high
6153a749623SJacob Keller 	 * register.
6163a749623SJacob Keller 	 */
6173a749623SJacob Keller 	*tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M);
6183a749623SJacob Keller 
6193a749623SJacob Keller 	return 0;
6203a749623SJacob Keller }
6213a749623SJacob Keller 
6223a749623SJacob Keller /**
6233a749623SJacob Keller  * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block
6243a749623SJacob Keller  * @hw: pointer to the HW struct
6253a749623SJacob Keller  * @quad: the quad to read from
6263a749623SJacob Keller  * @idx: the timestamp index to reset
6273a749623SJacob Keller  *
6283a749623SJacob Keller  * Clear a timestamp, resetting its valid bit, from the PHY quad block that is
6293a749623SJacob Keller  * shared between the internal PHYs on the E822 devices.
6303a749623SJacob Keller  */
6313a749623SJacob Keller static int
6323a749623SJacob Keller ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
6333a749623SJacob Keller {
6343a749623SJacob Keller 	u16 lo_addr, hi_addr;
6353a749623SJacob Keller 	int err;
6363a749623SJacob Keller 
6373a749623SJacob Keller 	lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
6383a749623SJacob Keller 	hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
6393a749623SJacob Keller 
6403a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0);
6413a749623SJacob Keller 	if (err) {
6423a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
6433a749623SJacob Keller 			  err);
6443a749623SJacob Keller 		return err;
6453a749623SJacob Keller 	}
6463a749623SJacob Keller 
6473a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0);
6483a749623SJacob Keller 	if (err) {
6493a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
6503a749623SJacob Keller 			  err);
6513a749623SJacob Keller 		return err;
6523a749623SJacob Keller 	}
6533a749623SJacob Keller 
6543a749623SJacob Keller 	return 0;
6553a749623SJacob Keller }
6563a749623SJacob Keller 
6573a749623SJacob Keller /**
658*b111ab5aSJacob Keller  * ice_read_cgu_reg_e822 - Read a CGU register
659*b111ab5aSJacob Keller  * @hw: pointer to the HW struct
660*b111ab5aSJacob Keller  * @addr: Register address to read
661*b111ab5aSJacob Keller  * @val: storage for register value read
662*b111ab5aSJacob Keller  *
663*b111ab5aSJacob Keller  * Read the contents of a register of the Clock Generation Unit. Only
664*b111ab5aSJacob Keller  * applicable to E822 devices.
665*b111ab5aSJacob Keller  */
666*b111ab5aSJacob Keller static int
667*b111ab5aSJacob Keller ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
668*b111ab5aSJacob Keller {
669*b111ab5aSJacob Keller 	struct ice_sbq_msg_input cgu_msg;
670*b111ab5aSJacob Keller 	int err;
671*b111ab5aSJacob Keller 
672*b111ab5aSJacob Keller 	cgu_msg.opcode = ice_sbq_msg_rd;
673*b111ab5aSJacob Keller 	cgu_msg.dest_dev = cgu;
674*b111ab5aSJacob Keller 	cgu_msg.msg_addr_low = addr;
675*b111ab5aSJacob Keller 	cgu_msg.msg_addr_high = 0x0;
676*b111ab5aSJacob Keller 
677*b111ab5aSJacob Keller 	err = ice_sbq_rw_reg(hw, &cgu_msg);
678*b111ab5aSJacob Keller 	if (err) {
679*b111ab5aSJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n",
680*b111ab5aSJacob Keller 			  addr, err);
681*b111ab5aSJacob Keller 		return err;
682*b111ab5aSJacob Keller 	}
683*b111ab5aSJacob Keller 
684*b111ab5aSJacob Keller 	*val = cgu_msg.data;
685*b111ab5aSJacob Keller 
686*b111ab5aSJacob Keller 	return err;
687*b111ab5aSJacob Keller }
688*b111ab5aSJacob Keller 
689*b111ab5aSJacob Keller /**
690*b111ab5aSJacob Keller  * ice_write_cgu_reg_e822 - Write a CGU register
691*b111ab5aSJacob Keller  * @hw: pointer to the HW struct
692*b111ab5aSJacob Keller  * @addr: Register address to write
693*b111ab5aSJacob Keller  * @val: value to write into the register
694*b111ab5aSJacob Keller  *
695*b111ab5aSJacob Keller  * Write the specified value to a register of the Clock Generation Unit. Only
696*b111ab5aSJacob Keller  * applicable to E822 devices.
697*b111ab5aSJacob Keller  */
698*b111ab5aSJacob Keller static int
699*b111ab5aSJacob Keller ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val)
700*b111ab5aSJacob Keller {
701*b111ab5aSJacob Keller 	struct ice_sbq_msg_input cgu_msg;
702*b111ab5aSJacob Keller 	int err;
703*b111ab5aSJacob Keller 
704*b111ab5aSJacob Keller 	cgu_msg.opcode = ice_sbq_msg_wr;
705*b111ab5aSJacob Keller 	cgu_msg.dest_dev = cgu;
706*b111ab5aSJacob Keller 	cgu_msg.msg_addr_low = addr;
707*b111ab5aSJacob Keller 	cgu_msg.msg_addr_high = 0x0;
708*b111ab5aSJacob Keller 	cgu_msg.data = val;
709*b111ab5aSJacob Keller 
710*b111ab5aSJacob Keller 	err = ice_sbq_rw_reg(hw, &cgu_msg);
711*b111ab5aSJacob Keller 	if (err) {
712*b111ab5aSJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n",
713*b111ab5aSJacob Keller 			  addr, err);
714*b111ab5aSJacob Keller 		return err;
715*b111ab5aSJacob Keller 	}
716*b111ab5aSJacob Keller 
717*b111ab5aSJacob Keller 	return err;
718*b111ab5aSJacob Keller }
719*b111ab5aSJacob Keller 
720*b111ab5aSJacob Keller /**
721*b111ab5aSJacob Keller  * ice_clk_freq_str - Convert time_ref_freq to string
722*b111ab5aSJacob Keller  * @clk_freq: Clock frequency
723*b111ab5aSJacob Keller  *
724*b111ab5aSJacob Keller  * Convert the specified TIME_REF clock frequency to a string.
725*b111ab5aSJacob Keller  */
726*b111ab5aSJacob Keller static const char *ice_clk_freq_str(u8 clk_freq)
727*b111ab5aSJacob Keller {
728*b111ab5aSJacob Keller 	switch ((enum ice_time_ref_freq)clk_freq) {
729*b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_25_000:
730*b111ab5aSJacob Keller 		return "25 MHz";
731*b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_122_880:
732*b111ab5aSJacob Keller 		return "122.88 MHz";
733*b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_125_000:
734*b111ab5aSJacob Keller 		return "125 MHz";
735*b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_153_600:
736*b111ab5aSJacob Keller 		return "153.6 MHz";
737*b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_156_250:
738*b111ab5aSJacob Keller 		return "156.25 MHz";
739*b111ab5aSJacob Keller 	case ICE_TIME_REF_FREQ_245_760:
740*b111ab5aSJacob Keller 		return "245.76 MHz";
741*b111ab5aSJacob Keller 	default:
742*b111ab5aSJacob Keller 		return "Unknown";
743*b111ab5aSJacob Keller 	}
744*b111ab5aSJacob Keller }
745*b111ab5aSJacob Keller 
746*b111ab5aSJacob Keller /**
747*b111ab5aSJacob Keller  * ice_clk_src_str - Convert time_ref_src to string
748*b111ab5aSJacob Keller  * @clk_src: Clock source
749*b111ab5aSJacob Keller  *
750*b111ab5aSJacob Keller  * Convert the specified clock source to its string name.
751*b111ab5aSJacob Keller  */
752*b111ab5aSJacob Keller static const char *ice_clk_src_str(u8 clk_src)
753*b111ab5aSJacob Keller {
754*b111ab5aSJacob Keller 	switch ((enum ice_clk_src)clk_src) {
755*b111ab5aSJacob Keller 	case ICE_CLK_SRC_TCX0:
756*b111ab5aSJacob Keller 		return "TCX0";
757*b111ab5aSJacob Keller 	case ICE_CLK_SRC_TIME_REF:
758*b111ab5aSJacob Keller 		return "TIME_REF";
759*b111ab5aSJacob Keller 	default:
760*b111ab5aSJacob Keller 		return "Unknown";
761*b111ab5aSJacob Keller 	}
762*b111ab5aSJacob Keller }
763*b111ab5aSJacob Keller 
764*b111ab5aSJacob Keller /**
765*b111ab5aSJacob Keller  * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit
766*b111ab5aSJacob Keller  * @hw: pointer to the HW struct
767*b111ab5aSJacob Keller  * @clk_freq: Clock frequency to program
768*b111ab5aSJacob Keller  * @clk_src: Clock source to select (TIME_REF, or TCX0)
769*b111ab5aSJacob Keller  *
770*b111ab5aSJacob Keller  * Configure the Clock Generation Unit with the desired clock frequency and
771*b111ab5aSJacob Keller  * time reference, enabling the PLL which drives the PTP hardware clock.
772*b111ab5aSJacob Keller  */
773*b111ab5aSJacob Keller static int
774*b111ab5aSJacob Keller ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
775*b111ab5aSJacob Keller 		     enum ice_clk_src clk_src)
776*b111ab5aSJacob Keller {
777*b111ab5aSJacob Keller 	union tspll_ro_bwm_lf bwm_lf;
778*b111ab5aSJacob Keller 	union nac_cgu_dword19 dw19;
779*b111ab5aSJacob Keller 	union nac_cgu_dword22 dw22;
780*b111ab5aSJacob Keller 	union nac_cgu_dword24 dw24;
781*b111ab5aSJacob Keller 	union nac_cgu_dword9 dw9;
782*b111ab5aSJacob Keller 	int err;
783*b111ab5aSJacob Keller 
784*b111ab5aSJacob Keller 	if (clk_freq >= NUM_ICE_TIME_REF_FREQ) {
785*b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n",
786*b111ab5aSJacob Keller 			 clk_freq);
787*b111ab5aSJacob Keller 		return -EINVAL;
788*b111ab5aSJacob Keller 	}
789*b111ab5aSJacob Keller 
790*b111ab5aSJacob Keller 	if (clk_src >= NUM_ICE_CLK_SRC) {
791*b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n",
792*b111ab5aSJacob Keller 			 clk_src);
793*b111ab5aSJacob Keller 		return -EINVAL;
794*b111ab5aSJacob Keller 	}
795*b111ab5aSJacob Keller 
796*b111ab5aSJacob Keller 	if (clk_src == ICE_CLK_SRC_TCX0 &&
797*b111ab5aSJacob Keller 	    clk_freq != ICE_TIME_REF_FREQ_25_000) {
798*b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw),
799*b111ab5aSJacob Keller 			 "TCX0 only supports 25 MHz frequency\n");
800*b111ab5aSJacob Keller 		return -EINVAL;
801*b111ab5aSJacob Keller 	}
802*b111ab5aSJacob Keller 
803*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val);
804*b111ab5aSJacob Keller 	if (err)
805*b111ab5aSJacob Keller 		return err;
806*b111ab5aSJacob Keller 
807*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
808*b111ab5aSJacob Keller 	if (err)
809*b111ab5aSJacob Keller 		return err;
810*b111ab5aSJacob Keller 
811*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
812*b111ab5aSJacob Keller 	if (err)
813*b111ab5aSJacob Keller 		return err;
814*b111ab5aSJacob Keller 
815*b111ab5aSJacob Keller 	/* Log the current clock configuration */
816*b111ab5aSJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
817*b111ab5aSJacob Keller 		  dw24.field.ts_pll_enable ? "enabled" : "disabled",
818*b111ab5aSJacob Keller 		  ice_clk_src_str(dw24.field.time_ref_sel),
819*b111ab5aSJacob Keller 		  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
820*b111ab5aSJacob Keller 		  bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
821*b111ab5aSJacob Keller 
822*b111ab5aSJacob Keller 	/* Disable the PLL before changing the clock source or frequency */
823*b111ab5aSJacob Keller 	if (dw24.field.ts_pll_enable) {
824*b111ab5aSJacob Keller 		dw24.field.ts_pll_enable = 0;
825*b111ab5aSJacob Keller 
826*b111ab5aSJacob Keller 		err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
827*b111ab5aSJacob Keller 		if (err)
828*b111ab5aSJacob Keller 			return err;
829*b111ab5aSJacob Keller 	}
830*b111ab5aSJacob Keller 
831*b111ab5aSJacob Keller 	/* Set the frequency */
832*b111ab5aSJacob Keller 	dw9.field.time_ref_freq_sel = clk_freq;
833*b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val);
834*b111ab5aSJacob Keller 	if (err)
835*b111ab5aSJacob Keller 		return err;
836*b111ab5aSJacob Keller 
837*b111ab5aSJacob Keller 	/* Configure the TS PLL feedback divisor */
838*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val);
839*b111ab5aSJacob Keller 	if (err)
840*b111ab5aSJacob Keller 		return err;
841*b111ab5aSJacob Keller 
842*b111ab5aSJacob Keller 	dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
843*b111ab5aSJacob Keller 	dw19.field.tspll_ndivratio = 1;
844*b111ab5aSJacob Keller 
845*b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val);
846*b111ab5aSJacob Keller 	if (err)
847*b111ab5aSJacob Keller 		return err;
848*b111ab5aSJacob Keller 
849*b111ab5aSJacob Keller 	/* Configure the TS PLL post divisor */
850*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val);
851*b111ab5aSJacob Keller 	if (err)
852*b111ab5aSJacob Keller 		return err;
853*b111ab5aSJacob Keller 
854*b111ab5aSJacob Keller 	dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
855*b111ab5aSJacob Keller 	dw22.field.time1588clk_sel_div2 = 0;
856*b111ab5aSJacob Keller 
857*b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val);
858*b111ab5aSJacob Keller 	if (err)
859*b111ab5aSJacob Keller 		return err;
860*b111ab5aSJacob Keller 
861*b111ab5aSJacob Keller 	/* Configure the TS PLL pre divisor and clock source */
862*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
863*b111ab5aSJacob Keller 	if (err)
864*b111ab5aSJacob Keller 		return err;
865*b111ab5aSJacob Keller 
866*b111ab5aSJacob Keller 	dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div;
867*b111ab5aSJacob Keller 	dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
868*b111ab5aSJacob Keller 	dw24.field.time_ref_sel = clk_src;
869*b111ab5aSJacob Keller 
870*b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
871*b111ab5aSJacob Keller 	if (err)
872*b111ab5aSJacob Keller 		return err;
873*b111ab5aSJacob Keller 
874*b111ab5aSJacob Keller 	/* Finally, enable the PLL */
875*b111ab5aSJacob Keller 	dw24.field.ts_pll_enable = 1;
876*b111ab5aSJacob Keller 
877*b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
878*b111ab5aSJacob Keller 	if (err)
879*b111ab5aSJacob Keller 		return err;
880*b111ab5aSJacob Keller 
881*b111ab5aSJacob Keller 	/* Wait to verify if the PLL locks */
882*b111ab5aSJacob Keller 	usleep_range(1000, 5000);
883*b111ab5aSJacob Keller 
884*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
885*b111ab5aSJacob Keller 	if (err)
886*b111ab5aSJacob Keller 		return err;
887*b111ab5aSJacob Keller 
888*b111ab5aSJacob Keller 	if (!bwm_lf.field.plllock_true_lock_cri) {
889*b111ab5aSJacob Keller 		dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n");
890*b111ab5aSJacob Keller 		return -EBUSY;
891*b111ab5aSJacob Keller 	}
892*b111ab5aSJacob Keller 
893*b111ab5aSJacob Keller 	/* Log the current clock configuration */
894*b111ab5aSJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n",
895*b111ab5aSJacob Keller 		  dw24.field.ts_pll_enable ? "enabled" : "disabled",
896*b111ab5aSJacob Keller 		  ice_clk_src_str(dw24.field.time_ref_sel),
897*b111ab5aSJacob Keller 		  ice_clk_freq_str(dw9.field.time_ref_freq_sel),
898*b111ab5aSJacob Keller 		  bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked");
899*b111ab5aSJacob Keller 
900*b111ab5aSJacob Keller 	return 0;
901*b111ab5aSJacob Keller }
902*b111ab5aSJacob Keller 
903*b111ab5aSJacob Keller /**
904*b111ab5aSJacob Keller  * ice_init_cgu_e822 - Initialize CGU with settings from firmware
905*b111ab5aSJacob Keller  * @hw: pointer to the HW structure
906*b111ab5aSJacob Keller  *
907*b111ab5aSJacob Keller  * Initialize the Clock Generation Unit of the E822 device.
908*b111ab5aSJacob Keller  */
909*b111ab5aSJacob Keller static int ice_init_cgu_e822(struct ice_hw *hw)
910*b111ab5aSJacob Keller {
911*b111ab5aSJacob Keller 	struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
912*b111ab5aSJacob Keller 	union tspll_cntr_bist_settings cntr_bist;
913*b111ab5aSJacob Keller 	int err;
914*b111ab5aSJacob Keller 
915*b111ab5aSJacob Keller 	err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
916*b111ab5aSJacob Keller 				    &cntr_bist.val);
917*b111ab5aSJacob Keller 	if (err)
918*b111ab5aSJacob Keller 		return err;
919*b111ab5aSJacob Keller 
920*b111ab5aSJacob Keller 	/* Disable sticky lock detection so lock err reported is accurate */
921*b111ab5aSJacob Keller 	cntr_bist.field.i_plllock_sel_0 = 0;
922*b111ab5aSJacob Keller 	cntr_bist.field.i_plllock_sel_1 = 0;
923*b111ab5aSJacob Keller 
924*b111ab5aSJacob Keller 	err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
925*b111ab5aSJacob Keller 				     cntr_bist.val);
926*b111ab5aSJacob Keller 	if (err)
927*b111ab5aSJacob Keller 		return err;
928*b111ab5aSJacob Keller 
929*b111ab5aSJacob Keller 	/* Configure the CGU PLL using the parameters from the function
930*b111ab5aSJacob Keller 	 * capabilities.
931*b111ab5aSJacob Keller 	 */
932*b111ab5aSJacob Keller 	err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref,
933*b111ab5aSJacob Keller 				   (enum ice_clk_src)ts_info->clk_src);
934*b111ab5aSJacob Keller 	if (err)
935*b111ab5aSJacob Keller 		return err;
936*b111ab5aSJacob Keller 
937*b111ab5aSJacob Keller 	return 0;
938*b111ab5aSJacob Keller }
939*b111ab5aSJacob Keller 
940*b111ab5aSJacob Keller /**
9413a749623SJacob Keller  * ice_ptp_set_vernier_wl - Set the window length for vernier calibration
9423a749623SJacob Keller  * @hw: pointer to the HW struct
9433a749623SJacob Keller  *
9443a749623SJacob Keller  * Set the window length used for the vernier port calibration process.
9453a749623SJacob Keller  */
9463a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw)
9473a749623SJacob Keller {
9483a749623SJacob Keller 	u8 port;
9493a749623SJacob Keller 
9503a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
9513a749623SJacob Keller 		int err;
9523a749623SJacob Keller 
9533a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_WL,
9543a749623SJacob Keller 					     PTP_VERNIER_WL);
9553a749623SJacob Keller 		if (err) {
9563a749623SJacob Keller 			ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n",
9573a749623SJacob Keller 				  port, err);
9583a749623SJacob Keller 			return err;
9593a749623SJacob Keller 		}
9603a749623SJacob Keller 	}
9613a749623SJacob Keller 
9623a749623SJacob Keller 	return 0;
9633a749623SJacob Keller }
9643a749623SJacob Keller 
9653a749623SJacob Keller /**
9663a749623SJacob Keller  * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization
9673a749623SJacob Keller  * @hw: pointer to HW struct
9683a749623SJacob Keller  *
9693a749623SJacob Keller  * Perform PHC initialization steps specific to E822 devices.
9703a749623SJacob Keller  */
9713a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw)
9723a749623SJacob Keller {
973*b111ab5aSJacob Keller 	int err;
9743a749623SJacob Keller 	u32 regval;
9753a749623SJacob Keller 
9763a749623SJacob Keller 	/* Enable reading switch and PHY registers over the sideband queue */
9773a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1)
9783a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2)
9793a749623SJacob Keller 	regval = rd32(hw, PF_SB_REM_DEV_CTL);
9803a749623SJacob Keller 	regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ |
9813a749623SJacob Keller 		   PF_SB_REM_DEV_CTL_PHY0);
9823a749623SJacob Keller 	wr32(hw, PF_SB_REM_DEV_CTL, regval);
9833a749623SJacob Keller 
984*b111ab5aSJacob Keller 	/* Initialize the Clock Generation Unit */
985*b111ab5aSJacob Keller 	err = ice_init_cgu_e822(hw);
986*b111ab5aSJacob Keller 	if (err)
987*b111ab5aSJacob Keller 		return err;
988*b111ab5aSJacob Keller 
9893a749623SJacob Keller 	/* Set window length for all the ports */
9903a749623SJacob Keller 	return ice_ptp_set_vernier_wl(hw);
9913a749623SJacob Keller }
9923a749623SJacob Keller 
9933a749623SJacob Keller /**
9943a749623SJacob Keller  * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time
9953a749623SJacob Keller  * @hw: pointer to the HW struct
9963a749623SJacob Keller  * @time: Time to initialize the PHY port clocks to
9973a749623SJacob Keller  *
9983a749623SJacob Keller  * Program the PHY port registers with a new initial time value. The port
9993a749623SJacob Keller  * clock will be initialized once the driver issues an INIT_TIME sync
10003a749623SJacob Keller  * command. The time value is the upper 32 bits of the PHY timer, usually in
10013a749623SJacob Keller  * units of nominal nanoseconds.
10023a749623SJacob Keller  */
10033a749623SJacob Keller static int
10043a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
10053a749623SJacob Keller {
10063a749623SJacob Keller 	u64 phy_time;
10073a749623SJacob Keller 	u8 port;
10083a749623SJacob Keller 	int err;
10093a749623SJacob Keller 
10103a749623SJacob Keller 	/* The time represents the upper 32 bits of the PHY timer, so we need
10113a749623SJacob Keller 	 * to shift to account for this when programming.
10123a749623SJacob Keller 	 */
10133a749623SJacob Keller 	phy_time = (u64)time << 32;
10143a749623SJacob Keller 
10153a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
10163a749623SJacob Keller 		/* Tx case */
10173a749623SJacob Keller 		err = ice_write_64b_phy_reg_e822(hw, port,
10183a749623SJacob Keller 						 P_REG_TX_TIMER_INC_PRE_L,
10193a749623SJacob Keller 						 phy_time);
10203a749623SJacob Keller 		if (err)
10213a749623SJacob Keller 			goto exit_err;
10223a749623SJacob Keller 
10233a749623SJacob Keller 		/* Rx case */
10243a749623SJacob Keller 		err = ice_write_64b_phy_reg_e822(hw, port,
10253a749623SJacob Keller 						 P_REG_RX_TIMER_INC_PRE_L,
10263a749623SJacob Keller 						 phy_time);
10273a749623SJacob Keller 		if (err)
10283a749623SJacob Keller 			goto exit_err;
10293a749623SJacob Keller 	}
10303a749623SJacob Keller 
10313a749623SJacob Keller 	return 0;
10323a749623SJacob Keller 
10333a749623SJacob Keller exit_err:
10343a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n",
10353a749623SJacob Keller 		  port, err);
10363a749623SJacob Keller 
10373a749623SJacob Keller 	return err;
10383a749623SJacob Keller }
10393a749623SJacob Keller 
10403a749623SJacob Keller /**
10413a749623SJacob Keller  * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust
10423a749623SJacob Keller  * @hw: pointer to HW struct
10433a749623SJacob Keller  * @port: Port number to be programmed
10443a749623SJacob Keller  * @time: time in cycles to adjust the port Tx and Rx clocks
10453a749623SJacob Keller  *
10463a749623SJacob Keller  * Program the port for an atomic adjustment by writing the Tx and Rx timer
10473a749623SJacob Keller  * registers. The atomic adjustment won't be completed until the driver issues
10483a749623SJacob Keller  * an ADJ_TIME command.
10493a749623SJacob Keller  *
10503a749623SJacob Keller  * Note that time is not in units of nanoseconds. It is in clock time
10513a749623SJacob Keller  * including the lower sub-nanosecond portion of the port timer.
10523a749623SJacob Keller  *
10533a749623SJacob Keller  * Negative adjustments are supported using 2s complement arithmetic.
10543a749623SJacob Keller  */
10553a749623SJacob Keller int
10563a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time)
10573a749623SJacob Keller {
10583a749623SJacob Keller 	u32 l_time, u_time;
10593a749623SJacob Keller 	int err;
10603a749623SJacob Keller 
10613a749623SJacob Keller 	l_time = lower_32_bits(time);
10623a749623SJacob Keller 	u_time = upper_32_bits(time);
10633a749623SJacob Keller 
10643a749623SJacob Keller 	/* Tx case */
10653a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L,
10663a749623SJacob Keller 				     l_time);
10673a749623SJacob Keller 	if (err)
10683a749623SJacob Keller 		goto exit_err;
10693a749623SJacob Keller 
10703a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U,
10713a749623SJacob Keller 				     u_time);
10723a749623SJacob Keller 	if (err)
10733a749623SJacob Keller 		goto exit_err;
10743a749623SJacob Keller 
10753a749623SJacob Keller 	/* Rx case */
10763a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L,
10773a749623SJacob Keller 				     l_time);
10783a749623SJacob Keller 	if (err)
10793a749623SJacob Keller 		goto exit_err;
10803a749623SJacob Keller 
10813a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U,
10823a749623SJacob Keller 				     u_time);
10833a749623SJacob Keller 	if (err)
10843a749623SJacob Keller 		goto exit_err;
10853a749623SJacob Keller 
10863a749623SJacob Keller 	return 0;
10873a749623SJacob Keller 
10883a749623SJacob Keller exit_err:
10893a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n",
10903a749623SJacob Keller 		  port, err);
10913a749623SJacob Keller 	return err;
10923a749623SJacob Keller }
10933a749623SJacob Keller 
10943a749623SJacob Keller /**
10953a749623SJacob Keller  * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment
10963a749623SJacob Keller  * @hw: pointer to HW struct
10973a749623SJacob Keller  * @adj: adjustment in nanoseconds
10983a749623SJacob Keller  *
10993a749623SJacob Keller  * Prepare the PHY ports for an atomic time adjustment by programming the PHY
11003a749623SJacob Keller  * Tx and Rx port registers. The actual adjustment is completed by issuing an
11013a749623SJacob Keller  * ADJ_TIME or ADJ_TIME_AT_TIME sync command.
11023a749623SJacob Keller  */
11033a749623SJacob Keller static int
11043a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
11053a749623SJacob Keller {
11063a749623SJacob Keller 	s64 cycles;
11073a749623SJacob Keller 	u8 port;
11083a749623SJacob Keller 
11093a749623SJacob Keller 	/* The port clock supports adjustment of the sub-nanosecond portion of
11103a749623SJacob Keller 	 * the clock. We shift the provided adjustment in nanoseconds to
11113a749623SJacob Keller 	 * calculate the appropriate adjustment to program into the PHY ports.
11123a749623SJacob Keller 	 */
11133a749623SJacob Keller 	if (adj > 0)
11143a749623SJacob Keller 		cycles = (s64)adj << 32;
11153a749623SJacob Keller 	else
11163a749623SJacob Keller 		cycles = -(((s64)-adj) << 32);
11173a749623SJacob Keller 
11183a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
11193a749623SJacob Keller 		int err;
11203a749623SJacob Keller 
11213a749623SJacob Keller 		err = ice_ptp_prep_port_adj_e822(hw, port, cycles);
11223a749623SJacob Keller 		if (err)
11233a749623SJacob Keller 			return err;
11243a749623SJacob Keller 	}
11253a749623SJacob Keller 
11263a749623SJacob Keller 	return 0;
11273a749623SJacob Keller }
11283a749623SJacob Keller 
11293a749623SJacob Keller /**
11303a749623SJacob Keller  * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment
11313a749623SJacob Keller  * @hw: pointer to HW struct
11323a749623SJacob Keller  * @incval: new increment value to prepare
11333a749623SJacob Keller  *
11343a749623SJacob Keller  * Prepare each of the PHY ports for a new increment value by programming the
11353a749623SJacob Keller  * port's TIMETUS registers. The new increment value will be updated after
11363a749623SJacob Keller  * issuing an INIT_INCVAL command.
11373a749623SJacob Keller  */
11383a749623SJacob Keller static int
11393a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
11403a749623SJacob Keller {
11413a749623SJacob Keller 	int err;
11423a749623SJacob Keller 	u8 port;
11433a749623SJacob Keller 
11443a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
11453a749623SJacob Keller 		err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,
11463a749623SJacob Keller 						 incval);
11473a749623SJacob Keller 		if (err)
11483a749623SJacob Keller 			goto exit_err;
11493a749623SJacob Keller 	}
11503a749623SJacob Keller 
11513a749623SJacob Keller 	return 0;
11523a749623SJacob Keller 
11533a749623SJacob Keller exit_err:
11543a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n",
11553a749623SJacob Keller 		  port, err);
11563a749623SJacob Keller 
11573a749623SJacob Keller 	return err;
11583a749623SJacob Keller }
11593a749623SJacob Keller 
11603a749623SJacob Keller /**
11613a749623SJacob Keller  * ice_ptp_read_port_capture - Read a port's local time capture
11623a749623SJacob Keller  * @hw: pointer to HW struct
11633a749623SJacob Keller  * @port: Port number to read
11643a749623SJacob Keller  * @tx_ts: on return, the Tx port time capture
11653a749623SJacob Keller  * @rx_ts: on return, the Rx port time capture
11663a749623SJacob Keller  *
11673a749623SJacob Keller  * Read the port's Tx and Rx local time capture values.
11683a749623SJacob Keller  *
11693a749623SJacob Keller  * Note this has no equivalent for the E810 devices.
11703a749623SJacob Keller  */
11713a749623SJacob Keller static int
11723a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
11733a749623SJacob Keller {
11743a749623SJacob Keller 	int err;
11753a749623SJacob Keller 
11763a749623SJacob Keller 	/* Tx case */
11773a749623SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
11783a749623SJacob Keller 	if (err) {
11793a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n",
11803a749623SJacob Keller 			  err);
11813a749623SJacob Keller 		return err;
11823a749623SJacob Keller 	}
11833a749623SJacob Keller 
11843a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n",
11853a749623SJacob Keller 		  (unsigned long long)*tx_ts);
11863a749623SJacob Keller 
11873a749623SJacob Keller 	/* Rx case */
11883a749623SJacob Keller 	err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
11893a749623SJacob Keller 	if (err) {
11903a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n",
11913a749623SJacob Keller 			  err);
11923a749623SJacob Keller 		return err;
11933a749623SJacob Keller 	}
11943a749623SJacob Keller 
11953a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n",
11963a749623SJacob Keller 		  (unsigned long long)*rx_ts);
11973a749623SJacob Keller 
11983a749623SJacob Keller 	return 0;
11993a749623SJacob Keller }
12003a749623SJacob Keller 
12013a749623SJacob Keller /**
12023a749623SJacob Keller  * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command
12033a749623SJacob Keller  * @hw: pointer to HW struct
12043a749623SJacob Keller  * @port: Port to which cmd has to be sent
12053a749623SJacob Keller  * @cmd: Command to be sent to the port
12063a749623SJacob Keller  *
12073a749623SJacob Keller  * Prepare the requested port for an upcoming timer sync command.
12083a749623SJacob Keller  *
12093a749623SJacob Keller  * Note there is no equivalent of this operation on E810, as that device
12103a749623SJacob Keller  * always handles all external PHYs internally.
12113a749623SJacob Keller  */
12123a749623SJacob Keller static int
12133a749623SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
12143a749623SJacob Keller {
12153a749623SJacob Keller 	u32 cmd_val, val;
12163a749623SJacob Keller 	u8 tmr_idx;
12173a749623SJacob Keller 	int err;
12183a749623SJacob Keller 
12193a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
12203a749623SJacob Keller 	cmd_val = tmr_idx << SEL_PHY_SRC;
12213a749623SJacob Keller 	switch (cmd) {
12223a749623SJacob Keller 	case INIT_TIME:
12233a749623SJacob Keller 		cmd_val |= PHY_CMD_INIT_TIME;
12243a749623SJacob Keller 		break;
12253a749623SJacob Keller 	case INIT_INCVAL:
12263a749623SJacob Keller 		cmd_val |= PHY_CMD_INIT_INCVAL;
12273a749623SJacob Keller 		break;
12283a749623SJacob Keller 	case ADJ_TIME:
12293a749623SJacob Keller 		cmd_val |= PHY_CMD_ADJ_TIME;
12303a749623SJacob Keller 		break;
12313a749623SJacob Keller 	case READ_TIME:
12323a749623SJacob Keller 		cmd_val |= PHY_CMD_READ_TIME;
12333a749623SJacob Keller 		break;
12343a749623SJacob Keller 	case ADJ_TIME_AT_TIME:
12353a749623SJacob Keller 		cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME;
12363a749623SJacob Keller 		break;
12373a749623SJacob Keller 	}
12383a749623SJacob Keller 
12393a749623SJacob Keller 	/* Tx case */
12403a749623SJacob Keller 	/* Read, modify, write */
12413a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val);
12423a749623SJacob Keller 	if (err) {
12433a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n",
12443a749623SJacob Keller 			  err);
12453a749623SJacob Keller 		return err;
12463a749623SJacob Keller 	}
12473a749623SJacob Keller 
12483a749623SJacob Keller 	/* Modify necessary bits only and perform write */
12493a749623SJacob Keller 	val &= ~TS_CMD_MASK;
12503a749623SJacob Keller 	val |= cmd_val;
12513a749623SJacob Keller 
12523a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val);
12533a749623SJacob Keller 	if (err) {
12543a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n",
12553a749623SJacob Keller 			  err);
12563a749623SJacob Keller 		return err;
12573a749623SJacob Keller 	}
12583a749623SJacob Keller 
12593a749623SJacob Keller 	/* Rx case */
12603a749623SJacob Keller 	/* Read, modify, write */
12613a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val);
12623a749623SJacob Keller 	if (err) {
12633a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n",
12643a749623SJacob Keller 			  err);
12653a749623SJacob Keller 		return err;
12663a749623SJacob Keller 	}
12673a749623SJacob Keller 
12683a749623SJacob Keller 	/* Modify necessary bits only and perform write */
12693a749623SJacob Keller 	val &= ~TS_CMD_MASK;
12703a749623SJacob Keller 	val |= cmd_val;
12713a749623SJacob Keller 
12723a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val);
12733a749623SJacob Keller 	if (err) {
12743a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n",
12753a749623SJacob Keller 			  err);
12763a749623SJacob Keller 		return err;
12773a749623SJacob Keller 	}
12783a749623SJacob Keller 
12793a749623SJacob Keller 	return 0;
12803a749623SJacob Keller }
12813a749623SJacob Keller 
12823a749623SJacob Keller /**
12833a749623SJacob Keller  * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
12843a749623SJacob Keller  * @hw: pointer to the HW struct
12853a749623SJacob Keller  * @cmd: timer command to prepare
12863a749623SJacob Keller  *
12873a749623SJacob Keller  * Prepare all ports connected to this device for an upcoming timer sync
12883a749623SJacob Keller  * command.
12893a749623SJacob Keller  */
12903a749623SJacob Keller static int
12913a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
12923a749623SJacob Keller {
12933a749623SJacob Keller 	u8 port;
12943a749623SJacob Keller 
12953a749623SJacob Keller 	for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
12963a749623SJacob Keller 		int err;
12973a749623SJacob Keller 
12983a749623SJacob Keller 		err = ice_ptp_one_port_cmd(hw, port, cmd);
12993a749623SJacob Keller 		if (err)
13003a749623SJacob Keller 			return err;
13013a749623SJacob Keller 	}
13023a749623SJacob Keller 
13033a749623SJacob Keller 	return 0;
13043a749623SJacob Keller }
13053a749623SJacob Keller 
13063a749623SJacob Keller /* E822 Vernier calibration functions
13073a749623SJacob Keller  *
13083a749623SJacob Keller  * The following functions are used as part of the vernier calibration of
13093a749623SJacob Keller  * a port. This calibration increases the precision of the timestamps on the
13103a749623SJacob Keller  * port.
13113a749623SJacob Keller  */
13123a749623SJacob Keller 
13133a749623SJacob Keller /**
13143a749623SJacob Keller  * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode
13153a749623SJacob Keller  * @hw: pointer to HW struct
13163a749623SJacob Keller  * @port: the port to read from
13173a749623SJacob Keller  * @link_out: if non-NULL, holds link speed on success
13183a749623SJacob Keller  * @fec_out: if non-NULL, holds FEC algorithm on success
13193a749623SJacob Keller  *
13203a749623SJacob Keller  * Read the serdes data for the PHY port and extract the link speed and FEC
13213a749623SJacob Keller  * algorithm.
13223a749623SJacob Keller  */
13233a749623SJacob Keller static int
13243a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
13253a749623SJacob Keller 			       enum ice_ptp_link_spd *link_out,
13263a749623SJacob Keller 			       enum ice_ptp_fec_mode *fec_out)
13273a749623SJacob Keller {
13283a749623SJacob Keller 	enum ice_ptp_link_spd link;
13293a749623SJacob Keller 	enum ice_ptp_fec_mode fec;
13303a749623SJacob Keller 	u32 serdes;
13313a749623SJacob Keller 	int err;
13323a749623SJacob Keller 
13333a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);
13343a749623SJacob Keller 	if (err) {
13353a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n");
13363a749623SJacob Keller 		return err;
13373a749623SJacob Keller 	}
13383a749623SJacob Keller 
13393a749623SJacob Keller 	/* Determine the FEC algorithm */
13403a749623SJacob Keller 	fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes);
13413a749623SJacob Keller 
13423a749623SJacob Keller 	serdes &= P_REG_LINK_SPEED_SERDES_M;
13433a749623SJacob Keller 
13443a749623SJacob Keller 	/* Determine the link speed */
13453a749623SJacob Keller 	if (fec == ICE_PTP_FEC_MODE_RS_FEC) {
13463a749623SJacob Keller 		switch (serdes) {
13473a749623SJacob Keller 		case ICE_PTP_SERDES_25G:
13483a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_25G_RS;
13493a749623SJacob Keller 			break;
13503a749623SJacob Keller 		case ICE_PTP_SERDES_50G:
13513a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_50G_RS;
13523a749623SJacob Keller 			break;
13533a749623SJacob Keller 		case ICE_PTP_SERDES_100G:
13543a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_100G_RS;
13553a749623SJacob Keller 			break;
13563a749623SJacob Keller 		default:
13573a749623SJacob Keller 			return -EIO;
13583a749623SJacob Keller 		}
13593a749623SJacob Keller 	} else {
13603a749623SJacob Keller 		switch (serdes) {
13613a749623SJacob Keller 		case ICE_PTP_SERDES_1G:
13623a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_1G;
13633a749623SJacob Keller 			break;
13643a749623SJacob Keller 		case ICE_PTP_SERDES_10G:
13653a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_10G;
13663a749623SJacob Keller 			break;
13673a749623SJacob Keller 		case ICE_PTP_SERDES_25G:
13683a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_25G;
13693a749623SJacob Keller 			break;
13703a749623SJacob Keller 		case ICE_PTP_SERDES_40G:
13713a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_40G;
13723a749623SJacob Keller 			break;
13733a749623SJacob Keller 		case ICE_PTP_SERDES_50G:
13743a749623SJacob Keller 			link = ICE_PTP_LNK_SPD_50G;
13753a749623SJacob Keller 			break;
13763a749623SJacob Keller 		default:
13773a749623SJacob Keller 			return -EIO;
13783a749623SJacob Keller 		}
13793a749623SJacob Keller 	}
13803a749623SJacob Keller 
13813a749623SJacob Keller 	if (link_out)
13823a749623SJacob Keller 		*link_out = link;
13833a749623SJacob Keller 	if (fec_out)
13843a749623SJacob Keller 		*fec_out = fec;
13853a749623SJacob Keller 
13863a749623SJacob Keller 	return 0;
13873a749623SJacob Keller }
13883a749623SJacob Keller 
13893a749623SJacob Keller /**
13903a749623SJacob Keller  * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp
13913a749623SJacob Keller  * @hw: pointer to HW struct
13923a749623SJacob Keller  * @port: to configure the quad for
13933a749623SJacob Keller  */
13943a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
13953a749623SJacob Keller {
13963a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
13973a749623SJacob Keller 	int err;
13983a749623SJacob Keller 	u32 val;
13993a749623SJacob Keller 	u8 quad;
14003a749623SJacob Keller 
14013a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);
14023a749623SJacob Keller 	if (err) {
14033a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n",
14043a749623SJacob Keller 			  err);
14053a749623SJacob Keller 		return;
14063a749623SJacob Keller 	}
14073a749623SJacob Keller 
14083a749623SJacob Keller 	quad = port / ICE_PORTS_PER_QUAD;
14093a749623SJacob Keller 
14103a749623SJacob Keller 	err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
14113a749623SJacob Keller 	if (err) {
14123a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n",
14133a749623SJacob Keller 			  err);
14143a749623SJacob Keller 		return;
14153a749623SJacob Keller 	}
14163a749623SJacob Keller 
14173a749623SJacob Keller 	if (link_spd >= ICE_PTP_LNK_SPD_40G)
14183a749623SJacob Keller 		val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
14193a749623SJacob Keller 	else
14203a749623SJacob Keller 		val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
14213a749623SJacob Keller 
14223a749623SJacob Keller 	err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
14233a749623SJacob Keller 	if (err) {
14243a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n",
14253a749623SJacob Keller 			  err);
14263a749623SJacob Keller 		return;
14273a749623SJacob Keller 	}
14283a749623SJacob Keller }
14293a749623SJacob Keller 
14303a749623SJacob Keller /**
14313a749623SJacob Keller  * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822
14323a749623SJacob Keller  * @hw: pointer to the HW structure
14333a749623SJacob Keller  * @port: the port to configure
14343a749623SJacob Keller  *
14353a749623SJacob Keller  * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC
14363a749623SJacob Keller  * hardware clock time units (TUs). That is, determine the number of TUs per
14373a749623SJacob Keller  * serdes unit interval, and program the UIX registers with this conversion.
14383a749623SJacob Keller  *
14393a749623SJacob Keller  * This conversion is used as part of the calibration process when determining
14403a749623SJacob Keller  * the additional error of a timestamp vs the real time of transmission or
14413a749623SJacob Keller  * receipt of the packet.
14423a749623SJacob Keller  *
14433a749623SJacob Keller  * Hardware uses the number of TUs per 66 UIs, written to the UIX registers
14443a749623SJacob Keller  * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks.
14453a749623SJacob Keller  *
14463a749623SJacob Keller  * To calculate the conversion ratio, we use the following facts:
14473a749623SJacob Keller  *
14483a749623SJacob Keller  * a) the clock frequency in Hz (cycles per second)
14493a749623SJacob Keller  * b) the number of TUs per cycle (the increment value of the clock)
14503a749623SJacob Keller  * c) 1 second per 1 billion nanoseconds
14513a749623SJacob Keller  * d) the duration of 66 UIs in nanoseconds
14523a749623SJacob Keller  *
14533a749623SJacob Keller  * Given these facts, we can use the following table to work out what ratios
14543a749623SJacob Keller  * to multiply in order to get the number of TUs per 66 UIs:
14553a749623SJacob Keller  *
14563a749623SJacob Keller  * cycles |   1 second   | incval (TUs) | nanoseconds
14573a749623SJacob Keller  * -------+--------------+--------------+-------------
14583a749623SJacob Keller  * second | 1 billion ns |    cycle     |   66 UIs
14593a749623SJacob Keller  *
14603a749623SJacob Keller  * To perform the multiplication using integers without too much loss of
14613a749623SJacob Keller  * precision, we can take use the following equation:
14623a749623SJacob Keller  *
14633a749623SJacob Keller  * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion)
14643a749623SJacob Keller  *
14653a749623SJacob Keller  * We scale up to using 6600 UI instead of 66 in order to avoid fractional
14663a749623SJacob Keller  * nanosecond UIs (66 UI at 10G/40G is 6.4 ns)
14673a749623SJacob Keller  *
14683a749623SJacob Keller  * The increment value has a maximum expected range of about 34 bits, while
14693a749623SJacob Keller  * the frequency value is about 29 bits. Multiplying these values shouldn't
14703a749623SJacob Keller  * overflow the 64 bits. However, we must then further multiply them again by
14713a749623SJacob Keller  * the Serdes unit interval duration. To avoid overflow here, we split the
14723a749623SJacob Keller  * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and
14733a749623SJacob Keller  * a divide by 390,625,000. This does lose some precision, but avoids
14743a749623SJacob Keller  * miscalculation due to arithmetic overflow.
14753a749623SJacob Keller  */
14763a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
14773a749623SJacob Keller {
14783a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, uix;
14793a749623SJacob Keller 	int err;
14803a749623SJacob Keller 
14813a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
14823a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
14833a749623SJacob Keller 
14843a749623SJacob Keller 	/* Calculate TUs per second divided by 256 */
14853a749623SJacob Keller 	tu_per_sec = (cur_freq * clk_incval) >> 8;
14863a749623SJacob Keller 
14873a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */
14883a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */
14893a749623SJacob Keller 
14903a749623SJacob Keller 	/* Program the 10Gb/40Gb conversion ratio */
14913a749623SJacob Keller 	uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000);
14923a749623SJacob Keller 
14933a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
14943a749623SJacob Keller 					 uix);
14953a749623SJacob Keller 	if (err) {
14963a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n",
14973a749623SJacob Keller 			  err);
14983a749623SJacob Keller 		return err;
14993a749623SJacob Keller 	}
15003a749623SJacob Keller 
15013a749623SJacob Keller 	/* Program the 25Gb/100Gb conversion ratio */
15023a749623SJacob Keller 	uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000);
15033a749623SJacob Keller 
15043a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
15053a749623SJacob Keller 					 uix);
15063a749623SJacob Keller 	if (err) {
15073a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n",
15083a749623SJacob Keller 			  err);
15093a749623SJacob Keller 		return err;
15103a749623SJacob Keller 	}
15113a749623SJacob Keller 
15123a749623SJacob Keller 	return 0;
15133a749623SJacob Keller }
15143a749623SJacob Keller 
15153a749623SJacob Keller /**
15163a749623SJacob Keller  * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle
15173a749623SJacob Keller  * @hw: pointer to the HW struct
15183a749623SJacob Keller  * @port: port to configure
15193a749623SJacob Keller  *
15203a749623SJacob Keller  * Configure the number of TUs for the PAR and PCS clocks used as part of the
15213a749623SJacob Keller  * timestamp calibration process. This depends on the link speed, as the PHY
15223a749623SJacob Keller  * uses different markers depending on the speed.
15233a749623SJacob Keller  *
15243a749623SJacob Keller  * 1Gb/10Gb/25Gb:
15253a749623SJacob Keller  * - Tx/Rx PAR/PCS markers
15263a749623SJacob Keller  *
15273a749623SJacob Keller  * 25Gb RS:
15283a749623SJacob Keller  * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
15293a749623SJacob Keller  *
15303a749623SJacob Keller  * 40Gb/50Gb:
15313a749623SJacob Keller  * - Tx/Rx PAR/PCS markers
15323a749623SJacob Keller  * - Rx Deskew PAR/PCS markers
15333a749623SJacob Keller  *
15343a749623SJacob Keller  * 50G RS and 100GB RS:
15353a749623SJacob Keller  * - Tx/Rx Reed Solomon gearbox PAR/PCS markers
15363a749623SJacob Keller  * - Rx Deskew PAR/PCS markers
15373a749623SJacob Keller  * - Tx PAR/PCS markers
15383a749623SJacob Keller  *
15393a749623SJacob Keller  * To calculate the conversion, we use the PHC clock frequency (cycles per
15403a749623SJacob Keller  * second), the increment value (TUs per cycle), and the related PHY clock
15413a749623SJacob Keller  * frequency to calculate the TUs per unit of the PHY link clock. The
15423a749623SJacob Keller  * following table shows how the units convert:
15433a749623SJacob Keller  *
15443a749623SJacob Keller  * cycles |  TUs  | second
15453a749623SJacob Keller  * -------+-------+--------
15463a749623SJacob Keller  * second | cycle | cycles
15473a749623SJacob Keller  *
15483a749623SJacob Keller  * For each conversion register, look up the appropriate frequency from the
15493a749623SJacob Keller  * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program
15503a749623SJacob Keller  * this to the appropriate register, preparing hardware to perform timestamp
15513a749623SJacob Keller  * calibration to calculate the total Tx or Rx offset to adjust the timestamp
15523a749623SJacob Keller  * in order to calibrate for the internal PHY delays.
15533a749623SJacob Keller  *
15543a749623SJacob Keller  * Note that the increment value ranges up to ~34 bits, and the clock
15553a749623SJacob Keller  * frequency is ~29 bits, so multiplying them together should fit within the
15563a749623SJacob Keller  * 64 bit arithmetic.
15573a749623SJacob Keller  */
15583a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
15593a749623SJacob Keller {
15603a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, phy_tus;
15613a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
15623a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
15633a749623SJacob Keller 	int err;
15643a749623SJacob Keller 
15653a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
15663a749623SJacob Keller 	if (err)
15673a749623SJacob Keller 		return err;
15683a749623SJacob Keller 
15693a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
15703a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
15713a749623SJacob Keller 
15723a749623SJacob Keller 	/* Calculate TUs per cycle of the PHC clock */
15733a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
15743a749623SJacob Keller 
15753a749623SJacob Keller 	/* For each PHY conversion register, look up the appropriate link
15763a749623SJacob Keller 	 * speed frequency and determine the TUs per that clock's cycle time.
15773a749623SJacob Keller 	 * Split this into a high and low value and then program the
15783a749623SJacob Keller 	 * appropriate register. If that link speed does not use the
15793a749623SJacob Keller 	 * associated register, write zeros to clear it instead.
15803a749623SJacob Keller 	 */
15813a749623SJacob Keller 
15823a749623SJacob Keller 	/* P_REG_PAR_TX_TUS */
15833a749623SJacob Keller 	if (e822_vernier[link_spd].tx_par_clk)
15843a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
15853a749623SJacob Keller 				  e822_vernier[link_spd].tx_par_clk);
15863a749623SJacob Keller 	else
15873a749623SJacob Keller 		phy_tus = 0;
15883a749623SJacob Keller 
15893a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,
15903a749623SJacob Keller 					 phy_tus);
15913a749623SJacob Keller 	if (err)
15923a749623SJacob Keller 		return err;
15933a749623SJacob Keller 
15943a749623SJacob Keller 	/* P_REG_PAR_RX_TUS */
15953a749623SJacob Keller 	if (e822_vernier[link_spd].rx_par_clk)
15963a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
15973a749623SJacob Keller 				  e822_vernier[link_spd].rx_par_clk);
15983a749623SJacob Keller 	else
15993a749623SJacob Keller 		phy_tus = 0;
16003a749623SJacob Keller 
16013a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,
16023a749623SJacob Keller 					 phy_tus);
16033a749623SJacob Keller 	if (err)
16043a749623SJacob Keller 		return err;
16053a749623SJacob Keller 
16063a749623SJacob Keller 	/* P_REG_PCS_TX_TUS */
16073a749623SJacob Keller 	if (e822_vernier[link_spd].tx_pcs_clk)
16083a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16093a749623SJacob Keller 				  e822_vernier[link_spd].tx_pcs_clk);
16103a749623SJacob Keller 	else
16113a749623SJacob Keller 		phy_tus = 0;
16123a749623SJacob Keller 
16133a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,
16143a749623SJacob Keller 					 phy_tus);
16153a749623SJacob Keller 	if (err)
16163a749623SJacob Keller 		return err;
16173a749623SJacob Keller 
16183a749623SJacob Keller 	/* P_REG_PCS_RX_TUS */
16193a749623SJacob Keller 	if (e822_vernier[link_spd].rx_pcs_clk)
16203a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16213a749623SJacob Keller 				  e822_vernier[link_spd].rx_pcs_clk);
16223a749623SJacob Keller 	else
16233a749623SJacob Keller 		phy_tus = 0;
16243a749623SJacob Keller 
16253a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,
16263a749623SJacob Keller 					 phy_tus);
16273a749623SJacob Keller 	if (err)
16283a749623SJacob Keller 		return err;
16293a749623SJacob Keller 
16303a749623SJacob Keller 	/* P_REG_DESK_PAR_TX_TUS */
16313a749623SJacob Keller 	if (e822_vernier[link_spd].tx_desk_rsgb_par)
16323a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16333a749623SJacob Keller 				  e822_vernier[link_spd].tx_desk_rsgb_par);
16343a749623SJacob Keller 	else
16353a749623SJacob Keller 		phy_tus = 0;
16363a749623SJacob Keller 
16373a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,
16383a749623SJacob Keller 					 phy_tus);
16393a749623SJacob Keller 	if (err)
16403a749623SJacob Keller 		return err;
16413a749623SJacob Keller 
16423a749623SJacob Keller 	/* P_REG_DESK_PAR_RX_TUS */
16433a749623SJacob Keller 	if (e822_vernier[link_spd].rx_desk_rsgb_par)
16443a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16453a749623SJacob Keller 				  e822_vernier[link_spd].rx_desk_rsgb_par);
16463a749623SJacob Keller 	else
16473a749623SJacob Keller 		phy_tus = 0;
16483a749623SJacob Keller 
16493a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,
16503a749623SJacob Keller 					 phy_tus);
16513a749623SJacob Keller 	if (err)
16523a749623SJacob Keller 		return err;
16533a749623SJacob Keller 
16543a749623SJacob Keller 	/* P_REG_DESK_PCS_TX_TUS */
16553a749623SJacob Keller 	if (e822_vernier[link_spd].tx_desk_rsgb_pcs)
16563a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16573a749623SJacob Keller 				  e822_vernier[link_spd].tx_desk_rsgb_pcs);
16583a749623SJacob Keller 	else
16593a749623SJacob Keller 		phy_tus = 0;
16603a749623SJacob Keller 
16613a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,
16623a749623SJacob Keller 					 phy_tus);
16633a749623SJacob Keller 	if (err)
16643a749623SJacob Keller 		return err;
16653a749623SJacob Keller 
16663a749623SJacob Keller 	/* P_REG_DESK_PCS_RX_TUS */
16673a749623SJacob Keller 	if (e822_vernier[link_spd].rx_desk_rsgb_pcs)
16683a749623SJacob Keller 		phy_tus = div_u64(tu_per_sec,
16693a749623SJacob Keller 				  e822_vernier[link_spd].rx_desk_rsgb_pcs);
16703a749623SJacob Keller 	else
16713a749623SJacob Keller 		phy_tus = 0;
16723a749623SJacob Keller 
16733a749623SJacob Keller 	return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,
16743a749623SJacob Keller 					  phy_tus);
16753a749623SJacob Keller }
16763a749623SJacob Keller 
16773a749623SJacob Keller /**
16783a749623SJacob Keller  * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port
16793a749623SJacob Keller  * @hw: pointer to the HW struct
16803a749623SJacob Keller  * @link_spd: the Link speed to calculate for
16813a749623SJacob Keller  *
16823a749623SJacob Keller  * Calculate the fixed offset due to known static latency data.
16833a749623SJacob Keller  */
16843a749623SJacob Keller static u64
16853a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
16863a749623SJacob Keller {
16873a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
16883a749623SJacob Keller 
16893a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
16903a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
16913a749623SJacob Keller 
16923a749623SJacob Keller 	/* Calculate TUs per second */
16933a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
16943a749623SJacob Keller 
16953a749623SJacob Keller 	/* Calculate number of TUs to add for the fixed Tx latency. Since the
16963a749623SJacob Keller 	 * latency measurement is in 1/100th of a nanosecond, we need to
16973a749623SJacob Keller 	 * multiply by tu_per_sec and then divide by 1e11. This calculation
16983a749623SJacob Keller 	 * overflows 64 bit integer arithmetic, so break it up into two
16993a749623SJacob Keller 	 * divisions by 1e4 first then by 1e7.
17003a749623SJacob Keller 	 */
17013a749623SJacob Keller 	fixed_offset = div_u64(tu_per_sec, 10000);
17023a749623SJacob Keller 	fixed_offset *= e822_vernier[link_spd].tx_fixed_delay;
17033a749623SJacob Keller 	fixed_offset = div_u64(fixed_offset, 10000000);
17043a749623SJacob Keller 
17053a749623SJacob Keller 	return fixed_offset;
17063a749623SJacob Keller }
17073a749623SJacob Keller 
17083a749623SJacob Keller /**
17093a749623SJacob Keller  * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode
17103a749623SJacob Keller  * @hw: pointer to the HW struct
17113a749623SJacob Keller  * @port: the PHY port to configure
17123a749623SJacob Keller  *
17133a749623SJacob Keller  * Calculate and program the fixed Tx offset, and indicate that the offset is
17143a749623SJacob Keller  * ready. This can be used when operating in bypass mode.
17153a749623SJacob Keller  */
17163a749623SJacob Keller static int
17173a749623SJacob Keller ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port)
17183a749623SJacob Keller {
17193a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
17203a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
17213a749623SJacob Keller 	u64 total_offset;
17223a749623SJacob Keller 	int err;
17233a749623SJacob Keller 
17243a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
17253a749623SJacob Keller 	if (err)
17263a749623SJacob Keller 		return err;
17273a749623SJacob Keller 
17283a749623SJacob Keller 	total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
17293a749623SJacob Keller 
17303a749623SJacob Keller 	/* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L
17313a749623SJacob Keller 	 * register, then indicate that the Tx offset is ready. After this,
17323a749623SJacob Keller 	 * timestamps will be enabled.
17333a749623SJacob Keller 	 *
17343a749623SJacob Keller 	 * Note that this skips including the more precise offsets generated
17353a749623SJacob Keller 	 * by the Vernier calibration.
17363a749623SJacob Keller 	 */
17373a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
17383a749623SJacob Keller 					 total_offset);
17393a749623SJacob Keller 	if (err)
17403a749623SJacob Keller 		return err;
17413a749623SJacob Keller 
17423a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
17433a749623SJacob Keller 	if (err)
17443a749623SJacob Keller 		return err;
17453a749623SJacob Keller 
17463a749623SJacob Keller 	return 0;
17473a749623SJacob Keller }
17483a749623SJacob Keller 
17493a749623SJacob Keller /**
17503a749623SJacob Keller  * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port
17513a749623SJacob Keller  * @hw: pointer to HW struct
17523a749623SJacob Keller  * @link_spd: The Link speed to calculate for
17533a749623SJacob Keller  *
17543a749623SJacob Keller  * Determine the fixed Rx latency for a given link speed.
17553a749623SJacob Keller  */
17563a749623SJacob Keller static u64
17573a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
17583a749623SJacob Keller {
17593a749623SJacob Keller 	u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
17603a749623SJacob Keller 
17613a749623SJacob Keller 	cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
17623a749623SJacob Keller 	clk_incval = ice_ptp_read_src_incval(hw);
17633a749623SJacob Keller 
17643a749623SJacob Keller 	/* Calculate TUs per second */
17653a749623SJacob Keller 	tu_per_sec = cur_freq * clk_incval;
17663a749623SJacob Keller 
17673a749623SJacob Keller 	/* Calculate number of TUs to add for the fixed Rx latency. Since the
17683a749623SJacob Keller 	 * latency measurement is in 1/100th of a nanosecond, we need to
17693a749623SJacob Keller 	 * multiply by tu_per_sec and then divide by 1e11. This calculation
17703a749623SJacob Keller 	 * overflows 64 bit integer arithmetic, so break it up into two
17713a749623SJacob Keller 	 * divisions by 1e4 first then by 1e7.
17723a749623SJacob Keller 	 */
17733a749623SJacob Keller 	fixed_offset = div_u64(tu_per_sec, 10000);
17743a749623SJacob Keller 	fixed_offset *= e822_vernier[link_spd].rx_fixed_delay;
17753a749623SJacob Keller 	fixed_offset = div_u64(fixed_offset, 10000000);
17763a749623SJacob Keller 
17773a749623SJacob Keller 	return fixed_offset;
17783a749623SJacob Keller }
17793a749623SJacob Keller 
17803a749623SJacob Keller /**
17813a749623SJacob Keller  * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode
17823a749623SJacob Keller  * @hw: pointer to the HW struct
17833a749623SJacob Keller  * @port: the PHY port to configure
17843a749623SJacob Keller  *
17853a749623SJacob Keller  * Calculate and program the fixed Rx offset, and indicate that the offset is
17863a749623SJacob Keller  * ready. This can be used when operating in bypass mode.
17873a749623SJacob Keller  */
17883a749623SJacob Keller static int
17893a749623SJacob Keller ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port)
17903a749623SJacob Keller {
17913a749623SJacob Keller 	enum ice_ptp_link_spd link_spd;
17923a749623SJacob Keller 	enum ice_ptp_fec_mode fec_mode;
17933a749623SJacob Keller 	u64 total_offset;
17943a749623SJacob Keller 	int err;
17953a749623SJacob Keller 
17963a749623SJacob Keller 	err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
17973a749623SJacob Keller 	if (err)
17983a749623SJacob Keller 		return err;
17993a749623SJacob Keller 
18003a749623SJacob Keller 	total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
18013a749623SJacob Keller 
18023a749623SJacob Keller 	/* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L
18033a749623SJacob Keller 	 * register, then indicate that the Rx offset is ready. After this,
18043a749623SJacob Keller 	 * timestamps will be enabled.
18053a749623SJacob Keller 	 *
18063a749623SJacob Keller 	 * Note that this skips including the more precise offsets generated
18073a749623SJacob Keller 	 * by Vernier calibration.
18083a749623SJacob Keller 	 */
18093a749623SJacob Keller 	err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
18103a749623SJacob Keller 					 total_offset);
18113a749623SJacob Keller 	if (err)
18123a749623SJacob Keller 		return err;
18133a749623SJacob Keller 
18143a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
18153a749623SJacob Keller 	if (err)
18163a749623SJacob Keller 		return err;
18173a749623SJacob Keller 
18183a749623SJacob Keller 	return 0;
18193a749623SJacob Keller }
18203a749623SJacob Keller 
18213a749623SJacob Keller /**
18223a749623SJacob Keller  * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time
18233a749623SJacob Keller  * @hw: pointer to the HW struct
18243a749623SJacob Keller  * @port: the PHY port to read
18253a749623SJacob Keller  * @phy_time: on return, the 64bit PHY timer value
18263a749623SJacob Keller  * @phc_time: on return, the lower 64bits of PHC time
18273a749623SJacob Keller  *
18283a749623SJacob Keller  * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC
18293a749623SJacob Keller  * timer values.
18303a749623SJacob Keller  */
18313a749623SJacob Keller static int
18323a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
18333a749623SJacob Keller 			       u64 *phc_time)
18343a749623SJacob Keller {
18353a749623SJacob Keller 	u64 tx_time, rx_time;
18363a749623SJacob Keller 	u32 zo, lo;
18373a749623SJacob Keller 	u8 tmr_idx;
18383a749623SJacob Keller 	int err;
18393a749623SJacob Keller 
18403a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
18413a749623SJacob Keller 
18423a749623SJacob Keller 	/* Prepare the PHC timer for a READ_TIME capture command */
18433a749623SJacob Keller 	ice_ptp_src_cmd(hw, READ_TIME);
18443a749623SJacob Keller 
18453a749623SJacob Keller 	/* Prepare the PHY timer for a READ_TIME capture command */
18463a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, READ_TIME);
18473a749623SJacob Keller 	if (err)
18483a749623SJacob Keller 		return err;
18493a749623SJacob Keller 
18503a749623SJacob Keller 	/* Issue the sync to start the READ_TIME capture */
18513a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
18523a749623SJacob Keller 
18533a749623SJacob Keller 	/* Read the captured PHC time from the shadow time registers */
18543a749623SJacob Keller 	zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx));
18553a749623SJacob Keller 	lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx));
18563a749623SJacob Keller 	*phc_time = (u64)lo << 32 | zo;
18573a749623SJacob Keller 
18583a749623SJacob Keller 	/* Read the captured PHY time from the PHY shadow registers */
18593a749623SJacob Keller 	err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time);
18603a749623SJacob Keller 	if (err)
18613a749623SJacob Keller 		return err;
18623a749623SJacob Keller 
18633a749623SJacob Keller 	/* If the PHY Tx and Rx timers don't match, log a warning message.
18643a749623SJacob Keller 	 * Note that this should not happen in normal circumstances since the
18653a749623SJacob Keller 	 * driver always programs them together.
18663a749623SJacob Keller 	 */
18673a749623SJacob Keller 	if (tx_time != rx_time)
18683a749623SJacob Keller 		dev_warn(ice_hw_to_dev(hw),
18693a749623SJacob Keller 			 "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n",
18703a749623SJacob Keller 			 port, (unsigned long long)tx_time,
18713a749623SJacob Keller 			 (unsigned long long)rx_time);
18723a749623SJacob Keller 
18733a749623SJacob Keller 	*phy_time = tx_time;
18743a749623SJacob Keller 
18753a749623SJacob Keller 	return 0;
18763a749623SJacob Keller }
18773a749623SJacob Keller 
18783a749623SJacob Keller /**
18793a749623SJacob Keller  * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer
18803a749623SJacob Keller  * @hw: pointer to the HW struct
18813a749623SJacob Keller  * @port: the PHY port to synchronize
18823a749623SJacob Keller  *
18833a749623SJacob Keller  * Perform an adjustment to ensure that the PHY and PHC timers are in sync.
18843a749623SJacob Keller  * This is done by issuing a READ_TIME command which triggers a simultaneous
18853a749623SJacob Keller  * read of the PHY timer and PHC timer. Then we use the difference to
18863a749623SJacob Keller  * calculate an appropriate 2s complement addition to add to the PHY timer in
18873a749623SJacob Keller  * order to ensure it reads the same value as the primary PHC timer.
18883a749623SJacob Keller  */
18893a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
18903a749623SJacob Keller {
18913a749623SJacob Keller 	u64 phc_time, phy_time, difference;
18923a749623SJacob Keller 	int err;
18933a749623SJacob Keller 
18943a749623SJacob Keller 	if (!ice_ptp_lock(hw)) {
18953a749623SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n");
18963a749623SJacob Keller 		return -EBUSY;
18973a749623SJacob Keller 	}
18983a749623SJacob Keller 
18993a749623SJacob Keller 	err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
19003a749623SJacob Keller 	if (err)
19013a749623SJacob Keller 		goto err_unlock;
19023a749623SJacob Keller 
19033a749623SJacob Keller 	/* Calculate the amount required to add to the port time in order for
19043a749623SJacob Keller 	 * it to match the PHC time.
19053a749623SJacob Keller 	 *
19063a749623SJacob Keller 	 * Note that the port adjustment is done using 2s complement
19073a749623SJacob Keller 	 * arithmetic. This is convenient since it means that we can simply
19083a749623SJacob Keller 	 * calculate the difference between the PHC time and the port time,
19093a749623SJacob Keller 	 * and it will be interpreted correctly.
19103a749623SJacob Keller 	 */
19113a749623SJacob Keller 	difference = phc_time - phy_time;
19123a749623SJacob Keller 
19133a749623SJacob Keller 	err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference);
19143a749623SJacob Keller 	if (err)
19153a749623SJacob Keller 		goto err_unlock;
19163a749623SJacob Keller 
19173a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME);
19183a749623SJacob Keller 	if (err)
19193a749623SJacob Keller 		goto err_unlock;
19203a749623SJacob Keller 
19213a749623SJacob Keller 	/* Issue the sync to activate the time adjustment */
19223a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
19233a749623SJacob Keller 
19243a749623SJacob Keller 	/* Re-capture the timer values to flush the command registers and
19253a749623SJacob Keller 	 * verify that the time was properly adjusted.
19263a749623SJacob Keller 	 */
19273a749623SJacob Keller 	err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
19283a749623SJacob Keller 	if (err)
19293a749623SJacob Keller 		goto err_unlock;
19303a749623SJacob Keller 
19313a749623SJacob Keller 	dev_info(ice_hw_to_dev(hw),
19323a749623SJacob Keller 		 "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n",
19333a749623SJacob Keller 		 port, (unsigned long long)phy_time,
19343a749623SJacob Keller 		 (unsigned long long)phc_time);
19353a749623SJacob Keller 
19363a749623SJacob Keller 	ice_ptp_unlock(hw);
19373a749623SJacob Keller 
19383a749623SJacob Keller 	return 0;
19393a749623SJacob Keller 
19403a749623SJacob Keller err_unlock:
19413a749623SJacob Keller 	ice_ptp_unlock(hw);
19423a749623SJacob Keller 	return err;
19433a749623SJacob Keller }
19443a749623SJacob Keller 
19453a749623SJacob Keller /**
19463a749623SJacob Keller  * ice_stop_phy_timer_e822 - Stop the PHY clock timer
19473a749623SJacob Keller  * @hw: pointer to the HW struct
19483a749623SJacob Keller  * @port: the PHY port to stop
19493a749623SJacob Keller  * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS
19503a749623SJacob Keller  *
19513a749623SJacob Keller  * Stop the clock of a PHY port. This must be done as part of the flow to
19523a749623SJacob Keller  * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
19533a749623SJacob Keller  * initialized or when link speed changes.
19543a749623SJacob Keller  */
19553a749623SJacob Keller int
19563a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
19573a749623SJacob Keller {
19583a749623SJacob Keller 	int err;
19593a749623SJacob Keller 	u32 val;
19603a749623SJacob Keller 
19613a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);
19623a749623SJacob Keller 	if (err)
19633a749623SJacob Keller 		return err;
19643a749623SJacob Keller 
19653a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);
19663a749623SJacob Keller 	if (err)
19673a749623SJacob Keller 		return err;
19683a749623SJacob Keller 
19693a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
19703a749623SJacob Keller 	if (err)
19713a749623SJacob Keller 		return err;
19723a749623SJacob Keller 
19733a749623SJacob Keller 	val &= ~P_REG_PS_START_M;
19743a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
19753a749623SJacob Keller 	if (err)
19763a749623SJacob Keller 		return err;
19773a749623SJacob Keller 
19783a749623SJacob Keller 	val &= ~P_REG_PS_ENA_CLK_M;
19793a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
19803a749623SJacob Keller 	if (err)
19813a749623SJacob Keller 		return err;
19823a749623SJacob Keller 
19833a749623SJacob Keller 	if (soft_reset) {
19843a749623SJacob Keller 		val |= P_REG_PS_SFT_RESET_M;
19853a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
19863a749623SJacob Keller 		if (err)
19873a749623SJacob Keller 			return err;
19883a749623SJacob Keller 	}
19893a749623SJacob Keller 
19903a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port);
19913a749623SJacob Keller 
19923a749623SJacob Keller 	return 0;
19933a749623SJacob Keller }
19943a749623SJacob Keller 
19953a749623SJacob Keller /**
19963a749623SJacob Keller  * ice_start_phy_timer_e822 - Start the PHY clock timer
19973a749623SJacob Keller  * @hw: pointer to the HW struct
19983a749623SJacob Keller  * @port: the PHY port to start
19993a749623SJacob Keller  * @bypass: if true, start the PHY in bypass mode
20003a749623SJacob Keller  *
20013a749623SJacob Keller  * Start the clock of a PHY port. This must be done as part of the flow to
20023a749623SJacob Keller  * re-calibrate Tx and Rx timestamping offsets whenever the clock time is
20033a749623SJacob Keller  * initialized or when link speed changes.
20043a749623SJacob Keller  *
20053a749623SJacob Keller  * Bypass mode enables timestamps immediately without waiting for Vernier
20063a749623SJacob Keller  * calibration to complete. Hardware will still continue taking Vernier
20073a749623SJacob Keller  * measurements on Tx or Rx of packets, but they will not be applied to
20083a749623SJacob Keller  * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware
20093a749623SJacob Keller  * has completed offset calculation.
20103a749623SJacob Keller  */
20113a749623SJacob Keller int
20123a749623SJacob Keller ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass)
20133a749623SJacob Keller {
20143a749623SJacob Keller 	u32 lo, hi, val;
20153a749623SJacob Keller 	u64 incval;
20163a749623SJacob Keller 	u8 tmr_idx;
20173a749623SJacob Keller 	int err;
20183a749623SJacob Keller 
20193a749623SJacob Keller 	tmr_idx = ice_get_ptp_src_clock_index(hw);
20203a749623SJacob Keller 
20213a749623SJacob Keller 	err = ice_stop_phy_timer_e822(hw, port, false);
20223a749623SJacob Keller 	if (err)
20233a749623SJacob Keller 		return err;
20243a749623SJacob Keller 
20253a749623SJacob Keller 	ice_phy_cfg_lane_e822(hw, port);
20263a749623SJacob Keller 
20273a749623SJacob Keller 	err = ice_phy_cfg_uix_e822(hw, port);
20283a749623SJacob Keller 	if (err)
20293a749623SJacob Keller 		return err;
20303a749623SJacob Keller 
20313a749623SJacob Keller 	err = ice_phy_cfg_parpcs_e822(hw, port);
20323a749623SJacob Keller 	if (err)
20333a749623SJacob Keller 		return err;
20343a749623SJacob Keller 
20353a749623SJacob Keller 	lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx));
20363a749623SJacob Keller 	hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
20373a749623SJacob Keller 	incval = (u64)hi << 32 | lo;
20383a749623SJacob Keller 
20393a749623SJacob Keller 	err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
20403a749623SJacob Keller 	if (err)
20413a749623SJacob Keller 		return err;
20423a749623SJacob Keller 
20433a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
20443a749623SJacob Keller 	if (err)
20453a749623SJacob Keller 		return err;
20463a749623SJacob Keller 
20473a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
20483a749623SJacob Keller 
20493a749623SJacob Keller 	err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
20503a749623SJacob Keller 	if (err)
20513a749623SJacob Keller 		return err;
20523a749623SJacob Keller 
20533a749623SJacob Keller 	val |= P_REG_PS_SFT_RESET_M;
20543a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
20553a749623SJacob Keller 	if (err)
20563a749623SJacob Keller 		return err;
20573a749623SJacob Keller 
20583a749623SJacob Keller 	val |= P_REG_PS_START_M;
20593a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
20603a749623SJacob Keller 	if (err)
20613a749623SJacob Keller 		return err;
20623a749623SJacob Keller 
20633a749623SJacob Keller 	val &= ~P_REG_PS_SFT_RESET_M;
20643a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
20653a749623SJacob Keller 	if (err)
20663a749623SJacob Keller 		return err;
20673a749623SJacob Keller 
20683a749623SJacob Keller 	err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL);
20693a749623SJacob Keller 	if (err)
20703a749623SJacob Keller 		return err;
20713a749623SJacob Keller 
20723a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
20733a749623SJacob Keller 
20743a749623SJacob Keller 	val |= P_REG_PS_ENA_CLK_M;
20753a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
20763a749623SJacob Keller 	if (err)
20773a749623SJacob Keller 		return err;
20783a749623SJacob Keller 
20793a749623SJacob Keller 	val |= P_REG_PS_LOAD_OFFSET_M;
20803a749623SJacob Keller 	err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
20813a749623SJacob Keller 	if (err)
20823a749623SJacob Keller 		return err;
20833a749623SJacob Keller 
20843a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
20853a749623SJacob Keller 
20863a749623SJacob Keller 	err = ice_sync_phy_timer_e822(hw, port);
20873a749623SJacob Keller 	if (err)
20883a749623SJacob Keller 		return err;
20893a749623SJacob Keller 
20903a749623SJacob Keller 	if (bypass) {
20913a749623SJacob Keller 		val |= P_REG_PS_BYPASS_MODE_M;
20923a749623SJacob Keller 		/* Enter BYPASS mode, enabling timestamps immediately. */
20933a749623SJacob Keller 		err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
20943a749623SJacob Keller 		if (err)
20953a749623SJacob Keller 			return err;
20963a749623SJacob Keller 
20973a749623SJacob Keller 		/* Program the fixed Tx offset */
20983a749623SJacob Keller 		err = ice_phy_cfg_fixed_tx_offset_e822(hw, port);
20993a749623SJacob Keller 		if (err)
21003a749623SJacob Keller 			return err;
21013a749623SJacob Keller 
21023a749623SJacob Keller 		/* Program the fixed Rx offset */
21033a749623SJacob Keller 		err = ice_phy_cfg_fixed_rx_offset_e822(hw, port);
21043a749623SJacob Keller 		if (err)
21053a749623SJacob Keller 			return err;
21063a749623SJacob Keller 	}
21073a749623SJacob Keller 
21083a749623SJacob Keller 	ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port);
21093a749623SJacob Keller 
21103a749623SJacob Keller 	return 0;
21113a749623SJacob Keller }
21123a749623SJacob Keller 
211303cb4473SJacob Keller /* E810 functions
211403cb4473SJacob Keller  *
211503cb4473SJacob Keller  * The following functions operate on the E810 series devices which use
211603cb4473SJacob Keller  * a separate external PHY.
211703cb4473SJacob Keller  */
211803cb4473SJacob Keller 
211903cb4473SJacob Keller /**
212003cb4473SJacob Keller  * ice_read_phy_reg_e810 - Read register from external PHY on E810
212103cb4473SJacob Keller  * @hw: pointer to the HW struct
212203cb4473SJacob Keller  * @addr: the address to read from
212303cb4473SJacob Keller  * @val: On return, the value read from the PHY
212403cb4473SJacob Keller  *
212503cb4473SJacob Keller  * Read a register from the external PHY on the E810 device.
212603cb4473SJacob Keller  */
212703cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val)
212803cb4473SJacob Keller {
212903cb4473SJacob Keller 	struct ice_sbq_msg_input msg = {0};
213039b28106SJacob Keller 	int err;
213103cb4473SJacob Keller 
213203cb4473SJacob Keller 	msg.msg_addr_low = lower_16_bits(addr);
213303cb4473SJacob Keller 	msg.msg_addr_high = upper_16_bits(addr);
213403cb4473SJacob Keller 	msg.opcode = ice_sbq_msg_rd;
213503cb4473SJacob Keller 	msg.dest_dev = rmn_0;
213603cb4473SJacob Keller 
213739b28106SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
213839b28106SJacob Keller 	if (err) {
213939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
214039b28106SJacob Keller 			  err);
214139b28106SJacob Keller 		return err;
214203cb4473SJacob Keller 	}
214303cb4473SJacob Keller 
214403cb4473SJacob Keller 	*val = msg.data;
214503cb4473SJacob Keller 
214603cb4473SJacob Keller 	return 0;
214703cb4473SJacob Keller }
214803cb4473SJacob Keller 
214903cb4473SJacob Keller /**
215003cb4473SJacob Keller  * ice_write_phy_reg_e810 - Write register on external PHY on E810
215103cb4473SJacob Keller  * @hw: pointer to the HW struct
215203cb4473SJacob Keller  * @addr: the address to writem to
215303cb4473SJacob Keller  * @val: the value to write to the PHY
215403cb4473SJacob Keller  *
215503cb4473SJacob Keller  * Write a value to a register of the external PHY on the E810 device.
215603cb4473SJacob Keller  */
215703cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val)
215803cb4473SJacob Keller {
215903cb4473SJacob Keller 	struct ice_sbq_msg_input msg = {0};
216039b28106SJacob Keller 	int err;
216103cb4473SJacob Keller 
216203cb4473SJacob Keller 	msg.msg_addr_low = lower_16_bits(addr);
216303cb4473SJacob Keller 	msg.msg_addr_high = upper_16_bits(addr);
216403cb4473SJacob Keller 	msg.opcode = ice_sbq_msg_wr;
216503cb4473SJacob Keller 	msg.dest_dev = rmn_0;
216603cb4473SJacob Keller 	msg.data = val;
216703cb4473SJacob Keller 
216839b28106SJacob Keller 	err = ice_sbq_rw_reg(hw, &msg);
216939b28106SJacob Keller 	if (err) {
217039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n",
217139b28106SJacob Keller 			  err);
217239b28106SJacob Keller 		return err;
217303cb4473SJacob Keller 	}
217403cb4473SJacob Keller 
217503cb4473SJacob Keller 	return 0;
217603cb4473SJacob Keller }
217703cb4473SJacob Keller 
217803cb4473SJacob Keller /**
217903cb4473SJacob Keller  * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY
218003cb4473SJacob Keller  * @hw: pointer to the HW struct
218103cb4473SJacob Keller  * @lport: the lport to read from
218203cb4473SJacob Keller  * @idx: the timestamp index to read
218303cb4473SJacob Keller  * @tstamp: on return, the 40bit timestamp value
218403cb4473SJacob Keller  *
218503cb4473SJacob Keller  * Read a 40bit timestamp value out of the timestamp block of the external PHY
218603cb4473SJacob Keller  * on the E810 device.
218703cb4473SJacob Keller  */
218803cb4473SJacob Keller static int
218903cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp)
219003cb4473SJacob Keller {
219103cb4473SJacob Keller 	u32 lo_addr, hi_addr, lo, hi;
219239b28106SJacob Keller 	int err;
219303cb4473SJacob Keller 
219403cb4473SJacob Keller 	lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
219503cb4473SJacob Keller 	hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
219603cb4473SJacob Keller 
219739b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, lo_addr, &lo);
219839b28106SJacob Keller 	if (err) {
219939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
220039b28106SJacob Keller 			  err);
220139b28106SJacob Keller 		return err;
220203cb4473SJacob Keller 	}
220303cb4473SJacob Keller 
220439b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, hi_addr, &hi);
220539b28106SJacob Keller 	if (err) {
220639b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
220739b28106SJacob Keller 			  err);
220839b28106SJacob Keller 		return err;
220903cb4473SJacob Keller 	}
221003cb4473SJacob Keller 
221103cb4473SJacob Keller 	/* For E810 devices, the timestamp is reported with the lower 32 bits
221203cb4473SJacob Keller 	 * in the low register, and the upper 8 bits in the high register.
221303cb4473SJacob Keller 	 */
221403cb4473SJacob Keller 	*tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M);
221503cb4473SJacob Keller 
221603cb4473SJacob Keller 	return 0;
221703cb4473SJacob Keller }
221803cb4473SJacob Keller 
221903cb4473SJacob Keller /**
222003cb4473SJacob Keller  * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY
222103cb4473SJacob Keller  * @hw: pointer to the HW struct
222203cb4473SJacob Keller  * @lport: the lport to read from
222303cb4473SJacob Keller  * @idx: the timestamp index to reset
222403cb4473SJacob Keller  *
222503cb4473SJacob Keller  * Clear a timestamp, resetting its valid bit, from the timestamp block of the
222603cb4473SJacob Keller  * external PHY on the E810 device.
222703cb4473SJacob Keller  */
222803cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx)
222903cb4473SJacob Keller {
223003cb4473SJacob Keller 	u32 lo_addr, hi_addr;
223139b28106SJacob Keller 	int err;
223203cb4473SJacob Keller 
223303cb4473SJacob Keller 	lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx);
223403cb4473SJacob Keller 	hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx);
223503cb4473SJacob Keller 
223639b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, lo_addr, 0);
223739b28106SJacob Keller 	if (err) {
223839b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n",
223939b28106SJacob Keller 			  err);
224039b28106SJacob Keller 		return err;
224103cb4473SJacob Keller 	}
224203cb4473SJacob Keller 
224339b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, hi_addr, 0);
224439b28106SJacob Keller 	if (err) {
224539b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n",
224639b28106SJacob Keller 			  err);
224739b28106SJacob Keller 		return err;
224803cb4473SJacob Keller 	}
224903cb4473SJacob Keller 
225003cb4473SJacob Keller 	return 0;
225103cb4473SJacob Keller }
225203cb4473SJacob Keller 
225303cb4473SJacob Keller /**
225403cb4473SJacob Keller  * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY
225503cb4473SJacob Keller  * @hw: pointer to HW struct
225603cb4473SJacob Keller  *
225703cb4473SJacob Keller  * Enable the timesync PTP functionality for the external PHY connected to
225803cb4473SJacob Keller  * this function.
225903cb4473SJacob Keller  */
226003cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw)
226103cb4473SJacob Keller {
226203cb4473SJacob Keller 	u8 tmr_idx;
226339b28106SJacob Keller 	int err;
226403cb4473SJacob Keller 
226503cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
226639b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx),
226703cb4473SJacob Keller 				     GLTSYN_ENA_TSYN_ENA_M);
226839b28106SJacob Keller 	if (err)
226903cb4473SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n",
227039b28106SJacob Keller 			  err);
227103cb4473SJacob Keller 
227239b28106SJacob Keller 	return err;
227303cb4473SJacob Keller }
227403cb4473SJacob Keller 
227503cb4473SJacob Keller /**
2276b2ee7256SJacob Keller  * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization
2277b2ee7256SJacob Keller  * @hw: pointer to HW struct
2278b2ee7256SJacob Keller  *
2279b2ee7256SJacob Keller  * Perform E810-specific PTP hardware clock initialization steps.
2280b2ee7256SJacob Keller  */
2281b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw)
2282b2ee7256SJacob Keller {
2283b2ee7256SJacob Keller 	/* Ensure synchronization delay is zero */
2284b2ee7256SJacob Keller 	wr32(hw, GLTSYN_SYNC_DLAY, 0);
2285b2ee7256SJacob Keller 
2286b2ee7256SJacob Keller 	/* Initialize the PHY */
2287b2ee7256SJacob Keller 	return ice_ptp_init_phy_e810(hw);
2288b2ee7256SJacob Keller }
2289b2ee7256SJacob Keller 
2290b2ee7256SJacob Keller /**
229103cb4473SJacob Keller  * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time
229203cb4473SJacob Keller  * @hw: Board private structure
229303cb4473SJacob Keller  * @time: Time to initialize the PHY port clock to
229403cb4473SJacob Keller  *
229503cb4473SJacob Keller  * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the
229603cb4473SJacob Keller  * initial clock time. The time will not actually be programmed until the
229703cb4473SJacob Keller  * driver issues an INIT_TIME command.
229803cb4473SJacob Keller  *
229903cb4473SJacob Keller  * The time value is the upper 32 bits of the PHY timer, usually in units of
230003cb4473SJacob Keller  * nominal nanoseconds.
230103cb4473SJacob Keller  */
230203cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time)
230303cb4473SJacob Keller {
230403cb4473SJacob Keller 	u8 tmr_idx;
230539b28106SJacob Keller 	int err;
230603cb4473SJacob Keller 
230703cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
230839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0);
230939b28106SJacob Keller 	if (err) {
231039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n",
231139b28106SJacob Keller 			  err);
231239b28106SJacob Keller 		return err;
231303cb4473SJacob Keller 	}
231403cb4473SJacob Keller 
231539b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time);
231639b28106SJacob Keller 	if (err) {
231739b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n",
231839b28106SJacob Keller 			  err);
231939b28106SJacob Keller 		return err;
232003cb4473SJacob Keller 	}
232103cb4473SJacob Keller 
232203cb4473SJacob Keller 	return 0;
232303cb4473SJacob Keller }
232403cb4473SJacob Keller 
232503cb4473SJacob Keller /**
232603cb4473SJacob Keller  * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment
232703cb4473SJacob Keller  * @hw: pointer to HW struct
232803cb4473SJacob Keller  * @adj: adjustment value to program
232903cb4473SJacob Keller  *
233003cb4473SJacob Keller  * Prepare the PHY port for an atomic adjustment by programming the PHY
233103cb4473SJacob Keller  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment
233203cb4473SJacob Keller  * is completed by issuing an ADJ_TIME sync command.
233303cb4473SJacob Keller  *
233403cb4473SJacob Keller  * The adjustment value only contains the portion used for the upper 32bits of
233503cb4473SJacob Keller  * the PHY timer, usually in units of nominal nanoseconds. Negative
233603cb4473SJacob Keller  * adjustments are supported using 2s complement arithmetic.
233703cb4473SJacob Keller  */
233803cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj)
233903cb4473SJacob Keller {
234003cb4473SJacob Keller 	u8 tmr_idx;
234139b28106SJacob Keller 	int err;
234203cb4473SJacob Keller 
234303cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
234403cb4473SJacob Keller 
234503cb4473SJacob Keller 	/* Adjustments are represented as signed 2's complement values in
234603cb4473SJacob Keller 	 * nanoseconds. Sub-nanosecond adjustment is not supported.
234703cb4473SJacob Keller 	 */
234839b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0);
234939b28106SJacob Keller 	if (err) {
235039b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n",
235139b28106SJacob Keller 			  err);
235239b28106SJacob Keller 		return err;
235303cb4473SJacob Keller 	}
235403cb4473SJacob Keller 
235539b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj);
235639b28106SJacob Keller 	if (err) {
235739b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n",
235839b28106SJacob Keller 			  err);
235939b28106SJacob Keller 		return err;
236003cb4473SJacob Keller 	}
236103cb4473SJacob Keller 
236203cb4473SJacob Keller 	return 0;
236303cb4473SJacob Keller }
236403cb4473SJacob Keller 
236503cb4473SJacob Keller /**
236603cb4473SJacob Keller  * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change
236703cb4473SJacob Keller  * @hw: pointer to HW struct
236803cb4473SJacob Keller  * @incval: The new 40bit increment value to prepare
236903cb4473SJacob Keller  *
237003cb4473SJacob Keller  * Prepare the PHY port for a new increment value by programming the PHY
237103cb4473SJacob Keller  * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is
237203cb4473SJacob Keller  * completed by issuing an INIT_INCVAL command.
237303cb4473SJacob Keller  */
237403cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval)
237503cb4473SJacob Keller {
237603cb4473SJacob Keller 	u32 high, low;
237703cb4473SJacob Keller 	u8 tmr_idx;
237839b28106SJacob Keller 	int err;
237903cb4473SJacob Keller 
238003cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
238103cb4473SJacob Keller 	low = lower_32_bits(incval);
238203cb4473SJacob Keller 	high = upper_32_bits(incval);
238303cb4473SJacob Keller 
238439b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low);
238539b28106SJacob Keller 	if (err) {
238639b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n",
238739b28106SJacob Keller 			  err);
238839b28106SJacob Keller 		return err;
238903cb4473SJacob Keller 	}
239003cb4473SJacob Keller 
239139b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high);
239239b28106SJacob Keller 	if (err) {
239339b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n",
239439b28106SJacob Keller 			  err);
239539b28106SJacob Keller 		return err;
239603cb4473SJacob Keller 	}
239703cb4473SJacob Keller 
239803cb4473SJacob Keller 	return 0;
239903cb4473SJacob Keller }
240003cb4473SJacob Keller 
240103cb4473SJacob Keller /**
240203cb4473SJacob Keller  * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command
240303cb4473SJacob Keller  * @hw: pointer to HW struct
240403cb4473SJacob Keller  * @cmd: Command to be sent to the port
240503cb4473SJacob Keller  *
240603cb4473SJacob Keller  * Prepare the external PHYs connected to this device for a timer sync
240703cb4473SJacob Keller  * command.
240803cb4473SJacob Keller  */
240903cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
241003cb4473SJacob Keller {
241103cb4473SJacob Keller 	u32 cmd_val, val;
241239b28106SJacob Keller 	int err;
241303cb4473SJacob Keller 
241403cb4473SJacob Keller 	switch (cmd) {
241503cb4473SJacob Keller 	case INIT_TIME:
241603cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_INIT_TIME;
241703cb4473SJacob Keller 		break;
241803cb4473SJacob Keller 	case INIT_INCVAL:
241903cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_INIT_INCVAL;
242003cb4473SJacob Keller 		break;
242103cb4473SJacob Keller 	case ADJ_TIME:
242203cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_ADJ_TIME;
242303cb4473SJacob Keller 		break;
242403cb4473SJacob Keller 	case READ_TIME:
242503cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_READ_TIME;
242603cb4473SJacob Keller 		break;
242703cb4473SJacob Keller 	case ADJ_TIME_AT_TIME:
242803cb4473SJacob Keller 		cmd_val = GLTSYN_CMD_ADJ_INIT_TIME;
242903cb4473SJacob Keller 		break;
243003cb4473SJacob Keller 	}
243103cb4473SJacob Keller 
243203cb4473SJacob Keller 	/* Read, modify, write */
243339b28106SJacob Keller 	err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val);
243439b28106SJacob Keller 	if (err) {
243539b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err);
243639b28106SJacob Keller 		return err;
243703cb4473SJacob Keller 	}
243803cb4473SJacob Keller 
243903cb4473SJacob Keller 	/* Modify necessary bits only and perform write */
244003cb4473SJacob Keller 	val &= ~TS_CMD_MASK_E810;
244103cb4473SJacob Keller 	val |= cmd_val;
244203cb4473SJacob Keller 
244339b28106SJacob Keller 	err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val);
244439b28106SJacob Keller 	if (err) {
244539b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err);
244639b28106SJacob Keller 		return err;
244703cb4473SJacob Keller 	}
244803cb4473SJacob Keller 
244903cb4473SJacob Keller 	return 0;
245003cb4473SJacob Keller }
245103cb4473SJacob Keller 
245203cb4473SJacob Keller /* Device agnostic functions
245303cb4473SJacob Keller  *
24543a749623SJacob Keller  * The following functions implement shared behavior common to both E822 and
24553a749623SJacob Keller  * E810 devices, possibly calling a device specific implementation where
24563a749623SJacob Keller  * necessary.
245703cb4473SJacob Keller  */
245803cb4473SJacob Keller 
245903cb4473SJacob Keller /**
246003cb4473SJacob Keller  * ice_ptp_lock - Acquire PTP global semaphore register lock
246103cb4473SJacob Keller  * @hw: pointer to the HW struct
246203cb4473SJacob Keller  *
246303cb4473SJacob Keller  * Acquire the global PTP hardware semaphore lock. Returns true if the lock
246403cb4473SJacob Keller  * was acquired, false otherwise.
246503cb4473SJacob Keller  *
246603cb4473SJacob Keller  * The PFTSYN_SEM register sets the busy bit on read, returning the previous
246703cb4473SJacob Keller  * value. If software sees the busy bit cleared, this means that this function
246803cb4473SJacob Keller  * acquired the lock (and the busy bit is now set). If software sees the busy
246903cb4473SJacob Keller  * bit set, it means that another function acquired the lock.
247003cb4473SJacob Keller  *
247103cb4473SJacob Keller  * Software must clear the busy bit with a write to release the lock for other
247203cb4473SJacob Keller  * functions when done.
247303cb4473SJacob Keller  */
247403cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw)
247503cb4473SJacob Keller {
247603cb4473SJacob Keller 	u32 hw_lock;
247703cb4473SJacob Keller 	int i;
247803cb4473SJacob Keller 
247903cb4473SJacob Keller #define MAX_TRIES 5
248003cb4473SJacob Keller 
248103cb4473SJacob Keller 	for (i = 0; i < MAX_TRIES; i++) {
248203cb4473SJacob Keller 		hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id));
248303cb4473SJacob Keller 		hw_lock = hw_lock & PFTSYN_SEM_BUSY_M;
2484587b839dSColin Ian King 		if (!hw_lock)
2485587b839dSColin Ian King 			break;
2486587b839dSColin Ian King 
248703cb4473SJacob Keller 		/* Somebody is holding the lock */
248803cb4473SJacob Keller 		usleep_range(10000, 20000);
248903cb4473SJacob Keller 	}
249003cb4473SJacob Keller 
249103cb4473SJacob Keller 	return !hw_lock;
249203cb4473SJacob Keller }
249303cb4473SJacob Keller 
249403cb4473SJacob Keller /**
249503cb4473SJacob Keller  * ice_ptp_unlock - Release PTP global semaphore register lock
249603cb4473SJacob Keller  * @hw: pointer to the HW struct
249703cb4473SJacob Keller  *
249803cb4473SJacob Keller  * Release the global PTP hardware semaphore lock. This is done by writing to
249903cb4473SJacob Keller  * the PFTSYN_SEM register.
250003cb4473SJacob Keller  */
250103cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw)
250203cb4473SJacob Keller {
250303cb4473SJacob Keller 	wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0);
250403cb4473SJacob Keller }
250503cb4473SJacob Keller 
250603cb4473SJacob Keller /**
250703cb4473SJacob Keller  * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command
250803cb4473SJacob Keller  * @hw: pointer to HW struct
250903cb4473SJacob Keller  * @cmd: the command to issue
251003cb4473SJacob Keller  *
251103cb4473SJacob Keller  * Prepare the source timer and PHY timers and then trigger the requested
251203cb4473SJacob Keller  * command. This causes the shadow registers previously written in preparation
251303cb4473SJacob Keller  * for the command to be synchronously applied to both the source and PHY
251403cb4473SJacob Keller  * timers.
251503cb4473SJacob Keller  */
251603cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
251703cb4473SJacob Keller {
251839b28106SJacob Keller 	int err;
251903cb4473SJacob Keller 
252003cb4473SJacob Keller 	/* First, prepare the source timer */
252103cb4473SJacob Keller 	ice_ptp_src_cmd(hw, cmd);
252203cb4473SJacob Keller 
252303cb4473SJacob Keller 	/* Next, prepare the ports */
25243a749623SJacob Keller 	if (ice_is_e810(hw))
252539b28106SJacob Keller 		err = ice_ptp_port_cmd_e810(hw, cmd);
25263a749623SJacob Keller 	else
25273a749623SJacob Keller 		err = ice_ptp_port_cmd_e822(hw, cmd);
252839b28106SJacob Keller 	if (err) {
252939b28106SJacob Keller 		ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n",
253039b28106SJacob Keller 			  cmd, err);
253139b28106SJacob Keller 		return err;
253203cb4473SJacob Keller 	}
253303cb4473SJacob Keller 
25343a749623SJacob Keller 	/* Write the sync command register to drive both source and PHY timer
25353a749623SJacob Keller 	 * commands synchronously
253603cb4473SJacob Keller 	 */
25373a749623SJacob Keller 	ice_ptp_exec_tmr_cmd(hw);
253803cb4473SJacob Keller 
253903cb4473SJacob Keller 	return 0;
254003cb4473SJacob Keller }
254103cb4473SJacob Keller 
254203cb4473SJacob Keller /**
254303cb4473SJacob Keller  * ice_ptp_init_time - Initialize device time to provided value
254403cb4473SJacob Keller  * @hw: pointer to HW struct
254503cb4473SJacob Keller  * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H)
254603cb4473SJacob Keller  *
254703cb4473SJacob Keller  * Initialize the device to the specified time provided. This requires a three
254803cb4473SJacob Keller  * step process:
254903cb4473SJacob Keller  *
255003cb4473SJacob Keller  * 1) write the new init time to the source timer shadow registers
255103cb4473SJacob Keller  * 2) write the new init time to the PHY timer shadow registers
255203cb4473SJacob Keller  * 3) issue an init_time timer command to synchronously switch both the source
255303cb4473SJacob Keller  *    and port timers to the new init time value at the next clock cycle.
255403cb4473SJacob Keller  */
255503cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time)
255603cb4473SJacob Keller {
255703cb4473SJacob Keller 	u8 tmr_idx;
255839b28106SJacob Keller 	int err;
255903cb4473SJacob Keller 
256003cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
256103cb4473SJacob Keller 
256203cb4473SJacob Keller 	/* Source timers */
256303cb4473SJacob Keller 	wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time));
256403cb4473SJacob Keller 	wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time));
256503cb4473SJacob Keller 	wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0);
256603cb4473SJacob Keller 
256703cb4473SJacob Keller 	/* PHY timers */
256803cb4473SJacob Keller 	/* Fill Rx and Tx ports and send msg to PHY */
25693a749623SJacob Keller 	if (ice_is_e810(hw))
257039b28106SJacob Keller 		err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
25713a749623SJacob Keller 	else
25723a749623SJacob Keller 		err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
257339b28106SJacob Keller 	if (err)
257439b28106SJacob Keller 		return err;
257503cb4473SJacob Keller 
257603cb4473SJacob Keller 	return ice_ptp_tmr_cmd(hw, INIT_TIME);
257703cb4473SJacob Keller }
257803cb4473SJacob Keller 
257903cb4473SJacob Keller /**
258003cb4473SJacob Keller  * ice_ptp_write_incval - Program PHC with new increment value
258103cb4473SJacob Keller  * @hw: pointer to HW struct
258203cb4473SJacob Keller  * @incval: Source timer increment value per clock cycle
258303cb4473SJacob Keller  *
258403cb4473SJacob Keller  * Program the PHC with a new increment value. This requires a three-step
258503cb4473SJacob Keller  * process:
258603cb4473SJacob Keller  *
258703cb4473SJacob Keller  * 1) Write the increment value to the source timer shadow registers
258803cb4473SJacob Keller  * 2) Write the increment value to the PHY timer shadow registers
258903cb4473SJacob Keller  * 3) Issue an INIT_INCVAL timer command to synchronously switch both the
259003cb4473SJacob Keller  *    source and port timers to the new increment value at the next clock
259103cb4473SJacob Keller  *    cycle.
259203cb4473SJacob Keller  */
259303cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
259403cb4473SJacob Keller {
259503cb4473SJacob Keller 	u8 tmr_idx;
259639b28106SJacob Keller 	int err;
259703cb4473SJacob Keller 
259803cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
259903cb4473SJacob Keller 
260003cb4473SJacob Keller 	/* Shadow Adjust */
260103cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval));
260203cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval));
260303cb4473SJacob Keller 
26043a749623SJacob Keller 	if (ice_is_e810(hw))
260539b28106SJacob Keller 		err = ice_ptp_prep_phy_incval_e810(hw, incval);
26063a749623SJacob Keller 	else
26073a749623SJacob Keller 		err = ice_ptp_prep_phy_incval_e822(hw, incval);
260839b28106SJacob Keller 	if (err)
260939b28106SJacob Keller 		return err;
261003cb4473SJacob Keller 
261103cb4473SJacob Keller 	return ice_ptp_tmr_cmd(hw, INIT_INCVAL);
261203cb4473SJacob Keller }
261303cb4473SJacob Keller 
261403cb4473SJacob Keller /**
261503cb4473SJacob Keller  * ice_ptp_write_incval_locked - Program new incval while holding semaphore
261603cb4473SJacob Keller  * @hw: pointer to HW struct
261703cb4473SJacob Keller  * @incval: Source timer increment value per clock cycle
261803cb4473SJacob Keller  *
261903cb4473SJacob Keller  * Program a new PHC incval while holding the PTP semaphore.
262003cb4473SJacob Keller  */
262103cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)
262203cb4473SJacob Keller {
262339b28106SJacob Keller 	int err;
262403cb4473SJacob Keller 
262503cb4473SJacob Keller 	if (!ice_ptp_lock(hw))
262603cb4473SJacob Keller 		return -EBUSY;
262703cb4473SJacob Keller 
262839b28106SJacob Keller 	err = ice_ptp_write_incval(hw, incval);
262903cb4473SJacob Keller 
263003cb4473SJacob Keller 	ice_ptp_unlock(hw);
263103cb4473SJacob Keller 
263239b28106SJacob Keller 	return err;
263303cb4473SJacob Keller }
263403cb4473SJacob Keller 
263503cb4473SJacob Keller /**
263603cb4473SJacob Keller  * ice_ptp_adj_clock - Adjust PHC clock time atomically
263703cb4473SJacob Keller  * @hw: pointer to HW struct
263803cb4473SJacob Keller  * @adj: Adjustment in nanoseconds
263903cb4473SJacob Keller  *
264003cb4473SJacob Keller  * Perform an atomic adjustment of the PHC time by the specified number of
264103cb4473SJacob Keller  * nanoseconds. This requires a three-step process:
264203cb4473SJacob Keller  *
264303cb4473SJacob Keller  * 1) Write the adjustment to the source timer shadow registers
264403cb4473SJacob Keller  * 2) Write the adjustment to the PHY timer shadow registers
264503cb4473SJacob Keller  * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to
264603cb4473SJacob Keller  *    both the source and port timers at the next clock cycle.
264703cb4473SJacob Keller  */
264803cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
264903cb4473SJacob Keller {
265003cb4473SJacob Keller 	u8 tmr_idx;
265139b28106SJacob Keller 	int err;
265203cb4473SJacob Keller 
265303cb4473SJacob Keller 	tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
265403cb4473SJacob Keller 
265503cb4473SJacob Keller 	/* Write the desired clock adjustment into the GLTSYN_SHADJ register.
265603cb4473SJacob Keller 	 * For an ADJ_TIME command, this set of registers represents the value
265703cb4473SJacob Keller 	 * to add to the clock time. It supports subtraction by interpreting
265803cb4473SJacob Keller 	 * the value as a 2's complement integer.
265903cb4473SJacob Keller 	 */
266003cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0);
266103cb4473SJacob Keller 	wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj);
266203cb4473SJacob Keller 
26633a749623SJacob Keller 	if (ice_is_e810(hw))
266439b28106SJacob Keller 		err = ice_ptp_prep_phy_adj_e810(hw, adj);
26653a749623SJacob Keller 	else
26663a749623SJacob Keller 		err = ice_ptp_prep_phy_adj_e822(hw, adj);
266739b28106SJacob Keller 	if (err)
266839b28106SJacob Keller 		return err;
266903cb4473SJacob Keller 
267003cb4473SJacob Keller 	return ice_ptp_tmr_cmd(hw, ADJ_TIME);
267103cb4473SJacob Keller }
267203cb4473SJacob Keller 
267303cb4473SJacob Keller /**
267403cb4473SJacob Keller  * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block
267503cb4473SJacob Keller  * @hw: pointer to the HW struct
267603cb4473SJacob Keller  * @block: the block to read from
267703cb4473SJacob Keller  * @idx: the timestamp index to read
267803cb4473SJacob Keller  * @tstamp: on return, the 40bit timestamp value
267903cb4473SJacob Keller  *
26803a749623SJacob Keller  * Read a 40bit timestamp value out of the timestamp block. For E822 devices,
26813a749623SJacob Keller  * the block is the quad to read from. For E810 devices, the block is the
26823a749623SJacob Keller  * logical port to read from.
268303cb4473SJacob Keller  */
268403cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
268503cb4473SJacob Keller {
26863a749623SJacob Keller 	if (ice_is_e810(hw))
268703cb4473SJacob Keller 		return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
26883a749623SJacob Keller 	else
26893a749623SJacob Keller 		return ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
269003cb4473SJacob Keller }
269103cb4473SJacob Keller 
269203cb4473SJacob Keller /**
269303cb4473SJacob Keller  * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block
269403cb4473SJacob Keller  * @hw: pointer to the HW struct
269503cb4473SJacob Keller  * @block: the block to read from
269603cb4473SJacob Keller  * @idx: the timestamp index to reset
269703cb4473SJacob Keller  *
26983a749623SJacob Keller  * Clear a timestamp, resetting its valid bit, from the timestamp block. For
26993a749623SJacob Keller  * E822 devices, the block is the quad to clear from. For E810 devices, the
27003a749623SJacob Keller  * block is the logical port to clear from.
270103cb4473SJacob Keller  */
270203cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
270303cb4473SJacob Keller {
27043a749623SJacob Keller 	if (ice_is_e810(hw))
270503cb4473SJacob Keller 		return ice_clear_phy_tstamp_e810(hw, block, idx);
27063a749623SJacob Keller 	else
27073a749623SJacob Keller 		return ice_clear_phy_tstamp_e822(hw, block, idx);
270803cb4473SJacob Keller }
2709885fe693SMaciej Machnikowski 
2710885fe693SMaciej Machnikowski /* E810T SMA functions
2711885fe693SMaciej Machnikowski  *
2712885fe693SMaciej Machnikowski  * The following functions operate specifically on E810T hardware and are used
2713885fe693SMaciej Machnikowski  * to access the extended GPIOs available.
2714885fe693SMaciej Machnikowski  */
2715885fe693SMaciej Machnikowski 
2716885fe693SMaciej Machnikowski /**
2717885fe693SMaciej Machnikowski  * ice_get_pca9575_handle
2718885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2719885fe693SMaciej Machnikowski  * @pca9575_handle: GPIO controller's handle
2720885fe693SMaciej Machnikowski  *
2721885fe693SMaciej Machnikowski  * Find and return the GPIO controller's handle in the netlist.
2722885fe693SMaciej Machnikowski  * When found - the value will be cached in the hw structure and following calls
2723885fe693SMaciej Machnikowski  * will return cached value
2724885fe693SMaciej Machnikowski  */
2725885fe693SMaciej Machnikowski static int
2726885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle)
2727885fe693SMaciej Machnikowski {
2728885fe693SMaciej Machnikowski 	struct ice_aqc_get_link_topo *cmd;
2729885fe693SMaciej Machnikowski 	struct ice_aq_desc desc;
2730885fe693SMaciej Machnikowski 	int status;
2731885fe693SMaciej Machnikowski 	u8 idx;
2732885fe693SMaciej Machnikowski 
2733885fe693SMaciej Machnikowski 	/* If handle was read previously return cached value */
2734885fe693SMaciej Machnikowski 	if (hw->io_expander_handle) {
2735885fe693SMaciej Machnikowski 		*pca9575_handle = hw->io_expander_handle;
2736885fe693SMaciej Machnikowski 		return 0;
2737885fe693SMaciej Machnikowski 	}
2738885fe693SMaciej Machnikowski 
2739885fe693SMaciej Machnikowski 	/* If handle was not detected read it from the netlist */
2740885fe693SMaciej Machnikowski 	cmd = &desc.params.get_link_topo;
2741885fe693SMaciej Machnikowski 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo);
2742885fe693SMaciej Machnikowski 
2743885fe693SMaciej Machnikowski 	/* Set node type to GPIO controller */
2744885fe693SMaciej Machnikowski 	cmd->addr.topo_params.node_type_ctx =
2745885fe693SMaciej Machnikowski 		(ICE_AQC_LINK_TOPO_NODE_TYPE_M &
2746885fe693SMaciej Machnikowski 		 ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL);
2747885fe693SMaciej Machnikowski 
2748885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX		2
2749885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX	1
2750885fe693SMaciej Machnikowski 
2751885fe693SMaciej Machnikowski 	/* Check if the SW IO expander controlling SMA exists in the netlist. */
2752885fe693SMaciej Machnikowski 	if (hw->device_id == ICE_DEV_ID_E810C_SFP)
2753885fe693SMaciej Machnikowski 		idx = SW_PCA9575_SFP_TOPO_IDX;
2754885fe693SMaciej Machnikowski 	else if (hw->device_id == ICE_DEV_ID_E810C_QSFP)
2755885fe693SMaciej Machnikowski 		idx = SW_PCA9575_QSFP_TOPO_IDX;
2756885fe693SMaciej Machnikowski 	else
2757885fe693SMaciej Machnikowski 		return -EOPNOTSUPP;
2758885fe693SMaciej Machnikowski 
2759885fe693SMaciej Machnikowski 	cmd->addr.topo_params.index = idx;
2760885fe693SMaciej Machnikowski 
2761885fe693SMaciej Machnikowski 	status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
2762885fe693SMaciej Machnikowski 	if (status)
2763885fe693SMaciej Machnikowski 		return -EOPNOTSUPP;
2764885fe693SMaciej Machnikowski 
2765885fe693SMaciej Machnikowski 	/* Verify if we found the right IO expander type */
2766885fe693SMaciej Machnikowski 	if (desc.params.get_link_topo.node_part_num !=
2767885fe693SMaciej Machnikowski 		ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575)
2768885fe693SMaciej Machnikowski 		return -EOPNOTSUPP;
2769885fe693SMaciej Machnikowski 
2770885fe693SMaciej Machnikowski 	/* If present save the handle and return it */
2771885fe693SMaciej Machnikowski 	hw->io_expander_handle =
2772885fe693SMaciej Machnikowski 		le16_to_cpu(desc.params.get_link_topo.addr.handle);
2773885fe693SMaciej Machnikowski 	*pca9575_handle = hw->io_expander_handle;
2774885fe693SMaciej Machnikowski 
2775885fe693SMaciej Machnikowski 	return 0;
2776885fe693SMaciej Machnikowski }
2777885fe693SMaciej Machnikowski 
2778885fe693SMaciej Machnikowski /**
2779885fe693SMaciej Machnikowski  * ice_read_sma_ctrl_e810t
2780885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2781885fe693SMaciej Machnikowski  * @data: pointer to data to be read from the GPIO controller
2782885fe693SMaciej Machnikowski  *
2783885fe693SMaciej Machnikowski  * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the
2784885fe693SMaciej Machnikowski  * PCA9575 expander, so only bits 3-7 in data are valid.
2785885fe693SMaciej Machnikowski  */
2786885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data)
2787885fe693SMaciej Machnikowski {
2788885fe693SMaciej Machnikowski 	int status;
2789885fe693SMaciej Machnikowski 	u16 handle;
2790885fe693SMaciej Machnikowski 	u8 i;
2791885fe693SMaciej Machnikowski 
2792885fe693SMaciej Machnikowski 	status = ice_get_pca9575_handle(hw, &handle);
2793885fe693SMaciej Machnikowski 	if (status)
2794885fe693SMaciej Machnikowski 		return status;
2795885fe693SMaciej Machnikowski 
2796885fe693SMaciej Machnikowski 	*data = 0;
2797885fe693SMaciej Machnikowski 
2798885fe693SMaciej Machnikowski 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
2799885fe693SMaciej Machnikowski 		bool pin;
2800885fe693SMaciej Machnikowski 
2801885fe693SMaciej Machnikowski 		status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
2802885fe693SMaciej Machnikowski 					 &pin, NULL);
2803885fe693SMaciej Machnikowski 		if (status)
2804885fe693SMaciej Machnikowski 			break;
2805885fe693SMaciej Machnikowski 		*data |= (u8)(!pin) << i;
2806885fe693SMaciej Machnikowski 	}
2807885fe693SMaciej Machnikowski 
2808885fe693SMaciej Machnikowski 	return status;
2809885fe693SMaciej Machnikowski }
2810885fe693SMaciej Machnikowski 
2811885fe693SMaciej Machnikowski /**
2812885fe693SMaciej Machnikowski  * ice_write_sma_ctrl_e810t
2813885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2814885fe693SMaciej Machnikowski  * @data: data to be written to the GPIO controller
2815885fe693SMaciej Machnikowski  *
2816885fe693SMaciej Machnikowski  * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1
2817885fe693SMaciej Machnikowski  * of the PCA9575 expander, so only bits 3-7 in data are valid.
2818885fe693SMaciej Machnikowski  */
2819885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data)
2820885fe693SMaciej Machnikowski {
2821885fe693SMaciej Machnikowski 	int status;
2822885fe693SMaciej Machnikowski 	u16 handle;
2823885fe693SMaciej Machnikowski 	u8 i;
2824885fe693SMaciej Machnikowski 
2825885fe693SMaciej Machnikowski 	status = ice_get_pca9575_handle(hw, &handle);
2826885fe693SMaciej Machnikowski 	if (status)
2827885fe693SMaciej Machnikowski 		return status;
2828885fe693SMaciej Machnikowski 
2829885fe693SMaciej Machnikowski 	for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) {
2830885fe693SMaciej Machnikowski 		bool pin;
2831885fe693SMaciej Machnikowski 
2832885fe693SMaciej Machnikowski 		pin = !(data & (1 << i));
2833885fe693SMaciej Machnikowski 		status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET,
2834885fe693SMaciej Machnikowski 					 pin, NULL);
2835885fe693SMaciej Machnikowski 		if (status)
2836885fe693SMaciej Machnikowski 			break;
2837885fe693SMaciej Machnikowski 	}
2838885fe693SMaciej Machnikowski 
2839885fe693SMaciej Machnikowski 	return status;
2840885fe693SMaciej Machnikowski }
2841885fe693SMaciej Machnikowski 
2842885fe693SMaciej Machnikowski /**
2843885fe693SMaciej Machnikowski  * ice_is_pca9575_present
2844885fe693SMaciej Machnikowski  * @hw: pointer to the hw struct
2845885fe693SMaciej Machnikowski  *
2846885fe693SMaciej Machnikowski  * Check if the SW IO expander is present in the netlist
2847885fe693SMaciej Machnikowski  */
2848885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw)
2849885fe693SMaciej Machnikowski {
2850885fe693SMaciej Machnikowski 	u16 handle = 0;
2851885fe693SMaciej Machnikowski 	int status;
2852885fe693SMaciej Machnikowski 
2853885fe693SMaciej Machnikowski 	if (!ice_is_e810t(hw))
2854885fe693SMaciej Machnikowski 		return false;
2855885fe693SMaciej Machnikowski 
2856885fe693SMaciej Machnikowski 	status = ice_get_pca9575_handle(hw, &handle);
2857885fe693SMaciej Machnikowski 
2858885fe693SMaciej Machnikowski 	return !status && handle;
2859885fe693SMaciej Machnikowski }
2860b2ee7256SJacob Keller 
2861b2ee7256SJacob Keller /**
2862b2ee7256SJacob Keller  * ice_ptp_init_phc - Initialize PTP hardware clock
2863b2ee7256SJacob Keller  * @hw: pointer to the HW struct
2864b2ee7256SJacob Keller  *
2865b2ee7256SJacob Keller  * Perform the steps required to initialize the PTP hardware clock.
2866b2ee7256SJacob Keller  */
2867b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw)
2868b2ee7256SJacob Keller {
2869b2ee7256SJacob Keller 	u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned;
2870b2ee7256SJacob Keller 
2871b2ee7256SJacob Keller 	/* Enable source clocks */
2872b2ee7256SJacob Keller 	wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M);
2873b2ee7256SJacob Keller 
2874b2ee7256SJacob Keller 	/* Clear event err indications for auxiliary pins */
2875b2ee7256SJacob Keller 	(void)rd32(hw, GLTSYN_STAT(src_idx));
2876b2ee7256SJacob Keller 
28773a749623SJacob Keller 	if (ice_is_e810(hw))
2878b2ee7256SJacob Keller 		return ice_ptp_init_phc_e810(hw);
28793a749623SJacob Keller 	else
28803a749623SJacob Keller 		return ice_ptp_init_phc_e822(hw);
2881b2ee7256SJacob Keller }
2882