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 * 1744*f029a343SSiddaraju DH * This function will not return successfully until the Tx offset calculations 1745*f029a343SSiddaraju DH * have been completed, which requires waiting until at least one packet has 1746*f029a343SSiddaraju DH * been transmitted by the device. It is safe to call this function 1747*f029a343SSiddaraju DH * periodically until calibration succeeds, as it will only program the offset 1748*f029a343SSiddaraju DH * once. 1749a69f1cb6SJacob Keller * 1750a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 1751a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 1752a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 1753a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 1754*f029a343SSiddaraju DH * 1755*f029a343SSiddaraju DH * Returns zero on success, -EBUSY if the hardware vernier offset 1756*f029a343SSiddaraju DH * calibration has not completed, or another error code on failure. 1757a69f1cb6SJacob Keller */ 1758*f029a343SSiddaraju DH int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) 1759a69f1cb6SJacob Keller { 1760a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 1761a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 1762a69f1cb6SJacob Keller u64 total_offset, val; 1763a69f1cb6SJacob Keller int err; 1764*f029a343SSiddaraju DH u32 reg; 1765*f029a343SSiddaraju DH 1766*f029a343SSiddaraju DH /* Nothing to do if we've already programmed the offset */ 1767*f029a343SSiddaraju DH err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OR, ®); 1768*f029a343SSiddaraju DH if (err) { 1769*f029a343SSiddaraju DH ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OR for port %u, err %d\n", 1770*f029a343SSiddaraju DH port, err); 1771*f029a343SSiddaraju DH return err; 1772*f029a343SSiddaraju DH } 1773*f029a343SSiddaraju DH 1774*f029a343SSiddaraju DH if (reg) 1775*f029a343SSiddaraju DH return 0; 1776*f029a343SSiddaraju DH 1777*f029a343SSiddaraju DH err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, ®); 1778*f029a343SSiddaraju DH if (err) { 1779*f029a343SSiddaraju DH ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n", 1780*f029a343SSiddaraju DH port, err); 1781*f029a343SSiddaraju DH return err; 1782*f029a343SSiddaraju DH } 1783*f029a343SSiddaraju DH 1784*f029a343SSiddaraju DH if (!(reg & P_REG_TX_OV_STATUS_OV_M)) 1785*f029a343SSiddaraju DH return -EBUSY; 1786a69f1cb6SJacob Keller 1787a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1788a69f1cb6SJacob Keller if (err) 1789a69f1cb6SJacob Keller return err; 1790a69f1cb6SJacob Keller 1791a69f1cb6SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 1792a69f1cb6SJacob Keller 1793a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 1794a69f1cb6SJacob Keller * the total offset. 1795a69f1cb6SJacob Keller */ 1796a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G || 1797a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_10G || 1798a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1799a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G_RS || 1800a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1801a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1802a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1803a69f1cb6SJacob Keller P_REG_PAR_PCS_TX_OFFSET_L, 1804a69f1cb6SJacob Keller &val); 1805a69f1cb6SJacob Keller if (err) 1806a69f1cb6SJacob Keller return err; 1807a69f1cb6SJacob Keller 1808a69f1cb6SJacob Keller total_offset += val; 1809a69f1cb6SJacob Keller } 1810a69f1cb6SJacob Keller 1811a69f1cb6SJacob Keller /* For Tx, we only need to use the second Vernier offset for 1812a69f1cb6SJacob Keller * multi-lane link speeds with RS-FEC. The lanes will always be 1813a69f1cb6SJacob Keller * aligned. 1814a69f1cb6SJacob Keller */ 1815a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_50G_RS || 1816a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1817a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1818a69f1cb6SJacob Keller P_REG_PAR_TX_TIME_L, 1819a69f1cb6SJacob Keller &val); 1820a69f1cb6SJacob Keller if (err) 1821a69f1cb6SJacob Keller return err; 1822a69f1cb6SJacob Keller 1823a69f1cb6SJacob Keller total_offset += val; 1824a69f1cb6SJacob Keller } 1825a69f1cb6SJacob Keller 1826a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 1827a69f1cb6SJacob Keller * PHY and indicate that the Tx offset is ready. After this, 1828a69f1cb6SJacob Keller * timestamps will be enabled. 1829a69f1cb6SJacob Keller */ 1830a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 1831a69f1cb6SJacob Keller total_offset); 1832a69f1cb6SJacob Keller if (err) 1833a69f1cb6SJacob Keller return err; 1834a69f1cb6SJacob Keller 1835a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 1836a69f1cb6SJacob Keller if (err) 1837a69f1cb6SJacob Keller return err; 1838a69f1cb6SJacob Keller 1839*f029a343SSiddaraju DH dev_info(ice_hw_to_dev(hw), "Port=%d Tx vernier offset calibration complete\n", 1840*f029a343SSiddaraju DH port); 1841*f029a343SSiddaraju DH 1842a69f1cb6SJacob Keller return 0; 1843a69f1cb6SJacob Keller } 1844a69f1cb6SJacob Keller 1845a69f1cb6SJacob Keller /** 1846a69f1cb6SJacob Keller * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx 1847a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1848a69f1cb6SJacob Keller * @port: the PHY port to adjust for 1849a69f1cb6SJacob Keller * @link_spd: the current link speed of the PHY 1850a69f1cb6SJacob Keller * @fec_mode: the current FEC mode of the PHY 1851a69f1cb6SJacob Keller * @pmd_adj: on return, the amount to adjust the Rx total offset by 1852a69f1cb6SJacob Keller * 1853a69f1cb6SJacob Keller * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY. 1854a69f1cb6SJacob Keller * This varies by link speed and FEC mode. The value calculated accounts for 1855a69f1cb6SJacob Keller * various delays caused when receiving a packet. 1856a69f1cb6SJacob Keller */ 1857a69f1cb6SJacob Keller static int 1858a69f1cb6SJacob Keller ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, 1859a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd, 1860a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj) 1861a69f1cb6SJacob Keller { 1862a69f1cb6SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, mult, adj; 1863a69f1cb6SJacob Keller u8 pmd_align; 1864a69f1cb6SJacob Keller u32 val; 1865a69f1cb6SJacob Keller int err; 1866a69f1cb6SJacob Keller 1867a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val); 1868a69f1cb6SJacob Keller if (err) { 1869a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n", 1870a69f1cb6SJacob Keller err); 1871a69f1cb6SJacob Keller return err; 1872a69f1cb6SJacob Keller } 1873a69f1cb6SJacob Keller 1874a69f1cb6SJacob Keller pmd_align = (u8)val; 1875a69f1cb6SJacob Keller 1876a69f1cb6SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1877a69f1cb6SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1878a69f1cb6SJacob Keller 1879a69f1cb6SJacob Keller /* Calculate TUs per second */ 1880a69f1cb6SJacob Keller tu_per_sec = cur_freq * clk_incval; 1881a69f1cb6SJacob Keller 1882a69f1cb6SJacob Keller /* The PMD alignment adjustment measurement depends on the link speed, 1883a69f1cb6SJacob Keller * and whether FEC is enabled. For each link speed, the alignment 1884a69f1cb6SJacob Keller * adjustment is calculated by dividing a value by the length of 1885a69f1cb6SJacob Keller * a Time Unit in nanoseconds. 1886a69f1cb6SJacob Keller * 1887a69f1cb6SJacob Keller * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8 1888a69f1cb6SJacob Keller * 10G: align == 65 ? 0 : (align * 0.1 * 32/33) 1889a69f1cb6SJacob Keller * 10G w/FEC: align * 0.1 * 32/33 1890a69f1cb6SJacob Keller * 25G: align == 65 ? 0 : (align * 0.4 * 32/33) 1891a69f1cb6SJacob Keller * 25G w/FEC: align * 0.4 * 32/33 1892a69f1cb6SJacob Keller * 40G: align == 65 ? 0 : (align * 0.1 * 32/33) 1893a69f1cb6SJacob Keller * 40G w/FEC: align * 0.1 * 32/33 1894a69f1cb6SJacob Keller * 50G: align == 65 ? 0 : (align * 0.4 * 32/33) 1895a69f1cb6SJacob Keller * 50G w/FEC: align * 0.8 * 32/33 1896a69f1cb6SJacob Keller * 1897a69f1cb6SJacob Keller * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33. 1898a69f1cb6SJacob Keller * 1899a69f1cb6SJacob Keller * To allow for calculating this value using integer arithmetic, we 1900a69f1cb6SJacob Keller * instead start with the number of TUs per second, (inverse of the 1901a69f1cb6SJacob Keller * length of a Time Unit in nanoseconds), multiply by a value based 1902a69f1cb6SJacob Keller * on the PMD alignment register, and then divide by the right value 1903a69f1cb6SJacob Keller * calculated based on the table above. To avoid integer overflow this 1904a69f1cb6SJacob Keller * division is broken up into a step of dividing by 125 first. 1905a69f1cb6SJacob Keller */ 1906a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G) { 1907a69f1cb6SJacob Keller if (pmd_align == 4) 1908a69f1cb6SJacob Keller mult = 10; 1909a69f1cb6SJacob Keller else 1910a69f1cb6SJacob Keller mult = (pmd_align + 6) % 10; 1911a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_10G || 1912a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1913a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1914a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1915a69f1cb6SJacob Keller /* If Clause 74 FEC, always calculate PMD adjust */ 1916a69f1cb6SJacob Keller if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74) 1917a69f1cb6SJacob Keller mult = pmd_align; 1918a69f1cb6SJacob Keller else 1919a69f1cb6SJacob Keller mult = 0; 1920a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS || 1921a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 1922a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1923a69f1cb6SJacob Keller if (pmd_align < 17) 1924a69f1cb6SJacob Keller mult = pmd_align + 40; 1925a69f1cb6SJacob Keller else 1926a69f1cb6SJacob Keller mult = pmd_align; 1927a69f1cb6SJacob Keller } else { 1928a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n", 1929a69f1cb6SJacob Keller link_spd); 1930a69f1cb6SJacob Keller mult = 0; 1931a69f1cb6SJacob Keller } 1932a69f1cb6SJacob Keller 1933a69f1cb6SJacob Keller /* In some cases, there's no need to adjust for the PMD alignment */ 1934a69f1cb6SJacob Keller if (!mult) { 1935a69f1cb6SJacob Keller *pmd_adj = 0; 1936a69f1cb6SJacob Keller return 0; 1937a69f1cb6SJacob Keller } 1938a69f1cb6SJacob Keller 1939a69f1cb6SJacob Keller /* Calculate the adjustment by multiplying TUs per second by the 1940a69f1cb6SJacob Keller * appropriate multiplier and divisor. To avoid overflow, we first 1941a69f1cb6SJacob Keller * divide by 125, and then handle remaining divisor based on the link 1942a69f1cb6SJacob Keller * speed pmd_adj_divisor value. 1943a69f1cb6SJacob Keller */ 1944a69f1cb6SJacob Keller adj = div_u64(tu_per_sec, 125); 1945a69f1cb6SJacob Keller adj *= mult; 1946a69f1cb6SJacob Keller adj = div_u64(adj, e822_vernier[link_spd].pmd_adj_divisor); 1947a69f1cb6SJacob Keller 1948a69f1cb6SJacob Keller /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx 1949a69f1cb6SJacob Keller * cycle count is necessary. 1950a69f1cb6SJacob Keller */ 1951a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_25G_RS) { 1952a69f1cb6SJacob Keller u64 cycle_adj; 1953a69f1cb6SJacob Keller u8 rx_cycle; 1954a69f1cb6SJacob Keller 1955a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT, 1956a69f1cb6SJacob Keller &val); 1957a69f1cb6SJacob Keller if (err) { 1958a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n", 1959a69f1cb6SJacob Keller err); 1960a69f1cb6SJacob Keller return err; 1961a69f1cb6SJacob Keller } 1962a69f1cb6SJacob Keller 1963a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M; 1964a69f1cb6SJacob Keller if (rx_cycle) { 1965a69f1cb6SJacob Keller mult = (4 - rx_cycle) * 40; 1966a69f1cb6SJacob Keller 1967a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1968a69f1cb6SJacob Keller cycle_adj *= mult; 1969a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1970a69f1cb6SJacob Keller 1971a69f1cb6SJacob Keller adj += cycle_adj; 1972a69f1cb6SJacob Keller } 1973a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) { 1974a69f1cb6SJacob Keller u64 cycle_adj; 1975a69f1cb6SJacob Keller u8 rx_cycle; 1976a69f1cb6SJacob Keller 1977a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT, 1978a69f1cb6SJacob Keller &val); 1979a69f1cb6SJacob Keller if (err) { 1980a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n", 1981a69f1cb6SJacob Keller err); 1982a69f1cb6SJacob Keller return err; 1983a69f1cb6SJacob Keller } 1984a69f1cb6SJacob Keller 1985a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M; 1986a69f1cb6SJacob Keller if (rx_cycle) { 1987a69f1cb6SJacob Keller mult = rx_cycle * 40; 1988a69f1cb6SJacob Keller 1989a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1990a69f1cb6SJacob Keller cycle_adj *= mult; 1991a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1992a69f1cb6SJacob Keller 1993a69f1cb6SJacob Keller adj += cycle_adj; 1994a69f1cb6SJacob Keller } 1995a69f1cb6SJacob Keller } 1996a69f1cb6SJacob Keller 1997a69f1cb6SJacob Keller /* Return the calculated adjustment */ 1998a69f1cb6SJacob Keller *pmd_adj = adj; 1999a69f1cb6SJacob Keller 2000a69f1cb6SJacob Keller return 0; 2001a69f1cb6SJacob Keller } 2002a69f1cb6SJacob Keller 2003a69f1cb6SJacob Keller /** 20043a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 20053a749623SJacob Keller * @hw: pointer to HW struct 20063a749623SJacob Keller * @link_spd: The Link speed to calculate for 20073a749623SJacob Keller * 20083a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 20093a749623SJacob Keller */ 20103a749623SJacob Keller static u64 20113a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 20123a749623SJacob Keller { 20133a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 20143a749623SJacob Keller 20153a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 20163a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 20173a749623SJacob Keller 20183a749623SJacob Keller /* Calculate TUs per second */ 20193a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 20203a749623SJacob Keller 20213a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 20223a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 20233a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 20243a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 20253a749623SJacob Keller * divisions by 1e4 first then by 1e7. 20263a749623SJacob Keller */ 20273a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 20283a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 20293a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 20303a749623SJacob Keller 20313a749623SJacob Keller return fixed_offset; 20323a749623SJacob Keller } 20333a749623SJacob Keller 20343a749623SJacob Keller /** 2035a69f1cb6SJacob Keller * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset 2036a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2037a69f1cb6SJacob Keller * @port: the PHY port to configure 2038a69f1cb6SJacob Keller * 2039a69f1cb6SJacob Keller * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to 2040a69f1cb6SJacob Keller * adjust Rx timestamps by. This combines calculations from the Vernier offset 2041a69f1cb6SJacob Keller * measurements taken in hardware with some data about known fixed delay as 2042a69f1cb6SJacob Keller * well as adjusting for multi-lane alignment delay. 2043a69f1cb6SJacob Keller * 2044*f029a343SSiddaraju DH * This function will not return successfully until the Rx offset calculations 2045*f029a343SSiddaraju DH * have been completed, which requires waiting until at least one packet has 2046*f029a343SSiddaraju DH * been received by the device. It is safe to call this function periodically 2047*f029a343SSiddaraju DH * until calibration succeeds, as it will only program the offset once. 2048*f029a343SSiddaraju DH * 2049a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 2050a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 2051a69f1cb6SJacob Keller * has measured the offset. 2052a69f1cb6SJacob Keller * 2053a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 2054a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 2055a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 2056a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 2057*f029a343SSiddaraju DH * 2058*f029a343SSiddaraju DH * Returns zero on success, -EBUSY if the hardware vernier offset 2059*f029a343SSiddaraju DH * calibration has not completed, or another error code on failure. 2060a69f1cb6SJacob Keller */ 2061*f029a343SSiddaraju DH int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) 2062a69f1cb6SJacob Keller { 2063a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 2064a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 2065a69f1cb6SJacob Keller u64 total_offset, pmd, val; 2066a69f1cb6SJacob Keller int err; 2067*f029a343SSiddaraju DH u32 reg; 2068*f029a343SSiddaraju DH 2069*f029a343SSiddaraju DH /* Nothing to do if we've already programmed the offset */ 2070*f029a343SSiddaraju DH err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OR, ®); 2071*f029a343SSiddaraju DH if (err) { 2072*f029a343SSiddaraju DH ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OR for port %u, err %d\n", 2073*f029a343SSiddaraju DH port, err); 2074*f029a343SSiddaraju DH return err; 2075*f029a343SSiddaraju DH } 2076*f029a343SSiddaraju DH 2077*f029a343SSiddaraju DH if (reg) 2078*f029a343SSiddaraju DH return 0; 2079*f029a343SSiddaraju DH 2080*f029a343SSiddaraju DH err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, ®); 2081*f029a343SSiddaraju DH if (err) { 2082*f029a343SSiddaraju DH ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n", 2083*f029a343SSiddaraju DH port, err); 2084*f029a343SSiddaraju DH return err; 2085*f029a343SSiddaraju DH } 2086*f029a343SSiddaraju DH 2087*f029a343SSiddaraju DH if (!(reg & P_REG_RX_OV_STATUS_OV_M)) 2088*f029a343SSiddaraju DH return -EBUSY; 2089a69f1cb6SJacob Keller 2090a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 2091a69f1cb6SJacob Keller if (err) 2092a69f1cb6SJacob Keller return err; 2093a69f1cb6SJacob Keller 2094a69f1cb6SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 2095a69f1cb6SJacob Keller 2096a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 2097a69f1cb6SJacob Keller * the total offset. 2098a69f1cb6SJacob Keller */ 2099a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2100a69f1cb6SJacob Keller P_REG_PAR_PCS_RX_OFFSET_L, 2101a69f1cb6SJacob Keller &val); 2102a69f1cb6SJacob Keller if (err) 2103a69f1cb6SJacob Keller return err; 2104a69f1cb6SJacob Keller 2105a69f1cb6SJacob Keller total_offset += val; 2106a69f1cb6SJacob Keller 2107a69f1cb6SJacob Keller /* For Rx, all multi-lane link speeds include a second Vernier 2108a69f1cb6SJacob Keller * calibration, because the lanes might not be aligned. 2109a69f1cb6SJacob Keller */ 2110a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_40G || 2111a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G || 2112a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 2113a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 2114a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2115a69f1cb6SJacob Keller P_REG_PAR_RX_TIME_L, 2116a69f1cb6SJacob Keller &val); 2117a69f1cb6SJacob Keller if (err) 2118a69f1cb6SJacob Keller return err; 2119a69f1cb6SJacob Keller 2120a69f1cb6SJacob Keller total_offset += val; 2121a69f1cb6SJacob Keller } 2122a69f1cb6SJacob Keller 2123a69f1cb6SJacob Keller /* In addition, Rx must account for the PMD alignment */ 2124a69f1cb6SJacob Keller err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd); 2125a69f1cb6SJacob Keller if (err) 2126a69f1cb6SJacob Keller return err; 2127a69f1cb6SJacob Keller 2128a69f1cb6SJacob Keller /* For RS-FEC, this adjustment adds delay, but for other modes, it 2129a69f1cb6SJacob Keller * subtracts delay. 2130a69f1cb6SJacob Keller */ 2131a69f1cb6SJacob Keller if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC) 2132a69f1cb6SJacob Keller total_offset += pmd; 2133a69f1cb6SJacob Keller else 2134a69f1cb6SJacob Keller total_offset -= pmd; 2135a69f1cb6SJacob Keller 2136a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 2137a69f1cb6SJacob Keller * PHY and indicate that the Rx offset is ready. After this, 2138a69f1cb6SJacob Keller * timestamps will be enabled. 2139a69f1cb6SJacob Keller */ 2140a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 2141a69f1cb6SJacob Keller total_offset); 2142a69f1cb6SJacob Keller if (err) 2143a69f1cb6SJacob Keller return err; 2144a69f1cb6SJacob Keller 2145a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 2146a69f1cb6SJacob Keller if (err) 2147a69f1cb6SJacob Keller return err; 2148a69f1cb6SJacob Keller 2149*f029a343SSiddaraju DH dev_info(ice_hw_to_dev(hw), "Port=%d Rx vernier offset calibration complete\n", 2150*f029a343SSiddaraju DH port); 2151*f029a343SSiddaraju DH 2152a69f1cb6SJacob Keller return 0; 2153a69f1cb6SJacob Keller } 2154a69f1cb6SJacob Keller 2155a69f1cb6SJacob Keller /** 21563a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 21573a749623SJacob Keller * @hw: pointer to the HW struct 21583a749623SJacob Keller * @port: the PHY port to read 21593a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 21603a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 21613a749623SJacob Keller * 21623a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 21633a749623SJacob Keller * timer values. 21643a749623SJacob Keller */ 21653a749623SJacob Keller static int 21663a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 21673a749623SJacob Keller u64 *phc_time) 21683a749623SJacob Keller { 21693a749623SJacob Keller u64 tx_time, rx_time; 21703a749623SJacob Keller u32 zo, lo; 21713a749623SJacob Keller u8 tmr_idx; 21723a749623SJacob Keller int err; 21733a749623SJacob Keller 21743a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 21753a749623SJacob Keller 21763a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 21773a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 21783a749623SJacob Keller 21793a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 21803a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 21813a749623SJacob Keller if (err) 21823a749623SJacob Keller return err; 21833a749623SJacob Keller 21843a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 21853a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 21863a749623SJacob Keller 21873a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 21883a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 21893a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 21903a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 21913a749623SJacob Keller 21923a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 21933a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 21943a749623SJacob Keller if (err) 21953a749623SJacob Keller return err; 21963a749623SJacob Keller 21973a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 21983a749623SJacob Keller * Note that this should not happen in normal circumstances since the 21993a749623SJacob Keller * driver always programs them together. 22003a749623SJacob Keller */ 22013a749623SJacob Keller if (tx_time != rx_time) 22023a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 22033a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 22043a749623SJacob Keller port, (unsigned long long)tx_time, 22053a749623SJacob Keller (unsigned long long)rx_time); 22063a749623SJacob Keller 22073a749623SJacob Keller *phy_time = tx_time; 22083a749623SJacob Keller 22093a749623SJacob Keller return 0; 22103a749623SJacob Keller } 22113a749623SJacob Keller 22123a749623SJacob Keller /** 22133a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 22143a749623SJacob Keller * @hw: pointer to the HW struct 22153a749623SJacob Keller * @port: the PHY port to synchronize 22163a749623SJacob Keller * 22173a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 22183a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 22193a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 22203a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 22213a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 22223a749623SJacob Keller */ 22233a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 22243a749623SJacob Keller { 22253a749623SJacob Keller u64 phc_time, phy_time, difference; 22263a749623SJacob Keller int err; 22273a749623SJacob Keller 22283a749623SJacob Keller if (!ice_ptp_lock(hw)) { 22293a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 22303a749623SJacob Keller return -EBUSY; 22313a749623SJacob Keller } 22323a749623SJacob Keller 22333a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 22343a749623SJacob Keller if (err) 22353a749623SJacob Keller goto err_unlock; 22363a749623SJacob Keller 22373a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 22383a749623SJacob Keller * it to match the PHC time. 22393a749623SJacob Keller * 22403a749623SJacob Keller * Note that the port adjustment is done using 2s complement 22413a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 22423a749623SJacob Keller * calculate the difference between the PHC time and the port time, 22433a749623SJacob Keller * and it will be interpreted correctly. 22443a749623SJacob Keller */ 22453a749623SJacob Keller difference = phc_time - phy_time; 22463a749623SJacob Keller 22473a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 22483a749623SJacob Keller if (err) 22493a749623SJacob Keller goto err_unlock; 22503a749623SJacob Keller 22513a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 22523a749623SJacob Keller if (err) 22533a749623SJacob Keller goto err_unlock; 22543a749623SJacob Keller 22553a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 22563a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 22573a749623SJacob Keller 22583a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 22593a749623SJacob Keller * verify that the time was properly adjusted. 22603a749623SJacob Keller */ 22613a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 22623a749623SJacob Keller if (err) 22633a749623SJacob Keller goto err_unlock; 22643a749623SJacob Keller 22653a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 22663a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 22673a749623SJacob Keller port, (unsigned long long)phy_time, 22683a749623SJacob Keller (unsigned long long)phc_time); 22693a749623SJacob Keller 22703a749623SJacob Keller ice_ptp_unlock(hw); 22713a749623SJacob Keller 22723a749623SJacob Keller return 0; 22733a749623SJacob Keller 22743a749623SJacob Keller err_unlock: 22753a749623SJacob Keller ice_ptp_unlock(hw); 22763a749623SJacob Keller return err; 22773a749623SJacob Keller } 22783a749623SJacob Keller 22793a749623SJacob Keller /** 22803a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 22813a749623SJacob Keller * @hw: pointer to the HW struct 22823a749623SJacob Keller * @port: the PHY port to stop 22833a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 22843a749623SJacob Keller * 22853a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 22863a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 22873a749623SJacob Keller * initialized or when link speed changes. 22883a749623SJacob Keller */ 22893a749623SJacob Keller int 22903a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 22913a749623SJacob Keller { 22923a749623SJacob Keller int err; 22933a749623SJacob Keller u32 val; 22943a749623SJacob Keller 22953a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 22963a749623SJacob Keller if (err) 22973a749623SJacob Keller return err; 22983a749623SJacob Keller 22993a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 23003a749623SJacob Keller if (err) 23013a749623SJacob Keller return err; 23023a749623SJacob Keller 23033a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 23043a749623SJacob Keller if (err) 23053a749623SJacob Keller return err; 23063a749623SJacob Keller 23073a749623SJacob Keller val &= ~P_REG_PS_START_M; 23083a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23093a749623SJacob Keller if (err) 23103a749623SJacob Keller return err; 23113a749623SJacob Keller 23123a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 23133a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23143a749623SJacob Keller if (err) 23153a749623SJacob Keller return err; 23163a749623SJacob Keller 23173a749623SJacob Keller if (soft_reset) { 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 23243a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 23253a749623SJacob Keller 23263a749623SJacob Keller return 0; 23273a749623SJacob Keller } 23283a749623SJacob Keller 23293a749623SJacob Keller /** 23303a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 23313a749623SJacob Keller * @hw: pointer to the HW struct 23323a749623SJacob Keller * @port: the PHY port to start 23333a749623SJacob Keller * 23343a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 23353a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 23363a749623SJacob Keller * initialized or when link speed changes. 23373a749623SJacob Keller * 23380357d5caSMilena Olech * Hardware will take Vernier measurements on Tx or Rx of packets. 23393a749623SJacob Keller */ 23400357d5caSMilena Olech int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) 23413a749623SJacob Keller { 23423a749623SJacob Keller u32 lo, hi, val; 23433a749623SJacob Keller u64 incval; 23443a749623SJacob Keller u8 tmr_idx; 23453a749623SJacob Keller int err; 23463a749623SJacob Keller 23473a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 23483a749623SJacob Keller 23493a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 23503a749623SJacob Keller if (err) 23513a749623SJacob Keller return err; 23523a749623SJacob Keller 23533a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 23543a749623SJacob Keller 23553a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 23563a749623SJacob Keller if (err) 23573a749623SJacob Keller return err; 23583a749623SJacob Keller 23593a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 23603a749623SJacob Keller if (err) 23613a749623SJacob Keller return err; 23623a749623SJacob Keller 23633a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 23643a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 23653a749623SJacob Keller incval = (u64)hi << 32 | lo; 23663a749623SJacob Keller 23673a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 23683a749623SJacob Keller if (err) 23693a749623SJacob Keller return err; 23703a749623SJacob Keller 23713a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23723a749623SJacob Keller if (err) 23733a749623SJacob Keller return err; 23743a749623SJacob Keller 23753a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23763a749623SJacob Keller 23773a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 23783a749623SJacob Keller if (err) 23793a749623SJacob Keller return err; 23803a749623SJacob Keller 23813a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 23823a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23833a749623SJacob Keller if (err) 23843a749623SJacob Keller return err; 23853a749623SJacob Keller 23863a749623SJacob Keller val |= P_REG_PS_START_M; 23873a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23883a749623SJacob Keller if (err) 23893a749623SJacob Keller return err; 23903a749623SJacob Keller 23913a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 23923a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23933a749623SJacob Keller if (err) 23943a749623SJacob Keller return err; 23953a749623SJacob Keller 23963a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23973a749623SJacob Keller if (err) 23983a749623SJacob Keller return err; 23993a749623SJacob Keller 24003a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 24013a749623SJacob Keller 24023a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 24033a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24043a749623SJacob Keller if (err) 24053a749623SJacob Keller return err; 24063a749623SJacob Keller 24073a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 24083a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24093a749623SJacob Keller if (err) 24103a749623SJacob Keller return err; 24113a749623SJacob Keller 24123a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 24133a749623SJacob Keller 24143a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 24153a749623SJacob Keller if (err) 24163a749623SJacob Keller return err; 24173a749623SJacob Keller 24183a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 24193a749623SJacob Keller 24203a749623SJacob Keller return 0; 24213a749623SJacob Keller } 24223a749623SJacob Keller 2423a69f1cb6SJacob Keller /** 242410e4b4a3SJacob Keller * ice_get_phy_tx_tstamp_ready_e822 - Read Tx memory status register 242510e4b4a3SJacob Keller * @hw: pointer to the HW struct 242610e4b4a3SJacob Keller * @quad: the timestamp quad to read from 242710e4b4a3SJacob Keller * @tstamp_ready: contents of the Tx memory status register 242810e4b4a3SJacob Keller * 242910e4b4a3SJacob Keller * Read the Q_REG_TX_MEMORY_STATUS register indicating which timestamps in 243010e4b4a3SJacob Keller * the PHY are ready. A set bit means the corresponding timestamp is valid and 243110e4b4a3SJacob Keller * ready to be captured from the PHY timestamp block. 243210e4b4a3SJacob Keller */ 243310e4b4a3SJacob Keller static int 243410e4b4a3SJacob Keller ice_get_phy_tx_tstamp_ready_e822(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) 243510e4b4a3SJacob Keller { 243610e4b4a3SJacob Keller u32 hi, lo; 243710e4b4a3SJacob Keller int err; 243810e4b4a3SJacob Keller 243910e4b4a3SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi); 244010e4b4a3SJacob Keller if (err) { 244110e4b4a3SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_U for quad %u, err %d\n", 244210e4b4a3SJacob Keller quad, err); 244310e4b4a3SJacob Keller return err; 244410e4b4a3SJacob Keller } 244510e4b4a3SJacob Keller 244610e4b4a3SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo); 244710e4b4a3SJacob Keller if (err) { 244810e4b4a3SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_L for quad %u, err %d\n", 244910e4b4a3SJacob Keller quad, err); 245010e4b4a3SJacob Keller return err; 245110e4b4a3SJacob Keller } 245210e4b4a3SJacob Keller 245310e4b4a3SJacob Keller *tstamp_ready = (u64)hi << 32 | (u64)lo; 245410e4b4a3SJacob Keller 245510e4b4a3SJacob Keller return 0; 245610e4b4a3SJacob Keller } 245710e4b4a3SJacob Keller 245803cb4473SJacob Keller /* E810 functions 245903cb4473SJacob Keller * 246003cb4473SJacob Keller * The following functions operate on the E810 series devices which use 246103cb4473SJacob Keller * a separate external PHY. 246203cb4473SJacob Keller */ 246303cb4473SJacob Keller 246403cb4473SJacob Keller /** 246503cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 246603cb4473SJacob Keller * @hw: pointer to the HW struct 246703cb4473SJacob Keller * @addr: the address to read from 246803cb4473SJacob Keller * @val: On return, the value read from the PHY 246903cb4473SJacob Keller * 247003cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 247103cb4473SJacob Keller */ 247203cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 247303cb4473SJacob Keller { 247403cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 247539b28106SJacob Keller int err; 247603cb4473SJacob Keller 247703cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 247803cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 247903cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 248003cb4473SJacob Keller msg.dest_dev = rmn_0; 248103cb4473SJacob Keller 248239b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 248339b28106SJacob Keller if (err) { 248439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 248539b28106SJacob Keller err); 248639b28106SJacob Keller return err; 248703cb4473SJacob Keller } 248803cb4473SJacob Keller 248903cb4473SJacob Keller *val = msg.data; 249003cb4473SJacob Keller 249103cb4473SJacob Keller return 0; 249203cb4473SJacob Keller } 249303cb4473SJacob Keller 249403cb4473SJacob Keller /** 249503cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 249603cb4473SJacob Keller * @hw: pointer to the HW struct 249703cb4473SJacob Keller * @addr: the address to writem to 249803cb4473SJacob Keller * @val: the value to write to the PHY 249903cb4473SJacob Keller * 250003cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 250103cb4473SJacob Keller */ 250203cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 250303cb4473SJacob Keller { 250403cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 250539b28106SJacob Keller int err; 250603cb4473SJacob Keller 250703cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 250803cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 250903cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 251003cb4473SJacob Keller msg.dest_dev = rmn_0; 251103cb4473SJacob Keller msg.data = val; 251203cb4473SJacob Keller 251339b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 251439b28106SJacob Keller if (err) { 251539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 251639b28106SJacob Keller err); 251739b28106SJacob Keller return err; 251803cb4473SJacob Keller } 251903cb4473SJacob Keller 252003cb4473SJacob Keller return 0; 252103cb4473SJacob Keller } 252203cb4473SJacob Keller 252303cb4473SJacob Keller /** 25241229b339SKarol Kolacinski * ice_read_phy_tstamp_ll_e810 - Read a PHY timestamp registers through the FW 25251229b339SKarol Kolacinski * @hw: pointer to the HW struct 25261229b339SKarol Kolacinski * @idx: the timestamp index to read 25271229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 25281229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 25291229b339SKarol Kolacinski * 25301229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 25311229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using the low latency 25321229b339SKarol Kolacinski * timestamp read. 25331229b339SKarol Kolacinski */ 25341229b339SKarol Kolacinski static int 25351229b339SKarol Kolacinski ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo) 25361229b339SKarol Kolacinski { 25371229b339SKarol Kolacinski u32 val; 25381229b339SKarol Kolacinski u8 i; 25391229b339SKarol Kolacinski 25401229b339SKarol Kolacinski /* Write TS index to read to the PF register so the FW can read it */ 25411229b339SKarol Kolacinski val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS; 25421229b339SKarol Kolacinski wr32(hw, PF_SB_ATQBAL, val); 25431229b339SKarol Kolacinski 25441229b339SKarol Kolacinski /* Read the register repeatedly until the FW provides us the TS */ 25451229b339SKarol Kolacinski for (i = TS_LL_READ_RETRIES; i > 0; i--) { 25461229b339SKarol Kolacinski val = rd32(hw, PF_SB_ATQBAL); 25471229b339SKarol Kolacinski 25481229b339SKarol Kolacinski /* When the bit is cleared, the TS is ready in the register */ 25491229b339SKarol Kolacinski if (!(FIELD_GET(TS_LL_READ_TS, val))) { 25501229b339SKarol Kolacinski /* High 8 bit value of the TS is on the bits 16:23 */ 25511229b339SKarol Kolacinski *hi = FIELD_GET(TS_LL_READ_TS_HIGH, val); 25521229b339SKarol Kolacinski 25531229b339SKarol Kolacinski /* Read the low 32 bit value and set the TS valid bit */ 25541229b339SKarol Kolacinski *lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID; 25551229b339SKarol Kolacinski return 0; 25561229b339SKarol Kolacinski } 25571229b339SKarol Kolacinski 25581229b339SKarol Kolacinski udelay(10); 25591229b339SKarol Kolacinski } 25601229b339SKarol Kolacinski 25611229b339SKarol Kolacinski /* FW failed to provide the TS in time */ 25621229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n"); 25631229b339SKarol Kolacinski return -EINVAL; 25641229b339SKarol Kolacinski } 25651229b339SKarol Kolacinski 25661229b339SKarol Kolacinski /** 25671229b339SKarol Kolacinski * ice_read_phy_tstamp_sbq_e810 - Read a PHY timestamp registers through the sbq 25681229b339SKarol Kolacinski * @hw: pointer to the HW struct 25691229b339SKarol Kolacinski * @lport: the lport to read from 25701229b339SKarol Kolacinski * @idx: the timestamp index to read 25711229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 25721229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 25731229b339SKarol Kolacinski * 25741229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 25751229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using sideband queue. 25761229b339SKarol Kolacinski */ 25771229b339SKarol Kolacinski static int 25781229b339SKarol Kolacinski ice_read_phy_tstamp_sbq_e810(struct ice_hw *hw, u8 lport, u8 idx, u8 *hi, 25791229b339SKarol Kolacinski u32 *lo) 25801229b339SKarol Kolacinski { 25811229b339SKarol Kolacinski u32 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 25821229b339SKarol Kolacinski u32 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 25831229b339SKarol Kolacinski u32 lo_val, hi_val; 25841229b339SKarol Kolacinski int err; 25851229b339SKarol Kolacinski 25861229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, lo_addr, &lo_val); 25871229b339SKarol Kolacinski if (err) { 25881229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 25891229b339SKarol Kolacinski err); 25901229b339SKarol Kolacinski return err; 25911229b339SKarol Kolacinski } 25921229b339SKarol Kolacinski 25931229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, hi_addr, &hi_val); 25941229b339SKarol Kolacinski if (err) { 25951229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 25961229b339SKarol Kolacinski err); 25971229b339SKarol Kolacinski return err; 25981229b339SKarol Kolacinski } 25991229b339SKarol Kolacinski 26001229b339SKarol Kolacinski *lo = lo_val; 26011229b339SKarol Kolacinski *hi = (u8)hi_val; 26021229b339SKarol Kolacinski 26031229b339SKarol Kolacinski return 0; 26041229b339SKarol Kolacinski } 26051229b339SKarol Kolacinski 26061229b339SKarol Kolacinski /** 260703cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 260803cb4473SJacob Keller * @hw: pointer to the HW struct 260903cb4473SJacob Keller * @lport: the lport to read from 261003cb4473SJacob Keller * @idx: the timestamp index to read 261103cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 261203cb4473SJacob Keller * 261303cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 261403cb4473SJacob Keller * on the E810 device. 261503cb4473SJacob Keller */ 261603cb4473SJacob Keller static int 261703cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 261803cb4473SJacob Keller { 26191229b339SKarol Kolacinski u32 lo = 0; 26201229b339SKarol Kolacinski u8 hi = 0; 262139b28106SJacob Keller int err; 262203cb4473SJacob Keller 26231229b339SKarol Kolacinski if (hw->dev_caps.ts_dev_info.ts_ll_read) 26241229b339SKarol Kolacinski err = ice_read_phy_tstamp_ll_e810(hw, idx, &hi, &lo); 26251229b339SKarol Kolacinski else 26261229b339SKarol Kolacinski err = ice_read_phy_tstamp_sbq_e810(hw, lport, idx, &hi, &lo); 262703cb4473SJacob Keller 26281229b339SKarol Kolacinski if (err) 262939b28106SJacob Keller return err; 263003cb4473SJacob Keller 263103cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 263203cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 263303cb4473SJacob Keller */ 263403cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 263503cb4473SJacob Keller 263603cb4473SJacob Keller return 0; 263703cb4473SJacob Keller } 263803cb4473SJacob Keller 263903cb4473SJacob Keller /** 264003cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 264103cb4473SJacob Keller * @hw: pointer to the HW struct 264203cb4473SJacob Keller * @lport: the lport to read from 264303cb4473SJacob Keller * @idx: the timestamp index to reset 264403cb4473SJacob Keller * 264503cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 264603cb4473SJacob Keller * external PHY on the E810 device. 264703cb4473SJacob Keller */ 264803cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 264903cb4473SJacob Keller { 265003cb4473SJacob Keller u32 lo_addr, hi_addr; 265139b28106SJacob Keller int err; 265203cb4473SJacob Keller 265303cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 265403cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 265503cb4473SJacob Keller 265639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 265739b28106SJacob Keller if (err) { 265839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 265939b28106SJacob Keller err); 266039b28106SJacob Keller return err; 266103cb4473SJacob Keller } 266203cb4473SJacob Keller 266339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 266439b28106SJacob Keller if (err) { 266539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 266639b28106SJacob Keller err); 266739b28106SJacob Keller return err; 266803cb4473SJacob Keller } 266903cb4473SJacob Keller 267003cb4473SJacob Keller return 0; 267103cb4473SJacob Keller } 267203cb4473SJacob Keller 267303cb4473SJacob Keller /** 267403cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 267503cb4473SJacob Keller * @hw: pointer to HW struct 267603cb4473SJacob Keller * 267703cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 267803cb4473SJacob Keller * this function. 267903cb4473SJacob Keller */ 268003cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 268103cb4473SJacob Keller { 268203cb4473SJacob Keller u8 tmr_idx; 268339b28106SJacob Keller int err; 268403cb4473SJacob Keller 268503cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 268639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 268703cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 268839b28106SJacob Keller if (err) 268903cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 269039b28106SJacob Keller err); 269103cb4473SJacob Keller 269239b28106SJacob Keller return err; 269303cb4473SJacob Keller } 269403cb4473SJacob Keller 269503cb4473SJacob Keller /** 2696b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 2697b2ee7256SJacob Keller * @hw: pointer to HW struct 2698b2ee7256SJacob Keller * 2699b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 2700b2ee7256SJacob Keller */ 2701b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 2702b2ee7256SJacob Keller { 2703b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 2704b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 2705b2ee7256SJacob Keller 2706b2ee7256SJacob Keller /* Initialize the PHY */ 2707b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 2708b2ee7256SJacob Keller } 2709b2ee7256SJacob Keller 2710b2ee7256SJacob Keller /** 271103cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 271203cb4473SJacob Keller * @hw: Board private structure 271303cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 271403cb4473SJacob Keller * 271503cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 271603cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 271703cb4473SJacob Keller * driver issues an INIT_TIME command. 271803cb4473SJacob Keller * 271903cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 272003cb4473SJacob Keller * nominal nanoseconds. 272103cb4473SJacob Keller */ 272203cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 272303cb4473SJacob Keller { 272403cb4473SJacob Keller u8 tmr_idx; 272539b28106SJacob Keller int err; 272603cb4473SJacob Keller 272703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 272839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 272939b28106SJacob Keller if (err) { 273039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 273139b28106SJacob Keller err); 273239b28106SJacob Keller return err; 273303cb4473SJacob Keller } 273403cb4473SJacob Keller 273539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 273639b28106SJacob Keller if (err) { 273739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 273839b28106SJacob Keller err); 273939b28106SJacob Keller return err; 274003cb4473SJacob Keller } 274103cb4473SJacob Keller 274203cb4473SJacob Keller return 0; 274303cb4473SJacob Keller } 274403cb4473SJacob Keller 274503cb4473SJacob Keller /** 274603cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 274703cb4473SJacob Keller * @hw: pointer to HW struct 274803cb4473SJacob Keller * @adj: adjustment value to program 274903cb4473SJacob Keller * 275003cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 275103cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 275203cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 275303cb4473SJacob Keller * 275403cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 275503cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 275603cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 275703cb4473SJacob Keller */ 275803cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 275903cb4473SJacob Keller { 276003cb4473SJacob Keller u8 tmr_idx; 276139b28106SJacob Keller int err; 276203cb4473SJacob Keller 276303cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 276403cb4473SJacob Keller 276503cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 276603cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 276703cb4473SJacob Keller */ 276839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 276939b28106SJacob Keller if (err) { 277039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 277139b28106SJacob Keller err); 277239b28106SJacob Keller return err; 277303cb4473SJacob Keller } 277403cb4473SJacob Keller 277539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 277639b28106SJacob Keller if (err) { 277739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 277839b28106SJacob Keller err); 277939b28106SJacob Keller return err; 278003cb4473SJacob Keller } 278103cb4473SJacob Keller 278203cb4473SJacob Keller return 0; 278303cb4473SJacob Keller } 278403cb4473SJacob Keller 278503cb4473SJacob Keller /** 278603cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 278703cb4473SJacob Keller * @hw: pointer to HW struct 278803cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 278903cb4473SJacob Keller * 279003cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 279103cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 279203cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 279303cb4473SJacob Keller */ 279403cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 279503cb4473SJacob Keller { 279603cb4473SJacob Keller u32 high, low; 279703cb4473SJacob Keller u8 tmr_idx; 279839b28106SJacob Keller int err; 279903cb4473SJacob Keller 280003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 280103cb4473SJacob Keller low = lower_32_bits(incval); 280203cb4473SJacob Keller high = upper_32_bits(incval); 280303cb4473SJacob Keller 280439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 280539b28106SJacob Keller if (err) { 280639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 280739b28106SJacob Keller err); 280839b28106SJacob Keller return err; 280903cb4473SJacob Keller } 281003cb4473SJacob Keller 281139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 281239b28106SJacob Keller if (err) { 281339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 281439b28106SJacob Keller err); 281539b28106SJacob Keller return err; 281603cb4473SJacob Keller } 281703cb4473SJacob Keller 281803cb4473SJacob Keller return 0; 281903cb4473SJacob Keller } 282003cb4473SJacob Keller 282103cb4473SJacob Keller /** 282203cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 282303cb4473SJacob Keller * @hw: pointer to HW struct 282403cb4473SJacob Keller * @cmd: Command to be sent to the port 282503cb4473SJacob Keller * 282603cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 282703cb4473SJacob Keller * command. 282803cb4473SJacob Keller */ 282903cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 283003cb4473SJacob Keller { 283103cb4473SJacob Keller u32 cmd_val, val; 283239b28106SJacob Keller int err; 283303cb4473SJacob Keller 283403cb4473SJacob Keller switch (cmd) { 283503cb4473SJacob Keller case INIT_TIME: 283603cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 283703cb4473SJacob Keller break; 283803cb4473SJacob Keller case INIT_INCVAL: 283903cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 284003cb4473SJacob Keller break; 284103cb4473SJacob Keller case ADJ_TIME: 284203cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 284303cb4473SJacob Keller break; 284403cb4473SJacob Keller case READ_TIME: 284503cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 284603cb4473SJacob Keller break; 284703cb4473SJacob Keller case ADJ_TIME_AT_TIME: 284803cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 284903cb4473SJacob Keller break; 285003cb4473SJacob Keller } 285103cb4473SJacob Keller 285203cb4473SJacob Keller /* Read, modify, write */ 285339b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 285439b28106SJacob Keller if (err) { 285539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 285639b28106SJacob Keller return err; 285703cb4473SJacob Keller } 285803cb4473SJacob Keller 285903cb4473SJacob Keller /* Modify necessary bits only and perform write */ 286003cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 286103cb4473SJacob Keller val |= cmd_val; 286203cb4473SJacob Keller 286339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 286439b28106SJacob Keller if (err) { 286539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 286639b28106SJacob Keller return err; 286703cb4473SJacob Keller } 286803cb4473SJacob Keller 286903cb4473SJacob Keller return 0; 287003cb4473SJacob Keller } 287103cb4473SJacob Keller 287203cb4473SJacob Keller /* Device agnostic functions 287303cb4473SJacob Keller * 28743a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 28753a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 28763a749623SJacob Keller * necessary. 287703cb4473SJacob Keller */ 287803cb4473SJacob Keller 287903cb4473SJacob Keller /** 288003cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 288103cb4473SJacob Keller * @hw: pointer to the HW struct 288203cb4473SJacob Keller * 288303cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 288403cb4473SJacob Keller * was acquired, false otherwise. 288503cb4473SJacob Keller * 288603cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 288703cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 288803cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 288903cb4473SJacob Keller * bit set, it means that another function acquired the lock. 289003cb4473SJacob Keller * 289103cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 289203cb4473SJacob Keller * functions when done. 289303cb4473SJacob Keller */ 289403cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 289503cb4473SJacob Keller { 289603cb4473SJacob Keller u32 hw_lock; 289703cb4473SJacob Keller int i; 289803cb4473SJacob Keller 2899a711a328SKarol Kolacinski #define MAX_TRIES 15 290003cb4473SJacob Keller 290103cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 290203cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 290303cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2904a711a328SKarol Kolacinski if (hw_lock) { 290503cb4473SJacob Keller /* Somebody is holding the lock */ 2906a711a328SKarol Kolacinski usleep_range(5000, 6000); 2907a711a328SKarol Kolacinski continue; 2908a711a328SKarol Kolacinski } 2909a711a328SKarol Kolacinski 2910a711a328SKarol Kolacinski break; 291103cb4473SJacob Keller } 291203cb4473SJacob Keller 291303cb4473SJacob Keller return !hw_lock; 291403cb4473SJacob Keller } 291503cb4473SJacob Keller 291603cb4473SJacob Keller /** 291703cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 291803cb4473SJacob Keller * @hw: pointer to the HW struct 291903cb4473SJacob Keller * 292003cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 292103cb4473SJacob Keller * the PFTSYN_SEM register. 292203cb4473SJacob Keller */ 292303cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 292403cb4473SJacob Keller { 292503cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 292603cb4473SJacob Keller } 292703cb4473SJacob Keller 292803cb4473SJacob Keller /** 292903cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 293003cb4473SJacob Keller * @hw: pointer to HW struct 293103cb4473SJacob Keller * @cmd: the command to issue 293203cb4473SJacob Keller * 293303cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 293403cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 293503cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 293603cb4473SJacob Keller * timers. 293703cb4473SJacob Keller */ 293803cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 293903cb4473SJacob Keller { 294039b28106SJacob Keller int err; 294103cb4473SJacob Keller 294203cb4473SJacob Keller /* First, prepare the source timer */ 294303cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 294403cb4473SJacob Keller 294503cb4473SJacob Keller /* Next, prepare the ports */ 29463a749623SJacob Keller if (ice_is_e810(hw)) 294739b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 29483a749623SJacob Keller else 29493a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 295039b28106SJacob Keller if (err) { 295139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 295239b28106SJacob Keller cmd, err); 295339b28106SJacob Keller return err; 295403cb4473SJacob Keller } 295503cb4473SJacob Keller 29563a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 29573a749623SJacob Keller * commands synchronously 295803cb4473SJacob Keller */ 29593a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 296003cb4473SJacob Keller 296103cb4473SJacob Keller return 0; 296203cb4473SJacob Keller } 296303cb4473SJacob Keller 296403cb4473SJacob Keller /** 296503cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 296603cb4473SJacob Keller * @hw: pointer to HW struct 296703cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 296803cb4473SJacob Keller * 296903cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 297003cb4473SJacob Keller * step process: 297103cb4473SJacob Keller * 297203cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 297303cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 297403cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 297503cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 297603cb4473SJacob Keller */ 297703cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 297803cb4473SJacob Keller { 297903cb4473SJacob Keller u8 tmr_idx; 298039b28106SJacob Keller int err; 298103cb4473SJacob Keller 298203cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 298303cb4473SJacob Keller 298403cb4473SJacob Keller /* Source timers */ 298503cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 298603cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 298703cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 298803cb4473SJacob Keller 298903cb4473SJacob Keller /* PHY timers */ 299003cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 29913a749623SJacob Keller if (ice_is_e810(hw)) 299239b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 29933a749623SJacob Keller else 29943a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 299539b28106SJacob Keller if (err) 299639b28106SJacob Keller return err; 299703cb4473SJacob Keller 299803cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 299903cb4473SJacob Keller } 300003cb4473SJacob Keller 300103cb4473SJacob Keller /** 300203cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 300303cb4473SJacob Keller * @hw: pointer to HW struct 300403cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 300503cb4473SJacob Keller * 300603cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 300703cb4473SJacob Keller * process: 300803cb4473SJacob Keller * 300903cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 301003cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 301103cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 301203cb4473SJacob Keller * source and port timers to the new increment value at the next clock 301303cb4473SJacob Keller * cycle. 301403cb4473SJacob Keller */ 301503cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 301603cb4473SJacob Keller { 301703cb4473SJacob Keller u8 tmr_idx; 301839b28106SJacob Keller int err; 301903cb4473SJacob Keller 302003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 302103cb4473SJacob Keller 302203cb4473SJacob Keller /* Shadow Adjust */ 302303cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 302403cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 302503cb4473SJacob Keller 30263a749623SJacob Keller if (ice_is_e810(hw)) 302739b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 30283a749623SJacob Keller else 30293a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 303039b28106SJacob Keller if (err) 303139b28106SJacob Keller return err; 303203cb4473SJacob Keller 303303cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 303403cb4473SJacob Keller } 303503cb4473SJacob Keller 303603cb4473SJacob Keller /** 303703cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 303803cb4473SJacob Keller * @hw: pointer to HW struct 303903cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 304003cb4473SJacob Keller * 304103cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 304203cb4473SJacob Keller */ 304303cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 304403cb4473SJacob Keller { 304539b28106SJacob Keller int err; 304603cb4473SJacob Keller 304703cb4473SJacob Keller if (!ice_ptp_lock(hw)) 304803cb4473SJacob Keller return -EBUSY; 304903cb4473SJacob Keller 305039b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 305103cb4473SJacob Keller 305203cb4473SJacob Keller ice_ptp_unlock(hw); 305303cb4473SJacob Keller 305439b28106SJacob Keller return err; 305503cb4473SJacob Keller } 305603cb4473SJacob Keller 305703cb4473SJacob Keller /** 305803cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 305903cb4473SJacob Keller * @hw: pointer to HW struct 306003cb4473SJacob Keller * @adj: Adjustment in nanoseconds 306103cb4473SJacob Keller * 306203cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 306303cb4473SJacob Keller * nanoseconds. This requires a three-step process: 306403cb4473SJacob Keller * 306503cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 306603cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 306703cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 306803cb4473SJacob Keller * both the source and port timers at the next clock cycle. 306903cb4473SJacob Keller */ 307003cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 307103cb4473SJacob Keller { 307203cb4473SJacob Keller u8 tmr_idx; 307339b28106SJacob Keller int err; 307403cb4473SJacob Keller 307503cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 307603cb4473SJacob Keller 307703cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 307803cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 307903cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 308003cb4473SJacob Keller * the value as a 2's complement integer. 308103cb4473SJacob Keller */ 308203cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 308303cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 308403cb4473SJacob Keller 30853a749623SJacob Keller if (ice_is_e810(hw)) 308639b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 30873a749623SJacob Keller else 30883a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 308939b28106SJacob Keller if (err) 309039b28106SJacob Keller return err; 309103cb4473SJacob Keller 309203cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 309303cb4473SJacob Keller } 309403cb4473SJacob Keller 309503cb4473SJacob Keller /** 309603cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 309703cb4473SJacob Keller * @hw: pointer to the HW struct 309803cb4473SJacob Keller * @block: the block to read from 309903cb4473SJacob Keller * @idx: the timestamp index to read 310003cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 310103cb4473SJacob Keller * 31023a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 31033a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 31043a749623SJacob Keller * logical port to read from. 310503cb4473SJacob Keller */ 310603cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 310703cb4473SJacob Keller { 31083a749623SJacob Keller if (ice_is_e810(hw)) 310903cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 31103a749623SJacob Keller else 31113a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 311203cb4473SJacob Keller } 311303cb4473SJacob Keller 311403cb4473SJacob Keller /** 311503cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 311603cb4473SJacob Keller * @hw: pointer to the HW struct 311703cb4473SJacob Keller * @block: the block to read from 311803cb4473SJacob Keller * @idx: the timestamp index to reset 311903cb4473SJacob Keller * 31203a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 31213a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 31223a749623SJacob Keller * block is the logical port to clear from. 312303cb4473SJacob Keller */ 312403cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 312503cb4473SJacob Keller { 31263a749623SJacob Keller if (ice_is_e810(hw)) 312703cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 31283a749623SJacob Keller else 31293a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 313003cb4473SJacob Keller } 3131885fe693SMaciej Machnikowski 313210e4b4a3SJacob Keller /** 313310e4b4a3SJacob Keller * ice_get_phy_tx_tstamp_ready_e810 - Read Tx memory status register 313410e4b4a3SJacob Keller * @hw: pointer to the HW struct 313510e4b4a3SJacob Keller * @port: the PHY port to read 313610e4b4a3SJacob Keller * @tstamp_ready: contents of the Tx memory status register 313710e4b4a3SJacob Keller * 313810e4b4a3SJacob Keller * E810 devices do not use a Tx memory status register. Instead simply 313910e4b4a3SJacob Keller * indicate that all timestamps are currently ready. 314010e4b4a3SJacob Keller */ 314110e4b4a3SJacob Keller static int 314210e4b4a3SJacob Keller ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) 314310e4b4a3SJacob Keller { 314410e4b4a3SJacob Keller *tstamp_ready = 0xFFFFFFFFFFFFFFFF; 314510e4b4a3SJacob Keller return 0; 314610e4b4a3SJacob Keller } 314710e4b4a3SJacob Keller 3148885fe693SMaciej Machnikowski /* E810T SMA functions 3149885fe693SMaciej Machnikowski * 3150885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 3151885fe693SMaciej Machnikowski * to access the extended GPIOs available. 3152885fe693SMaciej Machnikowski */ 3153885fe693SMaciej Machnikowski 3154885fe693SMaciej Machnikowski /** 3155885fe693SMaciej Machnikowski * ice_get_pca9575_handle 3156885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3157885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 3158885fe693SMaciej Machnikowski * 3159885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 3160885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 3161885fe693SMaciej Machnikowski * will return cached value 3162885fe693SMaciej Machnikowski */ 3163885fe693SMaciej Machnikowski static int 3164885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 3165885fe693SMaciej Machnikowski { 3166885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 3167885fe693SMaciej Machnikowski struct ice_aq_desc desc; 3168885fe693SMaciej Machnikowski int status; 3169885fe693SMaciej Machnikowski u8 idx; 3170885fe693SMaciej Machnikowski 3171885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 3172885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 3173885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3174885fe693SMaciej Machnikowski return 0; 3175885fe693SMaciej Machnikowski } 3176885fe693SMaciej Machnikowski 3177885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 3178885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 3179885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 3180885fe693SMaciej Machnikowski 3181885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 3182885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 3183885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 3184885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 3185885fe693SMaciej Machnikowski 3186885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 3187885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 3188885fe693SMaciej Machnikowski 3189885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 3190885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 3191885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 3192885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 3193885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 3194885fe693SMaciej Machnikowski else 3195885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3196885fe693SMaciej Machnikowski 3197885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 3198885fe693SMaciej Machnikowski 3199885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 3200885fe693SMaciej Machnikowski if (status) 3201885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3202885fe693SMaciej Machnikowski 3203885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 3204885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 3205885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 3206885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3207885fe693SMaciej Machnikowski 3208885fe693SMaciej Machnikowski /* If present save the handle and return it */ 3209885fe693SMaciej Machnikowski hw->io_expander_handle = 3210885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 3211885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3212885fe693SMaciej Machnikowski 3213885fe693SMaciej Machnikowski return 0; 3214885fe693SMaciej Machnikowski } 3215885fe693SMaciej Machnikowski 3216885fe693SMaciej Machnikowski /** 3217885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 3218885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3219885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 3220885fe693SMaciej Machnikowski * 3221885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 3222885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 3223885fe693SMaciej Machnikowski */ 3224885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 3225885fe693SMaciej Machnikowski { 3226885fe693SMaciej Machnikowski int status; 3227885fe693SMaciej Machnikowski u16 handle; 3228885fe693SMaciej Machnikowski u8 i; 3229885fe693SMaciej Machnikowski 3230885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3231885fe693SMaciej Machnikowski if (status) 3232885fe693SMaciej Machnikowski return status; 3233885fe693SMaciej Machnikowski 3234885fe693SMaciej Machnikowski *data = 0; 3235885fe693SMaciej Machnikowski 3236885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3237885fe693SMaciej Machnikowski bool pin; 3238885fe693SMaciej Machnikowski 3239885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3240885fe693SMaciej Machnikowski &pin, NULL); 3241885fe693SMaciej Machnikowski if (status) 3242885fe693SMaciej Machnikowski break; 3243885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 3244885fe693SMaciej Machnikowski } 3245885fe693SMaciej Machnikowski 3246885fe693SMaciej Machnikowski return status; 3247885fe693SMaciej Machnikowski } 3248885fe693SMaciej Machnikowski 3249885fe693SMaciej Machnikowski /** 3250885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 3251885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3252885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 3253885fe693SMaciej Machnikowski * 3254885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 3255885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 3256885fe693SMaciej Machnikowski */ 3257885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 3258885fe693SMaciej Machnikowski { 3259885fe693SMaciej Machnikowski int status; 3260885fe693SMaciej Machnikowski u16 handle; 3261885fe693SMaciej Machnikowski u8 i; 3262885fe693SMaciej Machnikowski 3263885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3264885fe693SMaciej Machnikowski if (status) 3265885fe693SMaciej Machnikowski return status; 3266885fe693SMaciej Machnikowski 3267885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3268885fe693SMaciej Machnikowski bool pin; 3269885fe693SMaciej Machnikowski 3270885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 3271885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3272885fe693SMaciej Machnikowski pin, NULL); 3273885fe693SMaciej Machnikowski if (status) 3274885fe693SMaciej Machnikowski break; 3275885fe693SMaciej Machnikowski } 3276885fe693SMaciej Machnikowski 3277885fe693SMaciej Machnikowski return status; 3278885fe693SMaciej Machnikowski } 3279885fe693SMaciej Machnikowski 3280885fe693SMaciej Machnikowski /** 328143113ff7SKarol Kolacinski * ice_read_pca9575_reg_e810t 328243113ff7SKarol Kolacinski * @hw: pointer to the hw struct 328343113ff7SKarol Kolacinski * @offset: GPIO controller register offset 328443113ff7SKarol Kolacinski * @data: pointer to data to be read from the GPIO controller 328543113ff7SKarol Kolacinski * 328643113ff7SKarol Kolacinski * Read the register from the GPIO controller 328743113ff7SKarol Kolacinski */ 328843113ff7SKarol Kolacinski int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) 328943113ff7SKarol Kolacinski { 329043113ff7SKarol Kolacinski struct ice_aqc_link_topo_addr link_topo; 329143113ff7SKarol Kolacinski __le16 addr; 329243113ff7SKarol Kolacinski u16 handle; 329343113ff7SKarol Kolacinski int err; 329443113ff7SKarol Kolacinski 329543113ff7SKarol Kolacinski memset(&link_topo, 0, sizeof(link_topo)); 329643113ff7SKarol Kolacinski 329743113ff7SKarol Kolacinski err = ice_get_pca9575_handle(hw, &handle); 329843113ff7SKarol Kolacinski if (err) 329943113ff7SKarol Kolacinski return err; 330043113ff7SKarol Kolacinski 330143113ff7SKarol Kolacinski link_topo.handle = cpu_to_le16(handle); 330243113ff7SKarol Kolacinski link_topo.topo_params.node_type_ctx = 330343113ff7SKarol Kolacinski FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, 330443113ff7SKarol Kolacinski ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED); 330543113ff7SKarol Kolacinski 330643113ff7SKarol Kolacinski addr = cpu_to_le16((u16)offset); 330743113ff7SKarol Kolacinski 330843113ff7SKarol Kolacinski return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL); 330943113ff7SKarol Kolacinski } 331043113ff7SKarol Kolacinski 331143113ff7SKarol Kolacinski /** 3312885fe693SMaciej Machnikowski * ice_is_pca9575_present 3313885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3314885fe693SMaciej Machnikowski * 3315885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 3316885fe693SMaciej Machnikowski */ 3317885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 3318885fe693SMaciej Machnikowski { 3319885fe693SMaciej Machnikowski u16 handle = 0; 3320885fe693SMaciej Machnikowski int status; 3321885fe693SMaciej Machnikowski 3322885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 3323885fe693SMaciej Machnikowski return false; 3324885fe693SMaciej Machnikowski 3325885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3326885fe693SMaciej Machnikowski 3327885fe693SMaciej Machnikowski return !status && handle; 3328885fe693SMaciej Machnikowski } 3329b2ee7256SJacob Keller 3330b2ee7256SJacob Keller /** 3331407b66c0SKarol Kolacinski * ice_ptp_reset_ts_memory - Reset timestamp memory for all blocks 3332407b66c0SKarol Kolacinski * @hw: pointer to the HW struct 3333407b66c0SKarol Kolacinski */ 3334407b66c0SKarol Kolacinski void ice_ptp_reset_ts_memory(struct ice_hw *hw) 3335407b66c0SKarol Kolacinski { 3336407b66c0SKarol Kolacinski if (ice_is_e810(hw)) 3337407b66c0SKarol Kolacinski return; 3338407b66c0SKarol Kolacinski 3339407b66c0SKarol Kolacinski ice_ptp_reset_ts_memory_e822(hw); 3340407b66c0SKarol Kolacinski } 3341407b66c0SKarol Kolacinski 3342407b66c0SKarol Kolacinski /** 3343b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 3344b2ee7256SJacob Keller * @hw: pointer to the HW struct 3345b2ee7256SJacob Keller * 3346b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 3347b2ee7256SJacob Keller */ 3348b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 3349b2ee7256SJacob Keller { 3350b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 3351b2ee7256SJacob Keller 3352b2ee7256SJacob Keller /* Enable source clocks */ 3353b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 3354b2ee7256SJacob Keller 3355b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 3356b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 3357b2ee7256SJacob Keller 33583a749623SJacob Keller if (ice_is_e810(hw)) 3359b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 33603a749623SJacob Keller else 33613a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 3362b2ee7256SJacob Keller } 336310e4b4a3SJacob Keller 336410e4b4a3SJacob Keller /** 336510e4b4a3SJacob Keller * ice_get_phy_tx_tstamp_ready - Read PHY Tx memory status indication 336610e4b4a3SJacob Keller * @hw: pointer to the HW struct 336710e4b4a3SJacob Keller * @block: the timestamp block to check 336810e4b4a3SJacob Keller * @tstamp_ready: storage for the PHY Tx memory status information 336910e4b4a3SJacob Keller * 337010e4b4a3SJacob Keller * Check the PHY for Tx timestamp memory status. This reports a 64 bit value 337110e4b4a3SJacob Keller * which indicates which timestamps in the block may be captured. A set bit 337210e4b4a3SJacob Keller * means the timestamp can be read. An unset bit means the timestamp is not 337310e4b4a3SJacob Keller * ready and software should avoid reading the register. 337410e4b4a3SJacob Keller */ 337510e4b4a3SJacob Keller int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) 337610e4b4a3SJacob Keller { 337710e4b4a3SJacob Keller if (ice_is_e810(hw)) 337810e4b4a3SJacob Keller return ice_get_phy_tx_tstamp_ready_e810(hw, block, 337910e4b4a3SJacob Keller tstamp_ready); 338010e4b4a3SJacob Keller else 338110e4b4a3SJacob Keller return ice_get_phy_tx_tstamp_ready_e822(hw, block, 338210e4b4a3SJacob Keller tstamp_ready); 338310e4b4a3SJacob Keller } 3384