103cb4473SJacob Keller // SPDX-License-Identifier: GPL-2.0 203cb4473SJacob Keller /* Copyright (C) 2021, Intel Corporation. */ 303cb4473SJacob Keller 41229b339SKarol Kolacinski #include <linux/delay.h> 503cb4473SJacob Keller #include "ice_common.h" 603cb4473SJacob Keller #include "ice_ptp_hw.h" 73a749623SJacob Keller #include "ice_ptp_consts.h" 8b111ab5aSJacob Keller #include "ice_cgu_regs.h" 903cb4473SJacob Keller 1003cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used 1103cb4473SJacob Keller * for the Precision Time Protocol. 1203cb4473SJacob Keller * 1303cb4473SJacob Keller * The ice hardware represents the current time using three registers: 1403cb4473SJacob Keller * 1503cb4473SJacob Keller * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R 1603cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1703cb4473SJacob Keller * | 32 bits | | 32 bits | | 32 bits | 1803cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1903cb4473SJacob Keller * 2003cb4473SJacob Keller * The registers are incremented every clock tick using a 40bit increment 2103cb4473SJacob Keller * value defined over two registers: 2203cb4473SJacob Keller * 2303cb4473SJacob Keller * GLTSYN_INCVAL_H GLTSYN_INCVAL_L 2403cb4473SJacob Keller * +---------------+ +---------------+ 2503cb4473SJacob Keller * | 8 bit s | | 32 bits | 2603cb4473SJacob Keller * +---------------+ +---------------+ 2703cb4473SJacob Keller * 2803cb4473SJacob Keller * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L 2903cb4473SJacob Keller * registers every clock source tick. Depending on the specific device 3003cb4473SJacob Keller * configuration, the clock source frequency could be one of a number of 3103cb4473SJacob Keller * values. 3203cb4473SJacob Keller * 3303cb4473SJacob Keller * For E810 devices, the increment frequency is 812.5 MHz 3403cb4473SJacob Keller * 353a749623SJacob Keller * For E822 devices the clock can be derived from different sources, and the 363a749623SJacob Keller * increment has an effective frequency of one of the following: 373a749623SJacob Keller * - 823.4375 MHz 383a749623SJacob Keller * - 783.36 MHz 393a749623SJacob Keller * - 796.875 MHz 403a749623SJacob Keller * - 816 MHz 413a749623SJacob Keller * - 830.078125 MHz 423a749623SJacob Keller * - 783.36 MHz 433a749623SJacob Keller * 4403cb4473SJacob Keller * The hardware captures timestamps in the PHY for incoming packets, and for 4503cb4473SJacob Keller * outgoing packets on request. To support this, the PHY maintains a timer 4603cb4473SJacob Keller * that matches the lower 64 bits of the global source timer. 4703cb4473SJacob Keller * 4803cb4473SJacob Keller * In order to ensure that the PHY timers and the source timer are equivalent, 4903cb4473SJacob Keller * shadow registers are used to prepare the desired initial values. A special 5003cb4473SJacob Keller * sync command is issued to trigger copying from the shadow registers into 5103cb4473SJacob Keller * the appropriate source and PHY registers simultaneously. 523a749623SJacob Keller * 533a749623SJacob Keller * The driver supports devices which have different PHYs with subtly different 543a749623SJacob Keller * mechanisms to program and control the timers. We divide the devices into 553a749623SJacob Keller * families named after the first major device, E810 and similar devices, and 563a749623SJacob Keller * E822 and similar devices. 573a749623SJacob Keller * 583a749623SJacob Keller * - E822 based devices have additional support for fine grained Vernier 593a749623SJacob Keller * calibration which requires significant setup 603a749623SJacob Keller * - The layout of timestamp data in the PHY register blocks is different 613a749623SJacob Keller * - The way timer synchronization commands are issued is different. 623a749623SJacob Keller * 633a749623SJacob Keller * To support this, very low level functions have an e810 or e822 suffix 643a749623SJacob Keller * indicating what type of device they work on. Higher level abstractions for 653a749623SJacob Keller * tasks that can be done on both devices do not have the suffix and will 663a749623SJacob Keller * correctly look up the appropriate low level function when running. 673a749623SJacob Keller * 683a749623SJacob Keller * Functions which only make sense on a single device family may not have 693a749623SJacob Keller * a suitable generic implementation 7003cb4473SJacob Keller */ 7103cb4473SJacob Keller 7203cb4473SJacob Keller /** 7303cb4473SJacob Keller * ice_get_ptp_src_clock_index - determine source clock index 7403cb4473SJacob Keller * @hw: pointer to HW struct 7503cb4473SJacob Keller * 7603cb4473SJacob Keller * Determine the source clock index currently in use, based on device 7703cb4473SJacob Keller * capabilities reported during initialization. 7803cb4473SJacob Keller */ 7903cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw) 8003cb4473SJacob Keller { 8103cb4473SJacob Keller return hw->func_caps.ts_func_info.tmr_index_assoc; 8203cb4473SJacob Keller } 8303cb4473SJacob Keller 843a749623SJacob Keller /** 853a749623SJacob Keller * ice_ptp_read_src_incval - Read source timer increment value 863a749623SJacob Keller * @hw: pointer to HW struct 873a749623SJacob Keller * 883a749623SJacob Keller * Read the increment value of the source timer and return it. 893a749623SJacob Keller */ 903a749623SJacob Keller static u64 ice_ptp_read_src_incval(struct ice_hw *hw) 913a749623SJacob Keller { 923a749623SJacob Keller u32 lo, hi; 933a749623SJacob Keller u8 tmr_idx; 943a749623SJacob Keller 953a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 963a749623SJacob Keller 973a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 983a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 993a749623SJacob Keller 1003a749623SJacob Keller return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo; 1013a749623SJacob Keller } 1023a749623SJacob Keller 1033a749623SJacob Keller /** 1043a749623SJacob Keller * ice_ptp_src_cmd - Prepare source timer for a timer command 1053a749623SJacob Keller * @hw: pointer to HW structure 1063a749623SJacob Keller * @cmd: Timer command 1073a749623SJacob Keller * 1083a749623SJacob Keller * Prepare the source timer for an upcoming timer sync command. 1093a749623SJacob Keller */ 1103a749623SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 1113a749623SJacob Keller { 1123a749623SJacob Keller u32 cmd_val; 1133a749623SJacob Keller u8 tmr_idx; 1143a749623SJacob Keller 1153a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 1163a749623SJacob Keller cmd_val = tmr_idx << SEL_CPK_SRC; 1173a749623SJacob Keller 1183a749623SJacob Keller switch (cmd) { 1193a749623SJacob Keller case INIT_TIME: 1203a749623SJacob Keller cmd_val |= GLTSYN_CMD_INIT_TIME; 1213a749623SJacob Keller break; 1223a749623SJacob Keller case INIT_INCVAL: 1233a749623SJacob Keller cmd_val |= GLTSYN_CMD_INIT_INCVAL; 1243a749623SJacob Keller break; 1253a749623SJacob Keller case ADJ_TIME: 1263a749623SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_TIME; 1273a749623SJacob Keller break; 1283a749623SJacob Keller case ADJ_TIME_AT_TIME: 1293a749623SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME; 1303a749623SJacob Keller break; 1313a749623SJacob Keller case READ_TIME: 1323a749623SJacob Keller cmd_val |= GLTSYN_CMD_READ_TIME; 1333a749623SJacob Keller break; 1343a749623SJacob Keller } 1353a749623SJacob Keller 1363a749623SJacob Keller wr32(hw, GLTSYN_CMD, cmd_val); 1373a749623SJacob Keller } 1383a749623SJacob Keller 1393a749623SJacob Keller /** 1403a749623SJacob Keller * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands 1413a749623SJacob Keller * @hw: pointer to HW struct 1423a749623SJacob Keller * 1433a749623SJacob Keller * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the 1443a749623SJacob Keller * write immediately. This triggers the hardware to begin executing all of the 1453a749623SJacob Keller * source and PHY timer commands synchronously. 1463a749623SJacob Keller */ 1473a749623SJacob Keller static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw) 1483a749623SJacob Keller { 1493a749623SJacob Keller wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD); 1503a749623SJacob Keller ice_flush(hw); 1513a749623SJacob Keller } 1523a749623SJacob Keller 1533a749623SJacob Keller /* E822 family functions 1543a749623SJacob Keller * 1553a749623SJacob Keller * The following functions operate on the E822 family of devices. 1563a749623SJacob Keller */ 1573a749623SJacob Keller 1583a749623SJacob Keller /** 1593a749623SJacob Keller * ice_fill_phy_msg_e822 - Fill message data for a PHY register access 1603a749623SJacob Keller * @msg: the PHY message buffer to fill in 1613a749623SJacob Keller * @port: the port to access 1623a749623SJacob Keller * @offset: the register offset 1633a749623SJacob Keller */ 1643a749623SJacob Keller static void 1653a749623SJacob Keller ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset) 1663a749623SJacob Keller { 1673a749623SJacob Keller int phy_port, phy, quadtype; 1683a749623SJacob Keller 1693a749623SJacob Keller phy_port = port % ICE_PORTS_PER_PHY; 1703a749623SJacob Keller phy = port / ICE_PORTS_PER_PHY; 1713a749623SJacob Keller quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE; 1723a749623SJacob Keller 1733a749623SJacob Keller if (quadtype == 0) { 1743a749623SJacob Keller msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port); 1753a749623SJacob Keller msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port); 1763a749623SJacob Keller } else { 1773a749623SJacob Keller msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port); 1783a749623SJacob Keller msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port); 1793a749623SJacob Keller } 1803a749623SJacob Keller 1813a749623SJacob Keller if (phy == 0) 1823a749623SJacob Keller msg->dest_dev = rmn_0; 1833a749623SJacob Keller else if (phy == 1) 1843a749623SJacob Keller msg->dest_dev = rmn_1; 1853a749623SJacob Keller else 1863a749623SJacob Keller msg->dest_dev = rmn_2; 1873a749623SJacob Keller } 1883a749623SJacob Keller 1893a749623SJacob Keller /** 1903a749623SJacob Keller * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register 1913a749623SJacob Keller * @low_addr: the low address to check 1923a749623SJacob Keller * @high_addr: on return, contains the high address of the 64bit register 1933a749623SJacob Keller * 1943a749623SJacob Keller * Checks if the provided low address is one of the known 64bit PHY values 1953a749623SJacob Keller * represented as two 32bit registers. If it is, return the appropriate high 1963a749623SJacob Keller * register offset to use. 1973a749623SJacob Keller */ 1983a749623SJacob Keller static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr) 1993a749623SJacob Keller { 2003a749623SJacob Keller switch (low_addr) { 2013a749623SJacob Keller case P_REG_PAR_PCS_TX_OFFSET_L: 2023a749623SJacob Keller *high_addr = P_REG_PAR_PCS_TX_OFFSET_U; 2033a749623SJacob Keller return true; 2043a749623SJacob Keller case P_REG_PAR_PCS_RX_OFFSET_L: 2053a749623SJacob Keller *high_addr = P_REG_PAR_PCS_RX_OFFSET_U; 2063a749623SJacob Keller return true; 2073a749623SJacob Keller case P_REG_PAR_TX_TIME_L: 2083a749623SJacob Keller *high_addr = P_REG_PAR_TX_TIME_U; 2093a749623SJacob Keller return true; 2103a749623SJacob Keller case P_REG_PAR_RX_TIME_L: 2113a749623SJacob Keller *high_addr = P_REG_PAR_RX_TIME_U; 2123a749623SJacob Keller return true; 2133a749623SJacob Keller case P_REG_TOTAL_TX_OFFSET_L: 2143a749623SJacob Keller *high_addr = P_REG_TOTAL_TX_OFFSET_U; 2153a749623SJacob Keller return true; 2163a749623SJacob Keller case P_REG_TOTAL_RX_OFFSET_L: 2173a749623SJacob Keller *high_addr = P_REG_TOTAL_RX_OFFSET_U; 2183a749623SJacob Keller return true; 2193a749623SJacob Keller case P_REG_UIX66_10G_40G_L: 2203a749623SJacob Keller *high_addr = P_REG_UIX66_10G_40G_U; 2213a749623SJacob Keller return true; 2223a749623SJacob Keller case P_REG_UIX66_25G_100G_L: 2233a749623SJacob Keller *high_addr = P_REG_UIX66_25G_100G_U; 2243a749623SJacob Keller return true; 2253a749623SJacob Keller case P_REG_TX_CAPTURE_L: 2263a749623SJacob Keller *high_addr = P_REG_TX_CAPTURE_U; 2273a749623SJacob Keller return true; 2283a749623SJacob Keller case P_REG_RX_CAPTURE_L: 2293a749623SJacob Keller *high_addr = P_REG_RX_CAPTURE_U; 2303a749623SJacob Keller return true; 2313a749623SJacob Keller case P_REG_TX_TIMER_INC_PRE_L: 2323a749623SJacob Keller *high_addr = P_REG_TX_TIMER_INC_PRE_U; 2333a749623SJacob Keller return true; 2343a749623SJacob Keller case P_REG_RX_TIMER_INC_PRE_L: 2353a749623SJacob Keller *high_addr = P_REG_RX_TIMER_INC_PRE_U; 2363a749623SJacob Keller return true; 2373a749623SJacob Keller default: 2383a749623SJacob Keller return false; 2393a749623SJacob Keller } 2403a749623SJacob Keller } 2413a749623SJacob Keller 2423a749623SJacob Keller /** 2433a749623SJacob Keller * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register 2443a749623SJacob Keller * @low_addr: the low address to check 2453a749623SJacob Keller * @high_addr: on return, contains the high address of the 40bit value 2463a749623SJacob Keller * 2473a749623SJacob Keller * Checks if the provided low address is one of the known 40bit PHY values 2483a749623SJacob Keller * split into two registers with the lower 8 bits in the low register and the 2493a749623SJacob Keller * upper 32 bits in the high register. If it is, return the appropriate high 2503a749623SJacob Keller * register offset to use. 2513a749623SJacob Keller */ 2523a749623SJacob Keller static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr) 2533a749623SJacob Keller { 2543a749623SJacob Keller switch (low_addr) { 2553a749623SJacob Keller case P_REG_TIMETUS_L: 2563a749623SJacob Keller *high_addr = P_REG_TIMETUS_U; 2573a749623SJacob Keller return true; 2583a749623SJacob Keller case P_REG_PAR_RX_TUS_L: 2593a749623SJacob Keller *high_addr = P_REG_PAR_RX_TUS_U; 2603a749623SJacob Keller return true; 2613a749623SJacob Keller case P_REG_PAR_TX_TUS_L: 2623a749623SJacob Keller *high_addr = P_REG_PAR_TX_TUS_U; 2633a749623SJacob Keller return true; 2643a749623SJacob Keller case P_REG_PCS_RX_TUS_L: 2653a749623SJacob Keller *high_addr = P_REG_PCS_RX_TUS_U; 2663a749623SJacob Keller return true; 2673a749623SJacob Keller case P_REG_PCS_TX_TUS_L: 2683a749623SJacob Keller *high_addr = P_REG_PCS_TX_TUS_U; 2693a749623SJacob Keller return true; 2703a749623SJacob Keller case P_REG_DESK_PAR_RX_TUS_L: 2713a749623SJacob Keller *high_addr = P_REG_DESK_PAR_RX_TUS_U; 2723a749623SJacob Keller return true; 2733a749623SJacob Keller case P_REG_DESK_PAR_TX_TUS_L: 2743a749623SJacob Keller *high_addr = P_REG_DESK_PAR_TX_TUS_U; 2753a749623SJacob Keller return true; 2763a749623SJacob Keller case P_REG_DESK_PCS_RX_TUS_L: 2773a749623SJacob Keller *high_addr = P_REG_DESK_PCS_RX_TUS_U; 2783a749623SJacob Keller return true; 2793a749623SJacob Keller case P_REG_DESK_PCS_TX_TUS_L: 2803a749623SJacob Keller *high_addr = P_REG_DESK_PCS_TX_TUS_U; 2813a749623SJacob Keller return true; 2823a749623SJacob Keller default: 2833a749623SJacob Keller return false; 2843a749623SJacob Keller } 2853a749623SJacob Keller } 2863a749623SJacob Keller 2873a749623SJacob Keller /** 2883a749623SJacob Keller * ice_read_phy_reg_e822 - Read a PHY register 2893a749623SJacob Keller * @hw: pointer to the HW struct 2903a749623SJacob Keller * @port: PHY port to read from 2913a749623SJacob Keller * @offset: PHY register offset to read 2923a749623SJacob Keller * @val: on return, the contents read from the PHY 2933a749623SJacob Keller * 2943a749623SJacob Keller * Read a PHY register for the given port over the device sideband queue. 2953a749623SJacob Keller */ 2963a749623SJacob Keller int 2973a749623SJacob Keller ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val) 2983a749623SJacob Keller { 2993a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 3003a749623SJacob Keller int err; 3013a749623SJacob Keller 3023a749623SJacob Keller ice_fill_phy_msg_e822(&msg, port, offset); 3033a749623SJacob Keller msg.opcode = ice_sbq_msg_rd; 3043a749623SJacob Keller 3053a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 3063a749623SJacob Keller if (err) { 3073a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 3083a749623SJacob Keller err); 3093a749623SJacob Keller return err; 3103a749623SJacob Keller } 3113a749623SJacob Keller 3123a749623SJacob Keller *val = msg.data; 3133a749623SJacob Keller 3143a749623SJacob Keller return 0; 3153a749623SJacob Keller } 3163a749623SJacob Keller 3173a749623SJacob Keller /** 3183a749623SJacob Keller * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers 3193a749623SJacob Keller * @hw: pointer to the HW struct 3203a749623SJacob Keller * @port: PHY port to read from 3213a749623SJacob Keller * @low_addr: offset of the lower register to read from 3223a749623SJacob Keller * @val: on return, the contents of the 64bit value from the PHY registers 3233a749623SJacob Keller * 3243a749623SJacob Keller * Reads the two registers associated with a 64bit value and returns it in the 3253a749623SJacob Keller * val pointer. The offset always specifies the lower register offset to use. 3263a749623SJacob Keller * The high offset is looked up. This function only operates on registers 3273a749623SJacob Keller * known to be two parts of a 64bit value. 3283a749623SJacob Keller */ 3293a749623SJacob Keller static int 3303a749623SJacob Keller ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) 3313a749623SJacob Keller { 3323a749623SJacob Keller u32 low, high; 3333a749623SJacob Keller u16 high_addr; 3343a749623SJacob Keller int err; 3353a749623SJacob Keller 3363a749623SJacob Keller /* Only operate on registers known to be split into two 32bit 3373a749623SJacob Keller * registers. 3383a749623SJacob Keller */ 3393a749623SJacob Keller if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { 3403a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", 3413a749623SJacob Keller low_addr); 3423a749623SJacob Keller return -EINVAL; 3433a749623SJacob Keller } 3443a749623SJacob Keller 3453a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, low_addr, &low); 3463a749623SJacob Keller if (err) { 3473a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d", 3483a749623SJacob Keller low_addr, err); 3493a749623SJacob Keller return err; 3503a749623SJacob Keller } 3513a749623SJacob Keller 3523a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, high_addr, &high); 3533a749623SJacob Keller if (err) { 3543a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d", 3553a749623SJacob Keller high_addr, err); 3563a749623SJacob Keller return err; 3573a749623SJacob Keller } 3583a749623SJacob Keller 3593a749623SJacob Keller *val = (u64)high << 32 | low; 3603a749623SJacob Keller 3613a749623SJacob Keller return 0; 3623a749623SJacob Keller } 3633a749623SJacob Keller 3643a749623SJacob Keller /** 3653a749623SJacob Keller * ice_write_phy_reg_e822 - Write a PHY register 3663a749623SJacob Keller * @hw: pointer to the HW struct 3673a749623SJacob Keller * @port: PHY port to write to 3683a749623SJacob Keller * @offset: PHY register offset to write 3693a749623SJacob Keller * @val: The value to write to the register 3703a749623SJacob Keller * 3713a749623SJacob Keller * Write a PHY register for the given port over the device sideband queue. 3723a749623SJacob Keller */ 3733a749623SJacob Keller int 3743a749623SJacob Keller ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val) 3753a749623SJacob Keller { 3763a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 3773a749623SJacob Keller int err; 3783a749623SJacob Keller 3793a749623SJacob Keller ice_fill_phy_msg_e822(&msg, port, offset); 3803a749623SJacob Keller msg.opcode = ice_sbq_msg_wr; 3813a749623SJacob Keller msg.data = val; 3823a749623SJacob Keller 3833a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 3843a749623SJacob Keller if (err) { 3853a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 3863a749623SJacob Keller err); 3873a749623SJacob Keller return err; 3883a749623SJacob Keller } 3893a749623SJacob Keller 3903a749623SJacob Keller return 0; 3913a749623SJacob Keller } 3923a749623SJacob Keller 3933a749623SJacob Keller /** 3943a749623SJacob Keller * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY 3953a749623SJacob Keller * @hw: pointer to the HW struct 3963a749623SJacob Keller * @port: port to write to 3973a749623SJacob Keller * @low_addr: offset of the low register 3983a749623SJacob Keller * @val: 40b value to write 3993a749623SJacob Keller * 4003a749623SJacob Keller * Write the provided 40b value to the two associated registers by splitting 4013a749623SJacob Keller * it up into two chunks, the lower 8 bits and the upper 32 bits. 4023a749623SJacob Keller */ 4033a749623SJacob Keller static int 4043a749623SJacob Keller ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) 4053a749623SJacob Keller { 4063a749623SJacob Keller u32 low, high; 4073a749623SJacob Keller u16 high_addr; 4083a749623SJacob Keller int err; 4093a749623SJacob Keller 4103a749623SJacob Keller /* Only operate on registers known to be split into a lower 8 bit 4113a749623SJacob Keller * register and an upper 32 bit register. 4123a749623SJacob Keller */ 4133a749623SJacob Keller if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) { 4143a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n", 4153a749623SJacob Keller low_addr); 4163a749623SJacob Keller return -EINVAL; 4173a749623SJacob Keller } 4183a749623SJacob Keller 4193a749623SJacob Keller low = (u32)(val & P_REG_40B_LOW_M); 4203a749623SJacob Keller high = (u32)(val >> P_REG_40B_HIGH_S); 4213a749623SJacob Keller 4223a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, low_addr, low); 4233a749623SJacob Keller if (err) { 4243a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", 4253a749623SJacob Keller low_addr, err); 4263a749623SJacob Keller return err; 4273a749623SJacob Keller } 4283a749623SJacob Keller 4293a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, high_addr, high); 4303a749623SJacob Keller if (err) { 4313a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", 4323a749623SJacob Keller high_addr, err); 4333a749623SJacob Keller return err; 4343a749623SJacob Keller } 4353a749623SJacob Keller 4363a749623SJacob Keller return 0; 4373a749623SJacob Keller } 4383a749623SJacob Keller 4393a749623SJacob Keller /** 4403a749623SJacob Keller * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers 4413a749623SJacob Keller * @hw: pointer to the HW struct 4423a749623SJacob Keller * @port: PHY port to read from 4433a749623SJacob Keller * @low_addr: offset of the lower register to read from 4443a749623SJacob Keller * @val: the contents of the 64bit value to write to PHY 4453a749623SJacob Keller * 4463a749623SJacob Keller * Write the 64bit value to the two associated 32bit PHY registers. The offset 4473a749623SJacob Keller * is always specified as the lower register, and the high address is looked 4483a749623SJacob Keller * up. This function only operates on registers known to be two parts of 4493a749623SJacob Keller * a 64bit value. 4503a749623SJacob Keller */ 4513a749623SJacob Keller static int 4523a749623SJacob Keller ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) 4533a749623SJacob Keller { 4543a749623SJacob Keller u32 low, high; 4553a749623SJacob Keller u16 high_addr; 4563a749623SJacob Keller int err; 4573a749623SJacob Keller 4583a749623SJacob Keller /* Only operate on registers known to be split into two 32bit 4593a749623SJacob Keller * registers. 4603a749623SJacob Keller */ 4613a749623SJacob Keller if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { 4623a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", 4633a749623SJacob Keller low_addr); 4643a749623SJacob Keller return -EINVAL; 4653a749623SJacob Keller } 4663a749623SJacob Keller 4673a749623SJacob Keller low = lower_32_bits(val); 4683a749623SJacob Keller high = upper_32_bits(val); 4693a749623SJacob Keller 4703a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, low_addr, low); 4713a749623SJacob Keller if (err) { 4723a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", 4733a749623SJacob Keller low_addr, err); 4743a749623SJacob Keller return err; 4753a749623SJacob Keller } 4763a749623SJacob Keller 4773a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, high_addr, high); 4783a749623SJacob Keller if (err) { 4793a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", 4803a749623SJacob Keller high_addr, err); 4813a749623SJacob Keller return err; 4823a749623SJacob Keller } 4833a749623SJacob Keller 4843a749623SJacob Keller return 0; 4853a749623SJacob Keller } 4863a749623SJacob Keller 4873a749623SJacob Keller /** 4883a749623SJacob Keller * ice_fill_quad_msg_e822 - Fill message data for quad register access 4893a749623SJacob Keller * @msg: the PHY message buffer to fill in 4903a749623SJacob Keller * @quad: the quad to access 4913a749623SJacob Keller * @offset: the register offset 4923a749623SJacob Keller * 4933a749623SJacob Keller * Fill a message buffer for accessing a register in a quad shared between 4943a749623SJacob Keller * multiple PHYs. 4953a749623SJacob Keller */ 4963a749623SJacob Keller static void 4973a749623SJacob Keller ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) 4983a749623SJacob Keller { 4993a749623SJacob Keller u32 addr; 5003a749623SJacob Keller 5013a749623SJacob Keller msg->dest_dev = rmn_0; 5023a749623SJacob Keller 5033a749623SJacob Keller if ((quad % ICE_NUM_QUAD_TYPE) == 0) 5043a749623SJacob Keller addr = Q_0_BASE + offset; 5053a749623SJacob Keller else 5063a749623SJacob Keller addr = Q_1_BASE + offset; 5073a749623SJacob Keller 5083a749623SJacob Keller msg->msg_addr_low = lower_16_bits(addr); 5093a749623SJacob Keller msg->msg_addr_high = upper_16_bits(addr); 5103a749623SJacob Keller } 5113a749623SJacob Keller 5123a749623SJacob Keller /** 5133a749623SJacob Keller * ice_read_quad_reg_e822 - Read a PHY quad register 5143a749623SJacob Keller * @hw: pointer to the HW struct 5153a749623SJacob Keller * @quad: quad to read from 5163a749623SJacob Keller * @offset: quad register offset to read 5173a749623SJacob Keller * @val: on return, the contents read from the quad 5183a749623SJacob Keller * 5193a749623SJacob Keller * Read a quad register over the device sideband queue. Quad registers are 5203a749623SJacob Keller * shared between multiple PHYs. 5213a749623SJacob Keller */ 5223a749623SJacob Keller int 5233a749623SJacob Keller ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) 5243a749623SJacob Keller { 5253a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 5263a749623SJacob Keller int err; 5273a749623SJacob Keller 5283a749623SJacob Keller if (quad >= ICE_MAX_QUAD) 5293a749623SJacob Keller return -EINVAL; 5303a749623SJacob Keller 5313a749623SJacob Keller ice_fill_quad_msg_e822(&msg, quad, offset); 5323a749623SJacob Keller msg.opcode = ice_sbq_msg_rd; 5333a749623SJacob Keller 5343a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 5353a749623SJacob Keller if (err) { 5363a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 5373a749623SJacob Keller err); 5383a749623SJacob Keller return err; 5393a749623SJacob Keller } 5403a749623SJacob Keller 5413a749623SJacob Keller *val = msg.data; 5423a749623SJacob Keller 5433a749623SJacob Keller return 0; 5443a749623SJacob Keller } 5453a749623SJacob Keller 5463a749623SJacob Keller /** 5473a749623SJacob Keller * ice_write_quad_reg_e822 - Write a PHY quad register 5483a749623SJacob Keller * @hw: pointer to the HW struct 5493a749623SJacob Keller * @quad: quad to write to 5503a749623SJacob Keller * @offset: quad register offset to write 5513a749623SJacob Keller * @val: The value to write to the register 5523a749623SJacob Keller * 5533a749623SJacob Keller * Write a quad register over the device sideband queue. Quad registers are 5543a749623SJacob Keller * shared between multiple PHYs. 5553a749623SJacob Keller */ 5563a749623SJacob Keller int 5573a749623SJacob Keller ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val) 5583a749623SJacob Keller { 5593a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 5603a749623SJacob Keller int err; 5613a749623SJacob Keller 5623a749623SJacob Keller if (quad >= ICE_MAX_QUAD) 5633a749623SJacob Keller return -EINVAL; 5643a749623SJacob Keller 5653a749623SJacob Keller ice_fill_quad_msg_e822(&msg, quad, offset); 5663a749623SJacob Keller msg.opcode = ice_sbq_msg_wr; 5673a749623SJacob Keller msg.data = val; 5683a749623SJacob Keller 5693a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 5703a749623SJacob Keller if (err) { 5713a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 5723a749623SJacob Keller err); 5733a749623SJacob Keller return err; 5743a749623SJacob Keller } 5753a749623SJacob Keller 5763a749623SJacob Keller return 0; 5773a749623SJacob Keller } 5783a749623SJacob Keller 5793a749623SJacob Keller /** 5803a749623SJacob Keller * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block 5813a749623SJacob Keller * @hw: pointer to the HW struct 5823a749623SJacob Keller * @quad: the quad to read from 5833a749623SJacob Keller * @idx: the timestamp index to read 5843a749623SJacob Keller * @tstamp: on return, the 40bit timestamp value 5853a749623SJacob Keller * 5863a749623SJacob Keller * Read a 40bit timestamp value out of the two associated registers in the 5873a749623SJacob Keller * quad memory block that is shared between the internal PHYs of the E822 5883a749623SJacob Keller * family of devices. 5893a749623SJacob Keller */ 5903a749623SJacob Keller static int 5913a749623SJacob Keller ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) 5923a749623SJacob Keller { 5933a749623SJacob Keller u16 lo_addr, hi_addr; 5943a749623SJacob Keller u32 lo, hi; 5953a749623SJacob Keller int err; 5963a749623SJacob Keller 5973a749623SJacob Keller lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); 5983a749623SJacob Keller hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); 5993a749623SJacob Keller 6003a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo); 6013a749623SJacob Keller if (err) { 6023a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 6033a749623SJacob Keller err); 6043a749623SJacob Keller return err; 6053a749623SJacob Keller } 6063a749623SJacob Keller 6073a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi); 6083a749623SJacob Keller if (err) { 6093a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 6103a749623SJacob Keller err); 6113a749623SJacob Keller return err; 6123a749623SJacob Keller } 6133a749623SJacob Keller 6143a749623SJacob Keller /* For E822 based internal PHYs, the timestamp is reported with the 6153a749623SJacob Keller * lower 8 bits in the low register, and the upper 32 bits in the high 6163a749623SJacob Keller * register. 6173a749623SJacob Keller */ 6183a749623SJacob Keller *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M); 6193a749623SJacob Keller 6203a749623SJacob Keller return 0; 6213a749623SJacob Keller } 6223a749623SJacob Keller 6233a749623SJacob Keller /** 6243a749623SJacob Keller * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block 6253a749623SJacob Keller * @hw: pointer to the HW struct 6263a749623SJacob Keller * @quad: the quad to read from 6273a749623SJacob Keller * @idx: the timestamp index to reset 6283a749623SJacob Keller * 6293a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the PHY quad block that is 6303a749623SJacob Keller * shared between the internal PHYs on the E822 devices. 6313a749623SJacob Keller */ 6323a749623SJacob Keller static int 6333a749623SJacob Keller ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx) 6343a749623SJacob Keller { 6353a749623SJacob Keller u16 lo_addr, hi_addr; 6363a749623SJacob Keller int err; 6373a749623SJacob Keller 6383a749623SJacob Keller lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); 6393a749623SJacob Keller hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); 6403a749623SJacob Keller 6413a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0); 6423a749623SJacob Keller if (err) { 6433a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 6443a749623SJacob Keller err); 6453a749623SJacob Keller return err; 6463a749623SJacob Keller } 6473a749623SJacob Keller 6483a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0); 6493a749623SJacob Keller if (err) { 6503a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 6513a749623SJacob Keller err); 6523a749623SJacob Keller return err; 6533a749623SJacob Keller } 6543a749623SJacob Keller 6553a749623SJacob Keller return 0; 6563a749623SJacob Keller } 6573a749623SJacob Keller 6583a749623SJacob Keller /** 659407b66c0SKarol Kolacinski * ice_ptp_reset_ts_memory_quad_e822 - Clear all timestamps from the quad block 660407b66c0SKarol Kolacinski * @hw: pointer to the HW struct 661407b66c0SKarol Kolacinski * @quad: the quad to read from 662407b66c0SKarol Kolacinski * 663407b66c0SKarol Kolacinski * Clear all timestamps from the PHY quad block that is shared between the 664407b66c0SKarol Kolacinski * internal PHYs on the E822 devices. 665407b66c0SKarol Kolacinski */ 666407b66c0SKarol Kolacinski void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad) 667407b66c0SKarol Kolacinski { 668407b66c0SKarol Kolacinski ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M); 669407b66c0SKarol Kolacinski ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M); 670407b66c0SKarol Kolacinski } 671407b66c0SKarol Kolacinski 672407b66c0SKarol Kolacinski /** 673407b66c0SKarol Kolacinski * ice_ptp_reset_ts_memory_e822 - Clear all timestamps from all quad blocks 674407b66c0SKarol Kolacinski * @hw: pointer to the HW struct 675407b66c0SKarol Kolacinski */ 676407b66c0SKarol Kolacinski static void ice_ptp_reset_ts_memory_e822(struct ice_hw *hw) 677407b66c0SKarol Kolacinski { 678407b66c0SKarol Kolacinski unsigned int quad; 679407b66c0SKarol Kolacinski 680407b66c0SKarol Kolacinski for (quad = 0; quad < ICE_MAX_QUAD; quad++) 681407b66c0SKarol Kolacinski ice_ptp_reset_ts_memory_quad_e822(hw, quad); 682407b66c0SKarol Kolacinski } 683407b66c0SKarol Kolacinski 684407b66c0SKarol Kolacinski /** 685b111ab5aSJacob Keller * ice_read_cgu_reg_e822 - Read a CGU register 686b111ab5aSJacob Keller * @hw: pointer to the HW struct 687b111ab5aSJacob Keller * @addr: Register address to read 688b111ab5aSJacob Keller * @val: storage for register value read 689b111ab5aSJacob Keller * 690b111ab5aSJacob Keller * Read the contents of a register of the Clock Generation Unit. Only 691b111ab5aSJacob Keller * applicable to E822 devices. 692b111ab5aSJacob Keller */ 693b111ab5aSJacob Keller static int 694b111ab5aSJacob Keller ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) 695b111ab5aSJacob Keller { 696b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 697b111ab5aSJacob Keller int err; 698b111ab5aSJacob Keller 699b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_rd; 700b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 701b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 702b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 703b111ab5aSJacob Keller 704b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 705b111ab5aSJacob Keller if (err) { 706b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n", 707b111ab5aSJacob Keller addr, err); 708b111ab5aSJacob Keller return err; 709b111ab5aSJacob Keller } 710b111ab5aSJacob Keller 711b111ab5aSJacob Keller *val = cgu_msg.data; 712b111ab5aSJacob Keller 713b111ab5aSJacob Keller return err; 714b111ab5aSJacob Keller } 715b111ab5aSJacob Keller 716b111ab5aSJacob Keller /** 717b111ab5aSJacob Keller * ice_write_cgu_reg_e822 - Write a CGU register 718b111ab5aSJacob Keller * @hw: pointer to the HW struct 719b111ab5aSJacob Keller * @addr: Register address to write 720b111ab5aSJacob Keller * @val: value to write into the register 721b111ab5aSJacob Keller * 722b111ab5aSJacob Keller * Write the specified value to a register of the Clock Generation Unit. Only 723b111ab5aSJacob Keller * applicable to E822 devices. 724b111ab5aSJacob Keller */ 725b111ab5aSJacob Keller static int 726b111ab5aSJacob Keller ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val) 727b111ab5aSJacob Keller { 728b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 729b111ab5aSJacob Keller int err; 730b111ab5aSJacob Keller 731b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_wr; 732b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 733b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 734b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 735b111ab5aSJacob Keller cgu_msg.data = val; 736b111ab5aSJacob Keller 737b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 738b111ab5aSJacob Keller if (err) { 739b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n", 740b111ab5aSJacob Keller addr, err); 741b111ab5aSJacob Keller return err; 742b111ab5aSJacob Keller } 743b111ab5aSJacob Keller 744b111ab5aSJacob Keller return err; 745b111ab5aSJacob Keller } 746b111ab5aSJacob Keller 747b111ab5aSJacob Keller /** 748b111ab5aSJacob Keller * ice_clk_freq_str - Convert time_ref_freq to string 749b111ab5aSJacob Keller * @clk_freq: Clock frequency 750b111ab5aSJacob Keller * 751b111ab5aSJacob Keller * Convert the specified TIME_REF clock frequency to a string. 752b111ab5aSJacob Keller */ 753b111ab5aSJacob Keller static const char *ice_clk_freq_str(u8 clk_freq) 754b111ab5aSJacob Keller { 755b111ab5aSJacob Keller switch ((enum ice_time_ref_freq)clk_freq) { 756b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_25_000: 757b111ab5aSJacob Keller return "25 MHz"; 758b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_122_880: 759b111ab5aSJacob Keller return "122.88 MHz"; 760b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_125_000: 761b111ab5aSJacob Keller return "125 MHz"; 762b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_153_600: 763b111ab5aSJacob Keller return "153.6 MHz"; 764b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_156_250: 765b111ab5aSJacob Keller return "156.25 MHz"; 766b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_245_760: 767b111ab5aSJacob Keller return "245.76 MHz"; 768b111ab5aSJacob Keller default: 769b111ab5aSJacob Keller return "Unknown"; 770b111ab5aSJacob Keller } 771b111ab5aSJacob Keller } 772b111ab5aSJacob Keller 773b111ab5aSJacob Keller /** 774b111ab5aSJacob Keller * ice_clk_src_str - Convert time_ref_src to string 775b111ab5aSJacob Keller * @clk_src: Clock source 776b111ab5aSJacob Keller * 777b111ab5aSJacob Keller * Convert the specified clock source to its string name. 778b111ab5aSJacob Keller */ 779b111ab5aSJacob Keller static const char *ice_clk_src_str(u8 clk_src) 780b111ab5aSJacob Keller { 781b111ab5aSJacob Keller switch ((enum ice_clk_src)clk_src) { 782b111ab5aSJacob Keller case ICE_CLK_SRC_TCX0: 783b111ab5aSJacob Keller return "TCX0"; 784b111ab5aSJacob Keller case ICE_CLK_SRC_TIME_REF: 785b111ab5aSJacob Keller return "TIME_REF"; 786b111ab5aSJacob Keller default: 787b111ab5aSJacob Keller return "Unknown"; 788b111ab5aSJacob Keller } 789b111ab5aSJacob Keller } 790b111ab5aSJacob Keller 791b111ab5aSJacob Keller /** 792b111ab5aSJacob Keller * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit 793b111ab5aSJacob Keller * @hw: pointer to the HW struct 794b111ab5aSJacob Keller * @clk_freq: Clock frequency to program 795b111ab5aSJacob Keller * @clk_src: Clock source to select (TIME_REF, or TCX0) 796b111ab5aSJacob Keller * 797b111ab5aSJacob Keller * Configure the Clock Generation Unit with the desired clock frequency and 798b111ab5aSJacob Keller * time reference, enabling the PLL which drives the PTP hardware clock. 799b111ab5aSJacob Keller */ 800b111ab5aSJacob Keller static int 801b111ab5aSJacob Keller ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, 802b111ab5aSJacob Keller enum ice_clk_src clk_src) 803b111ab5aSJacob Keller { 804b111ab5aSJacob Keller union tspll_ro_bwm_lf bwm_lf; 805b111ab5aSJacob Keller union nac_cgu_dword19 dw19; 806b111ab5aSJacob Keller union nac_cgu_dword22 dw22; 807b111ab5aSJacob Keller union nac_cgu_dword24 dw24; 808b111ab5aSJacob Keller union nac_cgu_dword9 dw9; 809b111ab5aSJacob Keller int err; 810b111ab5aSJacob Keller 811b111ab5aSJacob Keller if (clk_freq >= NUM_ICE_TIME_REF_FREQ) { 812b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", 813b111ab5aSJacob Keller clk_freq); 814b111ab5aSJacob Keller return -EINVAL; 815b111ab5aSJacob Keller } 816b111ab5aSJacob Keller 817b111ab5aSJacob Keller if (clk_src >= NUM_ICE_CLK_SRC) { 818b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", 819b111ab5aSJacob Keller clk_src); 820b111ab5aSJacob Keller return -EINVAL; 821b111ab5aSJacob Keller } 822b111ab5aSJacob Keller 823b111ab5aSJacob Keller if (clk_src == ICE_CLK_SRC_TCX0 && 824b111ab5aSJacob Keller clk_freq != ICE_TIME_REF_FREQ_25_000) { 825b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), 826b111ab5aSJacob Keller "TCX0 only supports 25 MHz frequency\n"); 827b111ab5aSJacob Keller return -EINVAL; 828b111ab5aSJacob Keller } 829b111ab5aSJacob Keller 830b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val); 831b111ab5aSJacob Keller if (err) 832b111ab5aSJacob Keller return err; 833b111ab5aSJacob Keller 834b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 835b111ab5aSJacob Keller if (err) 836b111ab5aSJacob Keller return err; 837b111ab5aSJacob Keller 838b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 839b111ab5aSJacob Keller if (err) 840b111ab5aSJacob Keller return err; 841b111ab5aSJacob Keller 842b111ab5aSJacob Keller /* Log the current clock configuration */ 843b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 844b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 845b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 846b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 847b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 848b111ab5aSJacob Keller 849b111ab5aSJacob Keller /* Disable the PLL before changing the clock source or frequency */ 850b111ab5aSJacob Keller if (dw24.field.ts_pll_enable) { 851b111ab5aSJacob Keller dw24.field.ts_pll_enable = 0; 852b111ab5aSJacob Keller 853b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 854b111ab5aSJacob Keller if (err) 855b111ab5aSJacob Keller return err; 856b111ab5aSJacob Keller } 857b111ab5aSJacob Keller 858b111ab5aSJacob Keller /* Set the frequency */ 859b111ab5aSJacob Keller dw9.field.time_ref_freq_sel = clk_freq; 860b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val); 861b111ab5aSJacob Keller if (err) 862b111ab5aSJacob Keller return err; 863b111ab5aSJacob Keller 864b111ab5aSJacob Keller /* Configure the TS PLL feedback divisor */ 865b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val); 866b111ab5aSJacob Keller if (err) 867b111ab5aSJacob Keller return err; 868b111ab5aSJacob Keller 869b111ab5aSJacob Keller dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; 870b111ab5aSJacob Keller dw19.field.tspll_ndivratio = 1; 871b111ab5aSJacob Keller 872b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val); 873b111ab5aSJacob Keller if (err) 874b111ab5aSJacob Keller return err; 875b111ab5aSJacob Keller 876b111ab5aSJacob Keller /* Configure the TS PLL post divisor */ 877b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val); 878b111ab5aSJacob Keller if (err) 879b111ab5aSJacob Keller return err; 880b111ab5aSJacob Keller 881b111ab5aSJacob Keller dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; 882b111ab5aSJacob Keller dw22.field.time1588clk_sel_div2 = 0; 883b111ab5aSJacob Keller 884b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val); 885b111ab5aSJacob Keller if (err) 886b111ab5aSJacob Keller return err; 887b111ab5aSJacob Keller 888b111ab5aSJacob Keller /* Configure the TS PLL pre divisor and clock source */ 889b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 890b111ab5aSJacob Keller if (err) 891b111ab5aSJacob Keller return err; 892b111ab5aSJacob Keller 893b111ab5aSJacob Keller dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div; 894b111ab5aSJacob Keller dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; 895b111ab5aSJacob Keller dw24.field.time_ref_sel = clk_src; 896b111ab5aSJacob Keller 897b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 898b111ab5aSJacob Keller if (err) 899b111ab5aSJacob Keller return err; 900b111ab5aSJacob Keller 901b111ab5aSJacob Keller /* Finally, enable the PLL */ 902b111ab5aSJacob Keller dw24.field.ts_pll_enable = 1; 903b111ab5aSJacob Keller 904b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 905b111ab5aSJacob Keller if (err) 906b111ab5aSJacob Keller return err; 907b111ab5aSJacob Keller 908b111ab5aSJacob Keller /* Wait to verify if the PLL locks */ 909b111ab5aSJacob Keller usleep_range(1000, 5000); 910b111ab5aSJacob Keller 911b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 912b111ab5aSJacob Keller if (err) 913b111ab5aSJacob Keller return err; 914b111ab5aSJacob Keller 915b111ab5aSJacob Keller if (!bwm_lf.field.plllock_true_lock_cri) { 916b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); 917b111ab5aSJacob Keller return -EBUSY; 918b111ab5aSJacob Keller } 919b111ab5aSJacob Keller 920b111ab5aSJacob Keller /* Log the current clock configuration */ 921b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 922b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 923b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 924b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 925b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 926b111ab5aSJacob Keller 927b111ab5aSJacob Keller return 0; 928b111ab5aSJacob Keller } 929b111ab5aSJacob Keller 930b111ab5aSJacob Keller /** 931b111ab5aSJacob Keller * ice_init_cgu_e822 - Initialize CGU with settings from firmware 932b111ab5aSJacob Keller * @hw: pointer to the HW structure 933b111ab5aSJacob Keller * 934b111ab5aSJacob Keller * Initialize the Clock Generation Unit of the E822 device. 935b111ab5aSJacob Keller */ 936b111ab5aSJacob Keller static int ice_init_cgu_e822(struct ice_hw *hw) 937b111ab5aSJacob Keller { 938b111ab5aSJacob Keller struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; 939b111ab5aSJacob Keller union tspll_cntr_bist_settings cntr_bist; 940b111ab5aSJacob Keller int err; 941b111ab5aSJacob Keller 942b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 943b111ab5aSJacob Keller &cntr_bist.val); 944b111ab5aSJacob Keller if (err) 945b111ab5aSJacob Keller return err; 946b111ab5aSJacob Keller 947b111ab5aSJacob Keller /* Disable sticky lock detection so lock err reported is accurate */ 948b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_0 = 0; 949b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_1 = 0; 950b111ab5aSJacob Keller 951b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 952b111ab5aSJacob Keller cntr_bist.val); 953b111ab5aSJacob Keller if (err) 954b111ab5aSJacob Keller return err; 955b111ab5aSJacob Keller 956b111ab5aSJacob Keller /* Configure the CGU PLL using the parameters from the function 957b111ab5aSJacob Keller * capabilities. 958b111ab5aSJacob Keller */ 959b111ab5aSJacob Keller err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref, 960b111ab5aSJacob Keller (enum ice_clk_src)ts_info->clk_src); 961b111ab5aSJacob Keller if (err) 962b111ab5aSJacob Keller return err; 963b111ab5aSJacob Keller 964b111ab5aSJacob Keller return 0; 965b111ab5aSJacob Keller } 966b111ab5aSJacob Keller 967b111ab5aSJacob Keller /** 9683a749623SJacob Keller * ice_ptp_set_vernier_wl - Set the window length for vernier calibration 9693a749623SJacob Keller * @hw: pointer to the HW struct 9703a749623SJacob Keller * 9713a749623SJacob Keller * Set the window length used for the vernier port calibration process. 9723a749623SJacob Keller */ 9733a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw) 9743a749623SJacob Keller { 9753a749623SJacob Keller u8 port; 9763a749623SJacob Keller 9773a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 9783a749623SJacob Keller int err; 9793a749623SJacob Keller 9803a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_WL, 9813a749623SJacob Keller PTP_VERNIER_WL); 9823a749623SJacob Keller if (err) { 9833a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n", 9843a749623SJacob Keller port, err); 9853a749623SJacob Keller return err; 9863a749623SJacob Keller } 9873a749623SJacob Keller } 9883a749623SJacob Keller 9893a749623SJacob Keller return 0; 9903a749623SJacob Keller } 9913a749623SJacob Keller 9923a749623SJacob Keller /** 9933a749623SJacob Keller * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization 9943a749623SJacob Keller * @hw: pointer to HW struct 9953a749623SJacob Keller * 9963a749623SJacob Keller * Perform PHC initialization steps specific to E822 devices. 9973a749623SJacob Keller */ 9983a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw) 9993a749623SJacob Keller { 1000b111ab5aSJacob Keller int err; 10013a749623SJacob Keller u32 regval; 10023a749623SJacob Keller 10033a749623SJacob Keller /* Enable reading switch and PHY registers over the sideband queue */ 10043a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1) 10053a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2) 10063a749623SJacob Keller regval = rd32(hw, PF_SB_REM_DEV_CTL); 10073a749623SJacob Keller regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ | 10083a749623SJacob Keller PF_SB_REM_DEV_CTL_PHY0); 10093a749623SJacob Keller wr32(hw, PF_SB_REM_DEV_CTL, regval); 10103a749623SJacob Keller 1011b111ab5aSJacob Keller /* Initialize the Clock Generation Unit */ 1012b111ab5aSJacob Keller err = ice_init_cgu_e822(hw); 1013b111ab5aSJacob Keller if (err) 1014b111ab5aSJacob Keller return err; 1015b111ab5aSJacob Keller 10163a749623SJacob Keller /* Set window length for all the ports */ 10173a749623SJacob Keller return ice_ptp_set_vernier_wl(hw); 10183a749623SJacob Keller } 10193a749623SJacob Keller 10203a749623SJacob Keller /** 10213a749623SJacob Keller * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time 10223a749623SJacob Keller * @hw: pointer to the HW struct 10233a749623SJacob Keller * @time: Time to initialize the PHY port clocks to 10243a749623SJacob Keller * 10253a749623SJacob Keller * Program the PHY port registers with a new initial time value. The port 10263a749623SJacob Keller * clock will be initialized once the driver issues an INIT_TIME sync 10273a749623SJacob Keller * command. The time value is the upper 32 bits of the PHY timer, usually in 10283a749623SJacob Keller * units of nominal nanoseconds. 10293a749623SJacob Keller */ 10303a749623SJacob Keller static int 10313a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) 10323a749623SJacob Keller { 10333a749623SJacob Keller u64 phy_time; 10343a749623SJacob Keller u8 port; 10353a749623SJacob Keller int err; 10363a749623SJacob Keller 10373a749623SJacob Keller /* The time represents the upper 32 bits of the PHY timer, so we need 10383a749623SJacob Keller * to shift to account for this when programming. 10393a749623SJacob Keller */ 10403a749623SJacob Keller phy_time = (u64)time << 32; 10413a749623SJacob Keller 10423a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 10433a749623SJacob Keller /* Tx case */ 10443a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 10453a749623SJacob Keller P_REG_TX_TIMER_INC_PRE_L, 10463a749623SJacob Keller phy_time); 10473a749623SJacob Keller if (err) 10483a749623SJacob Keller goto exit_err; 10493a749623SJacob Keller 10503a749623SJacob Keller /* Rx case */ 10513a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 10523a749623SJacob Keller P_REG_RX_TIMER_INC_PRE_L, 10533a749623SJacob Keller phy_time); 10543a749623SJacob Keller if (err) 10553a749623SJacob Keller goto exit_err; 10563a749623SJacob Keller } 10573a749623SJacob Keller 10583a749623SJacob Keller return 0; 10593a749623SJacob Keller 10603a749623SJacob Keller exit_err: 10613a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n", 10623a749623SJacob Keller port, err); 10633a749623SJacob Keller 10643a749623SJacob Keller return err; 10653a749623SJacob Keller } 10663a749623SJacob Keller 10673a749623SJacob Keller /** 10683a749623SJacob Keller * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust 10693a749623SJacob Keller * @hw: pointer to HW struct 10703a749623SJacob Keller * @port: Port number to be programmed 10713a749623SJacob Keller * @time: time in cycles to adjust the port Tx and Rx clocks 10723a749623SJacob Keller * 10733a749623SJacob Keller * Program the port for an atomic adjustment by writing the Tx and Rx timer 10743a749623SJacob Keller * registers. The atomic adjustment won't be completed until the driver issues 10753a749623SJacob Keller * an ADJ_TIME command. 10763a749623SJacob Keller * 10773a749623SJacob Keller * Note that time is not in units of nanoseconds. It is in clock time 10783a749623SJacob Keller * including the lower sub-nanosecond portion of the port timer. 10793a749623SJacob Keller * 10803a749623SJacob Keller * Negative adjustments are supported using 2s complement arithmetic. 10813a749623SJacob Keller */ 10823a749623SJacob Keller int 10833a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) 10843a749623SJacob Keller { 10853a749623SJacob Keller u32 l_time, u_time; 10863a749623SJacob Keller int err; 10873a749623SJacob Keller 10883a749623SJacob Keller l_time = lower_32_bits(time); 10893a749623SJacob Keller u_time = upper_32_bits(time); 10903a749623SJacob Keller 10913a749623SJacob Keller /* Tx case */ 10923a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L, 10933a749623SJacob Keller l_time); 10943a749623SJacob Keller if (err) 10953a749623SJacob Keller goto exit_err; 10963a749623SJacob Keller 10973a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U, 10983a749623SJacob Keller u_time); 10993a749623SJacob Keller if (err) 11003a749623SJacob Keller goto exit_err; 11013a749623SJacob Keller 11023a749623SJacob Keller /* Rx case */ 11033a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L, 11043a749623SJacob Keller l_time); 11053a749623SJacob Keller if (err) 11063a749623SJacob Keller goto exit_err; 11073a749623SJacob Keller 11083a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U, 11093a749623SJacob Keller u_time); 11103a749623SJacob Keller if (err) 11113a749623SJacob Keller goto exit_err; 11123a749623SJacob Keller 11133a749623SJacob Keller return 0; 11143a749623SJacob Keller 11153a749623SJacob Keller exit_err: 11163a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n", 11173a749623SJacob Keller port, err); 11183a749623SJacob Keller return err; 11193a749623SJacob Keller } 11203a749623SJacob Keller 11213a749623SJacob Keller /** 11223a749623SJacob Keller * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment 11233a749623SJacob Keller * @hw: pointer to HW struct 11243a749623SJacob Keller * @adj: adjustment in nanoseconds 11253a749623SJacob Keller * 11263a749623SJacob Keller * Prepare the PHY ports for an atomic time adjustment by programming the PHY 11273a749623SJacob Keller * Tx and Rx port registers. The actual adjustment is completed by issuing an 11283a749623SJacob Keller * ADJ_TIME or ADJ_TIME_AT_TIME sync command. 11293a749623SJacob Keller */ 11303a749623SJacob Keller static int 11313a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) 11323a749623SJacob Keller { 11333a749623SJacob Keller s64 cycles; 11343a749623SJacob Keller u8 port; 11353a749623SJacob Keller 11363a749623SJacob Keller /* The port clock supports adjustment of the sub-nanosecond portion of 11373a749623SJacob Keller * the clock. We shift the provided adjustment in nanoseconds to 11383a749623SJacob Keller * calculate the appropriate adjustment to program into the PHY ports. 11393a749623SJacob Keller */ 11403a749623SJacob Keller if (adj > 0) 11413a749623SJacob Keller cycles = (s64)adj << 32; 11423a749623SJacob Keller else 11433a749623SJacob Keller cycles = -(((s64)-adj) << 32); 11443a749623SJacob Keller 11453a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 11463a749623SJacob Keller int err; 11473a749623SJacob Keller 11483a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, cycles); 11493a749623SJacob Keller if (err) 11503a749623SJacob Keller return err; 11513a749623SJacob Keller } 11523a749623SJacob Keller 11533a749623SJacob Keller return 0; 11543a749623SJacob Keller } 11553a749623SJacob Keller 11563a749623SJacob Keller /** 11573a749623SJacob Keller * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment 11583a749623SJacob Keller * @hw: pointer to HW struct 11593a749623SJacob Keller * @incval: new increment value to prepare 11603a749623SJacob Keller * 11613a749623SJacob Keller * Prepare each of the PHY ports for a new increment value by programming the 11623a749623SJacob Keller * port's TIMETUS registers. The new increment value will be updated after 11633a749623SJacob Keller * issuing an INIT_INCVAL command. 11643a749623SJacob Keller */ 11653a749623SJacob Keller static int 11663a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval) 11673a749623SJacob Keller { 11683a749623SJacob Keller int err; 11693a749623SJacob Keller u8 port; 11703a749623SJacob Keller 11713a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 11723a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, 11733a749623SJacob Keller incval); 11743a749623SJacob Keller if (err) 11753a749623SJacob Keller goto exit_err; 11763a749623SJacob Keller } 11773a749623SJacob Keller 11783a749623SJacob Keller return 0; 11793a749623SJacob Keller 11803a749623SJacob Keller exit_err: 11813a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n", 11823a749623SJacob Keller port, err); 11833a749623SJacob Keller 11843a749623SJacob Keller return err; 11853a749623SJacob Keller } 11863a749623SJacob Keller 11873a749623SJacob Keller /** 11883a749623SJacob Keller * ice_ptp_read_port_capture - Read a port's local time capture 11893a749623SJacob Keller * @hw: pointer to HW struct 11903a749623SJacob Keller * @port: Port number to read 11913a749623SJacob Keller * @tx_ts: on return, the Tx port time capture 11923a749623SJacob Keller * @rx_ts: on return, the Rx port time capture 11933a749623SJacob Keller * 11943a749623SJacob Keller * Read the port's Tx and Rx local time capture values. 11953a749623SJacob Keller * 11963a749623SJacob Keller * Note this has no equivalent for the E810 devices. 11973a749623SJacob Keller */ 11983a749623SJacob Keller static int 11993a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) 12003a749623SJacob Keller { 12013a749623SJacob Keller int err; 12023a749623SJacob Keller 12033a749623SJacob Keller /* Tx case */ 12043a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts); 12053a749623SJacob Keller if (err) { 12063a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n", 12073a749623SJacob Keller err); 12083a749623SJacob Keller return err; 12093a749623SJacob Keller } 12103a749623SJacob Keller 12113a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n", 12123a749623SJacob Keller (unsigned long long)*tx_ts); 12133a749623SJacob Keller 12143a749623SJacob Keller /* Rx case */ 12153a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts); 12163a749623SJacob Keller if (err) { 12173a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n", 12183a749623SJacob Keller err); 12193a749623SJacob Keller return err; 12203a749623SJacob Keller } 12213a749623SJacob Keller 12223a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n", 12233a749623SJacob Keller (unsigned long long)*rx_ts); 12243a749623SJacob Keller 12253a749623SJacob Keller return 0; 12263a749623SJacob Keller } 12273a749623SJacob Keller 12283a749623SJacob Keller /** 12293a749623SJacob Keller * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command 12303a749623SJacob Keller * @hw: pointer to HW struct 12313a749623SJacob Keller * @port: Port to which cmd has to be sent 12323a749623SJacob Keller * @cmd: Command to be sent to the port 12333a749623SJacob Keller * 12343a749623SJacob Keller * Prepare the requested port for an upcoming timer sync command. 12353a749623SJacob Keller * 12363a749623SJacob Keller * Note there is no equivalent of this operation on E810, as that device 12373a749623SJacob Keller * always handles all external PHYs internally. 12383a749623SJacob Keller */ 12393a749623SJacob Keller static int 12403a749623SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) 12413a749623SJacob Keller { 12423a749623SJacob Keller u32 cmd_val, val; 12433a749623SJacob Keller u8 tmr_idx; 12443a749623SJacob Keller int err; 12453a749623SJacob Keller 12463a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 12473a749623SJacob Keller cmd_val = tmr_idx << SEL_PHY_SRC; 12483a749623SJacob Keller switch (cmd) { 12493a749623SJacob Keller case INIT_TIME: 12503a749623SJacob Keller cmd_val |= PHY_CMD_INIT_TIME; 12513a749623SJacob Keller break; 12523a749623SJacob Keller case INIT_INCVAL: 12533a749623SJacob Keller cmd_val |= PHY_CMD_INIT_INCVAL; 12543a749623SJacob Keller break; 12553a749623SJacob Keller case ADJ_TIME: 12563a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME; 12573a749623SJacob Keller break; 12583a749623SJacob Keller case READ_TIME: 12593a749623SJacob Keller cmd_val |= PHY_CMD_READ_TIME; 12603a749623SJacob Keller break; 12613a749623SJacob Keller case ADJ_TIME_AT_TIME: 12623a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; 12633a749623SJacob Keller break; 12643a749623SJacob Keller } 12653a749623SJacob Keller 12663a749623SJacob Keller /* Tx case */ 12673a749623SJacob Keller /* Read, modify, write */ 12683a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val); 12693a749623SJacob Keller if (err) { 12703a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n", 12713a749623SJacob Keller err); 12723a749623SJacob Keller return err; 12733a749623SJacob Keller } 12743a749623SJacob Keller 12753a749623SJacob Keller /* Modify necessary bits only and perform write */ 12763a749623SJacob Keller val &= ~TS_CMD_MASK; 12773a749623SJacob Keller val |= cmd_val; 12783a749623SJacob Keller 12793a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val); 12803a749623SJacob Keller if (err) { 12813a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n", 12823a749623SJacob Keller err); 12833a749623SJacob Keller return err; 12843a749623SJacob Keller } 12853a749623SJacob Keller 12863a749623SJacob Keller /* Rx case */ 12873a749623SJacob Keller /* Read, modify, write */ 12883a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val); 12893a749623SJacob Keller if (err) { 12903a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n", 12913a749623SJacob Keller err); 12923a749623SJacob Keller return err; 12933a749623SJacob Keller } 12943a749623SJacob Keller 12953a749623SJacob Keller /* Modify necessary bits only and perform write */ 12963a749623SJacob Keller val &= ~TS_CMD_MASK; 12973a749623SJacob Keller val |= cmd_val; 12983a749623SJacob Keller 12993a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val); 13003a749623SJacob Keller if (err) { 13013a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n", 13023a749623SJacob Keller err); 13033a749623SJacob Keller return err; 13043a749623SJacob Keller } 13053a749623SJacob Keller 13063a749623SJacob Keller return 0; 13073a749623SJacob Keller } 13083a749623SJacob Keller 13093a749623SJacob Keller /** 13103a749623SJacob Keller * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command 13113a749623SJacob Keller * @hw: pointer to the HW struct 13123a749623SJacob Keller * @cmd: timer command to prepare 13133a749623SJacob Keller * 13143a749623SJacob Keller * Prepare all ports connected to this device for an upcoming timer sync 13153a749623SJacob Keller * command. 13163a749623SJacob Keller */ 13173a749623SJacob Keller static int 13183a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 13193a749623SJacob Keller { 13203a749623SJacob Keller u8 port; 13213a749623SJacob Keller 13223a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 13233a749623SJacob Keller int err; 13243a749623SJacob Keller 13253a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, cmd); 13263a749623SJacob Keller if (err) 13273a749623SJacob Keller return err; 13283a749623SJacob Keller } 13293a749623SJacob Keller 13303a749623SJacob Keller return 0; 13313a749623SJacob Keller } 13323a749623SJacob Keller 13333a749623SJacob Keller /* E822 Vernier calibration functions 13343a749623SJacob Keller * 13353a749623SJacob Keller * The following functions are used as part of the vernier calibration of 13363a749623SJacob Keller * a port. This calibration increases the precision of the timestamps on the 13373a749623SJacob Keller * port. 13383a749623SJacob Keller */ 13393a749623SJacob Keller 13403a749623SJacob Keller /** 13413a749623SJacob Keller * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode 13423a749623SJacob Keller * @hw: pointer to HW struct 13433a749623SJacob Keller * @port: the port to read from 13443a749623SJacob Keller * @link_out: if non-NULL, holds link speed on success 13453a749623SJacob Keller * @fec_out: if non-NULL, holds FEC algorithm on success 13463a749623SJacob Keller * 13473a749623SJacob Keller * Read the serdes data for the PHY port and extract the link speed and FEC 13483a749623SJacob Keller * algorithm. 13493a749623SJacob Keller */ 13503a749623SJacob Keller static int 13513a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, 13523a749623SJacob Keller enum ice_ptp_link_spd *link_out, 13533a749623SJacob Keller enum ice_ptp_fec_mode *fec_out) 13543a749623SJacob Keller { 13553a749623SJacob Keller enum ice_ptp_link_spd link; 13563a749623SJacob Keller enum ice_ptp_fec_mode fec; 13573a749623SJacob Keller u32 serdes; 13583a749623SJacob Keller int err; 13593a749623SJacob Keller 13603a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes); 13613a749623SJacob Keller if (err) { 13623a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n"); 13633a749623SJacob Keller return err; 13643a749623SJacob Keller } 13653a749623SJacob Keller 13663a749623SJacob Keller /* Determine the FEC algorithm */ 13673a749623SJacob Keller fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes); 13683a749623SJacob Keller 13693a749623SJacob Keller serdes &= P_REG_LINK_SPEED_SERDES_M; 13703a749623SJacob Keller 13713a749623SJacob Keller /* Determine the link speed */ 13723a749623SJacob Keller if (fec == ICE_PTP_FEC_MODE_RS_FEC) { 13733a749623SJacob Keller switch (serdes) { 13743a749623SJacob Keller case ICE_PTP_SERDES_25G: 13753a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G_RS; 13763a749623SJacob Keller break; 13773a749623SJacob Keller case ICE_PTP_SERDES_50G: 13783a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G_RS; 13793a749623SJacob Keller break; 13803a749623SJacob Keller case ICE_PTP_SERDES_100G: 13813a749623SJacob Keller link = ICE_PTP_LNK_SPD_100G_RS; 13823a749623SJacob Keller break; 13833a749623SJacob Keller default: 13843a749623SJacob Keller return -EIO; 13853a749623SJacob Keller } 13863a749623SJacob Keller } else { 13873a749623SJacob Keller switch (serdes) { 13883a749623SJacob Keller case ICE_PTP_SERDES_1G: 13893a749623SJacob Keller link = ICE_PTP_LNK_SPD_1G; 13903a749623SJacob Keller break; 13913a749623SJacob Keller case ICE_PTP_SERDES_10G: 13923a749623SJacob Keller link = ICE_PTP_LNK_SPD_10G; 13933a749623SJacob Keller break; 13943a749623SJacob Keller case ICE_PTP_SERDES_25G: 13953a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G; 13963a749623SJacob Keller break; 13973a749623SJacob Keller case ICE_PTP_SERDES_40G: 13983a749623SJacob Keller link = ICE_PTP_LNK_SPD_40G; 13993a749623SJacob Keller break; 14003a749623SJacob Keller case ICE_PTP_SERDES_50G: 14013a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G; 14023a749623SJacob Keller break; 14033a749623SJacob Keller default: 14043a749623SJacob Keller return -EIO; 14053a749623SJacob Keller } 14063a749623SJacob Keller } 14073a749623SJacob Keller 14083a749623SJacob Keller if (link_out) 14093a749623SJacob Keller *link_out = link; 14103a749623SJacob Keller if (fec_out) 14113a749623SJacob Keller *fec_out = fec; 14123a749623SJacob Keller 14133a749623SJacob Keller return 0; 14143a749623SJacob Keller } 14153a749623SJacob Keller 14163a749623SJacob Keller /** 14173a749623SJacob Keller * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp 14183a749623SJacob Keller * @hw: pointer to HW struct 14193a749623SJacob Keller * @port: to configure the quad for 14203a749623SJacob Keller */ 14213a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) 14223a749623SJacob Keller { 14233a749623SJacob Keller enum ice_ptp_link_spd link_spd; 14243a749623SJacob Keller int err; 14253a749623SJacob Keller u32 val; 14263a749623SJacob Keller u8 quad; 14273a749623SJacob Keller 14283a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL); 14293a749623SJacob Keller if (err) { 14303a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n", 14313a749623SJacob Keller err); 14323a749623SJacob Keller return; 14333a749623SJacob Keller } 14343a749623SJacob Keller 14353a749623SJacob Keller quad = port / ICE_PORTS_PER_QUAD; 14363a749623SJacob Keller 14373a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); 14383a749623SJacob Keller if (err) { 14393a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n", 14403a749623SJacob Keller err); 14413a749623SJacob Keller return; 14423a749623SJacob Keller } 14433a749623SJacob Keller 14443a749623SJacob Keller if (link_spd >= ICE_PTP_LNK_SPD_40G) 14453a749623SJacob Keller val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 14463a749623SJacob Keller else 14473a749623SJacob Keller val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 14483a749623SJacob Keller 14493a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); 14503a749623SJacob Keller if (err) { 14513a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n", 14523a749623SJacob Keller err); 14533a749623SJacob Keller return; 14543a749623SJacob Keller } 14553a749623SJacob Keller } 14563a749623SJacob Keller 14573a749623SJacob Keller /** 14583a749623SJacob Keller * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822 14593a749623SJacob Keller * @hw: pointer to the HW structure 14603a749623SJacob Keller * @port: the port to configure 14613a749623SJacob Keller * 14623a749623SJacob Keller * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC 14633a749623SJacob Keller * hardware clock time units (TUs). That is, determine the number of TUs per 14643a749623SJacob Keller * serdes unit interval, and program the UIX registers with this conversion. 14653a749623SJacob Keller * 14663a749623SJacob Keller * This conversion is used as part of the calibration process when determining 14673a749623SJacob Keller * the additional error of a timestamp vs the real time of transmission or 14683a749623SJacob Keller * receipt of the packet. 14693a749623SJacob Keller * 14703a749623SJacob Keller * Hardware uses the number of TUs per 66 UIs, written to the UIX registers 14713a749623SJacob Keller * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks. 14723a749623SJacob Keller * 14733a749623SJacob Keller * To calculate the conversion ratio, we use the following facts: 14743a749623SJacob Keller * 14753a749623SJacob Keller * a) the clock frequency in Hz (cycles per second) 14763a749623SJacob Keller * b) the number of TUs per cycle (the increment value of the clock) 14773a749623SJacob Keller * c) 1 second per 1 billion nanoseconds 14783a749623SJacob Keller * d) the duration of 66 UIs in nanoseconds 14793a749623SJacob Keller * 14803a749623SJacob Keller * Given these facts, we can use the following table to work out what ratios 14813a749623SJacob Keller * to multiply in order to get the number of TUs per 66 UIs: 14823a749623SJacob Keller * 14833a749623SJacob Keller * cycles | 1 second | incval (TUs) | nanoseconds 14843a749623SJacob Keller * -------+--------------+--------------+------------- 14853a749623SJacob Keller * second | 1 billion ns | cycle | 66 UIs 14863a749623SJacob Keller * 14873a749623SJacob Keller * To perform the multiplication using integers without too much loss of 14883a749623SJacob Keller * precision, we can take use the following equation: 14893a749623SJacob Keller * 14903a749623SJacob Keller * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion) 14913a749623SJacob Keller * 14923a749623SJacob Keller * We scale up to using 6600 UI instead of 66 in order to avoid fractional 14933a749623SJacob Keller * nanosecond UIs (66 UI at 10G/40G is 6.4 ns) 14943a749623SJacob Keller * 14953a749623SJacob Keller * The increment value has a maximum expected range of about 34 bits, while 14963a749623SJacob Keller * the frequency value is about 29 bits. Multiplying these values shouldn't 14973a749623SJacob Keller * overflow the 64 bits. However, we must then further multiply them again by 14983a749623SJacob Keller * the Serdes unit interval duration. To avoid overflow here, we split the 14993a749623SJacob Keller * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and 15003a749623SJacob Keller * a divide by 390,625,000. This does lose some precision, but avoids 15013a749623SJacob Keller * miscalculation due to arithmetic overflow. 15023a749623SJacob Keller */ 15033a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) 15043a749623SJacob Keller { 15053a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, uix; 15063a749623SJacob Keller int err; 15073a749623SJacob Keller 15083a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 15093a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 15103a749623SJacob Keller 15113a749623SJacob Keller /* Calculate TUs per second divided by 256 */ 15123a749623SJacob Keller tu_per_sec = (cur_freq * clk_incval) >> 8; 15133a749623SJacob Keller 15143a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */ 15153a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */ 15163a749623SJacob Keller 15173a749623SJacob Keller /* Program the 10Gb/40Gb conversion ratio */ 15183a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000); 15193a749623SJacob Keller 15203a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L, 15213a749623SJacob Keller uix); 15223a749623SJacob Keller if (err) { 15233a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n", 15243a749623SJacob Keller err); 15253a749623SJacob Keller return err; 15263a749623SJacob Keller } 15273a749623SJacob Keller 15283a749623SJacob Keller /* Program the 25Gb/100Gb conversion ratio */ 15293a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000); 15303a749623SJacob Keller 15313a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L, 15323a749623SJacob Keller uix); 15333a749623SJacob Keller if (err) { 15343a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n", 15353a749623SJacob Keller err); 15363a749623SJacob Keller return err; 15373a749623SJacob Keller } 15383a749623SJacob Keller 15393a749623SJacob Keller return 0; 15403a749623SJacob Keller } 15413a749623SJacob Keller 15423a749623SJacob Keller /** 15433a749623SJacob Keller * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle 15443a749623SJacob Keller * @hw: pointer to the HW struct 15453a749623SJacob Keller * @port: port to configure 15463a749623SJacob Keller * 15473a749623SJacob Keller * Configure the number of TUs for the PAR and PCS clocks used as part of the 15483a749623SJacob Keller * timestamp calibration process. This depends on the link speed, as the PHY 15493a749623SJacob Keller * uses different markers depending on the speed. 15503a749623SJacob Keller * 15513a749623SJacob Keller * 1Gb/10Gb/25Gb: 15523a749623SJacob Keller * - Tx/Rx PAR/PCS markers 15533a749623SJacob Keller * 15543a749623SJacob Keller * 25Gb RS: 15553a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 15563a749623SJacob Keller * 15573a749623SJacob Keller * 40Gb/50Gb: 15583a749623SJacob Keller * - Tx/Rx PAR/PCS markers 15593a749623SJacob Keller * - Rx Deskew PAR/PCS markers 15603a749623SJacob Keller * 15613a749623SJacob Keller * 50G RS and 100GB RS: 15623a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 15633a749623SJacob Keller * - Rx Deskew PAR/PCS markers 15643a749623SJacob Keller * - Tx PAR/PCS markers 15653a749623SJacob Keller * 15663a749623SJacob Keller * To calculate the conversion, we use the PHC clock frequency (cycles per 15673a749623SJacob Keller * second), the increment value (TUs per cycle), and the related PHY clock 15683a749623SJacob Keller * frequency to calculate the TUs per unit of the PHY link clock. The 15693a749623SJacob Keller * following table shows how the units convert: 15703a749623SJacob Keller * 15713a749623SJacob Keller * cycles | TUs | second 15723a749623SJacob Keller * -------+-------+-------- 15733a749623SJacob Keller * second | cycle | cycles 15743a749623SJacob Keller * 15753a749623SJacob Keller * For each conversion register, look up the appropriate frequency from the 15763a749623SJacob Keller * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program 15773a749623SJacob Keller * this to the appropriate register, preparing hardware to perform timestamp 15783a749623SJacob Keller * calibration to calculate the total Tx or Rx offset to adjust the timestamp 15793a749623SJacob Keller * in order to calibrate for the internal PHY delays. 15803a749623SJacob Keller * 15813a749623SJacob Keller * Note that the increment value ranges up to ~34 bits, and the clock 15823a749623SJacob Keller * frequency is ~29 bits, so multiplying them together should fit within the 15833a749623SJacob Keller * 64 bit arithmetic. 15843a749623SJacob Keller */ 15853a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) 15863a749623SJacob Keller { 15873a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, phy_tus; 15883a749623SJacob Keller enum ice_ptp_link_spd link_spd; 15893a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 15903a749623SJacob Keller int err; 15913a749623SJacob Keller 15923a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 15933a749623SJacob Keller if (err) 15943a749623SJacob Keller return err; 15953a749623SJacob Keller 15963a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 15973a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 15983a749623SJacob Keller 15993a749623SJacob Keller /* Calculate TUs per cycle of the PHC clock */ 16003a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 16013a749623SJacob Keller 16023a749623SJacob Keller /* For each PHY conversion register, look up the appropriate link 16033a749623SJacob Keller * speed frequency and determine the TUs per that clock's cycle time. 16043a749623SJacob Keller * Split this into a high and low value and then program the 16053a749623SJacob Keller * appropriate register. If that link speed does not use the 16063a749623SJacob Keller * associated register, write zeros to clear it instead. 16073a749623SJacob Keller */ 16083a749623SJacob Keller 16093a749623SJacob Keller /* P_REG_PAR_TX_TUS */ 16103a749623SJacob Keller if (e822_vernier[link_spd].tx_par_clk) 16113a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16123a749623SJacob Keller e822_vernier[link_spd].tx_par_clk); 16133a749623SJacob Keller else 16143a749623SJacob Keller phy_tus = 0; 16153a749623SJacob Keller 16163a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L, 16173a749623SJacob Keller phy_tus); 16183a749623SJacob Keller if (err) 16193a749623SJacob Keller return err; 16203a749623SJacob Keller 16213a749623SJacob Keller /* P_REG_PAR_RX_TUS */ 16223a749623SJacob Keller if (e822_vernier[link_spd].rx_par_clk) 16233a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16243a749623SJacob Keller e822_vernier[link_spd].rx_par_clk); 16253a749623SJacob Keller else 16263a749623SJacob Keller phy_tus = 0; 16273a749623SJacob Keller 16283a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L, 16293a749623SJacob Keller phy_tus); 16303a749623SJacob Keller if (err) 16313a749623SJacob Keller return err; 16323a749623SJacob Keller 16333a749623SJacob Keller /* P_REG_PCS_TX_TUS */ 16343a749623SJacob Keller if (e822_vernier[link_spd].tx_pcs_clk) 16353a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16363a749623SJacob Keller e822_vernier[link_spd].tx_pcs_clk); 16373a749623SJacob Keller else 16383a749623SJacob Keller phy_tus = 0; 16393a749623SJacob Keller 16403a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L, 16413a749623SJacob Keller phy_tus); 16423a749623SJacob Keller if (err) 16433a749623SJacob Keller return err; 16443a749623SJacob Keller 16453a749623SJacob Keller /* P_REG_PCS_RX_TUS */ 16463a749623SJacob Keller if (e822_vernier[link_spd].rx_pcs_clk) 16473a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16483a749623SJacob Keller e822_vernier[link_spd].rx_pcs_clk); 16493a749623SJacob Keller else 16503a749623SJacob Keller phy_tus = 0; 16513a749623SJacob Keller 16523a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L, 16533a749623SJacob Keller phy_tus); 16543a749623SJacob Keller if (err) 16553a749623SJacob Keller return err; 16563a749623SJacob Keller 16573a749623SJacob Keller /* P_REG_DESK_PAR_TX_TUS */ 16583a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_par) 16593a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16603a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_par); 16613a749623SJacob Keller else 16623a749623SJacob Keller phy_tus = 0; 16633a749623SJacob Keller 16643a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L, 16653a749623SJacob Keller phy_tus); 16663a749623SJacob Keller if (err) 16673a749623SJacob Keller return err; 16683a749623SJacob Keller 16693a749623SJacob Keller /* P_REG_DESK_PAR_RX_TUS */ 16703a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_par) 16713a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16723a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_par); 16733a749623SJacob Keller else 16743a749623SJacob Keller phy_tus = 0; 16753a749623SJacob Keller 16763a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L, 16773a749623SJacob Keller phy_tus); 16783a749623SJacob Keller if (err) 16793a749623SJacob Keller return err; 16803a749623SJacob Keller 16813a749623SJacob Keller /* P_REG_DESK_PCS_TX_TUS */ 16823a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_pcs) 16833a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16843a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_pcs); 16853a749623SJacob Keller else 16863a749623SJacob Keller phy_tus = 0; 16873a749623SJacob Keller 16883a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L, 16893a749623SJacob Keller phy_tus); 16903a749623SJacob Keller if (err) 16913a749623SJacob Keller return err; 16923a749623SJacob Keller 16933a749623SJacob Keller /* P_REG_DESK_PCS_RX_TUS */ 16943a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_pcs) 16953a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16963a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_pcs); 16973a749623SJacob Keller else 16983a749623SJacob Keller phy_tus = 0; 16993a749623SJacob Keller 17003a749623SJacob Keller return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L, 17013a749623SJacob Keller phy_tus); 17023a749623SJacob Keller } 17033a749623SJacob Keller 17043a749623SJacob Keller /** 17053a749623SJacob Keller * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port 17063a749623SJacob Keller * @hw: pointer to the HW struct 17073a749623SJacob Keller * @link_spd: the Link speed to calculate for 17083a749623SJacob Keller * 17093a749623SJacob Keller * Calculate the fixed offset due to known static latency data. 17103a749623SJacob Keller */ 17113a749623SJacob Keller static u64 17123a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 17133a749623SJacob Keller { 17143a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 17153a749623SJacob Keller 17163a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 17173a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 17183a749623SJacob Keller 17193a749623SJacob Keller /* Calculate TUs per second */ 17203a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 17213a749623SJacob Keller 17223a749623SJacob Keller /* Calculate number of TUs to add for the fixed Tx latency. Since the 17233a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 17243a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 17253a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 17263a749623SJacob Keller * divisions by 1e4 first then by 1e7. 17273a749623SJacob Keller */ 17283a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 17293a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].tx_fixed_delay; 17303a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 17313a749623SJacob Keller 17323a749623SJacob Keller return fixed_offset; 17333a749623SJacob Keller } 17343a749623SJacob Keller 17353a749623SJacob Keller /** 1736a69f1cb6SJacob Keller * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset 1737a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1738a69f1cb6SJacob Keller * @port: the PHY port to configure 1739a69f1cb6SJacob Keller * 1740a69f1cb6SJacob Keller * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to 1741a69f1cb6SJacob Keller * adjust Tx timestamps by. This is calculated by combining some known static 1742a69f1cb6SJacob Keller * latency along with the Vernier offset computations done by hardware. 1743a69f1cb6SJacob Keller * 1744a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 1745a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 1746a69f1cb6SJacob Keller * has measured the offset. 1747a69f1cb6SJacob Keller * 1748a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 1749a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 1750a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 1751a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 1752a69f1cb6SJacob Keller */ 1753a69f1cb6SJacob Keller static int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) 1754a69f1cb6SJacob Keller { 1755a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 1756a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 1757a69f1cb6SJacob Keller u64 total_offset, val; 1758a69f1cb6SJacob Keller int err; 1759a69f1cb6SJacob Keller 1760a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1761a69f1cb6SJacob Keller if (err) 1762a69f1cb6SJacob Keller return err; 1763a69f1cb6SJacob Keller 1764a69f1cb6SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 1765a69f1cb6SJacob Keller 1766a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 1767a69f1cb6SJacob Keller * the total offset. 1768a69f1cb6SJacob Keller */ 1769a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G || 1770a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_10G || 1771a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1772a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G_RS || 1773a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1774a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1775a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1776a69f1cb6SJacob Keller P_REG_PAR_PCS_TX_OFFSET_L, 1777a69f1cb6SJacob Keller &val); 1778a69f1cb6SJacob Keller if (err) 1779a69f1cb6SJacob Keller return err; 1780a69f1cb6SJacob Keller 1781a69f1cb6SJacob Keller total_offset += val; 1782a69f1cb6SJacob Keller } 1783a69f1cb6SJacob Keller 1784a69f1cb6SJacob Keller /* For Tx, we only need to use the second Vernier offset for 1785a69f1cb6SJacob Keller * multi-lane link speeds with RS-FEC. The lanes will always be 1786a69f1cb6SJacob Keller * aligned. 1787a69f1cb6SJacob Keller */ 1788a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_50G_RS || 1789a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1790a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1791a69f1cb6SJacob Keller P_REG_PAR_TX_TIME_L, 1792a69f1cb6SJacob Keller &val); 1793a69f1cb6SJacob Keller if (err) 1794a69f1cb6SJacob Keller return err; 1795a69f1cb6SJacob Keller 1796a69f1cb6SJacob Keller total_offset += val; 1797a69f1cb6SJacob Keller } 1798a69f1cb6SJacob Keller 1799a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 1800a69f1cb6SJacob Keller * PHY and indicate that the Tx offset is ready. After this, 1801a69f1cb6SJacob Keller * timestamps will be enabled. 1802a69f1cb6SJacob Keller */ 1803a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 1804a69f1cb6SJacob Keller total_offset); 1805a69f1cb6SJacob Keller if (err) 1806a69f1cb6SJacob Keller return err; 1807a69f1cb6SJacob Keller 1808a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 1809a69f1cb6SJacob Keller if (err) 1810a69f1cb6SJacob Keller return err; 1811a69f1cb6SJacob Keller 1812a69f1cb6SJacob Keller return 0; 1813a69f1cb6SJacob Keller } 1814a69f1cb6SJacob Keller 1815a69f1cb6SJacob Keller /** 1816a69f1cb6SJacob Keller * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx 1817a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1818a69f1cb6SJacob Keller * @port: the PHY port to adjust for 1819a69f1cb6SJacob Keller * @link_spd: the current link speed of the PHY 1820a69f1cb6SJacob Keller * @fec_mode: the current FEC mode of the PHY 1821a69f1cb6SJacob Keller * @pmd_adj: on return, the amount to adjust the Rx total offset by 1822a69f1cb6SJacob Keller * 1823a69f1cb6SJacob Keller * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY. 1824a69f1cb6SJacob Keller * This varies by link speed and FEC mode. The value calculated accounts for 1825a69f1cb6SJacob Keller * various delays caused when receiving a packet. 1826a69f1cb6SJacob Keller */ 1827a69f1cb6SJacob Keller static int 1828a69f1cb6SJacob Keller ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, 1829a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd, 1830a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj) 1831a69f1cb6SJacob Keller { 1832a69f1cb6SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, mult, adj; 1833a69f1cb6SJacob Keller u8 pmd_align; 1834a69f1cb6SJacob Keller u32 val; 1835a69f1cb6SJacob Keller int err; 1836a69f1cb6SJacob Keller 1837a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val); 1838a69f1cb6SJacob Keller if (err) { 1839a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n", 1840a69f1cb6SJacob Keller err); 1841a69f1cb6SJacob Keller return err; 1842a69f1cb6SJacob Keller } 1843a69f1cb6SJacob Keller 1844a69f1cb6SJacob Keller pmd_align = (u8)val; 1845a69f1cb6SJacob Keller 1846a69f1cb6SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1847a69f1cb6SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1848a69f1cb6SJacob Keller 1849a69f1cb6SJacob Keller /* Calculate TUs per second */ 1850a69f1cb6SJacob Keller tu_per_sec = cur_freq * clk_incval; 1851a69f1cb6SJacob Keller 1852a69f1cb6SJacob Keller /* The PMD alignment adjustment measurement depends on the link speed, 1853a69f1cb6SJacob Keller * and whether FEC is enabled. For each link speed, the alignment 1854a69f1cb6SJacob Keller * adjustment is calculated by dividing a value by the length of 1855a69f1cb6SJacob Keller * a Time Unit in nanoseconds. 1856a69f1cb6SJacob Keller * 1857a69f1cb6SJacob Keller * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8 1858a69f1cb6SJacob Keller * 10G: align == 65 ? 0 : (align * 0.1 * 32/33) 1859a69f1cb6SJacob Keller * 10G w/FEC: align * 0.1 * 32/33 1860a69f1cb6SJacob Keller * 25G: align == 65 ? 0 : (align * 0.4 * 32/33) 1861a69f1cb6SJacob Keller * 25G w/FEC: align * 0.4 * 32/33 1862a69f1cb6SJacob Keller * 40G: align == 65 ? 0 : (align * 0.1 * 32/33) 1863a69f1cb6SJacob Keller * 40G w/FEC: align * 0.1 * 32/33 1864a69f1cb6SJacob Keller * 50G: align == 65 ? 0 : (align * 0.4 * 32/33) 1865a69f1cb6SJacob Keller * 50G w/FEC: align * 0.8 * 32/33 1866a69f1cb6SJacob Keller * 1867a69f1cb6SJacob Keller * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33. 1868a69f1cb6SJacob Keller * 1869a69f1cb6SJacob Keller * To allow for calculating this value using integer arithmetic, we 1870a69f1cb6SJacob Keller * instead start with the number of TUs per second, (inverse of the 1871a69f1cb6SJacob Keller * length of a Time Unit in nanoseconds), multiply by a value based 1872a69f1cb6SJacob Keller * on the PMD alignment register, and then divide by the right value 1873a69f1cb6SJacob Keller * calculated based on the table above. To avoid integer overflow this 1874a69f1cb6SJacob Keller * division is broken up into a step of dividing by 125 first. 1875a69f1cb6SJacob Keller */ 1876a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G) { 1877a69f1cb6SJacob Keller if (pmd_align == 4) 1878a69f1cb6SJacob Keller mult = 10; 1879a69f1cb6SJacob Keller else 1880a69f1cb6SJacob Keller mult = (pmd_align + 6) % 10; 1881a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_10G || 1882a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1883a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1884a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1885a69f1cb6SJacob Keller /* If Clause 74 FEC, always calculate PMD adjust */ 1886a69f1cb6SJacob Keller if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74) 1887a69f1cb6SJacob Keller mult = pmd_align; 1888a69f1cb6SJacob Keller else 1889a69f1cb6SJacob Keller mult = 0; 1890a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS || 1891a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 1892a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1893a69f1cb6SJacob Keller if (pmd_align < 17) 1894a69f1cb6SJacob Keller mult = pmd_align + 40; 1895a69f1cb6SJacob Keller else 1896a69f1cb6SJacob Keller mult = pmd_align; 1897a69f1cb6SJacob Keller } else { 1898a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n", 1899a69f1cb6SJacob Keller link_spd); 1900a69f1cb6SJacob Keller mult = 0; 1901a69f1cb6SJacob Keller } 1902a69f1cb6SJacob Keller 1903a69f1cb6SJacob Keller /* In some cases, there's no need to adjust for the PMD alignment */ 1904a69f1cb6SJacob Keller if (!mult) { 1905a69f1cb6SJacob Keller *pmd_adj = 0; 1906a69f1cb6SJacob Keller return 0; 1907a69f1cb6SJacob Keller } 1908a69f1cb6SJacob Keller 1909a69f1cb6SJacob Keller /* Calculate the adjustment by multiplying TUs per second by the 1910a69f1cb6SJacob Keller * appropriate multiplier and divisor. To avoid overflow, we first 1911a69f1cb6SJacob Keller * divide by 125, and then handle remaining divisor based on the link 1912a69f1cb6SJacob Keller * speed pmd_adj_divisor value. 1913a69f1cb6SJacob Keller */ 1914a69f1cb6SJacob Keller adj = div_u64(tu_per_sec, 125); 1915a69f1cb6SJacob Keller adj *= mult; 1916a69f1cb6SJacob Keller adj = div_u64(adj, e822_vernier[link_spd].pmd_adj_divisor); 1917a69f1cb6SJacob Keller 1918a69f1cb6SJacob Keller /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx 1919a69f1cb6SJacob Keller * cycle count is necessary. 1920a69f1cb6SJacob Keller */ 1921a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_25G_RS) { 1922a69f1cb6SJacob Keller u64 cycle_adj; 1923a69f1cb6SJacob Keller u8 rx_cycle; 1924a69f1cb6SJacob Keller 1925a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT, 1926a69f1cb6SJacob Keller &val); 1927a69f1cb6SJacob Keller if (err) { 1928a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n", 1929a69f1cb6SJacob Keller err); 1930a69f1cb6SJacob Keller return err; 1931a69f1cb6SJacob Keller } 1932a69f1cb6SJacob Keller 1933a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M; 1934a69f1cb6SJacob Keller if (rx_cycle) { 1935a69f1cb6SJacob Keller mult = (4 - rx_cycle) * 40; 1936a69f1cb6SJacob Keller 1937a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1938a69f1cb6SJacob Keller cycle_adj *= mult; 1939a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1940a69f1cb6SJacob Keller 1941a69f1cb6SJacob Keller adj += cycle_adj; 1942a69f1cb6SJacob Keller } 1943a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) { 1944a69f1cb6SJacob Keller u64 cycle_adj; 1945a69f1cb6SJacob Keller u8 rx_cycle; 1946a69f1cb6SJacob Keller 1947a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT, 1948a69f1cb6SJacob Keller &val); 1949a69f1cb6SJacob Keller if (err) { 1950a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n", 1951a69f1cb6SJacob Keller err); 1952a69f1cb6SJacob Keller return err; 1953a69f1cb6SJacob Keller } 1954a69f1cb6SJacob Keller 1955a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M; 1956a69f1cb6SJacob Keller if (rx_cycle) { 1957a69f1cb6SJacob Keller mult = rx_cycle * 40; 1958a69f1cb6SJacob Keller 1959a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1960a69f1cb6SJacob Keller cycle_adj *= mult; 1961a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1962a69f1cb6SJacob Keller 1963a69f1cb6SJacob Keller adj += cycle_adj; 1964a69f1cb6SJacob Keller } 1965a69f1cb6SJacob Keller } 1966a69f1cb6SJacob Keller 1967a69f1cb6SJacob Keller /* Return the calculated adjustment */ 1968a69f1cb6SJacob Keller *pmd_adj = adj; 1969a69f1cb6SJacob Keller 1970a69f1cb6SJacob Keller return 0; 1971a69f1cb6SJacob Keller } 1972a69f1cb6SJacob Keller 1973a69f1cb6SJacob Keller /** 19743a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 19753a749623SJacob Keller * @hw: pointer to HW struct 19763a749623SJacob Keller * @link_spd: The Link speed to calculate for 19773a749623SJacob Keller * 19783a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 19793a749623SJacob Keller */ 19803a749623SJacob Keller static u64 19813a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 19823a749623SJacob Keller { 19833a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 19843a749623SJacob Keller 19853a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 19863a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 19873a749623SJacob Keller 19883a749623SJacob Keller /* Calculate TUs per second */ 19893a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 19903a749623SJacob Keller 19913a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 19923a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 19933a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 19943a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 19953a749623SJacob Keller * divisions by 1e4 first then by 1e7. 19963a749623SJacob Keller */ 19973a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 19983a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 19993a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 20003a749623SJacob Keller 20013a749623SJacob Keller return fixed_offset; 20023a749623SJacob Keller } 20033a749623SJacob Keller 20043a749623SJacob Keller /** 2005a69f1cb6SJacob Keller * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset 2006a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2007a69f1cb6SJacob Keller * @port: the PHY port to configure 2008a69f1cb6SJacob Keller * 2009a69f1cb6SJacob Keller * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to 2010a69f1cb6SJacob Keller * adjust Rx timestamps by. This combines calculations from the Vernier offset 2011a69f1cb6SJacob Keller * measurements taken in hardware with some data about known fixed delay as 2012a69f1cb6SJacob Keller * well as adjusting for multi-lane alignment delay. 2013a69f1cb6SJacob Keller * 2014a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 2015a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 2016a69f1cb6SJacob Keller * has measured the offset. 2017a69f1cb6SJacob Keller * 2018a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 2019a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 2020a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 2021a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 2022a69f1cb6SJacob Keller */ 2023a69f1cb6SJacob Keller static int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) 2024a69f1cb6SJacob Keller { 2025a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 2026a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 2027a69f1cb6SJacob Keller u64 total_offset, pmd, val; 2028a69f1cb6SJacob Keller int err; 2029a69f1cb6SJacob Keller 2030a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 2031a69f1cb6SJacob Keller if (err) 2032a69f1cb6SJacob Keller return err; 2033a69f1cb6SJacob Keller 2034a69f1cb6SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 2035a69f1cb6SJacob Keller 2036a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 2037a69f1cb6SJacob Keller * the total offset. 2038a69f1cb6SJacob Keller */ 2039a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2040a69f1cb6SJacob Keller P_REG_PAR_PCS_RX_OFFSET_L, 2041a69f1cb6SJacob Keller &val); 2042a69f1cb6SJacob Keller if (err) 2043a69f1cb6SJacob Keller return err; 2044a69f1cb6SJacob Keller 2045a69f1cb6SJacob Keller total_offset += val; 2046a69f1cb6SJacob Keller 2047a69f1cb6SJacob Keller /* For Rx, all multi-lane link speeds include a second Vernier 2048a69f1cb6SJacob Keller * calibration, because the lanes might not be aligned. 2049a69f1cb6SJacob Keller */ 2050a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_40G || 2051a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G || 2052a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 2053a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 2054a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2055a69f1cb6SJacob Keller P_REG_PAR_RX_TIME_L, 2056a69f1cb6SJacob Keller &val); 2057a69f1cb6SJacob Keller if (err) 2058a69f1cb6SJacob Keller return err; 2059a69f1cb6SJacob Keller 2060a69f1cb6SJacob Keller total_offset += val; 2061a69f1cb6SJacob Keller } 2062a69f1cb6SJacob Keller 2063a69f1cb6SJacob Keller /* In addition, Rx must account for the PMD alignment */ 2064a69f1cb6SJacob Keller err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd); 2065a69f1cb6SJacob Keller if (err) 2066a69f1cb6SJacob Keller return err; 2067a69f1cb6SJacob Keller 2068a69f1cb6SJacob Keller /* For RS-FEC, this adjustment adds delay, but for other modes, it 2069a69f1cb6SJacob Keller * subtracts delay. 2070a69f1cb6SJacob Keller */ 2071a69f1cb6SJacob Keller if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC) 2072a69f1cb6SJacob Keller total_offset += pmd; 2073a69f1cb6SJacob Keller else 2074a69f1cb6SJacob Keller total_offset -= pmd; 2075a69f1cb6SJacob Keller 2076a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 2077a69f1cb6SJacob Keller * PHY and indicate that the Rx offset is ready. After this, 2078a69f1cb6SJacob Keller * timestamps will be enabled. 2079a69f1cb6SJacob Keller */ 2080a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 2081a69f1cb6SJacob Keller total_offset); 2082a69f1cb6SJacob Keller if (err) 2083a69f1cb6SJacob Keller return err; 2084a69f1cb6SJacob Keller 2085a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 2086a69f1cb6SJacob Keller if (err) 2087a69f1cb6SJacob Keller return err; 2088a69f1cb6SJacob Keller 2089a69f1cb6SJacob Keller return 0; 2090a69f1cb6SJacob Keller } 2091a69f1cb6SJacob Keller 2092a69f1cb6SJacob Keller /** 20933a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 20943a749623SJacob Keller * @hw: pointer to the HW struct 20953a749623SJacob Keller * @port: the PHY port to read 20963a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 20973a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 20983a749623SJacob Keller * 20993a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 21003a749623SJacob Keller * timer values. 21013a749623SJacob Keller */ 21023a749623SJacob Keller static int 21033a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 21043a749623SJacob Keller u64 *phc_time) 21053a749623SJacob Keller { 21063a749623SJacob Keller u64 tx_time, rx_time; 21073a749623SJacob Keller u32 zo, lo; 21083a749623SJacob Keller u8 tmr_idx; 21093a749623SJacob Keller int err; 21103a749623SJacob Keller 21113a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 21123a749623SJacob Keller 21133a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 21143a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 21153a749623SJacob Keller 21163a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 21173a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 21183a749623SJacob Keller if (err) 21193a749623SJacob Keller return err; 21203a749623SJacob Keller 21213a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 21223a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 21233a749623SJacob Keller 21243a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 21253a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 21263a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 21273a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 21283a749623SJacob Keller 21293a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 21303a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 21313a749623SJacob Keller if (err) 21323a749623SJacob Keller return err; 21333a749623SJacob Keller 21343a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 21353a749623SJacob Keller * Note that this should not happen in normal circumstances since the 21363a749623SJacob Keller * driver always programs them together. 21373a749623SJacob Keller */ 21383a749623SJacob Keller if (tx_time != rx_time) 21393a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 21403a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 21413a749623SJacob Keller port, (unsigned long long)tx_time, 21423a749623SJacob Keller (unsigned long long)rx_time); 21433a749623SJacob Keller 21443a749623SJacob Keller *phy_time = tx_time; 21453a749623SJacob Keller 21463a749623SJacob Keller return 0; 21473a749623SJacob Keller } 21483a749623SJacob Keller 21493a749623SJacob Keller /** 21503a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 21513a749623SJacob Keller * @hw: pointer to the HW struct 21523a749623SJacob Keller * @port: the PHY port to synchronize 21533a749623SJacob Keller * 21543a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 21553a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 21563a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 21573a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 21583a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 21593a749623SJacob Keller */ 21603a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 21613a749623SJacob Keller { 21623a749623SJacob Keller u64 phc_time, phy_time, difference; 21633a749623SJacob Keller int err; 21643a749623SJacob Keller 21653a749623SJacob Keller if (!ice_ptp_lock(hw)) { 21663a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 21673a749623SJacob Keller return -EBUSY; 21683a749623SJacob Keller } 21693a749623SJacob Keller 21703a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 21713a749623SJacob Keller if (err) 21723a749623SJacob Keller goto err_unlock; 21733a749623SJacob Keller 21743a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 21753a749623SJacob Keller * it to match the PHC time. 21763a749623SJacob Keller * 21773a749623SJacob Keller * Note that the port adjustment is done using 2s complement 21783a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 21793a749623SJacob Keller * calculate the difference between the PHC time and the port time, 21803a749623SJacob Keller * and it will be interpreted correctly. 21813a749623SJacob Keller */ 21823a749623SJacob Keller difference = phc_time - phy_time; 21833a749623SJacob Keller 21843a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 21853a749623SJacob Keller if (err) 21863a749623SJacob Keller goto err_unlock; 21873a749623SJacob Keller 21883a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 21893a749623SJacob Keller if (err) 21903a749623SJacob Keller goto err_unlock; 21913a749623SJacob Keller 21923a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 21933a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 21943a749623SJacob Keller 21953a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 21963a749623SJacob Keller * verify that the time was properly adjusted. 21973a749623SJacob Keller */ 21983a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 21993a749623SJacob Keller if (err) 22003a749623SJacob Keller goto err_unlock; 22013a749623SJacob Keller 22023a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 22033a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 22043a749623SJacob Keller port, (unsigned long long)phy_time, 22053a749623SJacob Keller (unsigned long long)phc_time); 22063a749623SJacob Keller 22073a749623SJacob Keller ice_ptp_unlock(hw); 22083a749623SJacob Keller 22093a749623SJacob Keller return 0; 22103a749623SJacob Keller 22113a749623SJacob Keller err_unlock: 22123a749623SJacob Keller ice_ptp_unlock(hw); 22133a749623SJacob Keller return err; 22143a749623SJacob Keller } 22153a749623SJacob Keller 22163a749623SJacob Keller /** 22173a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 22183a749623SJacob Keller * @hw: pointer to the HW struct 22193a749623SJacob Keller * @port: the PHY port to stop 22203a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 22213a749623SJacob Keller * 22223a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 22233a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 22243a749623SJacob Keller * initialized or when link speed changes. 22253a749623SJacob Keller */ 22263a749623SJacob Keller int 22273a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 22283a749623SJacob Keller { 22293a749623SJacob Keller int err; 22303a749623SJacob Keller u32 val; 22313a749623SJacob Keller 22323a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 22333a749623SJacob Keller if (err) 22343a749623SJacob Keller return err; 22353a749623SJacob Keller 22363a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 22373a749623SJacob Keller if (err) 22383a749623SJacob Keller return err; 22393a749623SJacob Keller 22403a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 22413a749623SJacob Keller if (err) 22423a749623SJacob Keller return err; 22433a749623SJacob Keller 22443a749623SJacob Keller val &= ~P_REG_PS_START_M; 22453a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22463a749623SJacob Keller if (err) 22473a749623SJacob Keller return err; 22483a749623SJacob Keller 22493a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 22503a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22513a749623SJacob Keller if (err) 22523a749623SJacob Keller return err; 22533a749623SJacob Keller 22543a749623SJacob Keller if (soft_reset) { 22553a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 22563a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22573a749623SJacob Keller if (err) 22583a749623SJacob Keller return err; 22593a749623SJacob Keller } 22603a749623SJacob Keller 22613a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 22623a749623SJacob Keller 22633a749623SJacob Keller return 0; 22643a749623SJacob Keller } 22653a749623SJacob Keller 22663a749623SJacob Keller /** 22673a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 22683a749623SJacob Keller * @hw: pointer to the HW struct 22693a749623SJacob Keller * @port: the PHY port to start 22703a749623SJacob Keller * 22713a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 22723a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 22733a749623SJacob Keller * initialized or when link speed changes. 22743a749623SJacob Keller * 22750357d5caSMilena Olech * Hardware will take Vernier measurements on Tx or Rx of packets. 22763a749623SJacob Keller */ 22770357d5caSMilena Olech int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) 22783a749623SJacob Keller { 22793a749623SJacob Keller u32 lo, hi, val; 22803a749623SJacob Keller u64 incval; 22813a749623SJacob Keller u8 tmr_idx; 22823a749623SJacob Keller int err; 22833a749623SJacob Keller 22843a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 22853a749623SJacob Keller 22863a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 22873a749623SJacob Keller if (err) 22883a749623SJacob Keller return err; 22893a749623SJacob Keller 22903a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 22913a749623SJacob Keller 22923a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 22933a749623SJacob Keller if (err) 22943a749623SJacob Keller return err; 22953a749623SJacob Keller 22963a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 22973a749623SJacob Keller if (err) 22983a749623SJacob Keller return err; 22993a749623SJacob Keller 23003a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 23013a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 23023a749623SJacob Keller incval = (u64)hi << 32 | lo; 23033a749623SJacob Keller 23043a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 23053a749623SJacob Keller if (err) 23063a749623SJacob Keller return err; 23073a749623SJacob Keller 23083a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23093a749623SJacob Keller if (err) 23103a749623SJacob Keller return err; 23113a749623SJacob Keller 23123a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23133a749623SJacob Keller 23143a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 23153a749623SJacob Keller if (err) 23163a749623SJacob Keller return err; 23173a749623SJacob Keller 23183a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 23193a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23203a749623SJacob Keller if (err) 23213a749623SJacob Keller return err; 23223a749623SJacob Keller 23233a749623SJacob Keller val |= P_REG_PS_START_M; 23243a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23253a749623SJacob Keller if (err) 23263a749623SJacob Keller return err; 23273a749623SJacob Keller 23283a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 23293a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23303a749623SJacob Keller if (err) 23313a749623SJacob Keller return err; 23323a749623SJacob Keller 23333a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23343a749623SJacob Keller if (err) 23353a749623SJacob Keller return err; 23363a749623SJacob Keller 23373a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23383a749623SJacob Keller 23393a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 23403a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23413a749623SJacob Keller if (err) 23423a749623SJacob Keller return err; 23433a749623SJacob Keller 23443a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 23453a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23463a749623SJacob Keller if (err) 23473a749623SJacob Keller return err; 23483a749623SJacob Keller 23493a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23503a749623SJacob Keller 23513a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 23523a749623SJacob Keller if (err) 23533a749623SJacob Keller return err; 23543a749623SJacob Keller 23553a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 23563a749623SJacob Keller 23573a749623SJacob Keller return 0; 23583a749623SJacob Keller } 23593a749623SJacob Keller 2360a69f1cb6SJacob Keller /** 23610357d5caSMilena Olech * ice_phy_calc_vernier_e822 - Perform vernier calculations 2362a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2363a69f1cb6SJacob Keller * @port: the PHY port to configure 2364a69f1cb6SJacob Keller * 23650357d5caSMilena Olech * Perform vernier calculations for the Tx and Rx offset. This will enable 23660357d5caSMilena Olech * hardware to include the more precise offset calibrations, 23670357d5caSMilena Olech * increasing precision of the generated timestamps. 2368a69f1cb6SJacob Keller * 2369a69f1cb6SJacob Keller * This cannot be done until hardware has measured the offsets, which requires 2370a69f1cb6SJacob Keller * waiting until at least one packet has been sent and received by the device. 2371a69f1cb6SJacob Keller */ 23720357d5caSMilena Olech int ice_phy_calc_vernier_e822(struct ice_hw *hw, u8 port) 2373a69f1cb6SJacob Keller { 2374a69f1cb6SJacob Keller int err; 2375a69f1cb6SJacob Keller u32 val; 2376a69f1cb6SJacob Keller 2377a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val); 2378a69f1cb6SJacob Keller if (err) { 2379a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n", 2380a69f1cb6SJacob Keller port, err); 2381a69f1cb6SJacob Keller return err; 2382a69f1cb6SJacob Keller } 2383a69f1cb6SJacob Keller 2384a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2385a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n", 2386a69f1cb6SJacob Keller port); 2387a69f1cb6SJacob Keller return -EBUSY; 2388a69f1cb6SJacob Keller } 2389a69f1cb6SJacob Keller 2390a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val); 2391a69f1cb6SJacob Keller if (err) { 2392a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n", 2393a69f1cb6SJacob Keller port, err); 2394a69f1cb6SJacob Keller return err; 2395a69f1cb6SJacob Keller } 2396a69f1cb6SJacob Keller 2397a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2398a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n", 2399a69f1cb6SJacob Keller port); 2400a69f1cb6SJacob Keller return -EBUSY; 2401a69f1cb6SJacob Keller } 2402a69f1cb6SJacob Keller 2403a69f1cb6SJacob Keller err = ice_phy_cfg_tx_offset_e822(hw, port); 2404a69f1cb6SJacob Keller if (err) { 2405a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, err %d\n", 2406a69f1cb6SJacob Keller port, err); 2407a69f1cb6SJacob Keller return err; 2408a69f1cb6SJacob Keller } 2409a69f1cb6SJacob Keller 2410a69f1cb6SJacob Keller err = ice_phy_cfg_rx_offset_e822(hw, port); 2411a69f1cb6SJacob Keller if (err) { 2412a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, err %d\n", 2413a69f1cb6SJacob Keller port, err); 2414a69f1cb6SJacob Keller return err; 2415a69f1cb6SJacob Keller } 2416a69f1cb6SJacob Keller 2417a69f1cb6SJacob Keller return 0; 2418a69f1cb6SJacob Keller } 2419a69f1cb6SJacob Keller 2420*10e4b4a3SJacob Keller /** 2421*10e4b4a3SJacob Keller * ice_get_phy_tx_tstamp_ready_e822 - Read Tx memory status register 2422*10e4b4a3SJacob Keller * @hw: pointer to the HW struct 2423*10e4b4a3SJacob Keller * @quad: the timestamp quad to read from 2424*10e4b4a3SJacob Keller * @tstamp_ready: contents of the Tx memory status register 2425*10e4b4a3SJacob Keller * 2426*10e4b4a3SJacob Keller * Read the Q_REG_TX_MEMORY_STATUS register indicating which timestamps in 2427*10e4b4a3SJacob Keller * the PHY are ready. A set bit means the corresponding timestamp is valid and 2428*10e4b4a3SJacob Keller * ready to be captured from the PHY timestamp block. 2429*10e4b4a3SJacob Keller */ 2430*10e4b4a3SJacob Keller static int 2431*10e4b4a3SJacob Keller ice_get_phy_tx_tstamp_ready_e822(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) 2432*10e4b4a3SJacob Keller { 2433*10e4b4a3SJacob Keller u32 hi, lo; 2434*10e4b4a3SJacob Keller int err; 2435*10e4b4a3SJacob Keller 2436*10e4b4a3SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi); 2437*10e4b4a3SJacob Keller if (err) { 2438*10e4b4a3SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_U for quad %u, err %d\n", 2439*10e4b4a3SJacob Keller quad, err); 2440*10e4b4a3SJacob Keller return err; 2441*10e4b4a3SJacob Keller } 2442*10e4b4a3SJacob Keller 2443*10e4b4a3SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo); 2444*10e4b4a3SJacob Keller if (err) { 2445*10e4b4a3SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_L for quad %u, err %d\n", 2446*10e4b4a3SJacob Keller quad, err); 2447*10e4b4a3SJacob Keller return err; 2448*10e4b4a3SJacob Keller } 2449*10e4b4a3SJacob Keller 2450*10e4b4a3SJacob Keller *tstamp_ready = (u64)hi << 32 | (u64)lo; 2451*10e4b4a3SJacob Keller 2452*10e4b4a3SJacob Keller return 0; 2453*10e4b4a3SJacob Keller } 2454*10e4b4a3SJacob Keller 245503cb4473SJacob Keller /* E810 functions 245603cb4473SJacob Keller * 245703cb4473SJacob Keller * The following functions operate on the E810 series devices which use 245803cb4473SJacob Keller * a separate external PHY. 245903cb4473SJacob Keller */ 246003cb4473SJacob Keller 246103cb4473SJacob Keller /** 246203cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 246303cb4473SJacob Keller * @hw: pointer to the HW struct 246403cb4473SJacob Keller * @addr: the address to read from 246503cb4473SJacob Keller * @val: On return, the value read from the PHY 246603cb4473SJacob Keller * 246703cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 246803cb4473SJacob Keller */ 246903cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 247003cb4473SJacob Keller { 247103cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 247239b28106SJacob Keller int err; 247303cb4473SJacob Keller 247403cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 247503cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 247603cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 247703cb4473SJacob Keller msg.dest_dev = rmn_0; 247803cb4473SJacob Keller 247939b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 248039b28106SJacob Keller if (err) { 248139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 248239b28106SJacob Keller err); 248339b28106SJacob Keller return err; 248403cb4473SJacob Keller } 248503cb4473SJacob Keller 248603cb4473SJacob Keller *val = msg.data; 248703cb4473SJacob Keller 248803cb4473SJacob Keller return 0; 248903cb4473SJacob Keller } 249003cb4473SJacob Keller 249103cb4473SJacob Keller /** 249203cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 249303cb4473SJacob Keller * @hw: pointer to the HW struct 249403cb4473SJacob Keller * @addr: the address to writem to 249503cb4473SJacob Keller * @val: the value to write to the PHY 249603cb4473SJacob Keller * 249703cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 249803cb4473SJacob Keller */ 249903cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 250003cb4473SJacob Keller { 250103cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 250239b28106SJacob Keller int err; 250303cb4473SJacob Keller 250403cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 250503cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 250603cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 250703cb4473SJacob Keller msg.dest_dev = rmn_0; 250803cb4473SJacob Keller msg.data = val; 250903cb4473SJacob Keller 251039b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 251139b28106SJacob Keller if (err) { 251239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 251339b28106SJacob Keller err); 251439b28106SJacob Keller return err; 251503cb4473SJacob Keller } 251603cb4473SJacob Keller 251703cb4473SJacob Keller return 0; 251803cb4473SJacob Keller } 251903cb4473SJacob Keller 252003cb4473SJacob Keller /** 25211229b339SKarol Kolacinski * ice_read_phy_tstamp_ll_e810 - Read a PHY timestamp registers through the FW 25221229b339SKarol Kolacinski * @hw: pointer to the HW struct 25231229b339SKarol Kolacinski * @idx: the timestamp index to read 25241229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 25251229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 25261229b339SKarol Kolacinski * 25271229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 25281229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using the low latency 25291229b339SKarol Kolacinski * timestamp read. 25301229b339SKarol Kolacinski */ 25311229b339SKarol Kolacinski static int 25321229b339SKarol Kolacinski ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo) 25331229b339SKarol Kolacinski { 25341229b339SKarol Kolacinski u32 val; 25351229b339SKarol Kolacinski u8 i; 25361229b339SKarol Kolacinski 25371229b339SKarol Kolacinski /* Write TS index to read to the PF register so the FW can read it */ 25381229b339SKarol Kolacinski val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS; 25391229b339SKarol Kolacinski wr32(hw, PF_SB_ATQBAL, val); 25401229b339SKarol Kolacinski 25411229b339SKarol Kolacinski /* Read the register repeatedly until the FW provides us the TS */ 25421229b339SKarol Kolacinski for (i = TS_LL_READ_RETRIES; i > 0; i--) { 25431229b339SKarol Kolacinski val = rd32(hw, PF_SB_ATQBAL); 25441229b339SKarol Kolacinski 25451229b339SKarol Kolacinski /* When the bit is cleared, the TS is ready in the register */ 25461229b339SKarol Kolacinski if (!(FIELD_GET(TS_LL_READ_TS, val))) { 25471229b339SKarol Kolacinski /* High 8 bit value of the TS is on the bits 16:23 */ 25481229b339SKarol Kolacinski *hi = FIELD_GET(TS_LL_READ_TS_HIGH, val); 25491229b339SKarol Kolacinski 25501229b339SKarol Kolacinski /* Read the low 32 bit value and set the TS valid bit */ 25511229b339SKarol Kolacinski *lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID; 25521229b339SKarol Kolacinski return 0; 25531229b339SKarol Kolacinski } 25541229b339SKarol Kolacinski 25551229b339SKarol Kolacinski udelay(10); 25561229b339SKarol Kolacinski } 25571229b339SKarol Kolacinski 25581229b339SKarol Kolacinski /* FW failed to provide the TS in time */ 25591229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n"); 25601229b339SKarol Kolacinski return -EINVAL; 25611229b339SKarol Kolacinski } 25621229b339SKarol Kolacinski 25631229b339SKarol Kolacinski /** 25641229b339SKarol Kolacinski * ice_read_phy_tstamp_sbq_e810 - Read a PHY timestamp registers through the sbq 25651229b339SKarol Kolacinski * @hw: pointer to the HW struct 25661229b339SKarol Kolacinski * @lport: the lport to read from 25671229b339SKarol Kolacinski * @idx: the timestamp index to read 25681229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 25691229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 25701229b339SKarol Kolacinski * 25711229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 25721229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using sideband queue. 25731229b339SKarol Kolacinski */ 25741229b339SKarol Kolacinski static int 25751229b339SKarol Kolacinski ice_read_phy_tstamp_sbq_e810(struct ice_hw *hw, u8 lport, u8 idx, u8 *hi, 25761229b339SKarol Kolacinski u32 *lo) 25771229b339SKarol Kolacinski { 25781229b339SKarol Kolacinski u32 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 25791229b339SKarol Kolacinski u32 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 25801229b339SKarol Kolacinski u32 lo_val, hi_val; 25811229b339SKarol Kolacinski int err; 25821229b339SKarol Kolacinski 25831229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, lo_addr, &lo_val); 25841229b339SKarol Kolacinski if (err) { 25851229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 25861229b339SKarol Kolacinski err); 25871229b339SKarol Kolacinski return err; 25881229b339SKarol Kolacinski } 25891229b339SKarol Kolacinski 25901229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, hi_addr, &hi_val); 25911229b339SKarol Kolacinski if (err) { 25921229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 25931229b339SKarol Kolacinski err); 25941229b339SKarol Kolacinski return err; 25951229b339SKarol Kolacinski } 25961229b339SKarol Kolacinski 25971229b339SKarol Kolacinski *lo = lo_val; 25981229b339SKarol Kolacinski *hi = (u8)hi_val; 25991229b339SKarol Kolacinski 26001229b339SKarol Kolacinski return 0; 26011229b339SKarol Kolacinski } 26021229b339SKarol Kolacinski 26031229b339SKarol Kolacinski /** 260403cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 260503cb4473SJacob Keller * @hw: pointer to the HW struct 260603cb4473SJacob Keller * @lport: the lport to read from 260703cb4473SJacob Keller * @idx: the timestamp index to read 260803cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 260903cb4473SJacob Keller * 261003cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 261103cb4473SJacob Keller * on the E810 device. 261203cb4473SJacob Keller */ 261303cb4473SJacob Keller static int 261403cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 261503cb4473SJacob Keller { 26161229b339SKarol Kolacinski u32 lo = 0; 26171229b339SKarol Kolacinski u8 hi = 0; 261839b28106SJacob Keller int err; 261903cb4473SJacob Keller 26201229b339SKarol Kolacinski if (hw->dev_caps.ts_dev_info.ts_ll_read) 26211229b339SKarol Kolacinski err = ice_read_phy_tstamp_ll_e810(hw, idx, &hi, &lo); 26221229b339SKarol Kolacinski else 26231229b339SKarol Kolacinski err = ice_read_phy_tstamp_sbq_e810(hw, lport, idx, &hi, &lo); 262403cb4473SJacob Keller 26251229b339SKarol Kolacinski if (err) 262639b28106SJacob Keller return err; 262703cb4473SJacob Keller 262803cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 262903cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 263003cb4473SJacob Keller */ 263103cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 263203cb4473SJacob Keller 263303cb4473SJacob Keller return 0; 263403cb4473SJacob Keller } 263503cb4473SJacob Keller 263603cb4473SJacob Keller /** 263703cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 263803cb4473SJacob Keller * @hw: pointer to the HW struct 263903cb4473SJacob Keller * @lport: the lport to read from 264003cb4473SJacob Keller * @idx: the timestamp index to reset 264103cb4473SJacob Keller * 264203cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 264303cb4473SJacob Keller * external PHY on the E810 device. 264403cb4473SJacob Keller */ 264503cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 264603cb4473SJacob Keller { 264703cb4473SJacob Keller u32 lo_addr, hi_addr; 264839b28106SJacob Keller int err; 264903cb4473SJacob Keller 265003cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 265103cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 265203cb4473SJacob Keller 265339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 265439b28106SJacob Keller if (err) { 265539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 265639b28106SJacob Keller err); 265739b28106SJacob Keller return err; 265803cb4473SJacob Keller } 265903cb4473SJacob Keller 266039b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 266139b28106SJacob Keller if (err) { 266239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 266339b28106SJacob Keller err); 266439b28106SJacob Keller return err; 266503cb4473SJacob Keller } 266603cb4473SJacob Keller 266703cb4473SJacob Keller return 0; 266803cb4473SJacob Keller } 266903cb4473SJacob Keller 267003cb4473SJacob Keller /** 267103cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 267203cb4473SJacob Keller * @hw: pointer to HW struct 267303cb4473SJacob Keller * 267403cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 267503cb4473SJacob Keller * this function. 267603cb4473SJacob Keller */ 267703cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 267803cb4473SJacob Keller { 267903cb4473SJacob Keller u8 tmr_idx; 268039b28106SJacob Keller int err; 268103cb4473SJacob Keller 268203cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 268339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 268403cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 268539b28106SJacob Keller if (err) 268603cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 268739b28106SJacob Keller err); 268803cb4473SJacob Keller 268939b28106SJacob Keller return err; 269003cb4473SJacob Keller } 269103cb4473SJacob Keller 269203cb4473SJacob Keller /** 2693b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 2694b2ee7256SJacob Keller * @hw: pointer to HW struct 2695b2ee7256SJacob Keller * 2696b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 2697b2ee7256SJacob Keller */ 2698b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 2699b2ee7256SJacob Keller { 2700b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 2701b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 2702b2ee7256SJacob Keller 2703b2ee7256SJacob Keller /* Initialize the PHY */ 2704b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 2705b2ee7256SJacob Keller } 2706b2ee7256SJacob Keller 2707b2ee7256SJacob Keller /** 270803cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 270903cb4473SJacob Keller * @hw: Board private structure 271003cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 271103cb4473SJacob Keller * 271203cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 271303cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 271403cb4473SJacob Keller * driver issues an INIT_TIME command. 271503cb4473SJacob Keller * 271603cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 271703cb4473SJacob Keller * nominal nanoseconds. 271803cb4473SJacob Keller */ 271903cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 272003cb4473SJacob Keller { 272103cb4473SJacob Keller u8 tmr_idx; 272239b28106SJacob Keller int err; 272303cb4473SJacob Keller 272403cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 272539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 272639b28106SJacob Keller if (err) { 272739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 272839b28106SJacob Keller err); 272939b28106SJacob Keller return err; 273003cb4473SJacob Keller } 273103cb4473SJacob Keller 273239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 273339b28106SJacob Keller if (err) { 273439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 273539b28106SJacob Keller err); 273639b28106SJacob Keller return err; 273703cb4473SJacob Keller } 273803cb4473SJacob Keller 273903cb4473SJacob Keller return 0; 274003cb4473SJacob Keller } 274103cb4473SJacob Keller 274203cb4473SJacob Keller /** 274303cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 274403cb4473SJacob Keller * @hw: pointer to HW struct 274503cb4473SJacob Keller * @adj: adjustment value to program 274603cb4473SJacob Keller * 274703cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 274803cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 274903cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 275003cb4473SJacob Keller * 275103cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 275203cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 275303cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 275403cb4473SJacob Keller */ 275503cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 275603cb4473SJacob Keller { 275703cb4473SJacob Keller u8 tmr_idx; 275839b28106SJacob Keller int err; 275903cb4473SJacob Keller 276003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 276103cb4473SJacob Keller 276203cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 276303cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 276403cb4473SJacob Keller */ 276539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 276639b28106SJacob Keller if (err) { 276739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 276839b28106SJacob Keller err); 276939b28106SJacob Keller return err; 277003cb4473SJacob Keller } 277103cb4473SJacob Keller 277239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 277339b28106SJacob Keller if (err) { 277439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 277539b28106SJacob Keller err); 277639b28106SJacob Keller return err; 277703cb4473SJacob Keller } 277803cb4473SJacob Keller 277903cb4473SJacob Keller return 0; 278003cb4473SJacob Keller } 278103cb4473SJacob Keller 278203cb4473SJacob Keller /** 278303cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 278403cb4473SJacob Keller * @hw: pointer to HW struct 278503cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 278603cb4473SJacob Keller * 278703cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 278803cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 278903cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 279003cb4473SJacob Keller */ 279103cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 279203cb4473SJacob Keller { 279303cb4473SJacob Keller u32 high, low; 279403cb4473SJacob Keller u8 tmr_idx; 279539b28106SJacob Keller int err; 279603cb4473SJacob Keller 279703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 279803cb4473SJacob Keller low = lower_32_bits(incval); 279903cb4473SJacob Keller high = upper_32_bits(incval); 280003cb4473SJacob Keller 280139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 280239b28106SJacob Keller if (err) { 280339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 280439b28106SJacob Keller err); 280539b28106SJacob Keller return err; 280603cb4473SJacob Keller } 280703cb4473SJacob Keller 280839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 280939b28106SJacob Keller if (err) { 281039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 281139b28106SJacob Keller err); 281239b28106SJacob Keller return err; 281303cb4473SJacob Keller } 281403cb4473SJacob Keller 281503cb4473SJacob Keller return 0; 281603cb4473SJacob Keller } 281703cb4473SJacob Keller 281803cb4473SJacob Keller /** 281903cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 282003cb4473SJacob Keller * @hw: pointer to HW struct 282103cb4473SJacob Keller * @cmd: Command to be sent to the port 282203cb4473SJacob Keller * 282303cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 282403cb4473SJacob Keller * command. 282503cb4473SJacob Keller */ 282603cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 282703cb4473SJacob Keller { 282803cb4473SJacob Keller u32 cmd_val, val; 282939b28106SJacob Keller int err; 283003cb4473SJacob Keller 283103cb4473SJacob Keller switch (cmd) { 283203cb4473SJacob Keller case INIT_TIME: 283303cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 283403cb4473SJacob Keller break; 283503cb4473SJacob Keller case INIT_INCVAL: 283603cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 283703cb4473SJacob Keller break; 283803cb4473SJacob Keller case ADJ_TIME: 283903cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 284003cb4473SJacob Keller break; 284103cb4473SJacob Keller case READ_TIME: 284203cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 284303cb4473SJacob Keller break; 284403cb4473SJacob Keller case ADJ_TIME_AT_TIME: 284503cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 284603cb4473SJacob Keller break; 284703cb4473SJacob Keller } 284803cb4473SJacob Keller 284903cb4473SJacob Keller /* Read, modify, write */ 285039b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 285139b28106SJacob Keller if (err) { 285239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 285339b28106SJacob Keller return err; 285403cb4473SJacob Keller } 285503cb4473SJacob Keller 285603cb4473SJacob Keller /* Modify necessary bits only and perform write */ 285703cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 285803cb4473SJacob Keller val |= cmd_val; 285903cb4473SJacob Keller 286039b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 286139b28106SJacob Keller if (err) { 286239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 286339b28106SJacob Keller return err; 286403cb4473SJacob Keller } 286503cb4473SJacob Keller 286603cb4473SJacob Keller return 0; 286703cb4473SJacob Keller } 286803cb4473SJacob Keller 286903cb4473SJacob Keller /* Device agnostic functions 287003cb4473SJacob Keller * 28713a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 28723a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 28733a749623SJacob Keller * necessary. 287403cb4473SJacob Keller */ 287503cb4473SJacob Keller 287603cb4473SJacob Keller /** 287703cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 287803cb4473SJacob Keller * @hw: pointer to the HW struct 287903cb4473SJacob Keller * 288003cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 288103cb4473SJacob Keller * was acquired, false otherwise. 288203cb4473SJacob Keller * 288303cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 288403cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 288503cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 288603cb4473SJacob Keller * bit set, it means that another function acquired the lock. 288703cb4473SJacob Keller * 288803cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 288903cb4473SJacob Keller * functions when done. 289003cb4473SJacob Keller */ 289103cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 289203cb4473SJacob Keller { 289303cb4473SJacob Keller u32 hw_lock; 289403cb4473SJacob Keller int i; 289503cb4473SJacob Keller 2896a711a328SKarol Kolacinski #define MAX_TRIES 15 289703cb4473SJacob Keller 289803cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 289903cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 290003cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2901a711a328SKarol Kolacinski if (hw_lock) { 290203cb4473SJacob Keller /* Somebody is holding the lock */ 2903a711a328SKarol Kolacinski usleep_range(5000, 6000); 2904a711a328SKarol Kolacinski continue; 2905a711a328SKarol Kolacinski } 2906a711a328SKarol Kolacinski 2907a711a328SKarol Kolacinski break; 290803cb4473SJacob Keller } 290903cb4473SJacob Keller 291003cb4473SJacob Keller return !hw_lock; 291103cb4473SJacob Keller } 291203cb4473SJacob Keller 291303cb4473SJacob Keller /** 291403cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 291503cb4473SJacob Keller * @hw: pointer to the HW struct 291603cb4473SJacob Keller * 291703cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 291803cb4473SJacob Keller * the PFTSYN_SEM register. 291903cb4473SJacob Keller */ 292003cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 292103cb4473SJacob Keller { 292203cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 292303cb4473SJacob Keller } 292403cb4473SJacob Keller 292503cb4473SJacob Keller /** 292603cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 292703cb4473SJacob Keller * @hw: pointer to HW struct 292803cb4473SJacob Keller * @cmd: the command to issue 292903cb4473SJacob Keller * 293003cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 293103cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 293203cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 293303cb4473SJacob Keller * timers. 293403cb4473SJacob Keller */ 293503cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 293603cb4473SJacob Keller { 293739b28106SJacob Keller int err; 293803cb4473SJacob Keller 293903cb4473SJacob Keller /* First, prepare the source timer */ 294003cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 294103cb4473SJacob Keller 294203cb4473SJacob Keller /* Next, prepare the ports */ 29433a749623SJacob Keller if (ice_is_e810(hw)) 294439b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 29453a749623SJacob Keller else 29463a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 294739b28106SJacob Keller if (err) { 294839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 294939b28106SJacob Keller cmd, err); 295039b28106SJacob Keller return err; 295103cb4473SJacob Keller } 295203cb4473SJacob Keller 29533a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 29543a749623SJacob Keller * commands synchronously 295503cb4473SJacob Keller */ 29563a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 295703cb4473SJacob Keller 295803cb4473SJacob Keller return 0; 295903cb4473SJacob Keller } 296003cb4473SJacob Keller 296103cb4473SJacob Keller /** 296203cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 296303cb4473SJacob Keller * @hw: pointer to HW struct 296403cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 296503cb4473SJacob Keller * 296603cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 296703cb4473SJacob Keller * step process: 296803cb4473SJacob Keller * 296903cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 297003cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 297103cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 297203cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 297303cb4473SJacob Keller */ 297403cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 297503cb4473SJacob Keller { 297603cb4473SJacob Keller u8 tmr_idx; 297739b28106SJacob Keller int err; 297803cb4473SJacob Keller 297903cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 298003cb4473SJacob Keller 298103cb4473SJacob Keller /* Source timers */ 298203cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 298303cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 298403cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 298503cb4473SJacob Keller 298603cb4473SJacob Keller /* PHY timers */ 298703cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 29883a749623SJacob Keller if (ice_is_e810(hw)) 298939b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 29903a749623SJacob Keller else 29913a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 299239b28106SJacob Keller if (err) 299339b28106SJacob Keller return err; 299403cb4473SJacob Keller 299503cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 299603cb4473SJacob Keller } 299703cb4473SJacob Keller 299803cb4473SJacob Keller /** 299903cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 300003cb4473SJacob Keller * @hw: pointer to HW struct 300103cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 300203cb4473SJacob Keller * 300303cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 300403cb4473SJacob Keller * process: 300503cb4473SJacob Keller * 300603cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 300703cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 300803cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 300903cb4473SJacob Keller * source and port timers to the new increment value at the next clock 301003cb4473SJacob Keller * cycle. 301103cb4473SJacob Keller */ 301203cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 301303cb4473SJacob Keller { 301403cb4473SJacob Keller u8 tmr_idx; 301539b28106SJacob Keller int err; 301603cb4473SJacob Keller 301703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 301803cb4473SJacob Keller 301903cb4473SJacob Keller /* Shadow Adjust */ 302003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 302103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 302203cb4473SJacob Keller 30233a749623SJacob Keller if (ice_is_e810(hw)) 302439b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 30253a749623SJacob Keller else 30263a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 302739b28106SJacob Keller if (err) 302839b28106SJacob Keller return err; 302903cb4473SJacob Keller 303003cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 303103cb4473SJacob Keller } 303203cb4473SJacob Keller 303303cb4473SJacob Keller /** 303403cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 303503cb4473SJacob Keller * @hw: pointer to HW struct 303603cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 303703cb4473SJacob Keller * 303803cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 303903cb4473SJacob Keller */ 304003cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 304103cb4473SJacob Keller { 304239b28106SJacob Keller int err; 304303cb4473SJacob Keller 304403cb4473SJacob Keller if (!ice_ptp_lock(hw)) 304503cb4473SJacob Keller return -EBUSY; 304603cb4473SJacob Keller 304739b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 304803cb4473SJacob Keller 304903cb4473SJacob Keller ice_ptp_unlock(hw); 305003cb4473SJacob Keller 305139b28106SJacob Keller return err; 305203cb4473SJacob Keller } 305303cb4473SJacob Keller 305403cb4473SJacob Keller /** 305503cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 305603cb4473SJacob Keller * @hw: pointer to HW struct 305703cb4473SJacob Keller * @adj: Adjustment in nanoseconds 305803cb4473SJacob Keller * 305903cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 306003cb4473SJacob Keller * nanoseconds. This requires a three-step process: 306103cb4473SJacob Keller * 306203cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 306303cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 306403cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 306503cb4473SJacob Keller * both the source and port timers at the next clock cycle. 306603cb4473SJacob Keller */ 306703cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 306803cb4473SJacob Keller { 306903cb4473SJacob Keller u8 tmr_idx; 307039b28106SJacob Keller int err; 307103cb4473SJacob Keller 307203cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 307303cb4473SJacob Keller 307403cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 307503cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 307603cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 307703cb4473SJacob Keller * the value as a 2's complement integer. 307803cb4473SJacob Keller */ 307903cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 308003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 308103cb4473SJacob Keller 30823a749623SJacob Keller if (ice_is_e810(hw)) 308339b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 30843a749623SJacob Keller else 30853a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 308639b28106SJacob Keller if (err) 308739b28106SJacob Keller return err; 308803cb4473SJacob Keller 308903cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 309003cb4473SJacob Keller } 309103cb4473SJacob Keller 309203cb4473SJacob Keller /** 309303cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 309403cb4473SJacob Keller * @hw: pointer to the HW struct 309503cb4473SJacob Keller * @block: the block to read from 309603cb4473SJacob Keller * @idx: the timestamp index to read 309703cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 309803cb4473SJacob Keller * 30993a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 31003a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 31013a749623SJacob Keller * logical port to read from. 310203cb4473SJacob Keller */ 310303cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 310403cb4473SJacob Keller { 31053a749623SJacob Keller if (ice_is_e810(hw)) 310603cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 31073a749623SJacob Keller else 31083a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 310903cb4473SJacob Keller } 311003cb4473SJacob Keller 311103cb4473SJacob Keller /** 311203cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 311303cb4473SJacob Keller * @hw: pointer to the HW struct 311403cb4473SJacob Keller * @block: the block to read from 311503cb4473SJacob Keller * @idx: the timestamp index to reset 311603cb4473SJacob Keller * 31173a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 31183a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 31193a749623SJacob Keller * block is the logical port to clear from. 312003cb4473SJacob Keller */ 312103cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 312203cb4473SJacob Keller { 31233a749623SJacob Keller if (ice_is_e810(hw)) 312403cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 31253a749623SJacob Keller else 31263a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 312703cb4473SJacob Keller } 3128885fe693SMaciej Machnikowski 3129*10e4b4a3SJacob Keller /** 3130*10e4b4a3SJacob Keller * ice_get_phy_tx_tstamp_ready_e810 - Read Tx memory status register 3131*10e4b4a3SJacob Keller * @hw: pointer to the HW struct 3132*10e4b4a3SJacob Keller * @port: the PHY port to read 3133*10e4b4a3SJacob Keller * @tstamp_ready: contents of the Tx memory status register 3134*10e4b4a3SJacob Keller * 3135*10e4b4a3SJacob Keller * E810 devices do not use a Tx memory status register. Instead simply 3136*10e4b4a3SJacob Keller * indicate that all timestamps are currently ready. 3137*10e4b4a3SJacob Keller */ 3138*10e4b4a3SJacob Keller static int 3139*10e4b4a3SJacob Keller ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) 3140*10e4b4a3SJacob Keller { 3141*10e4b4a3SJacob Keller *tstamp_ready = 0xFFFFFFFFFFFFFFFF; 3142*10e4b4a3SJacob Keller return 0; 3143*10e4b4a3SJacob Keller } 3144*10e4b4a3SJacob Keller 3145885fe693SMaciej Machnikowski /* E810T SMA functions 3146885fe693SMaciej Machnikowski * 3147885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 3148885fe693SMaciej Machnikowski * to access the extended GPIOs available. 3149885fe693SMaciej Machnikowski */ 3150885fe693SMaciej Machnikowski 3151885fe693SMaciej Machnikowski /** 3152885fe693SMaciej Machnikowski * ice_get_pca9575_handle 3153885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3154885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 3155885fe693SMaciej Machnikowski * 3156885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 3157885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 3158885fe693SMaciej Machnikowski * will return cached value 3159885fe693SMaciej Machnikowski */ 3160885fe693SMaciej Machnikowski static int 3161885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 3162885fe693SMaciej Machnikowski { 3163885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 3164885fe693SMaciej Machnikowski struct ice_aq_desc desc; 3165885fe693SMaciej Machnikowski int status; 3166885fe693SMaciej Machnikowski u8 idx; 3167885fe693SMaciej Machnikowski 3168885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 3169885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 3170885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3171885fe693SMaciej Machnikowski return 0; 3172885fe693SMaciej Machnikowski } 3173885fe693SMaciej Machnikowski 3174885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 3175885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 3176885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 3177885fe693SMaciej Machnikowski 3178885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 3179885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 3180885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 3181885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 3182885fe693SMaciej Machnikowski 3183885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 3184885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 3185885fe693SMaciej Machnikowski 3186885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 3187885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 3188885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 3189885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 3190885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 3191885fe693SMaciej Machnikowski else 3192885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3193885fe693SMaciej Machnikowski 3194885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 3195885fe693SMaciej Machnikowski 3196885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 3197885fe693SMaciej Machnikowski if (status) 3198885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3199885fe693SMaciej Machnikowski 3200885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 3201885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 3202885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 3203885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3204885fe693SMaciej Machnikowski 3205885fe693SMaciej Machnikowski /* If present save the handle and return it */ 3206885fe693SMaciej Machnikowski hw->io_expander_handle = 3207885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 3208885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3209885fe693SMaciej Machnikowski 3210885fe693SMaciej Machnikowski return 0; 3211885fe693SMaciej Machnikowski } 3212885fe693SMaciej Machnikowski 3213885fe693SMaciej Machnikowski /** 3214885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 3215885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3216885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 3217885fe693SMaciej Machnikowski * 3218885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 3219885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 3220885fe693SMaciej Machnikowski */ 3221885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 3222885fe693SMaciej Machnikowski { 3223885fe693SMaciej Machnikowski int status; 3224885fe693SMaciej Machnikowski u16 handle; 3225885fe693SMaciej Machnikowski u8 i; 3226885fe693SMaciej Machnikowski 3227885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3228885fe693SMaciej Machnikowski if (status) 3229885fe693SMaciej Machnikowski return status; 3230885fe693SMaciej Machnikowski 3231885fe693SMaciej Machnikowski *data = 0; 3232885fe693SMaciej Machnikowski 3233885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3234885fe693SMaciej Machnikowski bool pin; 3235885fe693SMaciej Machnikowski 3236885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3237885fe693SMaciej Machnikowski &pin, NULL); 3238885fe693SMaciej Machnikowski if (status) 3239885fe693SMaciej Machnikowski break; 3240885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 3241885fe693SMaciej Machnikowski } 3242885fe693SMaciej Machnikowski 3243885fe693SMaciej Machnikowski return status; 3244885fe693SMaciej Machnikowski } 3245885fe693SMaciej Machnikowski 3246885fe693SMaciej Machnikowski /** 3247885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 3248885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3249885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 3250885fe693SMaciej Machnikowski * 3251885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 3252885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 3253885fe693SMaciej Machnikowski */ 3254885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 3255885fe693SMaciej Machnikowski { 3256885fe693SMaciej Machnikowski int status; 3257885fe693SMaciej Machnikowski u16 handle; 3258885fe693SMaciej Machnikowski u8 i; 3259885fe693SMaciej Machnikowski 3260885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3261885fe693SMaciej Machnikowski if (status) 3262885fe693SMaciej Machnikowski return status; 3263885fe693SMaciej Machnikowski 3264885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3265885fe693SMaciej Machnikowski bool pin; 3266885fe693SMaciej Machnikowski 3267885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 3268885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3269885fe693SMaciej Machnikowski pin, NULL); 3270885fe693SMaciej Machnikowski if (status) 3271885fe693SMaciej Machnikowski break; 3272885fe693SMaciej Machnikowski } 3273885fe693SMaciej Machnikowski 3274885fe693SMaciej Machnikowski return status; 3275885fe693SMaciej Machnikowski } 3276885fe693SMaciej Machnikowski 3277885fe693SMaciej Machnikowski /** 327843113ff7SKarol Kolacinski * ice_read_pca9575_reg_e810t 327943113ff7SKarol Kolacinski * @hw: pointer to the hw struct 328043113ff7SKarol Kolacinski * @offset: GPIO controller register offset 328143113ff7SKarol Kolacinski * @data: pointer to data to be read from the GPIO controller 328243113ff7SKarol Kolacinski * 328343113ff7SKarol Kolacinski * Read the register from the GPIO controller 328443113ff7SKarol Kolacinski */ 328543113ff7SKarol Kolacinski int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) 328643113ff7SKarol Kolacinski { 328743113ff7SKarol Kolacinski struct ice_aqc_link_topo_addr link_topo; 328843113ff7SKarol Kolacinski __le16 addr; 328943113ff7SKarol Kolacinski u16 handle; 329043113ff7SKarol Kolacinski int err; 329143113ff7SKarol Kolacinski 329243113ff7SKarol Kolacinski memset(&link_topo, 0, sizeof(link_topo)); 329343113ff7SKarol Kolacinski 329443113ff7SKarol Kolacinski err = ice_get_pca9575_handle(hw, &handle); 329543113ff7SKarol Kolacinski if (err) 329643113ff7SKarol Kolacinski return err; 329743113ff7SKarol Kolacinski 329843113ff7SKarol Kolacinski link_topo.handle = cpu_to_le16(handle); 329943113ff7SKarol Kolacinski link_topo.topo_params.node_type_ctx = 330043113ff7SKarol Kolacinski FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, 330143113ff7SKarol Kolacinski ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED); 330243113ff7SKarol Kolacinski 330343113ff7SKarol Kolacinski addr = cpu_to_le16((u16)offset); 330443113ff7SKarol Kolacinski 330543113ff7SKarol Kolacinski return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL); 330643113ff7SKarol Kolacinski } 330743113ff7SKarol Kolacinski 330843113ff7SKarol Kolacinski /** 3309885fe693SMaciej Machnikowski * ice_is_pca9575_present 3310885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3311885fe693SMaciej Machnikowski * 3312885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 3313885fe693SMaciej Machnikowski */ 3314885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 3315885fe693SMaciej Machnikowski { 3316885fe693SMaciej Machnikowski u16 handle = 0; 3317885fe693SMaciej Machnikowski int status; 3318885fe693SMaciej Machnikowski 3319885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 3320885fe693SMaciej Machnikowski return false; 3321885fe693SMaciej Machnikowski 3322885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3323885fe693SMaciej Machnikowski 3324885fe693SMaciej Machnikowski return !status && handle; 3325885fe693SMaciej Machnikowski } 3326b2ee7256SJacob Keller 3327b2ee7256SJacob Keller /** 3328407b66c0SKarol Kolacinski * ice_ptp_reset_ts_memory - Reset timestamp memory for all blocks 3329407b66c0SKarol Kolacinski * @hw: pointer to the HW struct 3330407b66c0SKarol Kolacinski */ 3331407b66c0SKarol Kolacinski void ice_ptp_reset_ts_memory(struct ice_hw *hw) 3332407b66c0SKarol Kolacinski { 3333407b66c0SKarol Kolacinski if (ice_is_e810(hw)) 3334407b66c0SKarol Kolacinski return; 3335407b66c0SKarol Kolacinski 3336407b66c0SKarol Kolacinski ice_ptp_reset_ts_memory_e822(hw); 3337407b66c0SKarol Kolacinski } 3338407b66c0SKarol Kolacinski 3339407b66c0SKarol Kolacinski /** 3340b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 3341b2ee7256SJacob Keller * @hw: pointer to the HW struct 3342b2ee7256SJacob Keller * 3343b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 3344b2ee7256SJacob Keller */ 3345b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 3346b2ee7256SJacob Keller { 3347b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 3348b2ee7256SJacob Keller 3349b2ee7256SJacob Keller /* Enable source clocks */ 3350b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 3351b2ee7256SJacob Keller 3352b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 3353b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 3354b2ee7256SJacob Keller 33553a749623SJacob Keller if (ice_is_e810(hw)) 3356b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 33573a749623SJacob Keller else 33583a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 3359b2ee7256SJacob Keller } 3360*10e4b4a3SJacob Keller 3361*10e4b4a3SJacob Keller /** 3362*10e4b4a3SJacob Keller * ice_get_phy_tx_tstamp_ready - Read PHY Tx memory status indication 3363*10e4b4a3SJacob Keller * @hw: pointer to the HW struct 3364*10e4b4a3SJacob Keller * @block: the timestamp block to check 3365*10e4b4a3SJacob Keller * @tstamp_ready: storage for the PHY Tx memory status information 3366*10e4b4a3SJacob Keller * 3367*10e4b4a3SJacob Keller * Check the PHY for Tx timestamp memory status. This reports a 64 bit value 3368*10e4b4a3SJacob Keller * which indicates which timestamps in the block may be captured. A set bit 3369*10e4b4a3SJacob Keller * means the timestamp can be read. An unset bit means the timestamp is not 3370*10e4b4a3SJacob Keller * ready and software should avoid reading the register. 3371*10e4b4a3SJacob Keller */ 3372*10e4b4a3SJacob Keller int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) 3373*10e4b4a3SJacob Keller { 3374*10e4b4a3SJacob Keller if (ice_is_e810(hw)) 3375*10e4b4a3SJacob Keller return ice_get_phy_tx_tstamp_ready_e810(hw, block, 3376*10e4b4a3SJacob Keller tstamp_ready); 3377*10e4b4a3SJacob Keller else 3378*10e4b4a3SJacob Keller return ice_get_phy_tx_tstamp_ready_e822(hw, block, 3379*10e4b4a3SJacob Keller tstamp_ready); 3380*10e4b4a3SJacob Keller } 3381