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 /** 1790a69f1cb6SJacob Keller * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx 1791a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1792a69f1cb6SJacob Keller * @port: the PHY port to adjust for 1793a69f1cb6SJacob Keller * @link_spd: the current link speed of the PHY 1794a69f1cb6SJacob Keller * @fec_mode: the current FEC mode of the PHY 1795a69f1cb6SJacob Keller * @pmd_adj: on return, the amount to adjust the Rx total offset by 1796a69f1cb6SJacob Keller * 1797a69f1cb6SJacob Keller * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY. 1798a69f1cb6SJacob Keller * This varies by link speed and FEC mode. The value calculated accounts for 1799a69f1cb6SJacob Keller * various delays caused when receiving a packet. 1800a69f1cb6SJacob Keller */ 1801a69f1cb6SJacob Keller static int 1802a69f1cb6SJacob Keller ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, 1803a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd, 1804a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj) 1805a69f1cb6SJacob Keller { 1806a69f1cb6SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, mult, adj; 1807a69f1cb6SJacob Keller u8 pmd_align; 1808a69f1cb6SJacob Keller u32 val; 1809a69f1cb6SJacob Keller int err; 1810a69f1cb6SJacob Keller 1811a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val); 1812a69f1cb6SJacob Keller if (err) { 1813a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n", 1814a69f1cb6SJacob Keller err); 1815a69f1cb6SJacob Keller return err; 1816a69f1cb6SJacob Keller } 1817a69f1cb6SJacob Keller 1818a69f1cb6SJacob Keller pmd_align = (u8)val; 1819a69f1cb6SJacob Keller 1820a69f1cb6SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1821a69f1cb6SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1822a69f1cb6SJacob Keller 1823a69f1cb6SJacob Keller /* Calculate TUs per second */ 1824a69f1cb6SJacob Keller tu_per_sec = cur_freq * clk_incval; 1825a69f1cb6SJacob Keller 1826a69f1cb6SJacob Keller /* The PMD alignment adjustment measurement depends on the link speed, 1827a69f1cb6SJacob Keller * and whether FEC is enabled. For each link speed, the alignment 1828a69f1cb6SJacob Keller * adjustment is calculated by dividing a value by the length of 1829a69f1cb6SJacob Keller * a Time Unit in nanoseconds. 1830a69f1cb6SJacob Keller * 1831a69f1cb6SJacob Keller * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8 1832a69f1cb6SJacob Keller * 10G: align == 65 ? 0 : (align * 0.1 * 32/33) 1833a69f1cb6SJacob Keller * 10G w/FEC: align * 0.1 * 32/33 1834a69f1cb6SJacob Keller * 25G: align == 65 ? 0 : (align * 0.4 * 32/33) 1835a69f1cb6SJacob Keller * 25G w/FEC: align * 0.4 * 32/33 1836a69f1cb6SJacob Keller * 40G: align == 65 ? 0 : (align * 0.1 * 32/33) 1837a69f1cb6SJacob Keller * 40G w/FEC: align * 0.1 * 32/33 1838a69f1cb6SJacob Keller * 50G: align == 65 ? 0 : (align * 0.4 * 32/33) 1839a69f1cb6SJacob Keller * 50G w/FEC: align * 0.8 * 32/33 1840a69f1cb6SJacob Keller * 1841a69f1cb6SJacob Keller * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33. 1842a69f1cb6SJacob Keller * 1843a69f1cb6SJacob Keller * To allow for calculating this value using integer arithmetic, we 1844a69f1cb6SJacob Keller * instead start with the number of TUs per second, (inverse of the 1845a69f1cb6SJacob Keller * length of a Time Unit in nanoseconds), multiply by a value based 1846a69f1cb6SJacob Keller * on the PMD alignment register, and then divide by the right value 1847a69f1cb6SJacob Keller * calculated based on the table above. To avoid integer overflow this 1848a69f1cb6SJacob Keller * division is broken up into a step of dividing by 125 first. 1849a69f1cb6SJacob Keller */ 1850a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G) { 1851a69f1cb6SJacob Keller if (pmd_align == 4) 1852a69f1cb6SJacob Keller mult = 10; 1853a69f1cb6SJacob Keller else 1854a69f1cb6SJacob Keller mult = (pmd_align + 6) % 10; 1855a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_10G || 1856a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1857a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1858a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1859a69f1cb6SJacob Keller /* If Clause 74 FEC, always calculate PMD adjust */ 1860a69f1cb6SJacob Keller if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74) 1861a69f1cb6SJacob Keller mult = pmd_align; 1862a69f1cb6SJacob Keller else 1863a69f1cb6SJacob Keller mult = 0; 1864a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS || 1865a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 1866a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1867a69f1cb6SJacob Keller if (pmd_align < 17) 1868a69f1cb6SJacob Keller mult = pmd_align + 40; 1869a69f1cb6SJacob Keller else 1870a69f1cb6SJacob Keller mult = pmd_align; 1871a69f1cb6SJacob Keller } else { 1872a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n", 1873a69f1cb6SJacob Keller link_spd); 1874a69f1cb6SJacob Keller mult = 0; 1875a69f1cb6SJacob Keller } 1876a69f1cb6SJacob Keller 1877a69f1cb6SJacob Keller /* In some cases, there's no need to adjust for the PMD alignment */ 1878a69f1cb6SJacob Keller if (!mult) { 1879a69f1cb6SJacob Keller *pmd_adj = 0; 1880a69f1cb6SJacob Keller return 0; 1881a69f1cb6SJacob Keller } 1882a69f1cb6SJacob Keller 1883a69f1cb6SJacob Keller /* Calculate the adjustment by multiplying TUs per second by the 1884a69f1cb6SJacob Keller * appropriate multiplier and divisor. To avoid overflow, we first 1885a69f1cb6SJacob Keller * divide by 125, and then handle remaining divisor based on the link 1886a69f1cb6SJacob Keller * speed pmd_adj_divisor value. 1887a69f1cb6SJacob Keller */ 1888a69f1cb6SJacob Keller adj = div_u64(tu_per_sec, 125); 1889a69f1cb6SJacob Keller adj *= mult; 1890a69f1cb6SJacob Keller adj = div_u64(adj, e822_vernier[link_spd].pmd_adj_divisor); 1891a69f1cb6SJacob Keller 1892a69f1cb6SJacob Keller /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx 1893a69f1cb6SJacob Keller * cycle count is necessary. 1894a69f1cb6SJacob Keller */ 1895a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_25G_RS) { 1896a69f1cb6SJacob Keller u64 cycle_adj; 1897a69f1cb6SJacob Keller u8 rx_cycle; 1898a69f1cb6SJacob Keller 1899a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT, 1900a69f1cb6SJacob Keller &val); 1901a69f1cb6SJacob Keller if (err) { 1902a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n", 1903a69f1cb6SJacob Keller err); 1904a69f1cb6SJacob Keller return err; 1905a69f1cb6SJacob Keller } 1906a69f1cb6SJacob Keller 1907a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M; 1908a69f1cb6SJacob Keller if (rx_cycle) { 1909a69f1cb6SJacob Keller mult = (4 - rx_cycle) * 40; 1910a69f1cb6SJacob Keller 1911a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1912a69f1cb6SJacob Keller cycle_adj *= mult; 1913a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1914a69f1cb6SJacob Keller 1915a69f1cb6SJacob Keller adj += cycle_adj; 1916a69f1cb6SJacob Keller } 1917a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) { 1918a69f1cb6SJacob Keller u64 cycle_adj; 1919a69f1cb6SJacob Keller u8 rx_cycle; 1920a69f1cb6SJacob Keller 1921a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT, 1922a69f1cb6SJacob Keller &val); 1923a69f1cb6SJacob Keller if (err) { 1924a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n", 1925a69f1cb6SJacob Keller err); 1926a69f1cb6SJacob Keller return err; 1927a69f1cb6SJacob Keller } 1928a69f1cb6SJacob Keller 1929a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M; 1930a69f1cb6SJacob Keller if (rx_cycle) { 1931a69f1cb6SJacob Keller mult = rx_cycle * 40; 1932a69f1cb6SJacob Keller 1933a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1934a69f1cb6SJacob Keller cycle_adj *= mult; 1935a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1936a69f1cb6SJacob Keller 1937a69f1cb6SJacob Keller adj += cycle_adj; 1938a69f1cb6SJacob Keller } 1939a69f1cb6SJacob Keller } 1940a69f1cb6SJacob Keller 1941a69f1cb6SJacob Keller /* Return the calculated adjustment */ 1942a69f1cb6SJacob Keller *pmd_adj = adj; 1943a69f1cb6SJacob Keller 1944a69f1cb6SJacob Keller return 0; 1945a69f1cb6SJacob Keller } 1946a69f1cb6SJacob Keller 1947a69f1cb6SJacob Keller /** 19483a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 19493a749623SJacob Keller * @hw: pointer to HW struct 19503a749623SJacob Keller * @link_spd: The Link speed to calculate for 19513a749623SJacob Keller * 19523a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 19533a749623SJacob Keller */ 19543a749623SJacob Keller static u64 19553a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 19563a749623SJacob Keller { 19573a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 19583a749623SJacob Keller 19593a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 19603a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 19613a749623SJacob Keller 19623a749623SJacob Keller /* Calculate TUs per second */ 19633a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 19643a749623SJacob Keller 19653a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 19663a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 19673a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 19683a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 19693a749623SJacob Keller * divisions by 1e4 first then by 1e7. 19703a749623SJacob Keller */ 19713a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 19723a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 19733a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 19743a749623SJacob Keller 19753a749623SJacob Keller return fixed_offset; 19763a749623SJacob Keller } 19773a749623SJacob Keller 19783a749623SJacob Keller /** 1979a69f1cb6SJacob Keller * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset 1980a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1981a69f1cb6SJacob Keller * @port: the PHY port to configure 1982a69f1cb6SJacob Keller * 1983a69f1cb6SJacob Keller * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to 1984a69f1cb6SJacob Keller * adjust Rx timestamps by. This combines calculations from the Vernier offset 1985a69f1cb6SJacob Keller * measurements taken in hardware with some data about known fixed delay as 1986a69f1cb6SJacob Keller * well as adjusting for multi-lane alignment delay. 1987a69f1cb6SJacob Keller * 1988a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 1989a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 1990a69f1cb6SJacob Keller * has measured the offset. 1991a69f1cb6SJacob Keller * 1992a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 1993a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 1994a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 1995a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 1996a69f1cb6SJacob Keller */ 1997a69f1cb6SJacob Keller static int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) 1998a69f1cb6SJacob Keller { 1999a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 2000a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 2001a69f1cb6SJacob Keller u64 total_offset, pmd, val; 2002a69f1cb6SJacob Keller int err; 2003a69f1cb6SJacob Keller 2004a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 2005a69f1cb6SJacob Keller if (err) 2006a69f1cb6SJacob Keller return err; 2007a69f1cb6SJacob Keller 2008a69f1cb6SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 2009a69f1cb6SJacob Keller 2010a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 2011a69f1cb6SJacob Keller * the total offset. 2012a69f1cb6SJacob Keller */ 2013a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2014a69f1cb6SJacob Keller P_REG_PAR_PCS_RX_OFFSET_L, 2015a69f1cb6SJacob Keller &val); 2016a69f1cb6SJacob Keller if (err) 2017a69f1cb6SJacob Keller return err; 2018a69f1cb6SJacob Keller 2019a69f1cb6SJacob Keller total_offset += val; 2020a69f1cb6SJacob Keller 2021a69f1cb6SJacob Keller /* For Rx, all multi-lane link speeds include a second Vernier 2022a69f1cb6SJacob Keller * calibration, because the lanes might not be aligned. 2023a69f1cb6SJacob Keller */ 2024a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_40G || 2025a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G || 2026a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 2027a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 2028a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2029a69f1cb6SJacob Keller P_REG_PAR_RX_TIME_L, 2030a69f1cb6SJacob Keller &val); 2031a69f1cb6SJacob Keller if (err) 2032a69f1cb6SJacob Keller return err; 2033a69f1cb6SJacob Keller 2034a69f1cb6SJacob Keller total_offset += val; 2035a69f1cb6SJacob Keller } 2036a69f1cb6SJacob Keller 2037a69f1cb6SJacob Keller /* In addition, Rx must account for the PMD alignment */ 2038a69f1cb6SJacob Keller err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd); 2039a69f1cb6SJacob Keller if (err) 2040a69f1cb6SJacob Keller return err; 2041a69f1cb6SJacob Keller 2042a69f1cb6SJacob Keller /* For RS-FEC, this adjustment adds delay, but for other modes, it 2043a69f1cb6SJacob Keller * subtracts delay. 2044a69f1cb6SJacob Keller */ 2045a69f1cb6SJacob Keller if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC) 2046a69f1cb6SJacob Keller total_offset += pmd; 2047a69f1cb6SJacob Keller else 2048a69f1cb6SJacob Keller total_offset -= pmd; 2049a69f1cb6SJacob Keller 2050a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 2051a69f1cb6SJacob Keller * PHY and indicate that the Rx offset is ready. After this, 2052a69f1cb6SJacob Keller * timestamps will be enabled. 2053a69f1cb6SJacob Keller */ 2054a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 2055a69f1cb6SJacob Keller total_offset); 2056a69f1cb6SJacob Keller if (err) 2057a69f1cb6SJacob Keller return err; 2058a69f1cb6SJacob Keller 2059a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 2060a69f1cb6SJacob Keller if (err) 2061a69f1cb6SJacob Keller return err; 2062a69f1cb6SJacob Keller 2063a69f1cb6SJacob Keller return 0; 2064a69f1cb6SJacob Keller } 2065a69f1cb6SJacob Keller 2066a69f1cb6SJacob Keller /** 20673a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 20683a749623SJacob Keller * @hw: pointer to the HW struct 20693a749623SJacob Keller * @port: the PHY port to read 20703a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 20713a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 20723a749623SJacob Keller * 20733a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 20743a749623SJacob Keller * timer values. 20753a749623SJacob Keller */ 20763a749623SJacob Keller static int 20773a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 20783a749623SJacob Keller u64 *phc_time) 20793a749623SJacob Keller { 20803a749623SJacob Keller u64 tx_time, rx_time; 20813a749623SJacob Keller u32 zo, lo; 20823a749623SJacob Keller u8 tmr_idx; 20833a749623SJacob Keller int err; 20843a749623SJacob Keller 20853a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 20863a749623SJacob Keller 20873a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 20883a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 20893a749623SJacob Keller 20903a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 20913a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 20923a749623SJacob Keller if (err) 20933a749623SJacob Keller return err; 20943a749623SJacob Keller 20953a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 20963a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 20973a749623SJacob Keller 20983a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 20993a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 21003a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 21013a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 21023a749623SJacob Keller 21033a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 21043a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 21053a749623SJacob Keller if (err) 21063a749623SJacob Keller return err; 21073a749623SJacob Keller 21083a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 21093a749623SJacob Keller * Note that this should not happen in normal circumstances since the 21103a749623SJacob Keller * driver always programs them together. 21113a749623SJacob Keller */ 21123a749623SJacob Keller if (tx_time != rx_time) 21133a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 21143a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 21153a749623SJacob Keller port, (unsigned long long)tx_time, 21163a749623SJacob Keller (unsigned long long)rx_time); 21173a749623SJacob Keller 21183a749623SJacob Keller *phy_time = tx_time; 21193a749623SJacob Keller 21203a749623SJacob Keller return 0; 21213a749623SJacob Keller } 21223a749623SJacob Keller 21233a749623SJacob Keller /** 21243a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 21253a749623SJacob Keller * @hw: pointer to the HW struct 21263a749623SJacob Keller * @port: the PHY port to synchronize 21273a749623SJacob Keller * 21283a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 21293a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 21303a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 21313a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 21323a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 21333a749623SJacob Keller */ 21343a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 21353a749623SJacob Keller { 21363a749623SJacob Keller u64 phc_time, phy_time, difference; 21373a749623SJacob Keller int err; 21383a749623SJacob Keller 21393a749623SJacob Keller if (!ice_ptp_lock(hw)) { 21403a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 21413a749623SJacob Keller return -EBUSY; 21423a749623SJacob Keller } 21433a749623SJacob Keller 21443a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 21453a749623SJacob Keller if (err) 21463a749623SJacob Keller goto err_unlock; 21473a749623SJacob Keller 21483a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 21493a749623SJacob Keller * it to match the PHC time. 21503a749623SJacob Keller * 21513a749623SJacob Keller * Note that the port adjustment is done using 2s complement 21523a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 21533a749623SJacob Keller * calculate the difference between the PHC time and the port time, 21543a749623SJacob Keller * and it will be interpreted correctly. 21553a749623SJacob Keller */ 21563a749623SJacob Keller difference = phc_time - phy_time; 21573a749623SJacob Keller 21583a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 21593a749623SJacob Keller if (err) 21603a749623SJacob Keller goto err_unlock; 21613a749623SJacob Keller 21623a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 21633a749623SJacob Keller if (err) 21643a749623SJacob Keller goto err_unlock; 21653a749623SJacob Keller 21663a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 21673a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 21683a749623SJacob Keller 21693a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 21703a749623SJacob Keller * verify that the time was properly adjusted. 21713a749623SJacob Keller */ 21723a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 21733a749623SJacob Keller if (err) 21743a749623SJacob Keller goto err_unlock; 21753a749623SJacob Keller 21763a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 21773a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 21783a749623SJacob Keller port, (unsigned long long)phy_time, 21793a749623SJacob Keller (unsigned long long)phc_time); 21803a749623SJacob Keller 21813a749623SJacob Keller ice_ptp_unlock(hw); 21823a749623SJacob Keller 21833a749623SJacob Keller return 0; 21843a749623SJacob Keller 21853a749623SJacob Keller err_unlock: 21863a749623SJacob Keller ice_ptp_unlock(hw); 21873a749623SJacob Keller return err; 21883a749623SJacob Keller } 21893a749623SJacob Keller 21903a749623SJacob Keller /** 21913a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 21923a749623SJacob Keller * @hw: pointer to the HW struct 21933a749623SJacob Keller * @port: the PHY port to stop 21943a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 21953a749623SJacob Keller * 21963a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 21973a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 21983a749623SJacob Keller * initialized or when link speed changes. 21993a749623SJacob Keller */ 22003a749623SJacob Keller int 22013a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 22023a749623SJacob Keller { 22033a749623SJacob Keller int err; 22043a749623SJacob Keller u32 val; 22053a749623SJacob Keller 22063a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 22073a749623SJacob Keller if (err) 22083a749623SJacob Keller return err; 22093a749623SJacob Keller 22103a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 22113a749623SJacob Keller if (err) 22123a749623SJacob Keller return err; 22133a749623SJacob Keller 22143a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 22153a749623SJacob Keller if (err) 22163a749623SJacob Keller return err; 22173a749623SJacob Keller 22183a749623SJacob Keller val &= ~P_REG_PS_START_M; 22193a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22203a749623SJacob Keller if (err) 22213a749623SJacob Keller return err; 22223a749623SJacob Keller 22233a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 22243a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22253a749623SJacob Keller if (err) 22263a749623SJacob Keller return err; 22273a749623SJacob Keller 22283a749623SJacob Keller if (soft_reset) { 22293a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 22303a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22313a749623SJacob Keller if (err) 22323a749623SJacob Keller return err; 22333a749623SJacob Keller } 22343a749623SJacob Keller 22353a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 22363a749623SJacob Keller 22373a749623SJacob Keller return 0; 22383a749623SJacob Keller } 22393a749623SJacob Keller 22403a749623SJacob Keller /** 22413a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 22423a749623SJacob Keller * @hw: pointer to the HW struct 22433a749623SJacob Keller * @port: the PHY port to start 22443a749623SJacob Keller * 22453a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 22463a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 22473a749623SJacob Keller * initialized or when link speed changes. 22483a749623SJacob Keller * 2249*0357d5caSMilena Olech * Hardware will take Vernier measurements on Tx or Rx of packets. 22503a749623SJacob Keller */ 2251*0357d5caSMilena Olech int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port) 22523a749623SJacob Keller { 22533a749623SJacob Keller u32 lo, hi, val; 22543a749623SJacob Keller u64 incval; 22553a749623SJacob Keller u8 tmr_idx; 22563a749623SJacob Keller int err; 22573a749623SJacob Keller 22583a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 22593a749623SJacob Keller 22603a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 22613a749623SJacob Keller if (err) 22623a749623SJacob Keller return err; 22633a749623SJacob Keller 22643a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 22653a749623SJacob Keller 22663a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 22673a749623SJacob Keller if (err) 22683a749623SJacob Keller return err; 22693a749623SJacob Keller 22703a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 22713a749623SJacob Keller if (err) 22723a749623SJacob Keller return err; 22733a749623SJacob Keller 22743a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 22753a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 22763a749623SJacob Keller incval = (u64)hi << 32 | lo; 22773a749623SJacob Keller 22783a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 22793a749623SJacob Keller if (err) 22803a749623SJacob Keller return err; 22813a749623SJacob Keller 22823a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 22833a749623SJacob Keller if (err) 22843a749623SJacob Keller return err; 22853a749623SJacob Keller 22863a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 22873a749623SJacob Keller 22883a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 22893a749623SJacob Keller if (err) 22903a749623SJacob Keller return err; 22913a749623SJacob Keller 22923a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 22933a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22943a749623SJacob Keller if (err) 22953a749623SJacob Keller return err; 22963a749623SJacob Keller 22973a749623SJacob Keller val |= P_REG_PS_START_M; 22983a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 22993a749623SJacob Keller if (err) 23003a749623SJacob Keller return err; 23013a749623SJacob Keller 23023a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 23033a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23043a749623SJacob Keller if (err) 23053a749623SJacob Keller return err; 23063a749623SJacob Keller 23073a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23083a749623SJacob Keller if (err) 23093a749623SJacob Keller return err; 23103a749623SJacob Keller 23113a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23123a749623SJacob Keller 23133a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 23143a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23153a749623SJacob Keller if (err) 23163a749623SJacob Keller return err; 23173a749623SJacob Keller 23183a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 23193a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23203a749623SJacob Keller if (err) 23213a749623SJacob Keller return err; 23223a749623SJacob Keller 23233a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23243a749623SJacob Keller 23253a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 23263a749623SJacob Keller if (err) 23273a749623SJacob Keller return err; 23283a749623SJacob Keller 23293a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 23303a749623SJacob Keller 23313a749623SJacob Keller return 0; 23323a749623SJacob Keller } 23333a749623SJacob Keller 2334a69f1cb6SJacob Keller /** 2335*0357d5caSMilena Olech * ice_phy_calc_vernier_e822 - Perform vernier calculations 2336a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2337a69f1cb6SJacob Keller * @port: the PHY port to configure 2338a69f1cb6SJacob Keller * 2339*0357d5caSMilena Olech * Perform vernier calculations for the Tx and Rx offset. This will enable 2340*0357d5caSMilena Olech * hardware to include the more precise offset calibrations, 2341*0357d5caSMilena Olech * increasing precision of the generated timestamps. 2342a69f1cb6SJacob Keller * 2343a69f1cb6SJacob Keller * This cannot be done until hardware has measured the offsets, which requires 2344a69f1cb6SJacob Keller * waiting until at least one packet has been sent and received by the device. 2345a69f1cb6SJacob Keller */ 2346*0357d5caSMilena Olech int ice_phy_calc_vernier_e822(struct ice_hw *hw, u8 port) 2347a69f1cb6SJacob Keller { 2348a69f1cb6SJacob Keller int err; 2349a69f1cb6SJacob Keller u32 val; 2350a69f1cb6SJacob Keller 2351a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val); 2352a69f1cb6SJacob Keller if (err) { 2353a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n", 2354a69f1cb6SJacob Keller port, err); 2355a69f1cb6SJacob Keller return err; 2356a69f1cb6SJacob Keller } 2357a69f1cb6SJacob Keller 2358a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2359a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n", 2360a69f1cb6SJacob Keller port); 2361a69f1cb6SJacob Keller return -EBUSY; 2362a69f1cb6SJacob Keller } 2363a69f1cb6SJacob Keller 2364a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val); 2365a69f1cb6SJacob Keller if (err) { 2366a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n", 2367a69f1cb6SJacob Keller port, err); 2368a69f1cb6SJacob Keller return err; 2369a69f1cb6SJacob Keller } 2370a69f1cb6SJacob Keller 2371a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2372a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n", 2373a69f1cb6SJacob Keller port); 2374a69f1cb6SJacob Keller return -EBUSY; 2375a69f1cb6SJacob Keller } 2376a69f1cb6SJacob Keller 2377a69f1cb6SJacob Keller err = ice_phy_cfg_tx_offset_e822(hw, port); 2378a69f1cb6SJacob Keller if (err) { 2379a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, err %d\n", 2380a69f1cb6SJacob Keller port, err); 2381a69f1cb6SJacob Keller return err; 2382a69f1cb6SJacob Keller } 2383a69f1cb6SJacob Keller 2384a69f1cb6SJacob Keller err = ice_phy_cfg_rx_offset_e822(hw, port); 2385a69f1cb6SJacob Keller if (err) { 2386a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, err %d\n", 2387a69f1cb6SJacob Keller port, err); 2388a69f1cb6SJacob Keller return err; 2389a69f1cb6SJacob Keller } 2390a69f1cb6SJacob Keller 2391a69f1cb6SJacob Keller return 0; 2392a69f1cb6SJacob Keller } 2393a69f1cb6SJacob Keller 239403cb4473SJacob Keller /* E810 functions 239503cb4473SJacob Keller * 239603cb4473SJacob Keller * The following functions operate on the E810 series devices which use 239703cb4473SJacob Keller * a separate external PHY. 239803cb4473SJacob Keller */ 239903cb4473SJacob Keller 240003cb4473SJacob Keller /** 240103cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 240203cb4473SJacob Keller * @hw: pointer to the HW struct 240303cb4473SJacob Keller * @addr: the address to read from 240403cb4473SJacob Keller * @val: On return, the value read from the PHY 240503cb4473SJacob Keller * 240603cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 240703cb4473SJacob Keller */ 240803cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 240903cb4473SJacob Keller { 241003cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 241139b28106SJacob Keller int err; 241203cb4473SJacob Keller 241303cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 241403cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 241503cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 241603cb4473SJacob Keller msg.dest_dev = rmn_0; 241703cb4473SJacob Keller 241839b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 241939b28106SJacob Keller if (err) { 242039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 242139b28106SJacob Keller err); 242239b28106SJacob Keller return err; 242303cb4473SJacob Keller } 242403cb4473SJacob Keller 242503cb4473SJacob Keller *val = msg.data; 242603cb4473SJacob Keller 242703cb4473SJacob Keller return 0; 242803cb4473SJacob Keller } 242903cb4473SJacob Keller 243003cb4473SJacob Keller /** 243103cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 243203cb4473SJacob Keller * @hw: pointer to the HW struct 243303cb4473SJacob Keller * @addr: the address to writem to 243403cb4473SJacob Keller * @val: the value to write to the PHY 243503cb4473SJacob Keller * 243603cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 243703cb4473SJacob Keller */ 243803cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 243903cb4473SJacob Keller { 244003cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 244139b28106SJacob Keller int err; 244203cb4473SJacob Keller 244303cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 244403cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 244503cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 244603cb4473SJacob Keller msg.dest_dev = rmn_0; 244703cb4473SJacob Keller msg.data = val; 244803cb4473SJacob Keller 244939b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 245039b28106SJacob Keller if (err) { 245139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 245239b28106SJacob Keller err); 245339b28106SJacob Keller return err; 245403cb4473SJacob Keller } 245503cb4473SJacob Keller 245603cb4473SJacob Keller return 0; 245703cb4473SJacob Keller } 245803cb4473SJacob Keller 245903cb4473SJacob Keller /** 24601229b339SKarol Kolacinski * ice_read_phy_tstamp_ll_e810 - Read a PHY timestamp registers through the FW 24611229b339SKarol Kolacinski * @hw: pointer to the HW struct 24621229b339SKarol Kolacinski * @idx: the timestamp index to read 24631229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 24641229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 24651229b339SKarol Kolacinski * 24661229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 24671229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using the low latency 24681229b339SKarol Kolacinski * timestamp read. 24691229b339SKarol Kolacinski */ 24701229b339SKarol Kolacinski static int 24711229b339SKarol Kolacinski ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo) 24721229b339SKarol Kolacinski { 24731229b339SKarol Kolacinski u32 val; 24741229b339SKarol Kolacinski u8 i; 24751229b339SKarol Kolacinski 24761229b339SKarol Kolacinski /* Write TS index to read to the PF register so the FW can read it */ 24771229b339SKarol Kolacinski val = FIELD_PREP(TS_LL_READ_TS_IDX, idx) | TS_LL_READ_TS; 24781229b339SKarol Kolacinski wr32(hw, PF_SB_ATQBAL, val); 24791229b339SKarol Kolacinski 24801229b339SKarol Kolacinski /* Read the register repeatedly until the FW provides us the TS */ 24811229b339SKarol Kolacinski for (i = TS_LL_READ_RETRIES; i > 0; i--) { 24821229b339SKarol Kolacinski val = rd32(hw, PF_SB_ATQBAL); 24831229b339SKarol Kolacinski 24841229b339SKarol Kolacinski /* When the bit is cleared, the TS is ready in the register */ 24851229b339SKarol Kolacinski if (!(FIELD_GET(TS_LL_READ_TS, val))) { 24861229b339SKarol Kolacinski /* High 8 bit value of the TS is on the bits 16:23 */ 24871229b339SKarol Kolacinski *hi = FIELD_GET(TS_LL_READ_TS_HIGH, val); 24881229b339SKarol Kolacinski 24891229b339SKarol Kolacinski /* Read the low 32 bit value and set the TS valid bit */ 24901229b339SKarol Kolacinski *lo = rd32(hw, PF_SB_ATQBAH) | TS_VALID; 24911229b339SKarol Kolacinski return 0; 24921229b339SKarol Kolacinski } 24931229b339SKarol Kolacinski 24941229b339SKarol Kolacinski udelay(10); 24951229b339SKarol Kolacinski } 24961229b339SKarol Kolacinski 24971229b339SKarol Kolacinski /* FW failed to provide the TS in time */ 24981229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read PTP timestamp using low latency read\n"); 24991229b339SKarol Kolacinski return -EINVAL; 25001229b339SKarol Kolacinski } 25011229b339SKarol Kolacinski 25021229b339SKarol Kolacinski /** 25031229b339SKarol Kolacinski * ice_read_phy_tstamp_sbq_e810 - Read a PHY timestamp registers through the sbq 25041229b339SKarol Kolacinski * @hw: pointer to the HW struct 25051229b339SKarol Kolacinski * @lport: the lport to read from 25061229b339SKarol Kolacinski * @idx: the timestamp index to read 25071229b339SKarol Kolacinski * @hi: 8 bit timestamp high value 25081229b339SKarol Kolacinski * @lo: 32 bit timestamp low value 25091229b339SKarol Kolacinski * 25101229b339SKarol Kolacinski * Read a 8bit timestamp high value and 32 bit timestamp low value out of the 25111229b339SKarol Kolacinski * timestamp block of the external PHY on the E810 device using sideband queue. 25121229b339SKarol Kolacinski */ 25131229b339SKarol Kolacinski static int 25141229b339SKarol Kolacinski ice_read_phy_tstamp_sbq_e810(struct ice_hw *hw, u8 lport, u8 idx, u8 *hi, 25151229b339SKarol Kolacinski u32 *lo) 25161229b339SKarol Kolacinski { 25171229b339SKarol Kolacinski u32 hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 25181229b339SKarol Kolacinski u32 lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 25191229b339SKarol Kolacinski u32 lo_val, hi_val; 25201229b339SKarol Kolacinski int err; 25211229b339SKarol Kolacinski 25221229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, lo_addr, &lo_val); 25231229b339SKarol Kolacinski if (err) { 25241229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 25251229b339SKarol Kolacinski err); 25261229b339SKarol Kolacinski return err; 25271229b339SKarol Kolacinski } 25281229b339SKarol Kolacinski 25291229b339SKarol Kolacinski err = ice_read_phy_reg_e810(hw, hi_addr, &hi_val); 25301229b339SKarol Kolacinski if (err) { 25311229b339SKarol Kolacinski ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 25321229b339SKarol Kolacinski err); 25331229b339SKarol Kolacinski return err; 25341229b339SKarol Kolacinski } 25351229b339SKarol Kolacinski 25361229b339SKarol Kolacinski *lo = lo_val; 25371229b339SKarol Kolacinski *hi = (u8)hi_val; 25381229b339SKarol Kolacinski 25391229b339SKarol Kolacinski return 0; 25401229b339SKarol Kolacinski } 25411229b339SKarol Kolacinski 25421229b339SKarol Kolacinski /** 254303cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 254403cb4473SJacob Keller * @hw: pointer to the HW struct 254503cb4473SJacob Keller * @lport: the lport to read from 254603cb4473SJacob Keller * @idx: the timestamp index to read 254703cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 254803cb4473SJacob Keller * 254903cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 255003cb4473SJacob Keller * on the E810 device. 255103cb4473SJacob Keller */ 255203cb4473SJacob Keller static int 255303cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 255403cb4473SJacob Keller { 25551229b339SKarol Kolacinski u32 lo = 0; 25561229b339SKarol Kolacinski u8 hi = 0; 255739b28106SJacob Keller int err; 255803cb4473SJacob Keller 25591229b339SKarol Kolacinski if (hw->dev_caps.ts_dev_info.ts_ll_read) 25601229b339SKarol Kolacinski err = ice_read_phy_tstamp_ll_e810(hw, idx, &hi, &lo); 25611229b339SKarol Kolacinski else 25621229b339SKarol Kolacinski err = ice_read_phy_tstamp_sbq_e810(hw, lport, idx, &hi, &lo); 256303cb4473SJacob Keller 25641229b339SKarol Kolacinski if (err) 256539b28106SJacob Keller return err; 256603cb4473SJacob Keller 256703cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 256803cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 256903cb4473SJacob Keller */ 257003cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 257103cb4473SJacob Keller 257203cb4473SJacob Keller return 0; 257303cb4473SJacob Keller } 257403cb4473SJacob Keller 257503cb4473SJacob Keller /** 257603cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 257703cb4473SJacob Keller * @hw: pointer to the HW struct 257803cb4473SJacob Keller * @lport: the lport to read from 257903cb4473SJacob Keller * @idx: the timestamp index to reset 258003cb4473SJacob Keller * 258103cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 258203cb4473SJacob Keller * external PHY on the E810 device. 258303cb4473SJacob Keller */ 258403cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 258503cb4473SJacob Keller { 258603cb4473SJacob Keller u32 lo_addr, hi_addr; 258739b28106SJacob Keller int err; 258803cb4473SJacob Keller 258903cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 259003cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 259103cb4473SJacob Keller 259239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 259339b28106SJacob Keller if (err) { 259439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 259539b28106SJacob Keller err); 259639b28106SJacob Keller return err; 259703cb4473SJacob Keller } 259803cb4473SJacob Keller 259939b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 260039b28106SJacob Keller if (err) { 260139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 260239b28106SJacob Keller err); 260339b28106SJacob Keller return err; 260403cb4473SJacob Keller } 260503cb4473SJacob Keller 260603cb4473SJacob Keller return 0; 260703cb4473SJacob Keller } 260803cb4473SJacob Keller 260903cb4473SJacob Keller /** 261003cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 261103cb4473SJacob Keller * @hw: pointer to HW struct 261203cb4473SJacob Keller * 261303cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 261403cb4473SJacob Keller * this function. 261503cb4473SJacob Keller */ 261603cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 261703cb4473SJacob Keller { 261803cb4473SJacob Keller u8 tmr_idx; 261939b28106SJacob Keller int err; 262003cb4473SJacob Keller 262103cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 262239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 262303cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 262439b28106SJacob Keller if (err) 262503cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 262639b28106SJacob Keller err); 262703cb4473SJacob Keller 262839b28106SJacob Keller return err; 262903cb4473SJacob Keller } 263003cb4473SJacob Keller 263103cb4473SJacob Keller /** 2632b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 2633b2ee7256SJacob Keller * @hw: pointer to HW struct 2634b2ee7256SJacob Keller * 2635b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 2636b2ee7256SJacob Keller */ 2637b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 2638b2ee7256SJacob Keller { 2639b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 2640b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 2641b2ee7256SJacob Keller 2642b2ee7256SJacob Keller /* Initialize the PHY */ 2643b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 2644b2ee7256SJacob Keller } 2645b2ee7256SJacob Keller 2646b2ee7256SJacob Keller /** 264703cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 264803cb4473SJacob Keller * @hw: Board private structure 264903cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 265003cb4473SJacob Keller * 265103cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 265203cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 265303cb4473SJacob Keller * driver issues an INIT_TIME command. 265403cb4473SJacob Keller * 265503cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 265603cb4473SJacob Keller * nominal nanoseconds. 265703cb4473SJacob Keller */ 265803cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 265903cb4473SJacob Keller { 266003cb4473SJacob Keller u8 tmr_idx; 266139b28106SJacob Keller int err; 266203cb4473SJacob Keller 266303cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 266439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 266539b28106SJacob Keller if (err) { 266639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 266739b28106SJacob Keller err); 266839b28106SJacob Keller return err; 266903cb4473SJacob Keller } 267003cb4473SJacob Keller 267139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 267239b28106SJacob Keller if (err) { 267339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 267439b28106SJacob Keller err); 267539b28106SJacob Keller return err; 267603cb4473SJacob Keller } 267703cb4473SJacob Keller 267803cb4473SJacob Keller return 0; 267903cb4473SJacob Keller } 268003cb4473SJacob Keller 268103cb4473SJacob Keller /** 268203cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 268303cb4473SJacob Keller * @hw: pointer to HW struct 268403cb4473SJacob Keller * @adj: adjustment value to program 268503cb4473SJacob Keller * 268603cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 268703cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 268803cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 268903cb4473SJacob Keller * 269003cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 269103cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 269203cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 269303cb4473SJacob Keller */ 269403cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 269503cb4473SJacob Keller { 269603cb4473SJacob Keller u8 tmr_idx; 269739b28106SJacob Keller int err; 269803cb4473SJacob Keller 269903cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 270003cb4473SJacob Keller 270103cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 270203cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 270303cb4473SJacob Keller */ 270439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 270539b28106SJacob Keller if (err) { 270639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 270739b28106SJacob Keller err); 270839b28106SJacob Keller return err; 270903cb4473SJacob Keller } 271003cb4473SJacob Keller 271139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 271239b28106SJacob Keller if (err) { 271339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 271439b28106SJacob Keller err); 271539b28106SJacob Keller return err; 271603cb4473SJacob Keller } 271703cb4473SJacob Keller 271803cb4473SJacob Keller return 0; 271903cb4473SJacob Keller } 272003cb4473SJacob Keller 272103cb4473SJacob Keller /** 272203cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 272303cb4473SJacob Keller * @hw: pointer to HW struct 272403cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 272503cb4473SJacob Keller * 272603cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 272703cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 272803cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 272903cb4473SJacob Keller */ 273003cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 273103cb4473SJacob Keller { 273203cb4473SJacob Keller u32 high, low; 273303cb4473SJacob Keller u8 tmr_idx; 273439b28106SJacob Keller int err; 273503cb4473SJacob Keller 273603cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 273703cb4473SJacob Keller low = lower_32_bits(incval); 273803cb4473SJacob Keller high = upper_32_bits(incval); 273903cb4473SJacob Keller 274039b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 274139b28106SJacob Keller if (err) { 274239b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 274339b28106SJacob Keller err); 274439b28106SJacob Keller return err; 274503cb4473SJacob Keller } 274603cb4473SJacob Keller 274739b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 274839b28106SJacob Keller if (err) { 274939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 275039b28106SJacob Keller err); 275139b28106SJacob Keller return err; 275203cb4473SJacob Keller } 275303cb4473SJacob Keller 275403cb4473SJacob Keller return 0; 275503cb4473SJacob Keller } 275603cb4473SJacob Keller 275703cb4473SJacob Keller /** 275803cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 275903cb4473SJacob Keller * @hw: pointer to HW struct 276003cb4473SJacob Keller * @cmd: Command to be sent to the port 276103cb4473SJacob Keller * 276203cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 276303cb4473SJacob Keller * command. 276403cb4473SJacob Keller */ 276503cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 276603cb4473SJacob Keller { 276703cb4473SJacob Keller u32 cmd_val, val; 276839b28106SJacob Keller int err; 276903cb4473SJacob Keller 277003cb4473SJacob Keller switch (cmd) { 277103cb4473SJacob Keller case INIT_TIME: 277203cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 277303cb4473SJacob Keller break; 277403cb4473SJacob Keller case INIT_INCVAL: 277503cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 277603cb4473SJacob Keller break; 277703cb4473SJacob Keller case ADJ_TIME: 277803cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 277903cb4473SJacob Keller break; 278003cb4473SJacob Keller case READ_TIME: 278103cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 278203cb4473SJacob Keller break; 278303cb4473SJacob Keller case ADJ_TIME_AT_TIME: 278403cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 278503cb4473SJacob Keller break; 278603cb4473SJacob Keller } 278703cb4473SJacob Keller 278803cb4473SJacob Keller /* Read, modify, write */ 278939b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 279039b28106SJacob Keller if (err) { 279139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 279239b28106SJacob Keller return err; 279303cb4473SJacob Keller } 279403cb4473SJacob Keller 279503cb4473SJacob Keller /* Modify necessary bits only and perform write */ 279603cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 279703cb4473SJacob Keller val |= cmd_val; 279803cb4473SJacob Keller 279939b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 280039b28106SJacob Keller if (err) { 280139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 280239b28106SJacob Keller return err; 280303cb4473SJacob Keller } 280403cb4473SJacob Keller 280503cb4473SJacob Keller return 0; 280603cb4473SJacob Keller } 280703cb4473SJacob Keller 280803cb4473SJacob Keller /* Device agnostic functions 280903cb4473SJacob Keller * 28103a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 28113a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 28123a749623SJacob Keller * necessary. 281303cb4473SJacob Keller */ 281403cb4473SJacob Keller 281503cb4473SJacob Keller /** 281603cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 281703cb4473SJacob Keller * @hw: pointer to the HW struct 281803cb4473SJacob Keller * 281903cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 282003cb4473SJacob Keller * was acquired, false otherwise. 282103cb4473SJacob Keller * 282203cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 282303cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 282403cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 282503cb4473SJacob Keller * bit set, it means that another function acquired the lock. 282603cb4473SJacob Keller * 282703cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 282803cb4473SJacob Keller * functions when done. 282903cb4473SJacob Keller */ 283003cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 283103cb4473SJacob Keller { 283203cb4473SJacob Keller u32 hw_lock; 283303cb4473SJacob Keller int i; 283403cb4473SJacob Keller 2835a711a328SKarol Kolacinski #define MAX_TRIES 15 283603cb4473SJacob Keller 283703cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 283803cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 283903cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2840a711a328SKarol Kolacinski if (hw_lock) { 284103cb4473SJacob Keller /* Somebody is holding the lock */ 2842a711a328SKarol Kolacinski usleep_range(5000, 6000); 2843a711a328SKarol Kolacinski continue; 2844a711a328SKarol Kolacinski } 2845a711a328SKarol Kolacinski 2846a711a328SKarol Kolacinski break; 284703cb4473SJacob Keller } 284803cb4473SJacob Keller 284903cb4473SJacob Keller return !hw_lock; 285003cb4473SJacob Keller } 285103cb4473SJacob Keller 285203cb4473SJacob Keller /** 285303cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 285403cb4473SJacob Keller * @hw: pointer to the HW struct 285503cb4473SJacob Keller * 285603cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 285703cb4473SJacob Keller * the PFTSYN_SEM register. 285803cb4473SJacob Keller */ 285903cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 286003cb4473SJacob Keller { 286103cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 286203cb4473SJacob Keller } 286303cb4473SJacob Keller 286403cb4473SJacob Keller /** 286503cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 286603cb4473SJacob Keller * @hw: pointer to HW struct 286703cb4473SJacob Keller * @cmd: the command to issue 286803cb4473SJacob Keller * 286903cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 287003cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 287103cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 287203cb4473SJacob Keller * timers. 287303cb4473SJacob Keller */ 287403cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 287503cb4473SJacob Keller { 287639b28106SJacob Keller int err; 287703cb4473SJacob Keller 287803cb4473SJacob Keller /* First, prepare the source timer */ 287903cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 288003cb4473SJacob Keller 288103cb4473SJacob Keller /* Next, prepare the ports */ 28823a749623SJacob Keller if (ice_is_e810(hw)) 288339b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 28843a749623SJacob Keller else 28853a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 288639b28106SJacob Keller if (err) { 288739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 288839b28106SJacob Keller cmd, err); 288939b28106SJacob Keller return err; 289003cb4473SJacob Keller } 289103cb4473SJacob Keller 28923a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 28933a749623SJacob Keller * commands synchronously 289403cb4473SJacob Keller */ 28953a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 289603cb4473SJacob Keller 289703cb4473SJacob Keller return 0; 289803cb4473SJacob Keller } 289903cb4473SJacob Keller 290003cb4473SJacob Keller /** 290103cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 290203cb4473SJacob Keller * @hw: pointer to HW struct 290303cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 290403cb4473SJacob Keller * 290503cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 290603cb4473SJacob Keller * step process: 290703cb4473SJacob Keller * 290803cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 290903cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 291003cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 291103cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 291203cb4473SJacob Keller */ 291303cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 291403cb4473SJacob Keller { 291503cb4473SJacob Keller u8 tmr_idx; 291639b28106SJacob Keller int err; 291703cb4473SJacob Keller 291803cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 291903cb4473SJacob Keller 292003cb4473SJacob Keller /* Source timers */ 292103cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 292203cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 292303cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 292403cb4473SJacob Keller 292503cb4473SJacob Keller /* PHY timers */ 292603cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 29273a749623SJacob Keller if (ice_is_e810(hw)) 292839b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 29293a749623SJacob Keller else 29303a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 293139b28106SJacob Keller if (err) 293239b28106SJacob Keller return err; 293303cb4473SJacob Keller 293403cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 293503cb4473SJacob Keller } 293603cb4473SJacob Keller 293703cb4473SJacob Keller /** 293803cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 293903cb4473SJacob Keller * @hw: pointer to HW struct 294003cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 294103cb4473SJacob Keller * 294203cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 294303cb4473SJacob Keller * process: 294403cb4473SJacob Keller * 294503cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 294603cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 294703cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 294803cb4473SJacob Keller * source and port timers to the new increment value at the next clock 294903cb4473SJacob Keller * cycle. 295003cb4473SJacob Keller */ 295103cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 295203cb4473SJacob Keller { 295303cb4473SJacob Keller u8 tmr_idx; 295439b28106SJacob Keller int err; 295503cb4473SJacob Keller 295603cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 295703cb4473SJacob Keller 295803cb4473SJacob Keller /* Shadow Adjust */ 295903cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 296003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 296103cb4473SJacob Keller 29623a749623SJacob Keller if (ice_is_e810(hw)) 296339b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 29643a749623SJacob Keller else 29653a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 296639b28106SJacob Keller if (err) 296739b28106SJacob Keller return err; 296803cb4473SJacob Keller 296903cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 297003cb4473SJacob Keller } 297103cb4473SJacob Keller 297203cb4473SJacob Keller /** 297303cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 297403cb4473SJacob Keller * @hw: pointer to HW struct 297503cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 297603cb4473SJacob Keller * 297703cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 297803cb4473SJacob Keller */ 297903cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 298003cb4473SJacob Keller { 298139b28106SJacob Keller int err; 298203cb4473SJacob Keller 298303cb4473SJacob Keller if (!ice_ptp_lock(hw)) 298403cb4473SJacob Keller return -EBUSY; 298503cb4473SJacob Keller 298639b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 298703cb4473SJacob Keller 298803cb4473SJacob Keller ice_ptp_unlock(hw); 298903cb4473SJacob Keller 299039b28106SJacob Keller return err; 299103cb4473SJacob Keller } 299203cb4473SJacob Keller 299303cb4473SJacob Keller /** 299403cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 299503cb4473SJacob Keller * @hw: pointer to HW struct 299603cb4473SJacob Keller * @adj: Adjustment in nanoseconds 299703cb4473SJacob Keller * 299803cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 299903cb4473SJacob Keller * nanoseconds. This requires a three-step process: 300003cb4473SJacob Keller * 300103cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 300203cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 300303cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 300403cb4473SJacob Keller * both the source and port timers at the next clock cycle. 300503cb4473SJacob Keller */ 300603cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 300703cb4473SJacob Keller { 300803cb4473SJacob Keller u8 tmr_idx; 300939b28106SJacob Keller int err; 301003cb4473SJacob Keller 301103cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 301203cb4473SJacob Keller 301303cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 301403cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 301503cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 301603cb4473SJacob Keller * the value as a 2's complement integer. 301703cb4473SJacob Keller */ 301803cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 301903cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 302003cb4473SJacob Keller 30213a749623SJacob Keller if (ice_is_e810(hw)) 302239b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 30233a749623SJacob Keller else 30243a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 302539b28106SJacob Keller if (err) 302639b28106SJacob Keller return err; 302703cb4473SJacob Keller 302803cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 302903cb4473SJacob Keller } 303003cb4473SJacob Keller 303103cb4473SJacob Keller /** 303203cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 303303cb4473SJacob Keller * @hw: pointer to the HW struct 303403cb4473SJacob Keller * @block: the block to read from 303503cb4473SJacob Keller * @idx: the timestamp index to read 303603cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 303703cb4473SJacob Keller * 30383a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 30393a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 30403a749623SJacob Keller * logical port to read from. 304103cb4473SJacob Keller */ 304203cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 304303cb4473SJacob Keller { 30443a749623SJacob Keller if (ice_is_e810(hw)) 304503cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 30463a749623SJacob Keller else 30473a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 304803cb4473SJacob Keller } 304903cb4473SJacob Keller 305003cb4473SJacob Keller /** 305103cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 305203cb4473SJacob Keller * @hw: pointer to the HW struct 305303cb4473SJacob Keller * @block: the block to read from 305403cb4473SJacob Keller * @idx: the timestamp index to reset 305503cb4473SJacob Keller * 30563a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 30573a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 30583a749623SJacob Keller * block is the logical port to clear from. 305903cb4473SJacob Keller */ 306003cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 306103cb4473SJacob Keller { 30623a749623SJacob Keller if (ice_is_e810(hw)) 306303cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 30643a749623SJacob Keller else 30653a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 306603cb4473SJacob Keller } 3067885fe693SMaciej Machnikowski 3068885fe693SMaciej Machnikowski /* E810T SMA functions 3069885fe693SMaciej Machnikowski * 3070885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 3071885fe693SMaciej Machnikowski * to access the extended GPIOs available. 3072885fe693SMaciej Machnikowski */ 3073885fe693SMaciej Machnikowski 3074885fe693SMaciej Machnikowski /** 3075885fe693SMaciej Machnikowski * ice_get_pca9575_handle 3076885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3077885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 3078885fe693SMaciej Machnikowski * 3079885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 3080885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 3081885fe693SMaciej Machnikowski * will return cached value 3082885fe693SMaciej Machnikowski */ 3083885fe693SMaciej Machnikowski static int 3084885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 3085885fe693SMaciej Machnikowski { 3086885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 3087885fe693SMaciej Machnikowski struct ice_aq_desc desc; 3088885fe693SMaciej Machnikowski int status; 3089885fe693SMaciej Machnikowski u8 idx; 3090885fe693SMaciej Machnikowski 3091885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 3092885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 3093885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3094885fe693SMaciej Machnikowski return 0; 3095885fe693SMaciej Machnikowski } 3096885fe693SMaciej Machnikowski 3097885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 3098885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 3099885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 3100885fe693SMaciej Machnikowski 3101885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 3102885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 3103885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 3104885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 3105885fe693SMaciej Machnikowski 3106885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 3107885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 3108885fe693SMaciej Machnikowski 3109885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 3110885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 3111885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 3112885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 3113885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 3114885fe693SMaciej Machnikowski else 3115885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3116885fe693SMaciej Machnikowski 3117885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 3118885fe693SMaciej Machnikowski 3119885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 3120885fe693SMaciej Machnikowski if (status) 3121885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3122885fe693SMaciej Machnikowski 3123885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 3124885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 3125885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 3126885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3127885fe693SMaciej Machnikowski 3128885fe693SMaciej Machnikowski /* If present save the handle and return it */ 3129885fe693SMaciej Machnikowski hw->io_expander_handle = 3130885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 3131885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3132885fe693SMaciej Machnikowski 3133885fe693SMaciej Machnikowski return 0; 3134885fe693SMaciej Machnikowski } 3135885fe693SMaciej Machnikowski 3136885fe693SMaciej Machnikowski /** 3137885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 3138885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3139885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 3140885fe693SMaciej Machnikowski * 3141885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 3142885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 3143885fe693SMaciej Machnikowski */ 3144885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 3145885fe693SMaciej Machnikowski { 3146885fe693SMaciej Machnikowski int status; 3147885fe693SMaciej Machnikowski u16 handle; 3148885fe693SMaciej Machnikowski u8 i; 3149885fe693SMaciej Machnikowski 3150885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3151885fe693SMaciej Machnikowski if (status) 3152885fe693SMaciej Machnikowski return status; 3153885fe693SMaciej Machnikowski 3154885fe693SMaciej Machnikowski *data = 0; 3155885fe693SMaciej Machnikowski 3156885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3157885fe693SMaciej Machnikowski bool pin; 3158885fe693SMaciej Machnikowski 3159885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3160885fe693SMaciej Machnikowski &pin, NULL); 3161885fe693SMaciej Machnikowski if (status) 3162885fe693SMaciej Machnikowski break; 3163885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 3164885fe693SMaciej Machnikowski } 3165885fe693SMaciej Machnikowski 3166885fe693SMaciej Machnikowski return status; 3167885fe693SMaciej Machnikowski } 3168885fe693SMaciej Machnikowski 3169885fe693SMaciej Machnikowski /** 3170885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 3171885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3172885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 3173885fe693SMaciej Machnikowski * 3174885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 3175885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 3176885fe693SMaciej Machnikowski */ 3177885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 3178885fe693SMaciej Machnikowski { 3179885fe693SMaciej Machnikowski int status; 3180885fe693SMaciej Machnikowski u16 handle; 3181885fe693SMaciej Machnikowski u8 i; 3182885fe693SMaciej Machnikowski 3183885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3184885fe693SMaciej Machnikowski if (status) 3185885fe693SMaciej Machnikowski return status; 3186885fe693SMaciej Machnikowski 3187885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3188885fe693SMaciej Machnikowski bool pin; 3189885fe693SMaciej Machnikowski 3190885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 3191885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3192885fe693SMaciej Machnikowski pin, NULL); 3193885fe693SMaciej Machnikowski if (status) 3194885fe693SMaciej Machnikowski break; 3195885fe693SMaciej Machnikowski } 3196885fe693SMaciej Machnikowski 3197885fe693SMaciej Machnikowski return status; 3198885fe693SMaciej Machnikowski } 3199885fe693SMaciej Machnikowski 3200885fe693SMaciej Machnikowski /** 320143113ff7SKarol Kolacinski * ice_read_pca9575_reg_e810t 320243113ff7SKarol Kolacinski * @hw: pointer to the hw struct 320343113ff7SKarol Kolacinski * @offset: GPIO controller register offset 320443113ff7SKarol Kolacinski * @data: pointer to data to be read from the GPIO controller 320543113ff7SKarol Kolacinski * 320643113ff7SKarol Kolacinski * Read the register from the GPIO controller 320743113ff7SKarol Kolacinski */ 320843113ff7SKarol Kolacinski int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) 320943113ff7SKarol Kolacinski { 321043113ff7SKarol Kolacinski struct ice_aqc_link_topo_addr link_topo; 321143113ff7SKarol Kolacinski __le16 addr; 321243113ff7SKarol Kolacinski u16 handle; 321343113ff7SKarol Kolacinski int err; 321443113ff7SKarol Kolacinski 321543113ff7SKarol Kolacinski memset(&link_topo, 0, sizeof(link_topo)); 321643113ff7SKarol Kolacinski 321743113ff7SKarol Kolacinski err = ice_get_pca9575_handle(hw, &handle); 321843113ff7SKarol Kolacinski if (err) 321943113ff7SKarol Kolacinski return err; 322043113ff7SKarol Kolacinski 322143113ff7SKarol Kolacinski link_topo.handle = cpu_to_le16(handle); 322243113ff7SKarol Kolacinski link_topo.topo_params.node_type_ctx = 322343113ff7SKarol Kolacinski FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, 322443113ff7SKarol Kolacinski ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED); 322543113ff7SKarol Kolacinski 322643113ff7SKarol Kolacinski addr = cpu_to_le16((u16)offset); 322743113ff7SKarol Kolacinski 322843113ff7SKarol Kolacinski return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL); 322943113ff7SKarol Kolacinski } 323043113ff7SKarol Kolacinski 323143113ff7SKarol Kolacinski /** 3232885fe693SMaciej Machnikowski * ice_is_pca9575_present 3233885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3234885fe693SMaciej Machnikowski * 3235885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 3236885fe693SMaciej Machnikowski */ 3237885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 3238885fe693SMaciej Machnikowski { 3239885fe693SMaciej Machnikowski u16 handle = 0; 3240885fe693SMaciej Machnikowski int status; 3241885fe693SMaciej Machnikowski 3242885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 3243885fe693SMaciej Machnikowski return false; 3244885fe693SMaciej Machnikowski 3245885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3246885fe693SMaciej Machnikowski 3247885fe693SMaciej Machnikowski return !status && handle; 3248885fe693SMaciej Machnikowski } 3249b2ee7256SJacob Keller 3250b2ee7256SJacob Keller /** 3251b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 3252b2ee7256SJacob Keller * @hw: pointer to the HW struct 3253b2ee7256SJacob Keller * 3254b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 3255b2ee7256SJacob Keller */ 3256b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 3257b2ee7256SJacob Keller { 3258b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 3259b2ee7256SJacob Keller 3260b2ee7256SJacob Keller /* Enable source clocks */ 3261b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 3262b2ee7256SJacob Keller 3263b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 3264b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 3265b2ee7256SJacob Keller 32663a749623SJacob Keller if (ice_is_e810(hw)) 3267b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 32683a749623SJacob Keller else 32693a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 3270b2ee7256SJacob Keller } 3271