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 /** 659b111ab5aSJacob Keller * ice_read_cgu_reg_e822 - Read a CGU register 660b111ab5aSJacob Keller * @hw: pointer to the HW struct 661b111ab5aSJacob Keller * @addr: Register address to read 662b111ab5aSJacob Keller * @val: storage for register value read 663b111ab5aSJacob Keller * 664b111ab5aSJacob Keller * Read the contents of a register of the Clock Generation Unit. Only 665b111ab5aSJacob Keller * applicable to E822 devices. 666b111ab5aSJacob Keller */ 667b111ab5aSJacob Keller static int 668b111ab5aSJacob Keller ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) 669b111ab5aSJacob Keller { 670b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 671b111ab5aSJacob Keller int err; 672b111ab5aSJacob Keller 673b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_rd; 674b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 675b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 676b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 677b111ab5aSJacob Keller 678b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 679b111ab5aSJacob Keller if (err) { 680b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n", 681b111ab5aSJacob Keller addr, err); 682b111ab5aSJacob Keller return err; 683b111ab5aSJacob Keller } 684b111ab5aSJacob Keller 685b111ab5aSJacob Keller *val = cgu_msg.data; 686b111ab5aSJacob Keller 687b111ab5aSJacob Keller return err; 688b111ab5aSJacob Keller } 689b111ab5aSJacob Keller 690b111ab5aSJacob Keller /** 691b111ab5aSJacob Keller * ice_write_cgu_reg_e822 - Write a CGU register 692b111ab5aSJacob Keller * @hw: pointer to the HW struct 693b111ab5aSJacob Keller * @addr: Register address to write 694b111ab5aSJacob Keller * @val: value to write into the register 695b111ab5aSJacob Keller * 696b111ab5aSJacob Keller * Write the specified value to a register of the Clock Generation Unit. Only 697b111ab5aSJacob Keller * applicable to E822 devices. 698b111ab5aSJacob Keller */ 699b111ab5aSJacob Keller static int 700b111ab5aSJacob Keller ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val) 701b111ab5aSJacob Keller { 702b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 703b111ab5aSJacob Keller int err; 704b111ab5aSJacob Keller 705b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_wr; 706b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 707b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 708b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 709b111ab5aSJacob Keller cgu_msg.data = val; 710b111ab5aSJacob Keller 711b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 712b111ab5aSJacob Keller if (err) { 713b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n", 714b111ab5aSJacob Keller addr, err); 715b111ab5aSJacob Keller return err; 716b111ab5aSJacob Keller } 717b111ab5aSJacob Keller 718b111ab5aSJacob Keller return err; 719b111ab5aSJacob Keller } 720b111ab5aSJacob Keller 721b111ab5aSJacob Keller /** 722b111ab5aSJacob Keller * ice_clk_freq_str - Convert time_ref_freq to string 723b111ab5aSJacob Keller * @clk_freq: Clock frequency 724b111ab5aSJacob Keller * 725b111ab5aSJacob Keller * Convert the specified TIME_REF clock frequency to a string. 726b111ab5aSJacob Keller */ 727b111ab5aSJacob Keller static const char *ice_clk_freq_str(u8 clk_freq) 728b111ab5aSJacob Keller { 729b111ab5aSJacob Keller switch ((enum ice_time_ref_freq)clk_freq) { 730b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_25_000: 731b111ab5aSJacob Keller return "25 MHz"; 732b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_122_880: 733b111ab5aSJacob Keller return "122.88 MHz"; 734b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_125_000: 735b111ab5aSJacob Keller return "125 MHz"; 736b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_153_600: 737b111ab5aSJacob Keller return "153.6 MHz"; 738b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_156_250: 739b111ab5aSJacob Keller return "156.25 MHz"; 740b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_245_760: 741b111ab5aSJacob Keller return "245.76 MHz"; 742b111ab5aSJacob Keller default: 743b111ab5aSJacob Keller return "Unknown"; 744b111ab5aSJacob Keller } 745b111ab5aSJacob Keller } 746b111ab5aSJacob Keller 747b111ab5aSJacob Keller /** 748b111ab5aSJacob Keller * ice_clk_src_str - Convert time_ref_src to string 749b111ab5aSJacob Keller * @clk_src: Clock source 750b111ab5aSJacob Keller * 751b111ab5aSJacob Keller * Convert the specified clock source to its string name. 752b111ab5aSJacob Keller */ 753b111ab5aSJacob Keller static const char *ice_clk_src_str(u8 clk_src) 754b111ab5aSJacob Keller { 755b111ab5aSJacob Keller switch ((enum ice_clk_src)clk_src) { 756b111ab5aSJacob Keller case ICE_CLK_SRC_TCX0: 757b111ab5aSJacob Keller return "TCX0"; 758b111ab5aSJacob Keller case ICE_CLK_SRC_TIME_REF: 759b111ab5aSJacob Keller return "TIME_REF"; 760b111ab5aSJacob Keller default: 761b111ab5aSJacob Keller return "Unknown"; 762b111ab5aSJacob Keller } 763b111ab5aSJacob Keller } 764b111ab5aSJacob Keller 765b111ab5aSJacob Keller /** 766b111ab5aSJacob Keller * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit 767b111ab5aSJacob Keller * @hw: pointer to the HW struct 768b111ab5aSJacob Keller * @clk_freq: Clock frequency to program 769b111ab5aSJacob Keller * @clk_src: Clock source to select (TIME_REF, or TCX0) 770b111ab5aSJacob Keller * 771b111ab5aSJacob Keller * Configure the Clock Generation Unit with the desired clock frequency and 772b111ab5aSJacob Keller * time reference, enabling the PLL which drives the PTP hardware clock. 773b111ab5aSJacob Keller */ 774b111ab5aSJacob Keller static int 775b111ab5aSJacob Keller ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, 776b111ab5aSJacob Keller enum ice_clk_src clk_src) 777b111ab5aSJacob Keller { 778b111ab5aSJacob Keller union tspll_ro_bwm_lf bwm_lf; 779b111ab5aSJacob Keller union nac_cgu_dword19 dw19; 780b111ab5aSJacob Keller union nac_cgu_dword22 dw22; 781b111ab5aSJacob Keller union nac_cgu_dword24 dw24; 782b111ab5aSJacob Keller union nac_cgu_dword9 dw9; 783b111ab5aSJacob Keller int err; 784b111ab5aSJacob Keller 785b111ab5aSJacob Keller if (clk_freq >= NUM_ICE_TIME_REF_FREQ) { 786b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", 787b111ab5aSJacob Keller clk_freq); 788b111ab5aSJacob Keller return -EINVAL; 789b111ab5aSJacob Keller } 790b111ab5aSJacob Keller 791b111ab5aSJacob Keller if (clk_src >= NUM_ICE_CLK_SRC) { 792b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", 793b111ab5aSJacob Keller clk_src); 794b111ab5aSJacob Keller return -EINVAL; 795b111ab5aSJacob Keller } 796b111ab5aSJacob Keller 797b111ab5aSJacob Keller if (clk_src == ICE_CLK_SRC_TCX0 && 798b111ab5aSJacob Keller clk_freq != ICE_TIME_REF_FREQ_25_000) { 799b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), 800b111ab5aSJacob Keller "TCX0 only supports 25 MHz frequency\n"); 801b111ab5aSJacob Keller return -EINVAL; 802b111ab5aSJacob Keller } 803b111ab5aSJacob Keller 804b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val); 805b111ab5aSJacob Keller if (err) 806b111ab5aSJacob Keller return err; 807b111ab5aSJacob Keller 808b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 809b111ab5aSJacob Keller if (err) 810b111ab5aSJacob Keller return err; 811b111ab5aSJacob Keller 812b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 813b111ab5aSJacob Keller if (err) 814b111ab5aSJacob Keller return err; 815b111ab5aSJacob Keller 816b111ab5aSJacob Keller /* Log the current clock configuration */ 817b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 818b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 819b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 820b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 821b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 822b111ab5aSJacob Keller 823b111ab5aSJacob Keller /* Disable the PLL before changing the clock source or frequency */ 824b111ab5aSJacob Keller if (dw24.field.ts_pll_enable) { 825b111ab5aSJacob Keller dw24.field.ts_pll_enable = 0; 826b111ab5aSJacob Keller 827b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 828b111ab5aSJacob Keller if (err) 829b111ab5aSJacob Keller return err; 830b111ab5aSJacob Keller } 831b111ab5aSJacob Keller 832b111ab5aSJacob Keller /* Set the frequency */ 833b111ab5aSJacob Keller dw9.field.time_ref_freq_sel = clk_freq; 834b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val); 835b111ab5aSJacob Keller if (err) 836b111ab5aSJacob Keller return err; 837b111ab5aSJacob Keller 838b111ab5aSJacob Keller /* Configure the TS PLL feedback divisor */ 839b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val); 840b111ab5aSJacob Keller if (err) 841b111ab5aSJacob Keller return err; 842b111ab5aSJacob Keller 843b111ab5aSJacob Keller dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; 844b111ab5aSJacob Keller dw19.field.tspll_ndivratio = 1; 845b111ab5aSJacob Keller 846b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val); 847b111ab5aSJacob Keller if (err) 848b111ab5aSJacob Keller return err; 849b111ab5aSJacob Keller 850b111ab5aSJacob Keller /* Configure the TS PLL post divisor */ 851b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val); 852b111ab5aSJacob Keller if (err) 853b111ab5aSJacob Keller return err; 854b111ab5aSJacob Keller 855b111ab5aSJacob Keller dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; 856b111ab5aSJacob Keller dw22.field.time1588clk_sel_div2 = 0; 857b111ab5aSJacob Keller 858b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val); 859b111ab5aSJacob Keller if (err) 860b111ab5aSJacob Keller return err; 861b111ab5aSJacob Keller 862b111ab5aSJacob Keller /* Configure the TS PLL pre divisor and clock source */ 863b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 864b111ab5aSJacob Keller if (err) 865b111ab5aSJacob Keller return err; 866b111ab5aSJacob Keller 867b111ab5aSJacob Keller dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div; 868b111ab5aSJacob Keller dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; 869b111ab5aSJacob Keller dw24.field.time_ref_sel = clk_src; 870b111ab5aSJacob Keller 871b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 872b111ab5aSJacob Keller if (err) 873b111ab5aSJacob Keller return err; 874b111ab5aSJacob Keller 875b111ab5aSJacob Keller /* Finally, enable the PLL */ 876b111ab5aSJacob Keller dw24.field.ts_pll_enable = 1; 877b111ab5aSJacob Keller 878b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 879b111ab5aSJacob Keller if (err) 880b111ab5aSJacob Keller return err; 881b111ab5aSJacob Keller 882b111ab5aSJacob Keller /* Wait to verify if the PLL locks */ 883b111ab5aSJacob Keller usleep_range(1000, 5000); 884b111ab5aSJacob Keller 885b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 886b111ab5aSJacob Keller if (err) 887b111ab5aSJacob Keller return err; 888b111ab5aSJacob Keller 889b111ab5aSJacob Keller if (!bwm_lf.field.plllock_true_lock_cri) { 890b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); 891b111ab5aSJacob Keller return -EBUSY; 892b111ab5aSJacob Keller } 893b111ab5aSJacob Keller 894b111ab5aSJacob Keller /* Log the current clock configuration */ 895b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 896b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 897b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 898b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 899b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 900b111ab5aSJacob Keller 901b111ab5aSJacob Keller return 0; 902b111ab5aSJacob Keller } 903b111ab5aSJacob Keller 904b111ab5aSJacob Keller /** 905b111ab5aSJacob Keller * ice_init_cgu_e822 - Initialize CGU with settings from firmware 906b111ab5aSJacob Keller * @hw: pointer to the HW structure 907b111ab5aSJacob Keller * 908b111ab5aSJacob Keller * Initialize the Clock Generation Unit of the E822 device. 909b111ab5aSJacob Keller */ 910b111ab5aSJacob Keller static int ice_init_cgu_e822(struct ice_hw *hw) 911b111ab5aSJacob Keller { 912b111ab5aSJacob Keller struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; 913b111ab5aSJacob Keller union tspll_cntr_bist_settings cntr_bist; 914b111ab5aSJacob Keller int err; 915b111ab5aSJacob Keller 916b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 917b111ab5aSJacob Keller &cntr_bist.val); 918b111ab5aSJacob Keller if (err) 919b111ab5aSJacob Keller return err; 920b111ab5aSJacob Keller 921b111ab5aSJacob Keller /* Disable sticky lock detection so lock err reported is accurate */ 922b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_0 = 0; 923b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_1 = 0; 924b111ab5aSJacob Keller 925b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 926b111ab5aSJacob Keller cntr_bist.val); 927b111ab5aSJacob Keller if (err) 928b111ab5aSJacob Keller return err; 929b111ab5aSJacob Keller 930b111ab5aSJacob Keller /* Configure the CGU PLL using the parameters from the function 931b111ab5aSJacob Keller * capabilities. 932b111ab5aSJacob Keller */ 933b111ab5aSJacob Keller err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref, 934b111ab5aSJacob Keller (enum ice_clk_src)ts_info->clk_src); 935b111ab5aSJacob Keller if (err) 936b111ab5aSJacob Keller return err; 937b111ab5aSJacob Keller 938b111ab5aSJacob Keller return 0; 939b111ab5aSJacob Keller } 940b111ab5aSJacob Keller 941b111ab5aSJacob Keller /** 9423a749623SJacob Keller * ice_ptp_set_vernier_wl - Set the window length for vernier calibration 9433a749623SJacob Keller * @hw: pointer to the HW struct 9443a749623SJacob Keller * 9453a749623SJacob Keller * Set the window length used for the vernier port calibration process. 9463a749623SJacob Keller */ 9473a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw) 9483a749623SJacob Keller { 9493a749623SJacob Keller u8 port; 9503a749623SJacob Keller 9513a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 9523a749623SJacob Keller int err; 9533a749623SJacob Keller 9543a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_WL, 9553a749623SJacob Keller PTP_VERNIER_WL); 9563a749623SJacob Keller if (err) { 9573a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n", 9583a749623SJacob Keller port, err); 9593a749623SJacob Keller return err; 9603a749623SJacob Keller } 9613a749623SJacob Keller } 9623a749623SJacob Keller 9633a749623SJacob Keller return 0; 9643a749623SJacob Keller } 9653a749623SJacob Keller 9663a749623SJacob Keller /** 9673a749623SJacob Keller * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization 9683a749623SJacob Keller * @hw: pointer to HW struct 9693a749623SJacob Keller * 9703a749623SJacob Keller * Perform PHC initialization steps specific to E822 devices. 9713a749623SJacob Keller */ 9723a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw) 9733a749623SJacob Keller { 974b111ab5aSJacob Keller int err; 9753a749623SJacob Keller u32 regval; 9763a749623SJacob Keller 9773a749623SJacob Keller /* Enable reading switch and PHY registers over the sideband queue */ 9783a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1) 9793a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2) 9803a749623SJacob Keller regval = rd32(hw, PF_SB_REM_DEV_CTL); 9813a749623SJacob Keller regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ | 9823a749623SJacob Keller PF_SB_REM_DEV_CTL_PHY0); 9833a749623SJacob Keller wr32(hw, PF_SB_REM_DEV_CTL, regval); 9843a749623SJacob Keller 985b111ab5aSJacob Keller /* Initialize the Clock Generation Unit */ 986b111ab5aSJacob Keller err = ice_init_cgu_e822(hw); 987b111ab5aSJacob Keller if (err) 988b111ab5aSJacob Keller return err; 989b111ab5aSJacob Keller 9903a749623SJacob Keller /* Set window length for all the ports */ 9913a749623SJacob Keller return ice_ptp_set_vernier_wl(hw); 9923a749623SJacob Keller } 9933a749623SJacob Keller 9943a749623SJacob Keller /** 9953a749623SJacob Keller * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time 9963a749623SJacob Keller * @hw: pointer to the HW struct 9973a749623SJacob Keller * @time: Time to initialize the PHY port clocks to 9983a749623SJacob Keller * 9993a749623SJacob Keller * Program the PHY port registers with a new initial time value. The port 10003a749623SJacob Keller * clock will be initialized once the driver issues an INIT_TIME sync 10013a749623SJacob Keller * command. The time value is the upper 32 bits of the PHY timer, usually in 10023a749623SJacob Keller * units of nominal nanoseconds. 10033a749623SJacob Keller */ 10043a749623SJacob Keller static int 10053a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) 10063a749623SJacob Keller { 10073a749623SJacob Keller u64 phy_time; 10083a749623SJacob Keller u8 port; 10093a749623SJacob Keller int err; 10103a749623SJacob Keller 10113a749623SJacob Keller /* The time represents the upper 32 bits of the PHY timer, so we need 10123a749623SJacob Keller * to shift to account for this when programming. 10133a749623SJacob Keller */ 10143a749623SJacob Keller phy_time = (u64)time << 32; 10153a749623SJacob Keller 10163a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 10173a749623SJacob Keller /* Tx case */ 10183a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 10193a749623SJacob Keller P_REG_TX_TIMER_INC_PRE_L, 10203a749623SJacob Keller phy_time); 10213a749623SJacob Keller if (err) 10223a749623SJacob Keller goto exit_err; 10233a749623SJacob Keller 10243a749623SJacob Keller /* Rx case */ 10253a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 10263a749623SJacob Keller P_REG_RX_TIMER_INC_PRE_L, 10273a749623SJacob Keller phy_time); 10283a749623SJacob Keller if (err) 10293a749623SJacob Keller goto exit_err; 10303a749623SJacob Keller } 10313a749623SJacob Keller 10323a749623SJacob Keller return 0; 10333a749623SJacob Keller 10343a749623SJacob Keller exit_err: 10353a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n", 10363a749623SJacob Keller port, err); 10373a749623SJacob Keller 10383a749623SJacob Keller return err; 10393a749623SJacob Keller } 10403a749623SJacob Keller 10413a749623SJacob Keller /** 10423a749623SJacob Keller * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust 10433a749623SJacob Keller * @hw: pointer to HW struct 10443a749623SJacob Keller * @port: Port number to be programmed 10453a749623SJacob Keller * @time: time in cycles to adjust the port Tx and Rx clocks 10463a749623SJacob Keller * 10473a749623SJacob Keller * Program the port for an atomic adjustment by writing the Tx and Rx timer 10483a749623SJacob Keller * registers. The atomic adjustment won't be completed until the driver issues 10493a749623SJacob Keller * an ADJ_TIME command. 10503a749623SJacob Keller * 10513a749623SJacob Keller * Note that time is not in units of nanoseconds. It is in clock time 10523a749623SJacob Keller * including the lower sub-nanosecond portion of the port timer. 10533a749623SJacob Keller * 10543a749623SJacob Keller * Negative adjustments are supported using 2s complement arithmetic. 10553a749623SJacob Keller */ 10563a749623SJacob Keller int 10573a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) 10583a749623SJacob Keller { 10593a749623SJacob Keller u32 l_time, u_time; 10603a749623SJacob Keller int err; 10613a749623SJacob Keller 10623a749623SJacob Keller l_time = lower_32_bits(time); 10633a749623SJacob Keller u_time = upper_32_bits(time); 10643a749623SJacob Keller 10653a749623SJacob Keller /* Tx case */ 10663a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L, 10673a749623SJacob Keller l_time); 10683a749623SJacob Keller if (err) 10693a749623SJacob Keller goto exit_err; 10703a749623SJacob Keller 10713a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U, 10723a749623SJacob Keller u_time); 10733a749623SJacob Keller if (err) 10743a749623SJacob Keller goto exit_err; 10753a749623SJacob Keller 10763a749623SJacob Keller /* Rx case */ 10773a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L, 10783a749623SJacob Keller l_time); 10793a749623SJacob Keller if (err) 10803a749623SJacob Keller goto exit_err; 10813a749623SJacob Keller 10823a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U, 10833a749623SJacob Keller u_time); 10843a749623SJacob Keller if (err) 10853a749623SJacob Keller goto exit_err; 10863a749623SJacob Keller 10873a749623SJacob Keller return 0; 10883a749623SJacob Keller 10893a749623SJacob Keller exit_err: 10903a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n", 10913a749623SJacob Keller port, err); 10923a749623SJacob Keller return err; 10933a749623SJacob Keller } 10943a749623SJacob Keller 10953a749623SJacob Keller /** 10963a749623SJacob Keller * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment 10973a749623SJacob Keller * @hw: pointer to HW struct 10983a749623SJacob Keller * @adj: adjustment in nanoseconds 10993a749623SJacob Keller * 11003a749623SJacob Keller * Prepare the PHY ports for an atomic time adjustment by programming the PHY 11013a749623SJacob Keller * Tx and Rx port registers. The actual adjustment is completed by issuing an 11023a749623SJacob Keller * ADJ_TIME or ADJ_TIME_AT_TIME sync command. 11033a749623SJacob Keller */ 11043a749623SJacob Keller static int 11053a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) 11063a749623SJacob Keller { 11073a749623SJacob Keller s64 cycles; 11083a749623SJacob Keller u8 port; 11093a749623SJacob Keller 11103a749623SJacob Keller /* The port clock supports adjustment of the sub-nanosecond portion of 11113a749623SJacob Keller * the clock. We shift the provided adjustment in nanoseconds to 11123a749623SJacob Keller * calculate the appropriate adjustment to program into the PHY ports. 11133a749623SJacob Keller */ 11143a749623SJacob Keller if (adj > 0) 11153a749623SJacob Keller cycles = (s64)adj << 32; 11163a749623SJacob Keller else 11173a749623SJacob Keller cycles = -(((s64)-adj) << 32); 11183a749623SJacob Keller 11193a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 11203a749623SJacob Keller int err; 11213a749623SJacob Keller 11223a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, cycles); 11233a749623SJacob Keller if (err) 11243a749623SJacob Keller return err; 11253a749623SJacob Keller } 11263a749623SJacob Keller 11273a749623SJacob Keller return 0; 11283a749623SJacob Keller } 11293a749623SJacob Keller 11303a749623SJacob Keller /** 11313a749623SJacob Keller * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment 11323a749623SJacob Keller * @hw: pointer to HW struct 11333a749623SJacob Keller * @incval: new increment value to prepare 11343a749623SJacob Keller * 11353a749623SJacob Keller * Prepare each of the PHY ports for a new increment value by programming the 11363a749623SJacob Keller * port's TIMETUS registers. The new increment value will be updated after 11373a749623SJacob Keller * issuing an INIT_INCVAL command. 11383a749623SJacob Keller */ 11393a749623SJacob Keller static int 11403a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval) 11413a749623SJacob Keller { 11423a749623SJacob Keller int err; 11433a749623SJacob Keller u8 port; 11443a749623SJacob Keller 11453a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 11463a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, 11473a749623SJacob Keller incval); 11483a749623SJacob Keller if (err) 11493a749623SJacob Keller goto exit_err; 11503a749623SJacob Keller } 11513a749623SJacob Keller 11523a749623SJacob Keller return 0; 11533a749623SJacob Keller 11543a749623SJacob Keller exit_err: 11553a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n", 11563a749623SJacob Keller port, err); 11573a749623SJacob Keller 11583a749623SJacob Keller return err; 11593a749623SJacob Keller } 11603a749623SJacob Keller 11613a749623SJacob Keller /** 11623a749623SJacob Keller * ice_ptp_read_port_capture - Read a port's local time capture 11633a749623SJacob Keller * @hw: pointer to HW struct 11643a749623SJacob Keller * @port: Port number to read 11653a749623SJacob Keller * @tx_ts: on return, the Tx port time capture 11663a749623SJacob Keller * @rx_ts: on return, the Rx port time capture 11673a749623SJacob Keller * 11683a749623SJacob Keller * Read the port's Tx and Rx local time capture values. 11693a749623SJacob Keller * 11703a749623SJacob Keller * Note this has no equivalent for the E810 devices. 11713a749623SJacob Keller */ 11723a749623SJacob Keller static int 11733a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) 11743a749623SJacob Keller { 11753a749623SJacob Keller int err; 11763a749623SJacob Keller 11773a749623SJacob Keller /* Tx case */ 11783a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts); 11793a749623SJacob Keller if (err) { 11803a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n", 11813a749623SJacob Keller err); 11823a749623SJacob Keller return err; 11833a749623SJacob Keller } 11843a749623SJacob Keller 11853a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n", 11863a749623SJacob Keller (unsigned long long)*tx_ts); 11873a749623SJacob Keller 11883a749623SJacob Keller /* Rx case */ 11893a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts); 11903a749623SJacob Keller if (err) { 11913a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n", 11923a749623SJacob Keller err); 11933a749623SJacob Keller return err; 11943a749623SJacob Keller } 11953a749623SJacob Keller 11963a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n", 11973a749623SJacob Keller (unsigned long long)*rx_ts); 11983a749623SJacob Keller 11993a749623SJacob Keller return 0; 12003a749623SJacob Keller } 12013a749623SJacob Keller 12023a749623SJacob Keller /** 12033a749623SJacob Keller * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command 12043a749623SJacob Keller * @hw: pointer to HW struct 12053a749623SJacob Keller * @port: Port to which cmd has to be sent 12063a749623SJacob Keller * @cmd: Command to be sent to the port 12073a749623SJacob Keller * 12083a749623SJacob Keller * Prepare the requested port for an upcoming timer sync command. 12093a749623SJacob Keller * 12103a749623SJacob Keller * Note there is no equivalent of this operation on E810, as that device 12113a749623SJacob Keller * always handles all external PHYs internally. 12123a749623SJacob Keller */ 12133a749623SJacob Keller static int 12143a749623SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) 12153a749623SJacob Keller { 12163a749623SJacob Keller u32 cmd_val, val; 12173a749623SJacob Keller u8 tmr_idx; 12183a749623SJacob Keller int err; 12193a749623SJacob Keller 12203a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 12213a749623SJacob Keller cmd_val = tmr_idx << SEL_PHY_SRC; 12223a749623SJacob Keller switch (cmd) { 12233a749623SJacob Keller case INIT_TIME: 12243a749623SJacob Keller cmd_val |= PHY_CMD_INIT_TIME; 12253a749623SJacob Keller break; 12263a749623SJacob Keller case INIT_INCVAL: 12273a749623SJacob Keller cmd_val |= PHY_CMD_INIT_INCVAL; 12283a749623SJacob Keller break; 12293a749623SJacob Keller case ADJ_TIME: 12303a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME; 12313a749623SJacob Keller break; 12323a749623SJacob Keller case READ_TIME: 12333a749623SJacob Keller cmd_val |= PHY_CMD_READ_TIME; 12343a749623SJacob Keller break; 12353a749623SJacob Keller case ADJ_TIME_AT_TIME: 12363a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; 12373a749623SJacob Keller break; 12383a749623SJacob Keller } 12393a749623SJacob Keller 12403a749623SJacob Keller /* Tx case */ 12413a749623SJacob Keller /* Read, modify, write */ 12423a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val); 12433a749623SJacob Keller if (err) { 12443a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n", 12453a749623SJacob Keller err); 12463a749623SJacob Keller return err; 12473a749623SJacob Keller } 12483a749623SJacob Keller 12493a749623SJacob Keller /* Modify necessary bits only and perform write */ 12503a749623SJacob Keller val &= ~TS_CMD_MASK; 12513a749623SJacob Keller val |= cmd_val; 12523a749623SJacob Keller 12533a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val); 12543a749623SJacob Keller if (err) { 12553a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n", 12563a749623SJacob Keller err); 12573a749623SJacob Keller return err; 12583a749623SJacob Keller } 12593a749623SJacob Keller 12603a749623SJacob Keller /* Rx case */ 12613a749623SJacob Keller /* Read, modify, write */ 12623a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val); 12633a749623SJacob Keller if (err) { 12643a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n", 12653a749623SJacob Keller err); 12663a749623SJacob Keller return err; 12673a749623SJacob Keller } 12683a749623SJacob Keller 12693a749623SJacob Keller /* Modify necessary bits only and perform write */ 12703a749623SJacob Keller val &= ~TS_CMD_MASK; 12713a749623SJacob Keller val |= cmd_val; 12723a749623SJacob Keller 12733a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val); 12743a749623SJacob Keller if (err) { 12753a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n", 12763a749623SJacob Keller err); 12773a749623SJacob Keller return err; 12783a749623SJacob Keller } 12793a749623SJacob Keller 12803a749623SJacob Keller return 0; 12813a749623SJacob Keller } 12823a749623SJacob Keller 12833a749623SJacob Keller /** 12843a749623SJacob Keller * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command 12853a749623SJacob Keller * @hw: pointer to the HW struct 12863a749623SJacob Keller * @cmd: timer command to prepare 12873a749623SJacob Keller * 12883a749623SJacob Keller * Prepare all ports connected to this device for an upcoming timer sync 12893a749623SJacob Keller * command. 12903a749623SJacob Keller */ 12913a749623SJacob Keller static int 12923a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 12933a749623SJacob Keller { 12943a749623SJacob Keller u8 port; 12953a749623SJacob Keller 12963a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 12973a749623SJacob Keller int err; 12983a749623SJacob Keller 12993a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, cmd); 13003a749623SJacob Keller if (err) 13013a749623SJacob Keller return err; 13023a749623SJacob Keller } 13033a749623SJacob Keller 13043a749623SJacob Keller return 0; 13053a749623SJacob Keller } 13063a749623SJacob Keller 13073a749623SJacob Keller /* E822 Vernier calibration functions 13083a749623SJacob Keller * 13093a749623SJacob Keller * The following functions are used as part of the vernier calibration of 13103a749623SJacob Keller * a port. This calibration increases the precision of the timestamps on the 13113a749623SJacob Keller * port. 13123a749623SJacob Keller */ 13133a749623SJacob Keller 13143a749623SJacob Keller /** 13153a749623SJacob Keller * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode 13163a749623SJacob Keller * @hw: pointer to HW struct 13173a749623SJacob Keller * @port: the port to read from 13183a749623SJacob Keller * @link_out: if non-NULL, holds link speed on success 13193a749623SJacob Keller * @fec_out: if non-NULL, holds FEC algorithm on success 13203a749623SJacob Keller * 13213a749623SJacob Keller * Read the serdes data for the PHY port and extract the link speed and FEC 13223a749623SJacob Keller * algorithm. 13233a749623SJacob Keller */ 13243a749623SJacob Keller static int 13253a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, 13263a749623SJacob Keller enum ice_ptp_link_spd *link_out, 13273a749623SJacob Keller enum ice_ptp_fec_mode *fec_out) 13283a749623SJacob Keller { 13293a749623SJacob Keller enum ice_ptp_link_spd link; 13303a749623SJacob Keller enum ice_ptp_fec_mode fec; 13313a749623SJacob Keller u32 serdes; 13323a749623SJacob Keller int err; 13333a749623SJacob Keller 13343a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes); 13353a749623SJacob Keller if (err) { 13363a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n"); 13373a749623SJacob Keller return err; 13383a749623SJacob Keller } 13393a749623SJacob Keller 13403a749623SJacob Keller /* Determine the FEC algorithm */ 13413a749623SJacob Keller fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes); 13423a749623SJacob Keller 13433a749623SJacob Keller serdes &= P_REG_LINK_SPEED_SERDES_M; 13443a749623SJacob Keller 13453a749623SJacob Keller /* Determine the link speed */ 13463a749623SJacob Keller if (fec == ICE_PTP_FEC_MODE_RS_FEC) { 13473a749623SJacob Keller switch (serdes) { 13483a749623SJacob Keller case ICE_PTP_SERDES_25G: 13493a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G_RS; 13503a749623SJacob Keller break; 13513a749623SJacob Keller case ICE_PTP_SERDES_50G: 13523a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G_RS; 13533a749623SJacob Keller break; 13543a749623SJacob Keller case ICE_PTP_SERDES_100G: 13553a749623SJacob Keller link = ICE_PTP_LNK_SPD_100G_RS; 13563a749623SJacob Keller break; 13573a749623SJacob Keller default: 13583a749623SJacob Keller return -EIO; 13593a749623SJacob Keller } 13603a749623SJacob Keller } else { 13613a749623SJacob Keller switch (serdes) { 13623a749623SJacob Keller case ICE_PTP_SERDES_1G: 13633a749623SJacob Keller link = ICE_PTP_LNK_SPD_1G; 13643a749623SJacob Keller break; 13653a749623SJacob Keller case ICE_PTP_SERDES_10G: 13663a749623SJacob Keller link = ICE_PTP_LNK_SPD_10G; 13673a749623SJacob Keller break; 13683a749623SJacob Keller case ICE_PTP_SERDES_25G: 13693a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G; 13703a749623SJacob Keller break; 13713a749623SJacob Keller case ICE_PTP_SERDES_40G: 13723a749623SJacob Keller link = ICE_PTP_LNK_SPD_40G; 13733a749623SJacob Keller break; 13743a749623SJacob Keller case ICE_PTP_SERDES_50G: 13753a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G; 13763a749623SJacob Keller break; 13773a749623SJacob Keller default: 13783a749623SJacob Keller return -EIO; 13793a749623SJacob Keller } 13803a749623SJacob Keller } 13813a749623SJacob Keller 13823a749623SJacob Keller if (link_out) 13833a749623SJacob Keller *link_out = link; 13843a749623SJacob Keller if (fec_out) 13853a749623SJacob Keller *fec_out = fec; 13863a749623SJacob Keller 13873a749623SJacob Keller return 0; 13883a749623SJacob Keller } 13893a749623SJacob Keller 13903a749623SJacob Keller /** 13913a749623SJacob Keller * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp 13923a749623SJacob Keller * @hw: pointer to HW struct 13933a749623SJacob Keller * @port: to configure the quad for 13943a749623SJacob Keller */ 13953a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) 13963a749623SJacob Keller { 13973a749623SJacob Keller enum ice_ptp_link_spd link_spd; 13983a749623SJacob Keller int err; 13993a749623SJacob Keller u32 val; 14003a749623SJacob Keller u8 quad; 14013a749623SJacob Keller 14023a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL); 14033a749623SJacob Keller if (err) { 14043a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n", 14053a749623SJacob Keller err); 14063a749623SJacob Keller return; 14073a749623SJacob Keller } 14083a749623SJacob Keller 14093a749623SJacob Keller quad = port / ICE_PORTS_PER_QUAD; 14103a749623SJacob Keller 14113a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); 14123a749623SJacob Keller if (err) { 14133a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n", 14143a749623SJacob Keller err); 14153a749623SJacob Keller return; 14163a749623SJacob Keller } 14173a749623SJacob Keller 14183a749623SJacob Keller if (link_spd >= ICE_PTP_LNK_SPD_40G) 14193a749623SJacob Keller val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 14203a749623SJacob Keller else 14213a749623SJacob Keller val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 14223a749623SJacob Keller 14233a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); 14243a749623SJacob Keller if (err) { 14253a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n", 14263a749623SJacob Keller err); 14273a749623SJacob Keller return; 14283a749623SJacob Keller } 14293a749623SJacob Keller } 14303a749623SJacob Keller 14313a749623SJacob Keller /** 14323a749623SJacob Keller * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822 14333a749623SJacob Keller * @hw: pointer to the HW structure 14343a749623SJacob Keller * @port: the port to configure 14353a749623SJacob Keller * 14363a749623SJacob Keller * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC 14373a749623SJacob Keller * hardware clock time units (TUs). That is, determine the number of TUs per 14383a749623SJacob Keller * serdes unit interval, and program the UIX registers with this conversion. 14393a749623SJacob Keller * 14403a749623SJacob Keller * This conversion is used as part of the calibration process when determining 14413a749623SJacob Keller * the additional error of a timestamp vs the real time of transmission or 14423a749623SJacob Keller * receipt of the packet. 14433a749623SJacob Keller * 14443a749623SJacob Keller * Hardware uses the number of TUs per 66 UIs, written to the UIX registers 14453a749623SJacob Keller * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks. 14463a749623SJacob Keller * 14473a749623SJacob Keller * To calculate the conversion ratio, we use the following facts: 14483a749623SJacob Keller * 14493a749623SJacob Keller * a) the clock frequency in Hz (cycles per second) 14503a749623SJacob Keller * b) the number of TUs per cycle (the increment value of the clock) 14513a749623SJacob Keller * c) 1 second per 1 billion nanoseconds 14523a749623SJacob Keller * d) the duration of 66 UIs in nanoseconds 14533a749623SJacob Keller * 14543a749623SJacob Keller * Given these facts, we can use the following table to work out what ratios 14553a749623SJacob Keller * to multiply in order to get the number of TUs per 66 UIs: 14563a749623SJacob Keller * 14573a749623SJacob Keller * cycles | 1 second | incval (TUs) | nanoseconds 14583a749623SJacob Keller * -------+--------------+--------------+------------- 14593a749623SJacob Keller * second | 1 billion ns | cycle | 66 UIs 14603a749623SJacob Keller * 14613a749623SJacob Keller * To perform the multiplication using integers without too much loss of 14623a749623SJacob Keller * precision, we can take use the following equation: 14633a749623SJacob Keller * 14643a749623SJacob Keller * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion) 14653a749623SJacob Keller * 14663a749623SJacob Keller * We scale up to using 6600 UI instead of 66 in order to avoid fractional 14673a749623SJacob Keller * nanosecond UIs (66 UI at 10G/40G is 6.4 ns) 14683a749623SJacob Keller * 14693a749623SJacob Keller * The increment value has a maximum expected range of about 34 bits, while 14703a749623SJacob Keller * the frequency value is about 29 bits. Multiplying these values shouldn't 14713a749623SJacob Keller * overflow the 64 bits. However, we must then further multiply them again by 14723a749623SJacob Keller * the Serdes unit interval duration. To avoid overflow here, we split the 14733a749623SJacob Keller * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and 14743a749623SJacob Keller * a divide by 390,625,000. This does lose some precision, but avoids 14753a749623SJacob Keller * miscalculation due to arithmetic overflow. 14763a749623SJacob Keller */ 14773a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) 14783a749623SJacob Keller { 14793a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, uix; 14803a749623SJacob Keller int err; 14813a749623SJacob Keller 14823a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 14833a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 14843a749623SJacob Keller 14853a749623SJacob Keller /* Calculate TUs per second divided by 256 */ 14863a749623SJacob Keller tu_per_sec = (cur_freq * clk_incval) >> 8; 14873a749623SJacob Keller 14883a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */ 14893a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */ 14903a749623SJacob Keller 14913a749623SJacob Keller /* Program the 10Gb/40Gb conversion ratio */ 14923a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000); 14933a749623SJacob Keller 14943a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L, 14953a749623SJacob Keller uix); 14963a749623SJacob Keller if (err) { 14973a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n", 14983a749623SJacob Keller err); 14993a749623SJacob Keller return err; 15003a749623SJacob Keller } 15013a749623SJacob Keller 15023a749623SJacob Keller /* Program the 25Gb/100Gb conversion ratio */ 15033a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000); 15043a749623SJacob Keller 15053a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L, 15063a749623SJacob Keller uix); 15073a749623SJacob Keller if (err) { 15083a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n", 15093a749623SJacob Keller err); 15103a749623SJacob Keller return err; 15113a749623SJacob Keller } 15123a749623SJacob Keller 15133a749623SJacob Keller return 0; 15143a749623SJacob Keller } 15153a749623SJacob Keller 15163a749623SJacob Keller /** 15173a749623SJacob Keller * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle 15183a749623SJacob Keller * @hw: pointer to the HW struct 15193a749623SJacob Keller * @port: port to configure 15203a749623SJacob Keller * 15213a749623SJacob Keller * Configure the number of TUs for the PAR and PCS clocks used as part of the 15223a749623SJacob Keller * timestamp calibration process. This depends on the link speed, as the PHY 15233a749623SJacob Keller * uses different markers depending on the speed. 15243a749623SJacob Keller * 15253a749623SJacob Keller * 1Gb/10Gb/25Gb: 15263a749623SJacob Keller * - Tx/Rx PAR/PCS markers 15273a749623SJacob Keller * 15283a749623SJacob Keller * 25Gb RS: 15293a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 15303a749623SJacob Keller * 15313a749623SJacob Keller * 40Gb/50Gb: 15323a749623SJacob Keller * - Tx/Rx PAR/PCS markers 15333a749623SJacob Keller * - Rx Deskew PAR/PCS markers 15343a749623SJacob Keller * 15353a749623SJacob Keller * 50G RS and 100GB RS: 15363a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 15373a749623SJacob Keller * - Rx Deskew PAR/PCS markers 15383a749623SJacob Keller * - Tx PAR/PCS markers 15393a749623SJacob Keller * 15403a749623SJacob Keller * To calculate the conversion, we use the PHC clock frequency (cycles per 15413a749623SJacob Keller * second), the increment value (TUs per cycle), and the related PHY clock 15423a749623SJacob Keller * frequency to calculate the TUs per unit of the PHY link clock. The 15433a749623SJacob Keller * following table shows how the units convert: 15443a749623SJacob Keller * 15453a749623SJacob Keller * cycles | TUs | second 15463a749623SJacob Keller * -------+-------+-------- 15473a749623SJacob Keller * second | cycle | cycles 15483a749623SJacob Keller * 15493a749623SJacob Keller * For each conversion register, look up the appropriate frequency from the 15503a749623SJacob Keller * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program 15513a749623SJacob Keller * this to the appropriate register, preparing hardware to perform timestamp 15523a749623SJacob Keller * calibration to calculate the total Tx or Rx offset to adjust the timestamp 15533a749623SJacob Keller * in order to calibrate for the internal PHY delays. 15543a749623SJacob Keller * 15553a749623SJacob Keller * Note that the increment value ranges up to ~34 bits, and the clock 15563a749623SJacob Keller * frequency is ~29 bits, so multiplying them together should fit within the 15573a749623SJacob Keller * 64 bit arithmetic. 15583a749623SJacob Keller */ 15593a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) 15603a749623SJacob Keller { 15613a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, phy_tus; 15623a749623SJacob Keller enum ice_ptp_link_spd link_spd; 15633a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 15643a749623SJacob Keller int err; 15653a749623SJacob Keller 15663a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 15673a749623SJacob Keller if (err) 15683a749623SJacob Keller return err; 15693a749623SJacob Keller 15703a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 15713a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 15723a749623SJacob Keller 15733a749623SJacob Keller /* Calculate TUs per cycle of the PHC clock */ 15743a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 15753a749623SJacob Keller 15763a749623SJacob Keller /* For each PHY conversion register, look up the appropriate link 15773a749623SJacob Keller * speed frequency and determine the TUs per that clock's cycle time. 15783a749623SJacob Keller * Split this into a high and low value and then program the 15793a749623SJacob Keller * appropriate register. If that link speed does not use the 15803a749623SJacob Keller * associated register, write zeros to clear it instead. 15813a749623SJacob Keller */ 15823a749623SJacob Keller 15833a749623SJacob Keller /* P_REG_PAR_TX_TUS */ 15843a749623SJacob Keller if (e822_vernier[link_spd].tx_par_clk) 15853a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 15863a749623SJacob Keller e822_vernier[link_spd].tx_par_clk); 15873a749623SJacob Keller else 15883a749623SJacob Keller phy_tus = 0; 15893a749623SJacob Keller 15903a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L, 15913a749623SJacob Keller phy_tus); 15923a749623SJacob Keller if (err) 15933a749623SJacob Keller return err; 15943a749623SJacob Keller 15953a749623SJacob Keller /* P_REG_PAR_RX_TUS */ 15963a749623SJacob Keller if (e822_vernier[link_spd].rx_par_clk) 15973a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 15983a749623SJacob Keller e822_vernier[link_spd].rx_par_clk); 15993a749623SJacob Keller else 16003a749623SJacob Keller phy_tus = 0; 16013a749623SJacob Keller 16023a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L, 16033a749623SJacob Keller phy_tus); 16043a749623SJacob Keller if (err) 16053a749623SJacob Keller return err; 16063a749623SJacob Keller 16073a749623SJacob Keller /* P_REG_PCS_TX_TUS */ 16083a749623SJacob Keller if (e822_vernier[link_spd].tx_pcs_clk) 16093a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16103a749623SJacob Keller e822_vernier[link_spd].tx_pcs_clk); 16113a749623SJacob Keller else 16123a749623SJacob Keller phy_tus = 0; 16133a749623SJacob Keller 16143a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L, 16153a749623SJacob Keller phy_tus); 16163a749623SJacob Keller if (err) 16173a749623SJacob Keller return err; 16183a749623SJacob Keller 16193a749623SJacob Keller /* P_REG_PCS_RX_TUS */ 16203a749623SJacob Keller if (e822_vernier[link_spd].rx_pcs_clk) 16213a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16223a749623SJacob Keller e822_vernier[link_spd].rx_pcs_clk); 16233a749623SJacob Keller else 16243a749623SJacob Keller phy_tus = 0; 16253a749623SJacob Keller 16263a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L, 16273a749623SJacob Keller phy_tus); 16283a749623SJacob Keller if (err) 16293a749623SJacob Keller return err; 16303a749623SJacob Keller 16313a749623SJacob Keller /* P_REG_DESK_PAR_TX_TUS */ 16323a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_par) 16333a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16343a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_par); 16353a749623SJacob Keller else 16363a749623SJacob Keller phy_tus = 0; 16373a749623SJacob Keller 16383a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L, 16393a749623SJacob Keller phy_tus); 16403a749623SJacob Keller if (err) 16413a749623SJacob Keller return err; 16423a749623SJacob Keller 16433a749623SJacob Keller /* P_REG_DESK_PAR_RX_TUS */ 16443a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_par) 16453a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16463a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_par); 16473a749623SJacob Keller else 16483a749623SJacob Keller phy_tus = 0; 16493a749623SJacob Keller 16503a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L, 16513a749623SJacob Keller phy_tus); 16523a749623SJacob Keller if (err) 16533a749623SJacob Keller return err; 16543a749623SJacob Keller 16553a749623SJacob Keller /* P_REG_DESK_PCS_TX_TUS */ 16563a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_pcs) 16573a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16583a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_pcs); 16593a749623SJacob Keller else 16603a749623SJacob Keller phy_tus = 0; 16613a749623SJacob Keller 16623a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L, 16633a749623SJacob Keller phy_tus); 16643a749623SJacob Keller if (err) 16653a749623SJacob Keller return err; 16663a749623SJacob Keller 16673a749623SJacob Keller /* P_REG_DESK_PCS_RX_TUS */ 16683a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_pcs) 16693a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16703a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_pcs); 16713a749623SJacob Keller else 16723a749623SJacob Keller phy_tus = 0; 16733a749623SJacob Keller 16743a749623SJacob Keller return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L, 16753a749623SJacob Keller phy_tus); 16763a749623SJacob Keller } 16773a749623SJacob Keller 16783a749623SJacob Keller /** 16793a749623SJacob Keller * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port 16803a749623SJacob Keller * @hw: pointer to the HW struct 16813a749623SJacob Keller * @link_spd: the Link speed to calculate for 16823a749623SJacob Keller * 16833a749623SJacob Keller * Calculate the fixed offset due to known static latency data. 16843a749623SJacob Keller */ 16853a749623SJacob Keller static u64 16863a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 16873a749623SJacob Keller { 16883a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 16893a749623SJacob Keller 16903a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 16913a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 16923a749623SJacob Keller 16933a749623SJacob Keller /* Calculate TUs per second */ 16943a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 16953a749623SJacob Keller 16963a749623SJacob Keller /* Calculate number of TUs to add for the fixed Tx latency. Since the 16973a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 16983a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 16993a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 17003a749623SJacob Keller * divisions by 1e4 first then by 1e7. 17013a749623SJacob Keller */ 17023a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 17033a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].tx_fixed_delay; 17043a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 17053a749623SJacob Keller 17063a749623SJacob Keller return fixed_offset; 17073a749623SJacob Keller } 17083a749623SJacob Keller 17093a749623SJacob Keller /** 1710a69f1cb6SJacob Keller * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset 1711a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1712a69f1cb6SJacob Keller * @port: the PHY port to configure 1713a69f1cb6SJacob Keller * 1714a69f1cb6SJacob Keller * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to 1715a69f1cb6SJacob Keller * adjust Tx timestamps by. This is calculated by combining some known static 1716a69f1cb6SJacob Keller * latency along with the Vernier offset computations done by hardware. 1717a69f1cb6SJacob Keller * 1718a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 1719a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 1720a69f1cb6SJacob Keller * has measured the offset. 1721a69f1cb6SJacob Keller * 1722a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 1723a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 1724a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 1725a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 1726a69f1cb6SJacob Keller */ 1727a69f1cb6SJacob Keller static int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) 1728a69f1cb6SJacob Keller { 1729a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 1730a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 1731a69f1cb6SJacob Keller u64 total_offset, val; 1732a69f1cb6SJacob Keller int err; 1733a69f1cb6SJacob Keller 1734a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1735a69f1cb6SJacob Keller if (err) 1736a69f1cb6SJacob Keller return err; 1737a69f1cb6SJacob Keller 1738a69f1cb6SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 1739a69f1cb6SJacob Keller 1740a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 1741a69f1cb6SJacob Keller * the total offset. 1742a69f1cb6SJacob Keller */ 1743a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G || 1744a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_10G || 1745a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1746a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G_RS || 1747a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1748a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1749a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1750a69f1cb6SJacob Keller P_REG_PAR_PCS_TX_OFFSET_L, 1751a69f1cb6SJacob Keller &val); 1752a69f1cb6SJacob Keller if (err) 1753a69f1cb6SJacob Keller return err; 1754a69f1cb6SJacob Keller 1755a69f1cb6SJacob Keller total_offset += val; 1756a69f1cb6SJacob Keller } 1757a69f1cb6SJacob Keller 1758a69f1cb6SJacob Keller /* For Tx, we only need to use the second Vernier offset for 1759a69f1cb6SJacob Keller * multi-lane link speeds with RS-FEC. The lanes will always be 1760a69f1cb6SJacob Keller * aligned. 1761a69f1cb6SJacob Keller */ 1762a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_50G_RS || 1763a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1764a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1765a69f1cb6SJacob Keller P_REG_PAR_TX_TIME_L, 1766a69f1cb6SJacob Keller &val); 1767a69f1cb6SJacob Keller if (err) 1768a69f1cb6SJacob Keller return err; 1769a69f1cb6SJacob Keller 1770a69f1cb6SJacob Keller total_offset += val; 1771a69f1cb6SJacob Keller } 1772a69f1cb6SJacob Keller 1773a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 1774a69f1cb6SJacob Keller * PHY and indicate that the Tx offset is ready. After this, 1775a69f1cb6SJacob Keller * timestamps will be enabled. 1776a69f1cb6SJacob Keller */ 1777a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 1778a69f1cb6SJacob Keller total_offset); 1779a69f1cb6SJacob Keller if (err) 1780a69f1cb6SJacob Keller return err; 1781a69f1cb6SJacob Keller 1782a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 1783a69f1cb6SJacob Keller if (err) 1784a69f1cb6SJacob Keller return err; 1785a69f1cb6SJacob Keller 1786a69f1cb6SJacob Keller return 0; 1787a69f1cb6SJacob Keller } 1788a69f1cb6SJacob Keller 1789a69f1cb6SJacob Keller /** 17903a749623SJacob Keller * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode 17913a749623SJacob Keller * @hw: pointer to the HW struct 17923a749623SJacob Keller * @port: the PHY port to configure 17933a749623SJacob Keller * 17943a749623SJacob Keller * Calculate and program the fixed Tx offset, and indicate that the offset is 17953a749623SJacob Keller * ready. This can be used when operating in bypass mode. 17963a749623SJacob Keller */ 17973a749623SJacob Keller static int 17983a749623SJacob Keller ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port) 17993a749623SJacob Keller { 18003a749623SJacob Keller enum ice_ptp_link_spd link_spd; 18013a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 18023a749623SJacob Keller u64 total_offset; 18033a749623SJacob Keller int err; 18043a749623SJacob Keller 18053a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 18063a749623SJacob Keller if (err) 18073a749623SJacob Keller return err; 18083a749623SJacob Keller 18093a749623SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 18103a749623SJacob Keller 18113a749623SJacob Keller /* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L 18123a749623SJacob Keller * register, then indicate that the Tx offset is ready. After this, 18133a749623SJacob Keller * timestamps will be enabled. 18143a749623SJacob Keller * 18153a749623SJacob Keller * Note that this skips including the more precise offsets generated 18163a749623SJacob Keller * by the Vernier calibration. 18173a749623SJacob Keller */ 18183a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 18193a749623SJacob Keller total_offset); 18203a749623SJacob Keller if (err) 18213a749623SJacob Keller return err; 18223a749623SJacob Keller 18233a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 18243a749623SJacob Keller if (err) 18253a749623SJacob Keller return err; 18263a749623SJacob Keller 18273a749623SJacob Keller return 0; 18283a749623SJacob Keller } 18293a749623SJacob Keller 18303a749623SJacob Keller /** 1831a69f1cb6SJacob Keller * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx 1832a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1833a69f1cb6SJacob Keller * @port: the PHY port to adjust for 1834a69f1cb6SJacob Keller * @link_spd: the current link speed of the PHY 1835a69f1cb6SJacob Keller * @fec_mode: the current FEC mode of the PHY 1836a69f1cb6SJacob Keller * @pmd_adj: on return, the amount to adjust the Rx total offset by 1837a69f1cb6SJacob Keller * 1838a69f1cb6SJacob Keller * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY. 1839a69f1cb6SJacob Keller * This varies by link speed and FEC mode. The value calculated accounts for 1840a69f1cb6SJacob Keller * various delays caused when receiving a packet. 1841a69f1cb6SJacob Keller */ 1842a69f1cb6SJacob Keller static int 1843a69f1cb6SJacob Keller ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, 1844a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd, 1845a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj) 1846a69f1cb6SJacob Keller { 1847a69f1cb6SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, mult, adj; 1848a69f1cb6SJacob Keller u8 pmd_align; 1849a69f1cb6SJacob Keller u32 val; 1850a69f1cb6SJacob Keller int err; 1851a69f1cb6SJacob Keller 1852a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val); 1853a69f1cb6SJacob Keller if (err) { 1854a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n", 1855a69f1cb6SJacob Keller err); 1856a69f1cb6SJacob Keller return err; 1857a69f1cb6SJacob Keller } 1858a69f1cb6SJacob Keller 1859a69f1cb6SJacob Keller pmd_align = (u8)val; 1860a69f1cb6SJacob Keller 1861a69f1cb6SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1862a69f1cb6SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1863a69f1cb6SJacob Keller 1864a69f1cb6SJacob Keller /* Calculate TUs per second */ 1865a69f1cb6SJacob Keller tu_per_sec = cur_freq * clk_incval; 1866a69f1cb6SJacob Keller 1867a69f1cb6SJacob Keller /* The PMD alignment adjustment measurement depends on the link speed, 1868a69f1cb6SJacob Keller * and whether FEC is enabled. For each link speed, the alignment 1869a69f1cb6SJacob Keller * adjustment is calculated by dividing a value by the length of 1870a69f1cb6SJacob Keller * a Time Unit in nanoseconds. 1871a69f1cb6SJacob Keller * 1872a69f1cb6SJacob Keller * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8 1873a69f1cb6SJacob Keller * 10G: align == 65 ? 0 : (align * 0.1 * 32/33) 1874a69f1cb6SJacob Keller * 10G w/FEC: align * 0.1 * 32/33 1875a69f1cb6SJacob Keller * 25G: align == 65 ? 0 : (align * 0.4 * 32/33) 1876a69f1cb6SJacob Keller * 25G w/FEC: align * 0.4 * 32/33 1877a69f1cb6SJacob Keller * 40G: align == 65 ? 0 : (align * 0.1 * 32/33) 1878a69f1cb6SJacob Keller * 40G w/FEC: align * 0.1 * 32/33 1879a69f1cb6SJacob Keller * 50G: align == 65 ? 0 : (align * 0.4 * 32/33) 1880a69f1cb6SJacob Keller * 50G w/FEC: align * 0.8 * 32/33 1881a69f1cb6SJacob Keller * 1882a69f1cb6SJacob Keller * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33. 1883a69f1cb6SJacob Keller * 1884a69f1cb6SJacob Keller * To allow for calculating this value using integer arithmetic, we 1885a69f1cb6SJacob Keller * instead start with the number of TUs per second, (inverse of the 1886a69f1cb6SJacob Keller * length of a Time Unit in nanoseconds), multiply by a value based 1887a69f1cb6SJacob Keller * on the PMD alignment register, and then divide by the right value 1888a69f1cb6SJacob Keller * calculated based on the table above. To avoid integer overflow this 1889a69f1cb6SJacob Keller * division is broken up into a step of dividing by 125 first. 1890a69f1cb6SJacob Keller */ 1891a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G) { 1892a69f1cb6SJacob Keller if (pmd_align == 4) 1893a69f1cb6SJacob Keller mult = 10; 1894a69f1cb6SJacob Keller else 1895a69f1cb6SJacob Keller mult = (pmd_align + 6) % 10; 1896a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_10G || 1897a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1898a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1899a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1900a69f1cb6SJacob Keller /* If Clause 74 FEC, always calculate PMD adjust */ 1901a69f1cb6SJacob Keller if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74) 1902a69f1cb6SJacob Keller mult = pmd_align; 1903a69f1cb6SJacob Keller else 1904a69f1cb6SJacob Keller mult = 0; 1905a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS || 1906a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 1907a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1908a69f1cb6SJacob Keller if (pmd_align < 17) 1909a69f1cb6SJacob Keller mult = pmd_align + 40; 1910a69f1cb6SJacob Keller else 1911a69f1cb6SJacob Keller mult = pmd_align; 1912a69f1cb6SJacob Keller } else { 1913a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n", 1914a69f1cb6SJacob Keller link_spd); 1915a69f1cb6SJacob Keller mult = 0; 1916a69f1cb6SJacob Keller } 1917a69f1cb6SJacob Keller 1918a69f1cb6SJacob Keller /* In some cases, there's no need to adjust for the PMD alignment */ 1919a69f1cb6SJacob Keller if (!mult) { 1920a69f1cb6SJacob Keller *pmd_adj = 0; 1921a69f1cb6SJacob Keller return 0; 1922a69f1cb6SJacob Keller } 1923a69f1cb6SJacob Keller 1924a69f1cb6SJacob Keller /* Calculate the adjustment by multiplying TUs per second by the 1925a69f1cb6SJacob Keller * appropriate multiplier and divisor. To avoid overflow, we first 1926a69f1cb6SJacob Keller * divide by 125, and then handle remaining divisor based on the link 1927a69f1cb6SJacob Keller * speed pmd_adj_divisor value. 1928a69f1cb6SJacob Keller */ 1929a69f1cb6SJacob Keller adj = div_u64(tu_per_sec, 125); 1930a69f1cb6SJacob Keller adj *= mult; 1931a69f1cb6SJacob Keller adj = div_u64(adj, e822_vernier[link_spd].pmd_adj_divisor); 1932a69f1cb6SJacob Keller 1933a69f1cb6SJacob Keller /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx 1934a69f1cb6SJacob Keller * cycle count is necessary. 1935a69f1cb6SJacob Keller */ 1936a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_25G_RS) { 1937a69f1cb6SJacob Keller u64 cycle_adj; 1938a69f1cb6SJacob Keller u8 rx_cycle; 1939a69f1cb6SJacob Keller 1940a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT, 1941a69f1cb6SJacob Keller &val); 1942a69f1cb6SJacob Keller if (err) { 1943a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n", 1944a69f1cb6SJacob Keller err); 1945a69f1cb6SJacob Keller return err; 1946a69f1cb6SJacob Keller } 1947a69f1cb6SJacob Keller 1948a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M; 1949a69f1cb6SJacob Keller if (rx_cycle) { 1950a69f1cb6SJacob Keller mult = (4 - rx_cycle) * 40; 1951a69f1cb6SJacob Keller 1952a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1953a69f1cb6SJacob Keller cycle_adj *= mult; 1954a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1955a69f1cb6SJacob Keller 1956a69f1cb6SJacob Keller adj += cycle_adj; 1957a69f1cb6SJacob Keller } 1958a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) { 1959a69f1cb6SJacob Keller u64 cycle_adj; 1960a69f1cb6SJacob Keller u8 rx_cycle; 1961a69f1cb6SJacob Keller 1962a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT, 1963a69f1cb6SJacob Keller &val); 1964a69f1cb6SJacob Keller if (err) { 1965a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n", 1966a69f1cb6SJacob Keller err); 1967a69f1cb6SJacob Keller return err; 1968a69f1cb6SJacob Keller } 1969a69f1cb6SJacob Keller 1970a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M; 1971a69f1cb6SJacob Keller if (rx_cycle) { 1972a69f1cb6SJacob Keller mult = rx_cycle * 40; 1973a69f1cb6SJacob Keller 1974a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1975a69f1cb6SJacob Keller cycle_adj *= mult; 1976a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1977a69f1cb6SJacob Keller 1978a69f1cb6SJacob Keller adj += cycle_adj; 1979a69f1cb6SJacob Keller } 1980a69f1cb6SJacob Keller } 1981a69f1cb6SJacob Keller 1982a69f1cb6SJacob Keller /* Return the calculated adjustment */ 1983a69f1cb6SJacob Keller *pmd_adj = adj; 1984a69f1cb6SJacob Keller 1985a69f1cb6SJacob Keller return 0; 1986a69f1cb6SJacob Keller } 1987a69f1cb6SJacob Keller 1988a69f1cb6SJacob Keller /** 19893a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 19903a749623SJacob Keller * @hw: pointer to HW struct 19913a749623SJacob Keller * @link_spd: The Link speed to calculate for 19923a749623SJacob Keller * 19933a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 19943a749623SJacob Keller */ 19953a749623SJacob Keller static u64 19963a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 19973a749623SJacob Keller { 19983a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 19993a749623SJacob Keller 20003a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 20013a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 20023a749623SJacob Keller 20033a749623SJacob Keller /* Calculate TUs per second */ 20043a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 20053a749623SJacob Keller 20063a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 20073a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 20083a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 20093a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 20103a749623SJacob Keller * divisions by 1e4 first then by 1e7. 20113a749623SJacob Keller */ 20123a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 20133a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 20143a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 20153a749623SJacob Keller 20163a749623SJacob Keller return fixed_offset; 20173a749623SJacob Keller } 20183a749623SJacob Keller 20193a749623SJacob Keller /** 2020a69f1cb6SJacob Keller * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset 2021a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2022a69f1cb6SJacob Keller * @port: the PHY port to configure 2023a69f1cb6SJacob Keller * 2024a69f1cb6SJacob Keller * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to 2025a69f1cb6SJacob Keller * adjust Rx timestamps by. This combines calculations from the Vernier offset 2026a69f1cb6SJacob Keller * measurements taken in hardware with some data about known fixed delay as 2027a69f1cb6SJacob Keller * well as adjusting for multi-lane alignment delay. 2028a69f1cb6SJacob Keller * 2029a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 2030a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 2031a69f1cb6SJacob Keller * has measured the offset. 2032a69f1cb6SJacob Keller * 2033a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 2034a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 2035a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 2036a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 2037a69f1cb6SJacob Keller */ 2038a69f1cb6SJacob Keller static int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) 2039a69f1cb6SJacob Keller { 2040a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 2041a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 2042a69f1cb6SJacob Keller u64 total_offset, pmd, val; 2043a69f1cb6SJacob Keller int err; 2044a69f1cb6SJacob Keller 2045a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 2046a69f1cb6SJacob Keller if (err) 2047a69f1cb6SJacob Keller return err; 2048a69f1cb6SJacob Keller 2049a69f1cb6SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 2050a69f1cb6SJacob Keller 2051a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 2052a69f1cb6SJacob Keller * the total offset. 2053a69f1cb6SJacob Keller */ 2054a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2055a69f1cb6SJacob Keller P_REG_PAR_PCS_RX_OFFSET_L, 2056a69f1cb6SJacob Keller &val); 2057a69f1cb6SJacob Keller if (err) 2058a69f1cb6SJacob Keller return err; 2059a69f1cb6SJacob Keller 2060a69f1cb6SJacob Keller total_offset += val; 2061a69f1cb6SJacob Keller 2062a69f1cb6SJacob Keller /* For Rx, all multi-lane link speeds include a second Vernier 2063a69f1cb6SJacob Keller * calibration, because the lanes might not be aligned. 2064a69f1cb6SJacob Keller */ 2065a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_40G || 2066a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G || 2067a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 2068a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 2069a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2070a69f1cb6SJacob Keller P_REG_PAR_RX_TIME_L, 2071a69f1cb6SJacob Keller &val); 2072a69f1cb6SJacob Keller if (err) 2073a69f1cb6SJacob Keller return err; 2074a69f1cb6SJacob Keller 2075a69f1cb6SJacob Keller total_offset += val; 2076a69f1cb6SJacob Keller } 2077a69f1cb6SJacob Keller 2078a69f1cb6SJacob Keller /* In addition, Rx must account for the PMD alignment */ 2079a69f1cb6SJacob Keller err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd); 2080a69f1cb6SJacob Keller if (err) 2081a69f1cb6SJacob Keller return err; 2082a69f1cb6SJacob Keller 2083a69f1cb6SJacob Keller /* For RS-FEC, this adjustment adds delay, but for other modes, it 2084a69f1cb6SJacob Keller * subtracts delay. 2085a69f1cb6SJacob Keller */ 2086a69f1cb6SJacob Keller if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC) 2087a69f1cb6SJacob Keller total_offset += pmd; 2088a69f1cb6SJacob Keller else 2089a69f1cb6SJacob Keller total_offset -= pmd; 2090a69f1cb6SJacob Keller 2091a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 2092a69f1cb6SJacob Keller * PHY and indicate that the Rx offset is ready. After this, 2093a69f1cb6SJacob Keller * timestamps will be enabled. 2094a69f1cb6SJacob Keller */ 2095a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 2096a69f1cb6SJacob Keller total_offset); 2097a69f1cb6SJacob Keller if (err) 2098a69f1cb6SJacob Keller return err; 2099a69f1cb6SJacob Keller 2100a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 2101a69f1cb6SJacob Keller if (err) 2102a69f1cb6SJacob Keller return err; 2103a69f1cb6SJacob Keller 2104a69f1cb6SJacob Keller return 0; 2105a69f1cb6SJacob Keller } 2106a69f1cb6SJacob Keller 2107a69f1cb6SJacob Keller /** 21083a749623SJacob Keller * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode 21093a749623SJacob Keller * @hw: pointer to the HW struct 21103a749623SJacob Keller * @port: the PHY port to configure 21113a749623SJacob Keller * 21123a749623SJacob Keller * Calculate and program the fixed Rx offset, and indicate that the offset is 21133a749623SJacob Keller * ready. This can be used when operating in bypass mode. 21143a749623SJacob Keller */ 21153a749623SJacob Keller static int 21163a749623SJacob Keller ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port) 21173a749623SJacob Keller { 21183a749623SJacob Keller enum ice_ptp_link_spd link_spd; 21193a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 21203a749623SJacob Keller u64 total_offset; 21213a749623SJacob Keller int err; 21223a749623SJacob Keller 21233a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 21243a749623SJacob Keller if (err) 21253a749623SJacob Keller return err; 21263a749623SJacob Keller 21273a749623SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 21283a749623SJacob Keller 21293a749623SJacob Keller /* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L 21303a749623SJacob Keller * register, then indicate that the Rx offset is ready. After this, 21313a749623SJacob Keller * timestamps will be enabled. 21323a749623SJacob Keller * 21333a749623SJacob Keller * Note that this skips including the more precise offsets generated 21343a749623SJacob Keller * by Vernier calibration. 21353a749623SJacob Keller */ 21363a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 21373a749623SJacob Keller total_offset); 21383a749623SJacob Keller if (err) 21393a749623SJacob Keller return err; 21403a749623SJacob Keller 21413a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 21423a749623SJacob Keller if (err) 21433a749623SJacob Keller return err; 21443a749623SJacob Keller 21453a749623SJacob Keller return 0; 21463a749623SJacob Keller } 21473a749623SJacob Keller 21483a749623SJacob Keller /** 21493a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 21503a749623SJacob Keller * @hw: pointer to the HW struct 21513a749623SJacob Keller * @port: the PHY port to read 21523a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 21533a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 21543a749623SJacob Keller * 21553a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 21563a749623SJacob Keller * timer values. 21573a749623SJacob Keller */ 21583a749623SJacob Keller static int 21593a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 21603a749623SJacob Keller u64 *phc_time) 21613a749623SJacob Keller { 21623a749623SJacob Keller u64 tx_time, rx_time; 21633a749623SJacob Keller u32 zo, lo; 21643a749623SJacob Keller u8 tmr_idx; 21653a749623SJacob Keller int err; 21663a749623SJacob Keller 21673a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 21683a749623SJacob Keller 21693a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 21703a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 21713a749623SJacob Keller 21723a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 21733a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 21743a749623SJacob Keller if (err) 21753a749623SJacob Keller return err; 21763a749623SJacob Keller 21773a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 21783a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 21793a749623SJacob Keller 21803a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 21813a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 21823a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 21833a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 21843a749623SJacob Keller 21853a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 21863a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 21873a749623SJacob Keller if (err) 21883a749623SJacob Keller return err; 21893a749623SJacob Keller 21903a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 21913a749623SJacob Keller * Note that this should not happen in normal circumstances since the 21923a749623SJacob Keller * driver always programs them together. 21933a749623SJacob Keller */ 21943a749623SJacob Keller if (tx_time != rx_time) 21953a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 21963a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 21973a749623SJacob Keller port, (unsigned long long)tx_time, 21983a749623SJacob Keller (unsigned long long)rx_time); 21993a749623SJacob Keller 22003a749623SJacob Keller *phy_time = tx_time; 22013a749623SJacob Keller 22023a749623SJacob Keller return 0; 22033a749623SJacob Keller } 22043a749623SJacob Keller 22053a749623SJacob Keller /** 22063a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 22073a749623SJacob Keller * @hw: pointer to the HW struct 22083a749623SJacob Keller * @port: the PHY port to synchronize 22093a749623SJacob Keller * 22103a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 22113a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 22123a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 22133a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 22143a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 22153a749623SJacob Keller */ 22163a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 22173a749623SJacob Keller { 22183a749623SJacob Keller u64 phc_time, phy_time, difference; 22193a749623SJacob Keller int err; 22203a749623SJacob Keller 22213a749623SJacob Keller if (!ice_ptp_lock(hw)) { 22223a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 22233a749623SJacob Keller return -EBUSY; 22243a749623SJacob Keller } 22253a749623SJacob Keller 22263a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 22273a749623SJacob Keller if (err) 22283a749623SJacob Keller goto err_unlock; 22293a749623SJacob Keller 22303a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 22313a749623SJacob Keller * it to match the PHC time. 22323a749623SJacob Keller * 22333a749623SJacob Keller * Note that the port adjustment is done using 2s complement 22343a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 22353a749623SJacob Keller * calculate the difference between the PHC time and the port time, 22363a749623SJacob Keller * and it will be interpreted correctly. 22373a749623SJacob Keller */ 22383a749623SJacob Keller difference = phc_time - phy_time; 22393a749623SJacob Keller 22403a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 22413a749623SJacob Keller if (err) 22423a749623SJacob Keller goto err_unlock; 22433a749623SJacob Keller 22443a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 22453a749623SJacob Keller if (err) 22463a749623SJacob Keller goto err_unlock; 22473a749623SJacob Keller 22483a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 22493a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 22503a749623SJacob Keller 22513a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 22523a749623SJacob Keller * verify that the time was properly adjusted. 22533a749623SJacob Keller */ 22543a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 22553a749623SJacob Keller if (err) 22563a749623SJacob Keller goto err_unlock; 22573a749623SJacob Keller 22583a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 22593a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 22603a749623SJacob Keller port, (unsigned long long)phy_time, 22613a749623SJacob Keller (unsigned long long)phc_time); 22623a749623SJacob Keller 22633a749623SJacob Keller ice_ptp_unlock(hw); 22643a749623SJacob Keller 22653a749623SJacob Keller return 0; 22663a749623SJacob Keller 22673a749623SJacob Keller err_unlock: 22683a749623SJacob Keller ice_ptp_unlock(hw); 22693a749623SJacob Keller return err; 22703a749623SJacob Keller } 22713a749623SJacob Keller 22723a749623SJacob Keller /** 22733a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 22743a749623SJacob Keller * @hw: pointer to the HW struct 22753a749623SJacob Keller * @port: the PHY port to stop 22763a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 22773a749623SJacob Keller * 22783a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 22793a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 22803a749623SJacob Keller * initialized or when link speed changes. 22813a749623SJacob Keller */ 22823a749623SJacob Keller int 22833a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 22843a749623SJacob Keller { 22853a749623SJacob Keller int err; 22863a749623SJacob Keller u32 val; 22873a749623SJacob Keller 22883a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 22893a749623SJacob Keller if (err) 22903a749623SJacob Keller return err; 22913a749623SJacob Keller 22923a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 22933a749623SJacob Keller if (err) 22943a749623SJacob Keller return err; 22953a749623SJacob Keller 22963a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 22973a749623SJacob Keller if (err) 22983a749623SJacob Keller return err; 22993a749623SJacob Keller 23003a749623SJacob Keller val &= ~P_REG_PS_START_M; 23013a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23023a749623SJacob Keller if (err) 23033a749623SJacob Keller return err; 23043a749623SJacob Keller 23053a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 23063a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23073a749623SJacob Keller if (err) 23083a749623SJacob Keller return err; 23093a749623SJacob Keller 23103a749623SJacob Keller if (soft_reset) { 23113a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 23123a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23133a749623SJacob Keller if (err) 23143a749623SJacob Keller return err; 23153a749623SJacob Keller } 23163a749623SJacob Keller 23173a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 23183a749623SJacob Keller 23193a749623SJacob Keller return 0; 23203a749623SJacob Keller } 23213a749623SJacob Keller 23223a749623SJacob Keller /** 23233a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 23243a749623SJacob Keller * @hw: pointer to the HW struct 23253a749623SJacob Keller * @port: the PHY port to start 23263a749623SJacob Keller * @bypass: if true, start the PHY in bypass mode 23273a749623SJacob Keller * 23283a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 23293a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 23303a749623SJacob Keller * initialized or when link speed changes. 23313a749623SJacob Keller * 23323a749623SJacob Keller * Bypass mode enables timestamps immediately without waiting for Vernier 23333a749623SJacob Keller * calibration to complete. Hardware will still continue taking Vernier 23343a749623SJacob Keller * measurements on Tx or Rx of packets, but they will not be applied to 23353a749623SJacob Keller * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware 23363a749623SJacob Keller * has completed offset calculation. 23373a749623SJacob Keller */ 23383a749623SJacob Keller int 23393a749623SJacob Keller ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass) 23403a749623SJacob Keller { 23413a749623SJacob Keller u32 lo, hi, val; 23423a749623SJacob Keller u64 incval; 23433a749623SJacob Keller u8 tmr_idx; 23443a749623SJacob Keller int err; 23453a749623SJacob Keller 23463a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 23473a749623SJacob Keller 23483a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 23493a749623SJacob Keller if (err) 23503a749623SJacob Keller return err; 23513a749623SJacob Keller 23523a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 23533a749623SJacob Keller 23543a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 23553a749623SJacob Keller if (err) 23563a749623SJacob Keller return err; 23573a749623SJacob Keller 23583a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 23593a749623SJacob Keller if (err) 23603a749623SJacob Keller return err; 23613a749623SJacob Keller 23623a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 23633a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 23643a749623SJacob Keller incval = (u64)hi << 32 | lo; 23653a749623SJacob Keller 23663a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 23673a749623SJacob Keller if (err) 23683a749623SJacob Keller return err; 23693a749623SJacob Keller 23703a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23713a749623SJacob Keller if (err) 23723a749623SJacob Keller return err; 23733a749623SJacob Keller 23743a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23753a749623SJacob Keller 23763a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 23773a749623SJacob Keller if (err) 23783a749623SJacob Keller return err; 23793a749623SJacob Keller 23803a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 23813a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23823a749623SJacob Keller if (err) 23833a749623SJacob Keller return err; 23843a749623SJacob Keller 23853a749623SJacob Keller val |= P_REG_PS_START_M; 23863a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23873a749623SJacob Keller if (err) 23883a749623SJacob Keller return err; 23893a749623SJacob Keller 23903a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 23913a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23923a749623SJacob Keller if (err) 23933a749623SJacob Keller return err; 23943a749623SJacob Keller 23953a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23963a749623SJacob Keller if (err) 23973a749623SJacob Keller return err; 23983a749623SJacob Keller 23993a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 24003a749623SJacob Keller 24013a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 24023a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24033a749623SJacob Keller if (err) 24043a749623SJacob Keller return err; 24053a749623SJacob Keller 24063a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 24073a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24083a749623SJacob Keller if (err) 24093a749623SJacob Keller return err; 24103a749623SJacob Keller 24113a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 24123a749623SJacob Keller 24133a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 24143a749623SJacob Keller if (err) 24153a749623SJacob Keller return err; 24163a749623SJacob Keller 24173a749623SJacob Keller if (bypass) { 24183a749623SJacob Keller val |= P_REG_PS_BYPASS_MODE_M; 24193a749623SJacob Keller /* Enter BYPASS mode, enabling timestamps immediately. */ 24203a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24213a749623SJacob Keller if (err) 24223a749623SJacob Keller return err; 24233a749623SJacob Keller 24243a749623SJacob Keller /* Program the fixed Tx offset */ 24253a749623SJacob Keller err = ice_phy_cfg_fixed_tx_offset_e822(hw, port); 24263a749623SJacob Keller if (err) 24273a749623SJacob Keller return err; 24283a749623SJacob Keller 24293a749623SJacob Keller /* Program the fixed Rx offset */ 24303a749623SJacob Keller err = ice_phy_cfg_fixed_rx_offset_e822(hw, port); 24313a749623SJacob Keller if (err) 24323a749623SJacob Keller return err; 24333a749623SJacob Keller } 24343a749623SJacob Keller 24353a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 24363a749623SJacob Keller 24373a749623SJacob Keller return 0; 24383a749623SJacob Keller } 24393a749623SJacob Keller 2440a69f1cb6SJacob Keller /** 2441a69f1cb6SJacob Keller * ice_phy_exit_bypass_e822 - Exit bypass mode, after vernier calculations 2442a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2443a69f1cb6SJacob Keller * @port: the PHY port to configure 2444a69f1cb6SJacob Keller * 2445a69f1cb6SJacob Keller * After hardware finishes vernier calculations for the Tx and Rx offset, this 2446a69f1cb6SJacob Keller * function can be used to exit bypass mode by updating the total Tx and Rx 2447a69f1cb6SJacob Keller * offsets, and then disabling bypass. This will enable hardware to include 2448a69f1cb6SJacob Keller * the more precise offset calibrations, increasing precision of the generated 2449a69f1cb6SJacob Keller * timestamps. 2450a69f1cb6SJacob Keller * 2451a69f1cb6SJacob Keller * This cannot be done until hardware has measured the offsets, which requires 2452a69f1cb6SJacob Keller * waiting until at least one packet has been sent and received by the device. 2453a69f1cb6SJacob Keller */ 2454a69f1cb6SJacob Keller int ice_phy_exit_bypass_e822(struct ice_hw *hw, u8 port) 2455a69f1cb6SJacob Keller { 2456a69f1cb6SJacob Keller int err; 2457a69f1cb6SJacob Keller u32 val; 2458a69f1cb6SJacob Keller 2459a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val); 2460a69f1cb6SJacob Keller if (err) { 2461a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n", 2462a69f1cb6SJacob Keller port, err); 2463a69f1cb6SJacob Keller return err; 2464a69f1cb6SJacob Keller } 2465a69f1cb6SJacob Keller 2466a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2467a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n", 2468a69f1cb6SJacob Keller port); 2469a69f1cb6SJacob Keller return -EBUSY; 2470a69f1cb6SJacob Keller } 2471a69f1cb6SJacob Keller 2472a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val); 2473a69f1cb6SJacob Keller if (err) { 2474a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n", 2475a69f1cb6SJacob Keller port, err); 2476a69f1cb6SJacob Keller return err; 2477a69f1cb6SJacob Keller } 2478a69f1cb6SJacob Keller 2479a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2480a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n", 2481a69f1cb6SJacob Keller port); 2482a69f1cb6SJacob Keller return -EBUSY; 2483a69f1cb6SJacob Keller } 2484a69f1cb6SJacob Keller 2485a69f1cb6SJacob Keller err = ice_phy_cfg_tx_offset_e822(hw, port); 2486a69f1cb6SJacob Keller if (err) { 2487a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, err %d\n", 2488a69f1cb6SJacob Keller port, err); 2489a69f1cb6SJacob Keller return err; 2490a69f1cb6SJacob Keller } 2491a69f1cb6SJacob Keller 2492a69f1cb6SJacob Keller err = ice_phy_cfg_rx_offset_e822(hw, port); 2493a69f1cb6SJacob Keller if (err) { 2494a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, err %d\n", 2495a69f1cb6SJacob Keller port, err); 2496a69f1cb6SJacob Keller return err; 2497a69f1cb6SJacob Keller } 2498a69f1cb6SJacob Keller 2499a69f1cb6SJacob Keller /* Exit bypass mode now that the offset has been updated */ 2500a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 2501a69f1cb6SJacob Keller if (err) { 2502a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read P_REG_PS for port %u, err %d\n", 2503a69f1cb6SJacob Keller port, err); 2504a69f1cb6SJacob Keller return err; 2505a69f1cb6SJacob Keller } 2506a69f1cb6SJacob Keller 2507a69f1cb6SJacob Keller if (!(val & P_REG_PS_BYPASS_MODE_M)) 2508a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Port %u not in bypass mode\n", 2509a69f1cb6SJacob Keller port); 2510a69f1cb6SJacob Keller 2511a69f1cb6SJacob Keller val &= ~P_REG_PS_BYPASS_MODE_M; 2512a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 2513a69f1cb6SJacob Keller if (err) { 2514a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to disable bypass for port %u, err %d\n", 2515a69f1cb6SJacob Keller port, err); 2516a69f1cb6SJacob Keller return err; 2517a69f1cb6SJacob Keller } 2518a69f1cb6SJacob Keller 2519a69f1cb6SJacob Keller dev_info(ice_hw_to_dev(hw), "Exiting bypass mode on PHY port %u\n", 2520a69f1cb6SJacob Keller port); 2521a69f1cb6SJacob Keller 2522a69f1cb6SJacob Keller return 0; 2523a69f1cb6SJacob Keller } 2524a69f1cb6SJacob Keller 252503cb4473SJacob Keller /* E810 functions 252603cb4473SJacob Keller * 252703cb4473SJacob Keller * The following functions operate on the E810 series devices which use 252803cb4473SJacob Keller * a separate external PHY. 252903cb4473SJacob Keller */ 253003cb4473SJacob Keller 253103cb4473SJacob Keller /** 253203cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 253303cb4473SJacob Keller * @hw: pointer to the HW struct 253403cb4473SJacob Keller * @addr: the address to read from 253503cb4473SJacob Keller * @val: On return, the value read from the PHY 253603cb4473SJacob Keller * 253703cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 253803cb4473SJacob Keller */ 253903cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 254003cb4473SJacob Keller { 254103cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 254239b28106SJacob Keller int err; 254303cb4473SJacob Keller 254403cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 254503cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 254603cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 254703cb4473SJacob Keller msg.dest_dev = rmn_0; 254803cb4473SJacob Keller 254939b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 255039b28106SJacob Keller if (err) { 255139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 255239b28106SJacob Keller err); 255339b28106SJacob Keller return err; 255403cb4473SJacob Keller } 255503cb4473SJacob Keller 255603cb4473SJacob Keller *val = msg.data; 255703cb4473SJacob Keller 255803cb4473SJacob Keller return 0; 255903cb4473SJacob Keller } 256003cb4473SJacob Keller 256103cb4473SJacob Keller /** 256203cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 256303cb4473SJacob Keller * @hw: pointer to the HW struct 256403cb4473SJacob Keller * @addr: the address to writem to 256503cb4473SJacob Keller * @val: the value to write to the PHY 256603cb4473SJacob Keller * 256703cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 256803cb4473SJacob Keller */ 256903cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 257003cb4473SJacob Keller { 257103cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 257239b28106SJacob Keller int err; 257303cb4473SJacob Keller 257403cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 257503cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 257603cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 257703cb4473SJacob Keller msg.dest_dev = rmn_0; 257803cb4473SJacob Keller msg.data = val; 257903cb4473SJacob Keller 258039b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 258139b28106SJacob Keller if (err) { 258239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 258339b28106SJacob Keller err); 258439b28106SJacob Keller return err; 258503cb4473SJacob Keller } 258603cb4473SJacob Keller 258703cb4473SJacob Keller return 0; 258803cb4473SJacob Keller } 258903cb4473SJacob Keller 259003cb4473SJacob Keller /** 25911229b339SKarol Kolacinski * ice_read_phy_tstamp_ll_e810 - Read a PHY timestamp registers through the FW 25921229b339SKarol Kolacinski * @hw: pointer to the HW struct 25931229b339SKarol Kolacinski * @idx: the timestamp index to read 25941229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 25951229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 25961229b339SKarol Kolacinski * 25971229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 25981229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using the low latency 25991229b339SKarol Kolacinski * timestamp read. 26001229b339SKarol Kolacinski */ 26011229b339SKarol Kolacinski static int 26021229b339SKarol Kolacinski ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo) 26031229b339SKarol Kolacinski { 26041229b339SKarol Kolacinski u32 val; 26051229b339SKarol Kolacinski u8 i; 26061229b339SKarol Kolacinski 26071229b339SKarol Kolacinski /* Write TS index to read to the PF register so the FW can read it */ 26081229b339SKarol Kolacinski val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS; 26091229b339SKarol Kolacinski wr32(hw, PF_SB_ATQBAL, val); 26101229b339SKarol Kolacinski 26111229b339SKarol Kolacinski /* Read the register repeatedly until the FW provides us the TS */ 26121229b339SKarol Kolacinski for (i = TS_LL_READ_RETRIES; i > 0; i--) { 26131229b339SKarol Kolacinski val = rd32(hw, PF_SB_ATQBAL); 26141229b339SKarol Kolacinski 26151229b339SKarol Kolacinski /* When the bit is cleared, the TS is ready in the register */ 26161229b339SKarol Kolacinski if (!(FIELD_GET(TS_LL_READ_TS, val))) { 26171229b339SKarol Kolacinski /* High 8 bit value of the TS is on the bits 16:23 */ 26181229b339SKarol Kolacinski *hi = FIELD_GET(TS_LL_READ_TS_HIGH, val); 26191229b339SKarol Kolacinski 26201229b339SKarol Kolacinski /* Read the low 32 bit value and set the TS valid bit */ 26211229b339SKarol Kolacinski *lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID; 26221229b339SKarol Kolacinski return 0; 26231229b339SKarol Kolacinski } 26241229b339SKarol Kolacinski 26251229b339SKarol Kolacinski udelay(10); 26261229b339SKarol Kolacinski } 26271229b339SKarol Kolacinski 26281229b339SKarol Kolacinski /* FW failed to provide the TS in time */ 26291229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n"); 26301229b339SKarol Kolacinski return -EINVAL; 26311229b339SKarol Kolacinski } 26321229b339SKarol Kolacinski 26331229b339SKarol Kolacinski /** 26341229b339SKarol Kolacinski * ice_read_phy_tstamp_sbq_e810 - Read a PHY timestamp registers through the sbq 26351229b339SKarol Kolacinski * @hw: pointer to the HW struct 26361229b339SKarol Kolacinski * @lport: the lport to read from 26371229b339SKarol Kolacinski * @idx: the timestamp index to read 26381229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 26391229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 26401229b339SKarol Kolacinski * 26411229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 26421229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using sideband queue. 26431229b339SKarol Kolacinski */ 26441229b339SKarol Kolacinski static int 26451229b339SKarol Kolacinski ice_read_phy_tstamp_sbq_e810(struct ice_hw *hw, u8 lport, u8 idx, u8 *hi, 26461229b339SKarol Kolacinski u32 *lo) 26471229b339SKarol Kolacinski { 26481229b339SKarol Kolacinski u32 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 26491229b339SKarol Kolacinski u32 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 26501229b339SKarol Kolacinski u32 lo_val, hi_val; 26511229b339SKarol Kolacinski int err; 26521229b339SKarol Kolacinski 26531229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, lo_addr, &lo_val); 26541229b339SKarol Kolacinski if (err) { 26551229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 26561229b339SKarol Kolacinski err); 26571229b339SKarol Kolacinski return err; 26581229b339SKarol Kolacinski } 26591229b339SKarol Kolacinski 26601229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, hi_addr, &hi_val); 26611229b339SKarol Kolacinski if (err) { 26621229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 26631229b339SKarol Kolacinski err); 26641229b339SKarol Kolacinski return err; 26651229b339SKarol Kolacinski } 26661229b339SKarol Kolacinski 26671229b339SKarol Kolacinski *lo = lo_val; 26681229b339SKarol Kolacinski *hi = (u8)hi_val; 26691229b339SKarol Kolacinski 26701229b339SKarol Kolacinski return 0; 26711229b339SKarol Kolacinski } 26721229b339SKarol Kolacinski 26731229b339SKarol Kolacinski /** 267403cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 267503cb4473SJacob Keller * @hw: pointer to the HW struct 267603cb4473SJacob Keller * @lport: the lport to read from 267703cb4473SJacob Keller * @idx: the timestamp index to read 267803cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 267903cb4473SJacob Keller * 268003cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 268103cb4473SJacob Keller * on the E810 device. 268203cb4473SJacob Keller */ 268303cb4473SJacob Keller static int 268403cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 268503cb4473SJacob Keller { 26861229b339SKarol Kolacinski u32 lo = 0; 26871229b339SKarol Kolacinski u8 hi = 0; 268839b28106SJacob Keller int err; 268903cb4473SJacob Keller 26901229b339SKarol Kolacinski if (hw->dev_caps.ts_dev_info.ts_ll_read) 26911229b339SKarol Kolacinski err = ice_read_phy_tstamp_ll_e810(hw, idx, &hi, &lo); 26921229b339SKarol Kolacinski else 26931229b339SKarol Kolacinski err = ice_read_phy_tstamp_sbq_e810(hw, lport, idx, &hi, &lo); 269403cb4473SJacob Keller 26951229b339SKarol Kolacinski if (err) 269639b28106SJacob Keller return err; 269703cb4473SJacob Keller 269803cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 269903cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 270003cb4473SJacob Keller */ 270103cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 270203cb4473SJacob Keller 270303cb4473SJacob Keller return 0; 270403cb4473SJacob Keller } 270503cb4473SJacob Keller 270603cb4473SJacob Keller /** 270703cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 270803cb4473SJacob Keller * @hw: pointer to the HW struct 270903cb4473SJacob Keller * @lport: the lport to read from 271003cb4473SJacob Keller * @idx: the timestamp index to reset 271103cb4473SJacob Keller * 271203cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 271303cb4473SJacob Keller * external PHY on the E810 device. 271403cb4473SJacob Keller */ 271503cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 271603cb4473SJacob Keller { 271703cb4473SJacob Keller u32 lo_addr, hi_addr; 271839b28106SJacob Keller int err; 271903cb4473SJacob Keller 272003cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 272103cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 272203cb4473SJacob Keller 272339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 272439b28106SJacob Keller if (err) { 272539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 272639b28106SJacob Keller err); 272739b28106SJacob Keller return err; 272803cb4473SJacob Keller } 272903cb4473SJacob Keller 273039b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 273139b28106SJacob Keller if (err) { 273239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 273339b28106SJacob Keller err); 273439b28106SJacob Keller return err; 273503cb4473SJacob Keller } 273603cb4473SJacob Keller 273703cb4473SJacob Keller return 0; 273803cb4473SJacob Keller } 273903cb4473SJacob Keller 274003cb4473SJacob Keller /** 274103cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 274203cb4473SJacob Keller * @hw: pointer to HW struct 274303cb4473SJacob Keller * 274403cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 274503cb4473SJacob Keller * this function. 274603cb4473SJacob Keller */ 274703cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 274803cb4473SJacob Keller { 274903cb4473SJacob Keller u8 tmr_idx; 275039b28106SJacob Keller int err; 275103cb4473SJacob Keller 275203cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 275339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 275403cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 275539b28106SJacob Keller if (err) 275603cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 275739b28106SJacob Keller err); 275803cb4473SJacob Keller 275939b28106SJacob Keller return err; 276003cb4473SJacob Keller } 276103cb4473SJacob Keller 276203cb4473SJacob Keller /** 2763b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 2764b2ee7256SJacob Keller * @hw: pointer to HW struct 2765b2ee7256SJacob Keller * 2766b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 2767b2ee7256SJacob Keller */ 2768b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 2769b2ee7256SJacob Keller { 2770b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 2771b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 2772b2ee7256SJacob Keller 2773b2ee7256SJacob Keller /* Initialize the PHY */ 2774b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 2775b2ee7256SJacob Keller } 2776b2ee7256SJacob Keller 2777b2ee7256SJacob Keller /** 277803cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 277903cb4473SJacob Keller * @hw: Board private structure 278003cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 278103cb4473SJacob Keller * 278203cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 278303cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 278403cb4473SJacob Keller * driver issues an INIT_TIME command. 278503cb4473SJacob Keller * 278603cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 278703cb4473SJacob Keller * nominal nanoseconds. 278803cb4473SJacob Keller */ 278903cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 279003cb4473SJacob Keller { 279103cb4473SJacob Keller u8 tmr_idx; 279239b28106SJacob Keller int err; 279303cb4473SJacob Keller 279403cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 279539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 279639b28106SJacob Keller if (err) { 279739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 279839b28106SJacob Keller err); 279939b28106SJacob Keller return err; 280003cb4473SJacob Keller } 280103cb4473SJacob Keller 280239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 280339b28106SJacob Keller if (err) { 280439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 280539b28106SJacob Keller err); 280639b28106SJacob Keller return err; 280703cb4473SJacob Keller } 280803cb4473SJacob Keller 280903cb4473SJacob Keller return 0; 281003cb4473SJacob Keller } 281103cb4473SJacob Keller 281203cb4473SJacob Keller /** 281303cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 281403cb4473SJacob Keller * @hw: pointer to HW struct 281503cb4473SJacob Keller * @adj: adjustment value to program 281603cb4473SJacob Keller * 281703cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 281803cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 281903cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 282003cb4473SJacob Keller * 282103cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 282203cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 282303cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 282403cb4473SJacob Keller */ 282503cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 282603cb4473SJacob Keller { 282703cb4473SJacob Keller u8 tmr_idx; 282839b28106SJacob Keller int err; 282903cb4473SJacob Keller 283003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 283103cb4473SJacob Keller 283203cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 283303cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 283403cb4473SJacob Keller */ 283539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 283639b28106SJacob Keller if (err) { 283739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 283839b28106SJacob Keller err); 283939b28106SJacob Keller return err; 284003cb4473SJacob Keller } 284103cb4473SJacob Keller 284239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 284339b28106SJacob Keller if (err) { 284439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 284539b28106SJacob Keller err); 284639b28106SJacob Keller return err; 284703cb4473SJacob Keller } 284803cb4473SJacob Keller 284903cb4473SJacob Keller return 0; 285003cb4473SJacob Keller } 285103cb4473SJacob Keller 285203cb4473SJacob Keller /** 285303cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 285403cb4473SJacob Keller * @hw: pointer to HW struct 285503cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 285603cb4473SJacob Keller * 285703cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 285803cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 285903cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 286003cb4473SJacob Keller */ 286103cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 286203cb4473SJacob Keller { 286303cb4473SJacob Keller u32 high, low; 286403cb4473SJacob Keller u8 tmr_idx; 286539b28106SJacob Keller int err; 286603cb4473SJacob Keller 286703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 286803cb4473SJacob Keller low = lower_32_bits(incval); 286903cb4473SJacob Keller high = upper_32_bits(incval); 287003cb4473SJacob Keller 287139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 287239b28106SJacob Keller if (err) { 287339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 287439b28106SJacob Keller err); 287539b28106SJacob Keller return err; 287603cb4473SJacob Keller } 287703cb4473SJacob Keller 287839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 287939b28106SJacob Keller if (err) { 288039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 288139b28106SJacob Keller err); 288239b28106SJacob Keller return err; 288303cb4473SJacob Keller } 288403cb4473SJacob Keller 288503cb4473SJacob Keller return 0; 288603cb4473SJacob Keller } 288703cb4473SJacob Keller 288803cb4473SJacob Keller /** 288903cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 289003cb4473SJacob Keller * @hw: pointer to HW struct 289103cb4473SJacob Keller * @cmd: Command to be sent to the port 289203cb4473SJacob Keller * 289303cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 289403cb4473SJacob Keller * command. 289503cb4473SJacob Keller */ 289603cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 289703cb4473SJacob Keller { 289803cb4473SJacob Keller u32 cmd_val, val; 289939b28106SJacob Keller int err; 290003cb4473SJacob Keller 290103cb4473SJacob Keller switch (cmd) { 290203cb4473SJacob Keller case INIT_TIME: 290303cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 290403cb4473SJacob Keller break; 290503cb4473SJacob Keller case INIT_INCVAL: 290603cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 290703cb4473SJacob Keller break; 290803cb4473SJacob Keller case ADJ_TIME: 290903cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 291003cb4473SJacob Keller break; 291103cb4473SJacob Keller case READ_TIME: 291203cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 291303cb4473SJacob Keller break; 291403cb4473SJacob Keller case ADJ_TIME_AT_TIME: 291503cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 291603cb4473SJacob Keller break; 291703cb4473SJacob Keller } 291803cb4473SJacob Keller 291903cb4473SJacob Keller /* Read, modify, write */ 292039b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 292139b28106SJacob Keller if (err) { 292239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 292339b28106SJacob Keller return err; 292403cb4473SJacob Keller } 292503cb4473SJacob Keller 292603cb4473SJacob Keller /* Modify necessary bits only and perform write */ 292703cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 292803cb4473SJacob Keller val |= cmd_val; 292903cb4473SJacob Keller 293039b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 293139b28106SJacob Keller if (err) { 293239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 293339b28106SJacob Keller return err; 293403cb4473SJacob Keller } 293503cb4473SJacob Keller 293603cb4473SJacob Keller return 0; 293703cb4473SJacob Keller } 293803cb4473SJacob Keller 293903cb4473SJacob Keller /* Device agnostic functions 294003cb4473SJacob Keller * 29413a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 29423a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 29433a749623SJacob Keller * necessary. 294403cb4473SJacob Keller */ 294503cb4473SJacob Keller 294603cb4473SJacob Keller /** 294703cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 294803cb4473SJacob Keller * @hw: pointer to the HW struct 294903cb4473SJacob Keller * 295003cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 295103cb4473SJacob Keller * was acquired, false otherwise. 295203cb4473SJacob Keller * 295303cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 295403cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 295503cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 295603cb4473SJacob Keller * bit set, it means that another function acquired the lock. 295703cb4473SJacob Keller * 295803cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 295903cb4473SJacob Keller * functions when done. 296003cb4473SJacob Keller */ 296103cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 296203cb4473SJacob Keller { 296303cb4473SJacob Keller u32 hw_lock; 296403cb4473SJacob Keller int i; 296503cb4473SJacob Keller 2966*a711a328SKarol Kolacinski #define MAX_TRIES 15 296703cb4473SJacob Keller 296803cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 296903cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 297003cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2971*a711a328SKarol Kolacinski if (hw_lock) { 297203cb4473SJacob Keller /* Somebody is holding the lock */ 2973*a711a328SKarol Kolacinski usleep_range(5000, 6000); 2974*a711a328SKarol Kolacinski continue; 2975*a711a328SKarol Kolacinski } 2976*a711a328SKarol Kolacinski 2977*a711a328SKarol Kolacinski break; 297803cb4473SJacob Keller } 297903cb4473SJacob Keller 298003cb4473SJacob Keller return !hw_lock; 298103cb4473SJacob Keller } 298203cb4473SJacob Keller 298303cb4473SJacob Keller /** 298403cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 298503cb4473SJacob Keller * @hw: pointer to the HW struct 298603cb4473SJacob Keller * 298703cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 298803cb4473SJacob Keller * the PFTSYN_SEM register. 298903cb4473SJacob Keller */ 299003cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 299103cb4473SJacob Keller { 299203cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 299303cb4473SJacob Keller } 299403cb4473SJacob Keller 299503cb4473SJacob Keller /** 299603cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 299703cb4473SJacob Keller * @hw: pointer to HW struct 299803cb4473SJacob Keller * @cmd: the command to issue 299903cb4473SJacob Keller * 300003cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 300103cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 300203cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 300303cb4473SJacob Keller * timers. 300403cb4473SJacob Keller */ 300503cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 300603cb4473SJacob Keller { 300739b28106SJacob Keller int err; 300803cb4473SJacob Keller 300903cb4473SJacob Keller /* First, prepare the source timer */ 301003cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 301103cb4473SJacob Keller 301203cb4473SJacob Keller /* Next, prepare the ports */ 30133a749623SJacob Keller if (ice_is_e810(hw)) 301439b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 30153a749623SJacob Keller else 30163a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 301739b28106SJacob Keller if (err) { 301839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 301939b28106SJacob Keller cmd, err); 302039b28106SJacob Keller return err; 302103cb4473SJacob Keller } 302203cb4473SJacob Keller 30233a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 30243a749623SJacob Keller * commands synchronously 302503cb4473SJacob Keller */ 30263a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 302703cb4473SJacob Keller 302803cb4473SJacob Keller return 0; 302903cb4473SJacob Keller } 303003cb4473SJacob Keller 303103cb4473SJacob Keller /** 303203cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 303303cb4473SJacob Keller * @hw: pointer to HW struct 303403cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 303503cb4473SJacob Keller * 303603cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 303703cb4473SJacob Keller * step process: 303803cb4473SJacob Keller * 303903cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 304003cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 304103cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 304203cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 304303cb4473SJacob Keller */ 304403cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 304503cb4473SJacob Keller { 304603cb4473SJacob Keller u8 tmr_idx; 304739b28106SJacob Keller int err; 304803cb4473SJacob Keller 304903cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 305003cb4473SJacob Keller 305103cb4473SJacob Keller /* Source timers */ 305203cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 305303cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 305403cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 305503cb4473SJacob Keller 305603cb4473SJacob Keller /* PHY timers */ 305703cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 30583a749623SJacob Keller if (ice_is_e810(hw)) 305939b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 30603a749623SJacob Keller else 30613a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 306239b28106SJacob Keller if (err) 306339b28106SJacob Keller return err; 306403cb4473SJacob Keller 306503cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 306603cb4473SJacob Keller } 306703cb4473SJacob Keller 306803cb4473SJacob Keller /** 306903cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 307003cb4473SJacob Keller * @hw: pointer to HW struct 307103cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 307203cb4473SJacob Keller * 307303cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 307403cb4473SJacob Keller * process: 307503cb4473SJacob Keller * 307603cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 307703cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 307803cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 307903cb4473SJacob Keller * source and port timers to the new increment value at the next clock 308003cb4473SJacob Keller * cycle. 308103cb4473SJacob Keller */ 308203cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 308303cb4473SJacob Keller { 308403cb4473SJacob Keller u8 tmr_idx; 308539b28106SJacob Keller int err; 308603cb4473SJacob Keller 308703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 308803cb4473SJacob Keller 308903cb4473SJacob Keller /* Shadow Adjust */ 309003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 309103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 309203cb4473SJacob Keller 30933a749623SJacob Keller if (ice_is_e810(hw)) 309439b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 30953a749623SJacob Keller else 30963a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 309739b28106SJacob Keller if (err) 309839b28106SJacob Keller return err; 309903cb4473SJacob Keller 310003cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 310103cb4473SJacob Keller } 310203cb4473SJacob Keller 310303cb4473SJacob Keller /** 310403cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 310503cb4473SJacob Keller * @hw: pointer to HW struct 310603cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 310703cb4473SJacob Keller * 310803cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 310903cb4473SJacob Keller */ 311003cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 311103cb4473SJacob Keller { 311239b28106SJacob Keller int err; 311303cb4473SJacob Keller 311403cb4473SJacob Keller if (!ice_ptp_lock(hw)) 311503cb4473SJacob Keller return -EBUSY; 311603cb4473SJacob Keller 311739b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 311803cb4473SJacob Keller 311903cb4473SJacob Keller ice_ptp_unlock(hw); 312003cb4473SJacob Keller 312139b28106SJacob Keller return err; 312203cb4473SJacob Keller } 312303cb4473SJacob Keller 312403cb4473SJacob Keller /** 312503cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 312603cb4473SJacob Keller * @hw: pointer to HW struct 312703cb4473SJacob Keller * @adj: Adjustment in nanoseconds 312803cb4473SJacob Keller * 312903cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 313003cb4473SJacob Keller * nanoseconds. This requires a three-step process: 313103cb4473SJacob Keller * 313203cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 313303cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 313403cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 313503cb4473SJacob Keller * both the source and port timers at the next clock cycle. 313603cb4473SJacob Keller */ 313703cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 313803cb4473SJacob Keller { 313903cb4473SJacob Keller u8 tmr_idx; 314039b28106SJacob Keller int err; 314103cb4473SJacob Keller 314203cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 314303cb4473SJacob Keller 314403cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 314503cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 314603cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 314703cb4473SJacob Keller * the value as a 2's complement integer. 314803cb4473SJacob Keller */ 314903cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 315003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 315103cb4473SJacob Keller 31523a749623SJacob Keller if (ice_is_e810(hw)) 315339b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 31543a749623SJacob Keller else 31553a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 315639b28106SJacob Keller if (err) 315739b28106SJacob Keller return err; 315803cb4473SJacob Keller 315903cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 316003cb4473SJacob Keller } 316103cb4473SJacob Keller 316203cb4473SJacob Keller /** 316303cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 316403cb4473SJacob Keller * @hw: pointer to the HW struct 316503cb4473SJacob Keller * @block: the block to read from 316603cb4473SJacob Keller * @idx: the timestamp index to read 316703cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 316803cb4473SJacob Keller * 31693a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 31703a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 31713a749623SJacob Keller * logical port to read from. 317203cb4473SJacob Keller */ 317303cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 317403cb4473SJacob Keller { 31753a749623SJacob Keller if (ice_is_e810(hw)) 317603cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 31773a749623SJacob Keller else 31783a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 317903cb4473SJacob Keller } 318003cb4473SJacob Keller 318103cb4473SJacob Keller /** 318203cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 318303cb4473SJacob Keller * @hw: pointer to the HW struct 318403cb4473SJacob Keller * @block: the block to read from 318503cb4473SJacob Keller * @idx: the timestamp index to reset 318603cb4473SJacob Keller * 31873a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 31883a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 31893a749623SJacob Keller * block is the logical port to clear from. 319003cb4473SJacob Keller */ 319103cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 319203cb4473SJacob Keller { 31933a749623SJacob Keller if (ice_is_e810(hw)) 319403cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 31953a749623SJacob Keller else 31963a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 319703cb4473SJacob Keller } 3198885fe693SMaciej Machnikowski 3199885fe693SMaciej Machnikowski /* E810T SMA functions 3200885fe693SMaciej Machnikowski * 3201885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 3202885fe693SMaciej Machnikowski * to access the extended GPIOs available. 3203885fe693SMaciej Machnikowski */ 3204885fe693SMaciej Machnikowski 3205885fe693SMaciej Machnikowski /** 3206885fe693SMaciej Machnikowski * ice_get_pca9575_handle 3207885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3208885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 3209885fe693SMaciej Machnikowski * 3210885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 3211885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 3212885fe693SMaciej Machnikowski * will return cached value 3213885fe693SMaciej Machnikowski */ 3214885fe693SMaciej Machnikowski static int 3215885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 3216885fe693SMaciej Machnikowski { 3217885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 3218885fe693SMaciej Machnikowski struct ice_aq_desc desc; 3219885fe693SMaciej Machnikowski int status; 3220885fe693SMaciej Machnikowski u8 idx; 3221885fe693SMaciej Machnikowski 3222885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 3223885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 3224885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3225885fe693SMaciej Machnikowski return 0; 3226885fe693SMaciej Machnikowski } 3227885fe693SMaciej Machnikowski 3228885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 3229885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 3230885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 3231885fe693SMaciej Machnikowski 3232885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 3233885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 3234885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 3235885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 3236885fe693SMaciej Machnikowski 3237885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 3238885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 3239885fe693SMaciej Machnikowski 3240885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 3241885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 3242885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 3243885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 3244885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 3245885fe693SMaciej Machnikowski else 3246885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3247885fe693SMaciej Machnikowski 3248885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 3249885fe693SMaciej Machnikowski 3250885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 3251885fe693SMaciej Machnikowski if (status) 3252885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3253885fe693SMaciej Machnikowski 3254885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 3255885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 3256885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 3257885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3258885fe693SMaciej Machnikowski 3259885fe693SMaciej Machnikowski /* If present save the handle and return it */ 3260885fe693SMaciej Machnikowski hw->io_expander_handle = 3261885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 3262885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3263885fe693SMaciej Machnikowski 3264885fe693SMaciej Machnikowski return 0; 3265885fe693SMaciej Machnikowski } 3266885fe693SMaciej Machnikowski 3267885fe693SMaciej Machnikowski /** 3268885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 3269885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3270885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 3271885fe693SMaciej Machnikowski * 3272885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 3273885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 3274885fe693SMaciej Machnikowski */ 3275885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 3276885fe693SMaciej Machnikowski { 3277885fe693SMaciej Machnikowski int status; 3278885fe693SMaciej Machnikowski u16 handle; 3279885fe693SMaciej Machnikowski u8 i; 3280885fe693SMaciej Machnikowski 3281885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3282885fe693SMaciej Machnikowski if (status) 3283885fe693SMaciej Machnikowski return status; 3284885fe693SMaciej Machnikowski 3285885fe693SMaciej Machnikowski *data = 0; 3286885fe693SMaciej Machnikowski 3287885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3288885fe693SMaciej Machnikowski bool pin; 3289885fe693SMaciej Machnikowski 3290885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3291885fe693SMaciej Machnikowski &pin, NULL); 3292885fe693SMaciej Machnikowski if (status) 3293885fe693SMaciej Machnikowski break; 3294885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 3295885fe693SMaciej Machnikowski } 3296885fe693SMaciej Machnikowski 3297885fe693SMaciej Machnikowski return status; 3298885fe693SMaciej Machnikowski } 3299885fe693SMaciej Machnikowski 3300885fe693SMaciej Machnikowski /** 3301885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 3302885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3303885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 3304885fe693SMaciej Machnikowski * 3305885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 3306885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 3307885fe693SMaciej Machnikowski */ 3308885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 3309885fe693SMaciej Machnikowski { 3310885fe693SMaciej Machnikowski int status; 3311885fe693SMaciej Machnikowski u16 handle; 3312885fe693SMaciej Machnikowski u8 i; 3313885fe693SMaciej Machnikowski 3314885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3315885fe693SMaciej Machnikowski if (status) 3316885fe693SMaciej Machnikowski return status; 3317885fe693SMaciej Machnikowski 3318885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3319885fe693SMaciej Machnikowski bool pin; 3320885fe693SMaciej Machnikowski 3321885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 3322885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3323885fe693SMaciej Machnikowski pin, NULL); 3324885fe693SMaciej Machnikowski if (status) 3325885fe693SMaciej Machnikowski break; 3326885fe693SMaciej Machnikowski } 3327885fe693SMaciej Machnikowski 3328885fe693SMaciej Machnikowski return status; 3329885fe693SMaciej Machnikowski } 3330885fe693SMaciej Machnikowski 3331885fe693SMaciej Machnikowski /** 333243113ff7SKarol Kolacinski * ice_read_pca9575_reg_e810t 333343113ff7SKarol Kolacinski * @hw: pointer to the hw struct 333443113ff7SKarol Kolacinski * @offset: GPIO controller register offset 333543113ff7SKarol Kolacinski * @data: pointer to data to be read from the GPIO controller 333643113ff7SKarol Kolacinski * 333743113ff7SKarol Kolacinski * Read the register from the GPIO controller 333843113ff7SKarol Kolacinski */ 333943113ff7SKarol Kolacinski int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) 334043113ff7SKarol Kolacinski { 334143113ff7SKarol Kolacinski struct ice_aqc_link_topo_addr link_topo; 334243113ff7SKarol Kolacinski __le16 addr; 334343113ff7SKarol Kolacinski u16 handle; 334443113ff7SKarol Kolacinski int err; 334543113ff7SKarol Kolacinski 334643113ff7SKarol Kolacinski memset(&link_topo, 0, sizeof(link_topo)); 334743113ff7SKarol Kolacinski 334843113ff7SKarol Kolacinski err = ice_get_pca9575_handle(hw, &handle); 334943113ff7SKarol Kolacinski if (err) 335043113ff7SKarol Kolacinski return err; 335143113ff7SKarol Kolacinski 335243113ff7SKarol Kolacinski link_topo.handle = cpu_to_le16(handle); 335343113ff7SKarol Kolacinski link_topo.topo_params.node_type_ctx = 335443113ff7SKarol Kolacinski FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, 335543113ff7SKarol Kolacinski ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED); 335643113ff7SKarol Kolacinski 335743113ff7SKarol Kolacinski addr = cpu_to_le16((u16)offset); 335843113ff7SKarol Kolacinski 335943113ff7SKarol Kolacinski return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL); 336043113ff7SKarol Kolacinski } 336143113ff7SKarol Kolacinski 336243113ff7SKarol Kolacinski /** 3363885fe693SMaciej Machnikowski * ice_is_pca9575_present 3364885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3365885fe693SMaciej Machnikowski * 3366885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 3367885fe693SMaciej Machnikowski */ 3368885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 3369885fe693SMaciej Machnikowski { 3370885fe693SMaciej Machnikowski u16 handle = 0; 3371885fe693SMaciej Machnikowski int status; 3372885fe693SMaciej Machnikowski 3373885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 3374885fe693SMaciej Machnikowski return false; 3375885fe693SMaciej Machnikowski 3376885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3377885fe693SMaciej Machnikowski 3378885fe693SMaciej Machnikowski return !status && handle; 3379885fe693SMaciej Machnikowski } 3380b2ee7256SJacob Keller 3381b2ee7256SJacob Keller /** 3382b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 3383b2ee7256SJacob Keller * @hw: pointer to the HW struct 3384b2ee7256SJacob Keller * 3385b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 3386b2ee7256SJacob Keller */ 3387b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 3388b2ee7256SJacob Keller { 3389b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 3390b2ee7256SJacob Keller 3391b2ee7256SJacob Keller /* Enable source clocks */ 3392b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 3393b2ee7256SJacob Keller 3394b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 3395b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 3396b2ee7256SJacob Keller 33973a749623SJacob Keller if (ice_is_e810(hw)) 3398b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 33993a749623SJacob Keller else 34003a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 3401b2ee7256SJacob Keller } 3402