103cb4473SJacob Keller // SPDX-License-Identifier: GPL-2.0 203cb4473SJacob Keller /* Copyright (C) 2021, Intel Corporation. */ 303cb4473SJacob Keller 403cb4473SJacob Keller #include "ice_common.h" 503cb4473SJacob Keller #include "ice_ptp_hw.h" 63a749623SJacob Keller #include "ice_ptp_consts.h" 7b111ab5aSJacob Keller #include "ice_cgu_regs.h" 803cb4473SJacob Keller 903cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used 1003cb4473SJacob Keller * for the Precision Time Protocol. 1103cb4473SJacob Keller * 1203cb4473SJacob Keller * The ice hardware represents the current time using three registers: 1303cb4473SJacob Keller * 1403cb4473SJacob Keller * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R 1503cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1603cb4473SJacob Keller * | 32 bits | | 32 bits | | 32 bits | 1703cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1803cb4473SJacob Keller * 1903cb4473SJacob Keller * The registers are incremented every clock tick using a 40bit increment 2003cb4473SJacob Keller * value defined over two registers: 2103cb4473SJacob Keller * 2203cb4473SJacob Keller * GLTSYN_INCVAL_H GLTSYN_INCVAL_L 2303cb4473SJacob Keller * +---------------+ +---------------+ 2403cb4473SJacob Keller * | 8 bit s | | 32 bits | 2503cb4473SJacob Keller * +---------------+ +---------------+ 2603cb4473SJacob Keller * 2703cb4473SJacob Keller * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L 2803cb4473SJacob Keller * registers every clock source tick. Depending on the specific device 2903cb4473SJacob Keller * configuration, the clock source frequency could be one of a number of 3003cb4473SJacob Keller * values. 3103cb4473SJacob Keller * 3203cb4473SJacob Keller * For E810 devices, the increment frequency is 812.5 MHz 3303cb4473SJacob Keller * 343a749623SJacob Keller * For E822 devices the clock can be derived from different sources, and the 353a749623SJacob Keller * increment has an effective frequency of one of the following: 363a749623SJacob Keller * - 823.4375 MHz 373a749623SJacob Keller * - 783.36 MHz 383a749623SJacob Keller * - 796.875 MHz 393a749623SJacob Keller * - 816 MHz 403a749623SJacob Keller * - 830.078125 MHz 413a749623SJacob Keller * - 783.36 MHz 423a749623SJacob Keller * 4303cb4473SJacob Keller * The hardware captures timestamps in the PHY for incoming packets, and for 4403cb4473SJacob Keller * outgoing packets on request. To support this, the PHY maintains a timer 4503cb4473SJacob Keller * that matches the lower 64 bits of the global source timer. 4603cb4473SJacob Keller * 4703cb4473SJacob Keller * In order to ensure that the PHY timers and the source timer are equivalent, 4803cb4473SJacob Keller * shadow registers are used to prepare the desired initial values. A special 4903cb4473SJacob Keller * sync command is issued to trigger copying from the shadow registers into 5003cb4473SJacob Keller * the appropriate source and PHY registers simultaneously. 513a749623SJacob Keller * 523a749623SJacob Keller * The driver supports devices which have different PHYs with subtly different 533a749623SJacob Keller * mechanisms to program and control the timers. We divide the devices into 543a749623SJacob Keller * families named after the first major device, E810 and similar devices, and 553a749623SJacob Keller * E822 and similar devices. 563a749623SJacob Keller * 573a749623SJacob Keller * - E822 based devices have additional support for fine grained Vernier 583a749623SJacob Keller * calibration which requires significant setup 593a749623SJacob Keller * - The layout of timestamp data in the PHY register blocks is different 603a749623SJacob Keller * - The way timer synchronization commands are issued is different. 613a749623SJacob Keller * 623a749623SJacob Keller * To support this, very low level functions have an e810 or e822 suffix 633a749623SJacob Keller * indicating what type of device they work on. Higher level abstractions for 643a749623SJacob Keller * tasks that can be done on both devices do not have the suffix and will 653a749623SJacob Keller * correctly look up the appropriate low level function when running. 663a749623SJacob Keller * 673a749623SJacob Keller * Functions which only make sense on a single device family may not have 683a749623SJacob Keller * a suitable generic implementation 6903cb4473SJacob Keller */ 7003cb4473SJacob Keller 7103cb4473SJacob Keller /** 7203cb4473SJacob Keller * ice_get_ptp_src_clock_index - determine source clock index 7303cb4473SJacob Keller * @hw: pointer to HW struct 7403cb4473SJacob Keller * 7503cb4473SJacob Keller * Determine the source clock index currently in use, based on device 7603cb4473SJacob Keller * capabilities reported during initialization. 7703cb4473SJacob Keller */ 7803cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw) 7903cb4473SJacob Keller { 8003cb4473SJacob Keller return hw->func_caps.ts_func_info.tmr_index_assoc; 8103cb4473SJacob Keller } 8203cb4473SJacob Keller 833a749623SJacob Keller /** 843a749623SJacob Keller * ice_ptp_read_src_incval - Read source timer increment value 853a749623SJacob Keller * @hw: pointer to HW struct 863a749623SJacob Keller * 873a749623SJacob Keller * Read the increment value of the source timer and return it. 883a749623SJacob Keller */ 893a749623SJacob Keller static u64 ice_ptp_read_src_incval(struct ice_hw *hw) 903a749623SJacob Keller { 913a749623SJacob Keller u32 lo, hi; 923a749623SJacob Keller u8 tmr_idx; 933a749623SJacob Keller 943a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 953a749623SJacob Keller 963a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 973a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 983a749623SJacob Keller 993a749623SJacob Keller return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo; 1003a749623SJacob Keller } 1013a749623SJacob Keller 1023a749623SJacob Keller /** 1033a749623SJacob Keller * ice_ptp_src_cmd - Prepare source timer for a timer command 1043a749623SJacob Keller * @hw: pointer to HW structure 1053a749623SJacob Keller * @cmd: Timer command 1063a749623SJacob Keller * 1073a749623SJacob Keller * Prepare the source timer for an upcoming timer sync command. 1083a749623SJacob Keller */ 1093a749623SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 1103a749623SJacob Keller { 1113a749623SJacob Keller u32 cmd_val; 1123a749623SJacob Keller u8 tmr_idx; 1133a749623SJacob Keller 1143a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 1153a749623SJacob Keller cmd_val = tmr_idx << SEL_CPK_SRC; 1163a749623SJacob Keller 1173a749623SJacob Keller switch (cmd) { 1183a749623SJacob Keller case INIT_TIME: 1193a749623SJacob Keller cmd_val |= GLTSYN_CMD_INIT_TIME; 1203a749623SJacob Keller break; 1213a749623SJacob Keller case INIT_INCVAL: 1223a749623SJacob Keller cmd_val |= GLTSYN_CMD_INIT_INCVAL; 1233a749623SJacob Keller break; 1243a749623SJacob Keller case ADJ_TIME: 1253a749623SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_TIME; 1263a749623SJacob Keller break; 1273a749623SJacob Keller case ADJ_TIME_AT_TIME: 1283a749623SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME; 1293a749623SJacob Keller break; 1303a749623SJacob Keller case READ_TIME: 1313a749623SJacob Keller cmd_val |= GLTSYN_CMD_READ_TIME; 1323a749623SJacob Keller break; 1333a749623SJacob Keller } 1343a749623SJacob Keller 1353a749623SJacob Keller wr32(hw, GLTSYN_CMD, cmd_val); 1363a749623SJacob Keller } 1373a749623SJacob Keller 1383a749623SJacob Keller /** 1393a749623SJacob Keller * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands 1403a749623SJacob Keller * @hw: pointer to HW struct 1413a749623SJacob Keller * 1423a749623SJacob Keller * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the 1433a749623SJacob Keller * write immediately. This triggers the hardware to begin executing all of the 1443a749623SJacob Keller * source and PHY timer commands synchronously. 1453a749623SJacob Keller */ 1463a749623SJacob Keller static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw) 1473a749623SJacob Keller { 1483a749623SJacob Keller wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD); 1493a749623SJacob Keller ice_flush(hw); 1503a749623SJacob Keller } 1513a749623SJacob Keller 1523a749623SJacob Keller /* E822 family functions 1533a749623SJacob Keller * 1543a749623SJacob Keller * The following functions operate on the E822 family of devices. 1553a749623SJacob Keller */ 1563a749623SJacob Keller 1573a749623SJacob Keller /** 1583a749623SJacob Keller * ice_fill_phy_msg_e822 - Fill message data for a PHY register access 1593a749623SJacob Keller * @msg: the PHY message buffer to fill in 1603a749623SJacob Keller * @port: the port to access 1613a749623SJacob Keller * @offset: the register offset 1623a749623SJacob Keller */ 1633a749623SJacob Keller static void 1643a749623SJacob Keller ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset) 1653a749623SJacob Keller { 1663a749623SJacob Keller int phy_port, phy, quadtype; 1673a749623SJacob Keller 1683a749623SJacob Keller phy_port = port % ICE_PORTS_PER_PHY; 1693a749623SJacob Keller phy = port / ICE_PORTS_PER_PHY; 1703a749623SJacob Keller quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE; 1713a749623SJacob Keller 1723a749623SJacob Keller if (quadtype == 0) { 1733a749623SJacob Keller msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port); 1743a749623SJacob Keller msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port); 1753a749623SJacob Keller } else { 1763a749623SJacob Keller msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port); 1773a749623SJacob Keller msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port); 1783a749623SJacob Keller } 1793a749623SJacob Keller 1803a749623SJacob Keller if (phy == 0) 1813a749623SJacob Keller msg->dest_dev = rmn_0; 1823a749623SJacob Keller else if (phy == 1) 1833a749623SJacob Keller msg->dest_dev = rmn_1; 1843a749623SJacob Keller else 1853a749623SJacob Keller msg->dest_dev = rmn_2; 1863a749623SJacob Keller } 1873a749623SJacob Keller 1883a749623SJacob Keller /** 1893a749623SJacob Keller * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register 1903a749623SJacob Keller * @low_addr: the low address to check 1913a749623SJacob Keller * @high_addr: on return, contains the high address of the 64bit register 1923a749623SJacob Keller * 1933a749623SJacob Keller * Checks if the provided low address is one of the known 64bit PHY values 1943a749623SJacob Keller * represented as two 32bit registers. If it is, return the appropriate high 1953a749623SJacob Keller * register offset to use. 1963a749623SJacob Keller */ 1973a749623SJacob Keller static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr) 1983a749623SJacob Keller { 1993a749623SJacob Keller switch (low_addr) { 2003a749623SJacob Keller case P_REG_PAR_PCS_TX_OFFSET_L: 2013a749623SJacob Keller *high_addr = P_REG_PAR_PCS_TX_OFFSET_U; 2023a749623SJacob Keller return true; 2033a749623SJacob Keller case P_REG_PAR_PCS_RX_OFFSET_L: 2043a749623SJacob Keller *high_addr = P_REG_PAR_PCS_RX_OFFSET_U; 2053a749623SJacob Keller return true; 2063a749623SJacob Keller case P_REG_PAR_TX_TIME_L: 2073a749623SJacob Keller *high_addr = P_REG_PAR_TX_TIME_U; 2083a749623SJacob Keller return true; 2093a749623SJacob Keller case P_REG_PAR_RX_TIME_L: 2103a749623SJacob Keller *high_addr = P_REG_PAR_RX_TIME_U; 2113a749623SJacob Keller return true; 2123a749623SJacob Keller case P_REG_TOTAL_TX_OFFSET_L: 2133a749623SJacob Keller *high_addr = P_REG_TOTAL_TX_OFFSET_U; 2143a749623SJacob Keller return true; 2153a749623SJacob Keller case P_REG_TOTAL_RX_OFFSET_L: 2163a749623SJacob Keller *high_addr = P_REG_TOTAL_RX_OFFSET_U; 2173a749623SJacob Keller return true; 2183a749623SJacob Keller case P_REG_UIX66_10G_40G_L: 2193a749623SJacob Keller *high_addr = P_REG_UIX66_10G_40G_U; 2203a749623SJacob Keller return true; 2213a749623SJacob Keller case P_REG_UIX66_25G_100G_L: 2223a749623SJacob Keller *high_addr = P_REG_UIX66_25G_100G_U; 2233a749623SJacob Keller return true; 2243a749623SJacob Keller case P_REG_TX_CAPTURE_L: 2253a749623SJacob Keller *high_addr = P_REG_TX_CAPTURE_U; 2263a749623SJacob Keller return true; 2273a749623SJacob Keller case P_REG_RX_CAPTURE_L: 2283a749623SJacob Keller *high_addr = P_REG_RX_CAPTURE_U; 2293a749623SJacob Keller return true; 2303a749623SJacob Keller case P_REG_TX_TIMER_INC_PRE_L: 2313a749623SJacob Keller *high_addr = P_REG_TX_TIMER_INC_PRE_U; 2323a749623SJacob Keller return true; 2333a749623SJacob Keller case P_REG_RX_TIMER_INC_PRE_L: 2343a749623SJacob Keller *high_addr = P_REG_RX_TIMER_INC_PRE_U; 2353a749623SJacob Keller return true; 2363a749623SJacob Keller default: 2373a749623SJacob Keller return false; 2383a749623SJacob Keller } 2393a749623SJacob Keller } 2403a749623SJacob Keller 2413a749623SJacob Keller /** 2423a749623SJacob Keller * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register 2433a749623SJacob Keller * @low_addr: the low address to check 2443a749623SJacob Keller * @high_addr: on return, contains the high address of the 40bit value 2453a749623SJacob Keller * 2463a749623SJacob Keller * Checks if the provided low address is one of the known 40bit PHY values 2473a749623SJacob Keller * split into two registers with the lower 8 bits in the low register and the 2483a749623SJacob Keller * upper 32 bits in the high register. If it is, return the appropriate high 2493a749623SJacob Keller * register offset to use. 2503a749623SJacob Keller */ 2513a749623SJacob Keller static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr) 2523a749623SJacob Keller { 2533a749623SJacob Keller switch (low_addr) { 2543a749623SJacob Keller case P_REG_TIMETUS_L: 2553a749623SJacob Keller *high_addr = P_REG_TIMETUS_U; 2563a749623SJacob Keller return true; 2573a749623SJacob Keller case P_REG_PAR_RX_TUS_L: 2583a749623SJacob Keller *high_addr = P_REG_PAR_RX_TUS_U; 2593a749623SJacob Keller return true; 2603a749623SJacob Keller case P_REG_PAR_TX_TUS_L: 2613a749623SJacob Keller *high_addr = P_REG_PAR_TX_TUS_U; 2623a749623SJacob Keller return true; 2633a749623SJacob Keller case P_REG_PCS_RX_TUS_L: 2643a749623SJacob Keller *high_addr = P_REG_PCS_RX_TUS_U; 2653a749623SJacob Keller return true; 2663a749623SJacob Keller case P_REG_PCS_TX_TUS_L: 2673a749623SJacob Keller *high_addr = P_REG_PCS_TX_TUS_U; 2683a749623SJacob Keller return true; 2693a749623SJacob Keller case P_REG_DESK_PAR_RX_TUS_L: 2703a749623SJacob Keller *high_addr = P_REG_DESK_PAR_RX_TUS_U; 2713a749623SJacob Keller return true; 2723a749623SJacob Keller case P_REG_DESK_PAR_TX_TUS_L: 2733a749623SJacob Keller *high_addr = P_REG_DESK_PAR_TX_TUS_U; 2743a749623SJacob Keller return true; 2753a749623SJacob Keller case P_REG_DESK_PCS_RX_TUS_L: 2763a749623SJacob Keller *high_addr = P_REG_DESK_PCS_RX_TUS_U; 2773a749623SJacob Keller return true; 2783a749623SJacob Keller case P_REG_DESK_PCS_TX_TUS_L: 2793a749623SJacob Keller *high_addr = P_REG_DESK_PCS_TX_TUS_U; 2803a749623SJacob Keller return true; 2813a749623SJacob Keller default: 2823a749623SJacob Keller return false; 2833a749623SJacob Keller } 2843a749623SJacob Keller } 2853a749623SJacob Keller 2863a749623SJacob Keller /** 2873a749623SJacob Keller * ice_read_phy_reg_e822 - Read a PHY register 2883a749623SJacob Keller * @hw: pointer to the HW struct 2893a749623SJacob Keller * @port: PHY port to read from 2903a749623SJacob Keller * @offset: PHY register offset to read 2913a749623SJacob Keller * @val: on return, the contents read from the PHY 2923a749623SJacob Keller * 2933a749623SJacob Keller * Read a PHY register for the given port over the device sideband queue. 2943a749623SJacob Keller */ 2953a749623SJacob Keller int 2963a749623SJacob Keller ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val) 2973a749623SJacob Keller { 2983a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 2993a749623SJacob Keller int err; 3003a749623SJacob Keller 3013a749623SJacob Keller ice_fill_phy_msg_e822(&msg, port, offset); 3023a749623SJacob Keller msg.opcode = ice_sbq_msg_rd; 3033a749623SJacob Keller 3043a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 3053a749623SJacob Keller if (err) { 3063a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 3073a749623SJacob Keller err); 3083a749623SJacob Keller return err; 3093a749623SJacob Keller } 3103a749623SJacob Keller 3113a749623SJacob Keller *val = msg.data; 3123a749623SJacob Keller 3133a749623SJacob Keller return 0; 3143a749623SJacob Keller } 3153a749623SJacob Keller 3163a749623SJacob Keller /** 3173a749623SJacob Keller * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers 3183a749623SJacob Keller * @hw: pointer to the HW struct 3193a749623SJacob Keller * @port: PHY port to read from 3203a749623SJacob Keller * @low_addr: offset of the lower register to read from 3213a749623SJacob Keller * @val: on return, the contents of the 64bit value from the PHY registers 3223a749623SJacob Keller * 3233a749623SJacob Keller * Reads the two registers associated with a 64bit value and returns it in the 3243a749623SJacob Keller * val pointer. The offset always specifies the lower register offset to use. 3253a749623SJacob Keller * The high offset is looked up. This function only operates on registers 3263a749623SJacob Keller * known to be two parts of a 64bit value. 3273a749623SJacob Keller */ 3283a749623SJacob Keller static int 3293a749623SJacob Keller ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) 3303a749623SJacob Keller { 3313a749623SJacob Keller u32 low, high; 3323a749623SJacob Keller u16 high_addr; 3333a749623SJacob Keller int err; 3343a749623SJacob Keller 3353a749623SJacob Keller /* Only operate on registers known to be split into two 32bit 3363a749623SJacob Keller * registers. 3373a749623SJacob Keller */ 3383a749623SJacob Keller if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { 3393a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", 3403a749623SJacob Keller low_addr); 3413a749623SJacob Keller return -EINVAL; 3423a749623SJacob Keller } 3433a749623SJacob Keller 3443a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, low_addr, &low); 3453a749623SJacob Keller if (err) { 3463a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d", 3473a749623SJacob Keller low_addr, err); 3483a749623SJacob Keller return err; 3493a749623SJacob Keller } 3503a749623SJacob Keller 3513a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, high_addr, &high); 3523a749623SJacob Keller if (err) { 3533a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d", 3543a749623SJacob Keller high_addr, err); 3553a749623SJacob Keller return err; 3563a749623SJacob Keller } 3573a749623SJacob Keller 3583a749623SJacob Keller *val = (u64)high << 32 | low; 3593a749623SJacob Keller 3603a749623SJacob Keller return 0; 3613a749623SJacob Keller } 3623a749623SJacob Keller 3633a749623SJacob Keller /** 3643a749623SJacob Keller * ice_write_phy_reg_e822 - Write a PHY register 3653a749623SJacob Keller * @hw: pointer to the HW struct 3663a749623SJacob Keller * @port: PHY port to write to 3673a749623SJacob Keller * @offset: PHY register offset to write 3683a749623SJacob Keller * @val: The value to write to the register 3693a749623SJacob Keller * 3703a749623SJacob Keller * Write a PHY register for the given port over the device sideband queue. 3713a749623SJacob Keller */ 3723a749623SJacob Keller int 3733a749623SJacob Keller ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val) 3743a749623SJacob Keller { 3753a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 3763a749623SJacob Keller int err; 3773a749623SJacob Keller 3783a749623SJacob Keller ice_fill_phy_msg_e822(&msg, port, offset); 3793a749623SJacob Keller msg.opcode = ice_sbq_msg_wr; 3803a749623SJacob Keller msg.data = val; 3813a749623SJacob Keller 3823a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 3833a749623SJacob Keller if (err) { 3843a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 3853a749623SJacob Keller err); 3863a749623SJacob Keller return err; 3873a749623SJacob Keller } 3883a749623SJacob Keller 3893a749623SJacob Keller return 0; 3903a749623SJacob Keller } 3913a749623SJacob Keller 3923a749623SJacob Keller /** 3933a749623SJacob Keller * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY 3943a749623SJacob Keller * @hw: pointer to the HW struct 3953a749623SJacob Keller * @port: port to write to 3963a749623SJacob Keller * @low_addr: offset of the low register 3973a749623SJacob Keller * @val: 40b value to write 3983a749623SJacob Keller * 3993a749623SJacob Keller * Write the provided 40b value to the two associated registers by splitting 4003a749623SJacob Keller * it up into two chunks, the lower 8 bits and the upper 32 bits. 4013a749623SJacob Keller */ 4023a749623SJacob Keller static int 4033a749623SJacob Keller ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) 4043a749623SJacob Keller { 4053a749623SJacob Keller u32 low, high; 4063a749623SJacob Keller u16 high_addr; 4073a749623SJacob Keller int err; 4083a749623SJacob Keller 4093a749623SJacob Keller /* Only operate on registers known to be split into a lower 8 bit 4103a749623SJacob Keller * register and an upper 32 bit register. 4113a749623SJacob Keller */ 4123a749623SJacob Keller if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) { 4133a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n", 4143a749623SJacob Keller low_addr); 4153a749623SJacob Keller return -EINVAL; 4163a749623SJacob Keller } 4173a749623SJacob Keller 4183a749623SJacob Keller low = (u32)(val & P_REG_40B_LOW_M); 4193a749623SJacob Keller high = (u32)(val >> P_REG_40B_HIGH_S); 4203a749623SJacob Keller 4213a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, low_addr, low); 4223a749623SJacob Keller if (err) { 4233a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", 4243a749623SJacob Keller low_addr, err); 4253a749623SJacob Keller return err; 4263a749623SJacob Keller } 4273a749623SJacob Keller 4283a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, high_addr, high); 4293a749623SJacob Keller if (err) { 4303a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", 4313a749623SJacob Keller high_addr, err); 4323a749623SJacob Keller return err; 4333a749623SJacob Keller } 4343a749623SJacob Keller 4353a749623SJacob Keller return 0; 4363a749623SJacob Keller } 4373a749623SJacob Keller 4383a749623SJacob Keller /** 4393a749623SJacob Keller * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers 4403a749623SJacob Keller * @hw: pointer to the HW struct 4413a749623SJacob Keller * @port: PHY port to read from 4423a749623SJacob Keller * @low_addr: offset of the lower register to read from 4433a749623SJacob Keller * @val: the contents of the 64bit value to write to PHY 4443a749623SJacob Keller * 4453a749623SJacob Keller * Write the 64bit value to the two associated 32bit PHY registers. The offset 4463a749623SJacob Keller * is always specified as the lower register, and the high address is looked 4473a749623SJacob Keller * up. This function only operates on registers known to be two parts of 4483a749623SJacob Keller * a 64bit value. 4493a749623SJacob Keller */ 4503a749623SJacob Keller static int 4513a749623SJacob Keller ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) 4523a749623SJacob Keller { 4533a749623SJacob Keller u32 low, high; 4543a749623SJacob Keller u16 high_addr; 4553a749623SJacob Keller int err; 4563a749623SJacob Keller 4573a749623SJacob Keller /* Only operate on registers known to be split into two 32bit 4583a749623SJacob Keller * registers. 4593a749623SJacob Keller */ 4603a749623SJacob Keller if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { 4613a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", 4623a749623SJacob Keller low_addr); 4633a749623SJacob Keller return -EINVAL; 4643a749623SJacob Keller } 4653a749623SJacob Keller 4663a749623SJacob Keller low = lower_32_bits(val); 4673a749623SJacob Keller high = upper_32_bits(val); 4683a749623SJacob Keller 4693a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, low_addr, low); 4703a749623SJacob Keller if (err) { 4713a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", 4723a749623SJacob Keller low_addr, err); 4733a749623SJacob Keller return err; 4743a749623SJacob Keller } 4753a749623SJacob Keller 4763a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, high_addr, high); 4773a749623SJacob Keller if (err) { 4783a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", 4793a749623SJacob Keller high_addr, err); 4803a749623SJacob Keller return err; 4813a749623SJacob Keller } 4823a749623SJacob Keller 4833a749623SJacob Keller return 0; 4843a749623SJacob Keller } 4853a749623SJacob Keller 4863a749623SJacob Keller /** 4873a749623SJacob Keller * ice_fill_quad_msg_e822 - Fill message data for quad register access 4883a749623SJacob Keller * @msg: the PHY message buffer to fill in 4893a749623SJacob Keller * @quad: the quad to access 4903a749623SJacob Keller * @offset: the register offset 4913a749623SJacob Keller * 4923a749623SJacob Keller * Fill a message buffer for accessing a register in a quad shared between 4933a749623SJacob Keller * multiple PHYs. 4943a749623SJacob Keller */ 4953a749623SJacob Keller static void 4963a749623SJacob Keller ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) 4973a749623SJacob Keller { 4983a749623SJacob Keller u32 addr; 4993a749623SJacob Keller 5003a749623SJacob Keller msg->dest_dev = rmn_0; 5013a749623SJacob Keller 5023a749623SJacob Keller if ((quad % ICE_NUM_QUAD_TYPE) == 0) 5033a749623SJacob Keller addr = Q_0_BASE + offset; 5043a749623SJacob Keller else 5053a749623SJacob Keller addr = Q_1_BASE + offset; 5063a749623SJacob Keller 5073a749623SJacob Keller msg->msg_addr_low = lower_16_bits(addr); 5083a749623SJacob Keller msg->msg_addr_high = upper_16_bits(addr); 5093a749623SJacob Keller } 5103a749623SJacob Keller 5113a749623SJacob Keller /** 5123a749623SJacob Keller * ice_read_quad_reg_e822 - Read a PHY quad register 5133a749623SJacob Keller * @hw: pointer to the HW struct 5143a749623SJacob Keller * @quad: quad to read from 5153a749623SJacob Keller * @offset: quad register offset to read 5163a749623SJacob Keller * @val: on return, the contents read from the quad 5173a749623SJacob Keller * 5183a749623SJacob Keller * Read a quad register over the device sideband queue. Quad registers are 5193a749623SJacob Keller * shared between multiple PHYs. 5203a749623SJacob Keller */ 5213a749623SJacob Keller int 5223a749623SJacob Keller ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) 5233a749623SJacob Keller { 5243a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 5253a749623SJacob Keller int err; 5263a749623SJacob Keller 5273a749623SJacob Keller if (quad >= ICE_MAX_QUAD) 5283a749623SJacob Keller return -EINVAL; 5293a749623SJacob Keller 5303a749623SJacob Keller ice_fill_quad_msg_e822(&msg, quad, offset); 5313a749623SJacob Keller msg.opcode = ice_sbq_msg_rd; 5323a749623SJacob Keller 5333a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 5343a749623SJacob Keller if (err) { 5353a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 5363a749623SJacob Keller err); 5373a749623SJacob Keller return err; 5383a749623SJacob Keller } 5393a749623SJacob Keller 5403a749623SJacob Keller *val = msg.data; 5413a749623SJacob Keller 5423a749623SJacob Keller return 0; 5433a749623SJacob Keller } 5443a749623SJacob Keller 5453a749623SJacob Keller /** 5463a749623SJacob Keller * ice_write_quad_reg_e822 - Write a PHY quad register 5473a749623SJacob Keller * @hw: pointer to the HW struct 5483a749623SJacob Keller * @quad: quad to write to 5493a749623SJacob Keller * @offset: quad register offset to write 5503a749623SJacob Keller * @val: The value to write to the register 5513a749623SJacob Keller * 5523a749623SJacob Keller * Write a quad register over the device sideband queue. Quad registers are 5533a749623SJacob Keller * shared between multiple PHYs. 5543a749623SJacob Keller */ 5553a749623SJacob Keller int 5563a749623SJacob Keller ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val) 5573a749623SJacob Keller { 5583a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 5593a749623SJacob Keller int err; 5603a749623SJacob Keller 5613a749623SJacob Keller if (quad >= ICE_MAX_QUAD) 5623a749623SJacob Keller return -EINVAL; 5633a749623SJacob Keller 5643a749623SJacob Keller ice_fill_quad_msg_e822(&msg, quad, offset); 5653a749623SJacob Keller msg.opcode = ice_sbq_msg_wr; 5663a749623SJacob Keller msg.data = val; 5673a749623SJacob Keller 5683a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 5693a749623SJacob Keller if (err) { 5703a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 5713a749623SJacob Keller err); 5723a749623SJacob Keller return err; 5733a749623SJacob Keller } 5743a749623SJacob Keller 5753a749623SJacob Keller return 0; 5763a749623SJacob Keller } 5773a749623SJacob Keller 5783a749623SJacob Keller /** 5793a749623SJacob Keller * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block 5803a749623SJacob Keller * @hw: pointer to the HW struct 5813a749623SJacob Keller * @quad: the quad to read from 5823a749623SJacob Keller * @idx: the timestamp index to read 5833a749623SJacob Keller * @tstamp: on return, the 40bit timestamp value 5843a749623SJacob Keller * 5853a749623SJacob Keller * Read a 40bit timestamp value out of the two associated registers in the 5863a749623SJacob Keller * quad memory block that is shared between the internal PHYs of the E822 5873a749623SJacob Keller * family of devices. 5883a749623SJacob Keller */ 5893a749623SJacob Keller static int 5903a749623SJacob Keller ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) 5913a749623SJacob Keller { 5923a749623SJacob Keller u16 lo_addr, hi_addr; 5933a749623SJacob Keller u32 lo, hi; 5943a749623SJacob Keller int err; 5953a749623SJacob Keller 5963a749623SJacob Keller lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); 5973a749623SJacob Keller hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); 5983a749623SJacob Keller 5993a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo); 6003a749623SJacob Keller if (err) { 6013a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 6023a749623SJacob Keller err); 6033a749623SJacob Keller return err; 6043a749623SJacob Keller } 6053a749623SJacob Keller 6063a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi); 6073a749623SJacob Keller if (err) { 6083a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 6093a749623SJacob Keller err); 6103a749623SJacob Keller return err; 6113a749623SJacob Keller } 6123a749623SJacob Keller 6133a749623SJacob Keller /* For E822 based internal PHYs, the timestamp is reported with the 6143a749623SJacob Keller * lower 8 bits in the low register, and the upper 32 bits in the high 6153a749623SJacob Keller * register. 6163a749623SJacob Keller */ 6173a749623SJacob Keller *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M); 6183a749623SJacob Keller 6193a749623SJacob Keller return 0; 6203a749623SJacob Keller } 6213a749623SJacob Keller 6223a749623SJacob Keller /** 6233a749623SJacob Keller * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block 6243a749623SJacob Keller * @hw: pointer to the HW struct 6253a749623SJacob Keller * @quad: the quad to read from 6263a749623SJacob Keller * @idx: the timestamp index to reset 6273a749623SJacob Keller * 6283a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the PHY quad block that is 6293a749623SJacob Keller * shared between the internal PHYs on the E822 devices. 6303a749623SJacob Keller */ 6313a749623SJacob Keller static int 6323a749623SJacob Keller ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx) 6333a749623SJacob Keller { 6343a749623SJacob Keller u16 lo_addr, hi_addr; 6353a749623SJacob Keller int err; 6363a749623SJacob Keller 6373a749623SJacob Keller lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); 6383a749623SJacob Keller hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); 6393a749623SJacob Keller 6403a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0); 6413a749623SJacob Keller if (err) { 6423a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 6433a749623SJacob Keller err); 6443a749623SJacob Keller return err; 6453a749623SJacob Keller } 6463a749623SJacob Keller 6473a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0); 6483a749623SJacob Keller if (err) { 6493a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 6503a749623SJacob Keller err); 6513a749623SJacob Keller return err; 6523a749623SJacob Keller } 6533a749623SJacob Keller 6543a749623SJacob Keller return 0; 6553a749623SJacob Keller } 6563a749623SJacob Keller 6573a749623SJacob Keller /** 658b111ab5aSJacob Keller * ice_read_cgu_reg_e822 - Read a CGU register 659b111ab5aSJacob Keller * @hw: pointer to the HW struct 660b111ab5aSJacob Keller * @addr: Register address to read 661b111ab5aSJacob Keller * @val: storage for register value read 662b111ab5aSJacob Keller * 663b111ab5aSJacob Keller * Read the contents of a register of the Clock Generation Unit. Only 664b111ab5aSJacob Keller * applicable to E822 devices. 665b111ab5aSJacob Keller */ 666b111ab5aSJacob Keller static int 667b111ab5aSJacob Keller ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) 668b111ab5aSJacob Keller { 669b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 670b111ab5aSJacob Keller int err; 671b111ab5aSJacob Keller 672b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_rd; 673b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 674b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 675b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 676b111ab5aSJacob Keller 677b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 678b111ab5aSJacob Keller if (err) { 679b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n", 680b111ab5aSJacob Keller addr, err); 681b111ab5aSJacob Keller return err; 682b111ab5aSJacob Keller } 683b111ab5aSJacob Keller 684b111ab5aSJacob Keller *val = cgu_msg.data; 685b111ab5aSJacob Keller 686b111ab5aSJacob Keller return err; 687b111ab5aSJacob Keller } 688b111ab5aSJacob Keller 689b111ab5aSJacob Keller /** 690b111ab5aSJacob Keller * ice_write_cgu_reg_e822 - Write a CGU register 691b111ab5aSJacob Keller * @hw: pointer to the HW struct 692b111ab5aSJacob Keller * @addr: Register address to write 693b111ab5aSJacob Keller * @val: value to write into the register 694b111ab5aSJacob Keller * 695b111ab5aSJacob Keller * Write the specified value to a register of the Clock Generation Unit. Only 696b111ab5aSJacob Keller * applicable to E822 devices. 697b111ab5aSJacob Keller */ 698b111ab5aSJacob Keller static int 699b111ab5aSJacob Keller ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val) 700b111ab5aSJacob Keller { 701b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 702b111ab5aSJacob Keller int err; 703b111ab5aSJacob Keller 704b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_wr; 705b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 706b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 707b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 708b111ab5aSJacob Keller cgu_msg.data = val; 709b111ab5aSJacob Keller 710b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 711b111ab5aSJacob Keller if (err) { 712b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n", 713b111ab5aSJacob Keller addr, err); 714b111ab5aSJacob Keller return err; 715b111ab5aSJacob Keller } 716b111ab5aSJacob Keller 717b111ab5aSJacob Keller return err; 718b111ab5aSJacob Keller } 719b111ab5aSJacob Keller 720b111ab5aSJacob Keller /** 721b111ab5aSJacob Keller * ice_clk_freq_str - Convert time_ref_freq to string 722b111ab5aSJacob Keller * @clk_freq: Clock frequency 723b111ab5aSJacob Keller * 724b111ab5aSJacob Keller * Convert the specified TIME_REF clock frequency to a string. 725b111ab5aSJacob Keller */ 726b111ab5aSJacob Keller static const char *ice_clk_freq_str(u8 clk_freq) 727b111ab5aSJacob Keller { 728b111ab5aSJacob Keller switch ((enum ice_time_ref_freq)clk_freq) { 729b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_25_000: 730b111ab5aSJacob Keller return "25 MHz"; 731b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_122_880: 732b111ab5aSJacob Keller return "122.88 MHz"; 733b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_125_000: 734b111ab5aSJacob Keller return "125 MHz"; 735b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_153_600: 736b111ab5aSJacob Keller return "153.6 MHz"; 737b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_156_250: 738b111ab5aSJacob Keller return "156.25 MHz"; 739b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_245_760: 740b111ab5aSJacob Keller return "245.76 MHz"; 741b111ab5aSJacob Keller default: 742b111ab5aSJacob Keller return "Unknown"; 743b111ab5aSJacob Keller } 744b111ab5aSJacob Keller } 745b111ab5aSJacob Keller 746b111ab5aSJacob Keller /** 747b111ab5aSJacob Keller * ice_clk_src_str - Convert time_ref_src to string 748b111ab5aSJacob Keller * @clk_src: Clock source 749b111ab5aSJacob Keller * 750b111ab5aSJacob Keller * Convert the specified clock source to its string name. 751b111ab5aSJacob Keller */ 752b111ab5aSJacob Keller static const char *ice_clk_src_str(u8 clk_src) 753b111ab5aSJacob Keller { 754b111ab5aSJacob Keller switch ((enum ice_clk_src)clk_src) { 755b111ab5aSJacob Keller case ICE_CLK_SRC_TCX0: 756b111ab5aSJacob Keller return "TCX0"; 757b111ab5aSJacob Keller case ICE_CLK_SRC_TIME_REF: 758b111ab5aSJacob Keller return "TIME_REF"; 759b111ab5aSJacob Keller default: 760b111ab5aSJacob Keller return "Unknown"; 761b111ab5aSJacob Keller } 762b111ab5aSJacob Keller } 763b111ab5aSJacob Keller 764b111ab5aSJacob Keller /** 765b111ab5aSJacob Keller * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit 766b111ab5aSJacob Keller * @hw: pointer to the HW struct 767b111ab5aSJacob Keller * @clk_freq: Clock frequency to program 768b111ab5aSJacob Keller * @clk_src: Clock source to select (TIME_REF, or TCX0) 769b111ab5aSJacob Keller * 770b111ab5aSJacob Keller * Configure the Clock Generation Unit with the desired clock frequency and 771b111ab5aSJacob Keller * time reference, enabling the PLL which drives the PTP hardware clock. 772b111ab5aSJacob Keller */ 773b111ab5aSJacob Keller static int 774b111ab5aSJacob Keller ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, 775b111ab5aSJacob Keller enum ice_clk_src clk_src) 776b111ab5aSJacob Keller { 777b111ab5aSJacob Keller union tspll_ro_bwm_lf bwm_lf; 778b111ab5aSJacob Keller union nac_cgu_dword19 dw19; 779b111ab5aSJacob Keller union nac_cgu_dword22 dw22; 780b111ab5aSJacob Keller union nac_cgu_dword24 dw24; 781b111ab5aSJacob Keller union nac_cgu_dword9 dw9; 782b111ab5aSJacob Keller int err; 783b111ab5aSJacob Keller 784b111ab5aSJacob Keller if (clk_freq >= NUM_ICE_TIME_REF_FREQ) { 785b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", 786b111ab5aSJacob Keller clk_freq); 787b111ab5aSJacob Keller return -EINVAL; 788b111ab5aSJacob Keller } 789b111ab5aSJacob Keller 790b111ab5aSJacob Keller if (clk_src >= NUM_ICE_CLK_SRC) { 791b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", 792b111ab5aSJacob Keller clk_src); 793b111ab5aSJacob Keller return -EINVAL; 794b111ab5aSJacob Keller } 795b111ab5aSJacob Keller 796b111ab5aSJacob Keller if (clk_src == ICE_CLK_SRC_TCX0 && 797b111ab5aSJacob Keller clk_freq != ICE_TIME_REF_FREQ_25_000) { 798b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), 799b111ab5aSJacob Keller "TCX0 only supports 25 MHz frequency\n"); 800b111ab5aSJacob Keller return -EINVAL; 801b111ab5aSJacob Keller } 802b111ab5aSJacob Keller 803b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val); 804b111ab5aSJacob Keller if (err) 805b111ab5aSJacob Keller return err; 806b111ab5aSJacob Keller 807b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 808b111ab5aSJacob Keller if (err) 809b111ab5aSJacob Keller return err; 810b111ab5aSJacob Keller 811b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 812b111ab5aSJacob Keller if (err) 813b111ab5aSJacob Keller return err; 814b111ab5aSJacob Keller 815b111ab5aSJacob Keller /* Log the current clock configuration */ 816b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 817b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 818b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 819b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 820b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 821b111ab5aSJacob Keller 822b111ab5aSJacob Keller /* Disable the PLL before changing the clock source or frequency */ 823b111ab5aSJacob Keller if (dw24.field.ts_pll_enable) { 824b111ab5aSJacob Keller dw24.field.ts_pll_enable = 0; 825b111ab5aSJacob Keller 826b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 827b111ab5aSJacob Keller if (err) 828b111ab5aSJacob Keller return err; 829b111ab5aSJacob Keller } 830b111ab5aSJacob Keller 831b111ab5aSJacob Keller /* Set the frequency */ 832b111ab5aSJacob Keller dw9.field.time_ref_freq_sel = clk_freq; 833b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val); 834b111ab5aSJacob Keller if (err) 835b111ab5aSJacob Keller return err; 836b111ab5aSJacob Keller 837b111ab5aSJacob Keller /* Configure the TS PLL feedback divisor */ 838b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val); 839b111ab5aSJacob Keller if (err) 840b111ab5aSJacob Keller return err; 841b111ab5aSJacob Keller 842b111ab5aSJacob Keller dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; 843b111ab5aSJacob Keller dw19.field.tspll_ndivratio = 1; 844b111ab5aSJacob Keller 845b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val); 846b111ab5aSJacob Keller if (err) 847b111ab5aSJacob Keller return err; 848b111ab5aSJacob Keller 849b111ab5aSJacob Keller /* Configure the TS PLL post divisor */ 850b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val); 851b111ab5aSJacob Keller if (err) 852b111ab5aSJacob Keller return err; 853b111ab5aSJacob Keller 854b111ab5aSJacob Keller dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; 855b111ab5aSJacob Keller dw22.field.time1588clk_sel_div2 = 0; 856b111ab5aSJacob Keller 857b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val); 858b111ab5aSJacob Keller if (err) 859b111ab5aSJacob Keller return err; 860b111ab5aSJacob Keller 861b111ab5aSJacob Keller /* Configure the TS PLL pre divisor and clock source */ 862b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 863b111ab5aSJacob Keller if (err) 864b111ab5aSJacob Keller return err; 865b111ab5aSJacob Keller 866b111ab5aSJacob Keller dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div; 867b111ab5aSJacob Keller dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; 868b111ab5aSJacob Keller dw24.field.time_ref_sel = clk_src; 869b111ab5aSJacob Keller 870b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 871b111ab5aSJacob Keller if (err) 872b111ab5aSJacob Keller return err; 873b111ab5aSJacob Keller 874b111ab5aSJacob Keller /* Finally, enable the PLL */ 875b111ab5aSJacob Keller dw24.field.ts_pll_enable = 1; 876b111ab5aSJacob Keller 877b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 878b111ab5aSJacob Keller if (err) 879b111ab5aSJacob Keller return err; 880b111ab5aSJacob Keller 881b111ab5aSJacob Keller /* Wait to verify if the PLL locks */ 882b111ab5aSJacob Keller usleep_range(1000, 5000); 883b111ab5aSJacob Keller 884b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 885b111ab5aSJacob Keller if (err) 886b111ab5aSJacob Keller return err; 887b111ab5aSJacob Keller 888b111ab5aSJacob Keller if (!bwm_lf.field.plllock_true_lock_cri) { 889b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); 890b111ab5aSJacob Keller return -EBUSY; 891b111ab5aSJacob Keller } 892b111ab5aSJacob Keller 893b111ab5aSJacob Keller /* Log the current clock configuration */ 894b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 895b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 896b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 897b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 898b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 899b111ab5aSJacob Keller 900b111ab5aSJacob Keller return 0; 901b111ab5aSJacob Keller } 902b111ab5aSJacob Keller 903b111ab5aSJacob Keller /** 904b111ab5aSJacob Keller * ice_init_cgu_e822 - Initialize CGU with settings from firmware 905b111ab5aSJacob Keller * @hw: pointer to the HW structure 906b111ab5aSJacob Keller * 907b111ab5aSJacob Keller * Initialize the Clock Generation Unit of the E822 device. 908b111ab5aSJacob Keller */ 909b111ab5aSJacob Keller static int ice_init_cgu_e822(struct ice_hw *hw) 910b111ab5aSJacob Keller { 911b111ab5aSJacob Keller struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; 912b111ab5aSJacob Keller union tspll_cntr_bist_settings cntr_bist; 913b111ab5aSJacob Keller int err; 914b111ab5aSJacob Keller 915b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 916b111ab5aSJacob Keller &cntr_bist.val); 917b111ab5aSJacob Keller if (err) 918b111ab5aSJacob Keller return err; 919b111ab5aSJacob Keller 920b111ab5aSJacob Keller /* Disable sticky lock detection so lock err reported is accurate */ 921b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_0 = 0; 922b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_1 = 0; 923b111ab5aSJacob Keller 924b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 925b111ab5aSJacob Keller cntr_bist.val); 926b111ab5aSJacob Keller if (err) 927b111ab5aSJacob Keller return err; 928b111ab5aSJacob Keller 929b111ab5aSJacob Keller /* Configure the CGU PLL using the parameters from the function 930b111ab5aSJacob Keller * capabilities. 931b111ab5aSJacob Keller */ 932b111ab5aSJacob Keller err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref, 933b111ab5aSJacob Keller (enum ice_clk_src)ts_info->clk_src); 934b111ab5aSJacob Keller if (err) 935b111ab5aSJacob Keller return err; 936b111ab5aSJacob Keller 937b111ab5aSJacob Keller return 0; 938b111ab5aSJacob Keller } 939b111ab5aSJacob Keller 940b111ab5aSJacob Keller /** 9413a749623SJacob Keller * ice_ptp_set_vernier_wl - Set the window length for vernier calibration 9423a749623SJacob Keller * @hw: pointer to the HW struct 9433a749623SJacob Keller * 9443a749623SJacob Keller * Set the window length used for the vernier port calibration process. 9453a749623SJacob Keller */ 9463a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw) 9473a749623SJacob Keller { 9483a749623SJacob Keller u8 port; 9493a749623SJacob Keller 9503a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 9513a749623SJacob Keller int err; 9523a749623SJacob Keller 9533a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_WL, 9543a749623SJacob Keller PTP_VERNIER_WL); 9553a749623SJacob Keller if (err) { 9563a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n", 9573a749623SJacob Keller port, err); 9583a749623SJacob Keller return err; 9593a749623SJacob Keller } 9603a749623SJacob Keller } 9613a749623SJacob Keller 9623a749623SJacob Keller return 0; 9633a749623SJacob Keller } 9643a749623SJacob Keller 9653a749623SJacob Keller /** 9663a749623SJacob Keller * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization 9673a749623SJacob Keller * @hw: pointer to HW struct 9683a749623SJacob Keller * 9693a749623SJacob Keller * Perform PHC initialization steps specific to E822 devices. 9703a749623SJacob Keller */ 9713a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw) 9723a749623SJacob Keller { 973b111ab5aSJacob Keller int err; 9743a749623SJacob Keller u32 regval; 9753a749623SJacob Keller 9763a749623SJacob Keller /* Enable reading switch and PHY registers over the sideband queue */ 9773a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1) 9783a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2) 9793a749623SJacob Keller regval = rd32(hw, PF_SB_REM_DEV_CTL); 9803a749623SJacob Keller regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ | 9813a749623SJacob Keller PF_SB_REM_DEV_CTL_PHY0); 9823a749623SJacob Keller wr32(hw, PF_SB_REM_DEV_CTL, regval); 9833a749623SJacob Keller 984b111ab5aSJacob Keller /* Initialize the Clock Generation Unit */ 985b111ab5aSJacob Keller err = ice_init_cgu_e822(hw); 986b111ab5aSJacob Keller if (err) 987b111ab5aSJacob Keller return err; 988b111ab5aSJacob Keller 9893a749623SJacob Keller /* Set window length for all the ports */ 9903a749623SJacob Keller return ice_ptp_set_vernier_wl(hw); 9913a749623SJacob Keller } 9923a749623SJacob Keller 9933a749623SJacob Keller /** 9943a749623SJacob Keller * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time 9953a749623SJacob Keller * @hw: pointer to the HW struct 9963a749623SJacob Keller * @time: Time to initialize the PHY port clocks to 9973a749623SJacob Keller * 9983a749623SJacob Keller * Program the PHY port registers with a new initial time value. The port 9993a749623SJacob Keller * clock will be initialized once the driver issues an INIT_TIME sync 10003a749623SJacob Keller * command. The time value is the upper 32 bits of the PHY timer, usually in 10013a749623SJacob Keller * units of nominal nanoseconds. 10023a749623SJacob Keller */ 10033a749623SJacob Keller static int 10043a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) 10053a749623SJacob Keller { 10063a749623SJacob Keller u64 phy_time; 10073a749623SJacob Keller u8 port; 10083a749623SJacob Keller int err; 10093a749623SJacob Keller 10103a749623SJacob Keller /* The time represents the upper 32 bits of the PHY timer, so we need 10113a749623SJacob Keller * to shift to account for this when programming. 10123a749623SJacob Keller */ 10133a749623SJacob Keller phy_time = (u64)time << 32; 10143a749623SJacob Keller 10153a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 10163a749623SJacob Keller /* Tx case */ 10173a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 10183a749623SJacob Keller P_REG_TX_TIMER_INC_PRE_L, 10193a749623SJacob Keller phy_time); 10203a749623SJacob Keller if (err) 10213a749623SJacob Keller goto exit_err; 10223a749623SJacob Keller 10233a749623SJacob Keller /* Rx case */ 10243a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 10253a749623SJacob Keller P_REG_RX_TIMER_INC_PRE_L, 10263a749623SJacob Keller phy_time); 10273a749623SJacob Keller if (err) 10283a749623SJacob Keller goto exit_err; 10293a749623SJacob Keller } 10303a749623SJacob Keller 10313a749623SJacob Keller return 0; 10323a749623SJacob Keller 10333a749623SJacob Keller exit_err: 10343a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n", 10353a749623SJacob Keller port, err); 10363a749623SJacob Keller 10373a749623SJacob Keller return err; 10383a749623SJacob Keller } 10393a749623SJacob Keller 10403a749623SJacob Keller /** 10413a749623SJacob Keller * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust 10423a749623SJacob Keller * @hw: pointer to HW struct 10433a749623SJacob Keller * @port: Port number to be programmed 10443a749623SJacob Keller * @time: time in cycles to adjust the port Tx and Rx clocks 10453a749623SJacob Keller * 10463a749623SJacob Keller * Program the port for an atomic adjustment by writing the Tx and Rx timer 10473a749623SJacob Keller * registers. The atomic adjustment won't be completed until the driver issues 10483a749623SJacob Keller * an ADJ_TIME command. 10493a749623SJacob Keller * 10503a749623SJacob Keller * Note that time is not in units of nanoseconds. It is in clock time 10513a749623SJacob Keller * including the lower sub-nanosecond portion of the port timer. 10523a749623SJacob Keller * 10533a749623SJacob Keller * Negative adjustments are supported using 2s complement arithmetic. 10543a749623SJacob Keller */ 10553a749623SJacob Keller int 10563a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) 10573a749623SJacob Keller { 10583a749623SJacob Keller u32 l_time, u_time; 10593a749623SJacob Keller int err; 10603a749623SJacob Keller 10613a749623SJacob Keller l_time = lower_32_bits(time); 10623a749623SJacob Keller u_time = upper_32_bits(time); 10633a749623SJacob Keller 10643a749623SJacob Keller /* Tx case */ 10653a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L, 10663a749623SJacob Keller l_time); 10673a749623SJacob Keller if (err) 10683a749623SJacob Keller goto exit_err; 10693a749623SJacob Keller 10703a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U, 10713a749623SJacob Keller u_time); 10723a749623SJacob Keller if (err) 10733a749623SJacob Keller goto exit_err; 10743a749623SJacob Keller 10753a749623SJacob Keller /* Rx case */ 10763a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L, 10773a749623SJacob Keller l_time); 10783a749623SJacob Keller if (err) 10793a749623SJacob Keller goto exit_err; 10803a749623SJacob Keller 10813a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U, 10823a749623SJacob Keller u_time); 10833a749623SJacob Keller if (err) 10843a749623SJacob Keller goto exit_err; 10853a749623SJacob Keller 10863a749623SJacob Keller return 0; 10873a749623SJacob Keller 10883a749623SJacob Keller exit_err: 10893a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n", 10903a749623SJacob Keller port, err); 10913a749623SJacob Keller return err; 10923a749623SJacob Keller } 10933a749623SJacob Keller 10943a749623SJacob Keller /** 10953a749623SJacob Keller * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment 10963a749623SJacob Keller * @hw: pointer to HW struct 10973a749623SJacob Keller * @adj: adjustment in nanoseconds 10983a749623SJacob Keller * 10993a749623SJacob Keller * Prepare the PHY ports for an atomic time adjustment by programming the PHY 11003a749623SJacob Keller * Tx and Rx port registers. The actual adjustment is completed by issuing an 11013a749623SJacob Keller * ADJ_TIME or ADJ_TIME_AT_TIME sync command. 11023a749623SJacob Keller */ 11033a749623SJacob Keller static int 11043a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) 11053a749623SJacob Keller { 11063a749623SJacob Keller s64 cycles; 11073a749623SJacob Keller u8 port; 11083a749623SJacob Keller 11093a749623SJacob Keller /* The port clock supports adjustment of the sub-nanosecond portion of 11103a749623SJacob Keller * the clock. We shift the provided adjustment in nanoseconds to 11113a749623SJacob Keller * calculate the appropriate adjustment to program into the PHY ports. 11123a749623SJacob Keller */ 11133a749623SJacob Keller if (adj > 0) 11143a749623SJacob Keller cycles = (s64)adj << 32; 11153a749623SJacob Keller else 11163a749623SJacob Keller cycles = -(((s64)-adj) << 32); 11173a749623SJacob Keller 11183a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 11193a749623SJacob Keller int err; 11203a749623SJacob Keller 11213a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, cycles); 11223a749623SJacob Keller if (err) 11233a749623SJacob Keller return err; 11243a749623SJacob Keller } 11253a749623SJacob Keller 11263a749623SJacob Keller return 0; 11273a749623SJacob Keller } 11283a749623SJacob Keller 11293a749623SJacob Keller /** 11303a749623SJacob Keller * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment 11313a749623SJacob Keller * @hw: pointer to HW struct 11323a749623SJacob Keller * @incval: new increment value to prepare 11333a749623SJacob Keller * 11343a749623SJacob Keller * Prepare each of the PHY ports for a new increment value by programming the 11353a749623SJacob Keller * port's TIMETUS registers. The new increment value will be updated after 11363a749623SJacob Keller * issuing an INIT_INCVAL command. 11373a749623SJacob Keller */ 11383a749623SJacob Keller static int 11393a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval) 11403a749623SJacob Keller { 11413a749623SJacob Keller int err; 11423a749623SJacob Keller u8 port; 11433a749623SJacob Keller 11443a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 11453a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, 11463a749623SJacob Keller incval); 11473a749623SJacob Keller if (err) 11483a749623SJacob Keller goto exit_err; 11493a749623SJacob Keller } 11503a749623SJacob Keller 11513a749623SJacob Keller return 0; 11523a749623SJacob Keller 11533a749623SJacob Keller exit_err: 11543a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n", 11553a749623SJacob Keller port, err); 11563a749623SJacob Keller 11573a749623SJacob Keller return err; 11583a749623SJacob Keller } 11593a749623SJacob Keller 11603a749623SJacob Keller /** 11613a749623SJacob Keller * ice_ptp_read_port_capture - Read a port's local time capture 11623a749623SJacob Keller * @hw: pointer to HW struct 11633a749623SJacob Keller * @port: Port number to read 11643a749623SJacob Keller * @tx_ts: on return, the Tx port time capture 11653a749623SJacob Keller * @rx_ts: on return, the Rx port time capture 11663a749623SJacob Keller * 11673a749623SJacob Keller * Read the port's Tx and Rx local time capture values. 11683a749623SJacob Keller * 11693a749623SJacob Keller * Note this has no equivalent for the E810 devices. 11703a749623SJacob Keller */ 11713a749623SJacob Keller static int 11723a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) 11733a749623SJacob Keller { 11743a749623SJacob Keller int err; 11753a749623SJacob Keller 11763a749623SJacob Keller /* Tx case */ 11773a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts); 11783a749623SJacob Keller if (err) { 11793a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n", 11803a749623SJacob Keller err); 11813a749623SJacob Keller return err; 11823a749623SJacob Keller } 11833a749623SJacob Keller 11843a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n", 11853a749623SJacob Keller (unsigned long long)*tx_ts); 11863a749623SJacob Keller 11873a749623SJacob Keller /* Rx case */ 11883a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts); 11893a749623SJacob Keller if (err) { 11903a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n", 11913a749623SJacob Keller err); 11923a749623SJacob Keller return err; 11933a749623SJacob Keller } 11943a749623SJacob Keller 11953a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n", 11963a749623SJacob Keller (unsigned long long)*rx_ts); 11973a749623SJacob Keller 11983a749623SJacob Keller return 0; 11993a749623SJacob Keller } 12003a749623SJacob Keller 12013a749623SJacob Keller /** 12023a749623SJacob Keller * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command 12033a749623SJacob Keller * @hw: pointer to HW struct 12043a749623SJacob Keller * @port: Port to which cmd has to be sent 12053a749623SJacob Keller * @cmd: Command to be sent to the port 12063a749623SJacob Keller * 12073a749623SJacob Keller * Prepare the requested port for an upcoming timer sync command. 12083a749623SJacob Keller * 12093a749623SJacob Keller * Note there is no equivalent of this operation on E810, as that device 12103a749623SJacob Keller * always handles all external PHYs internally. 12113a749623SJacob Keller */ 12123a749623SJacob Keller static int 12133a749623SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) 12143a749623SJacob Keller { 12153a749623SJacob Keller u32 cmd_val, val; 12163a749623SJacob Keller u8 tmr_idx; 12173a749623SJacob Keller int err; 12183a749623SJacob Keller 12193a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 12203a749623SJacob Keller cmd_val = tmr_idx << SEL_PHY_SRC; 12213a749623SJacob Keller switch (cmd) { 12223a749623SJacob Keller case INIT_TIME: 12233a749623SJacob Keller cmd_val |= PHY_CMD_INIT_TIME; 12243a749623SJacob Keller break; 12253a749623SJacob Keller case INIT_INCVAL: 12263a749623SJacob Keller cmd_val |= PHY_CMD_INIT_INCVAL; 12273a749623SJacob Keller break; 12283a749623SJacob Keller case ADJ_TIME: 12293a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME; 12303a749623SJacob Keller break; 12313a749623SJacob Keller case READ_TIME: 12323a749623SJacob Keller cmd_val |= PHY_CMD_READ_TIME; 12333a749623SJacob Keller break; 12343a749623SJacob Keller case ADJ_TIME_AT_TIME: 12353a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; 12363a749623SJacob Keller break; 12373a749623SJacob Keller } 12383a749623SJacob Keller 12393a749623SJacob Keller /* Tx case */ 12403a749623SJacob Keller /* Read, modify, write */ 12413a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val); 12423a749623SJacob Keller if (err) { 12433a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n", 12443a749623SJacob Keller err); 12453a749623SJacob Keller return err; 12463a749623SJacob Keller } 12473a749623SJacob Keller 12483a749623SJacob Keller /* Modify necessary bits only and perform write */ 12493a749623SJacob Keller val &= ~TS_CMD_MASK; 12503a749623SJacob Keller val |= cmd_val; 12513a749623SJacob Keller 12523a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val); 12533a749623SJacob Keller if (err) { 12543a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n", 12553a749623SJacob Keller err); 12563a749623SJacob Keller return err; 12573a749623SJacob Keller } 12583a749623SJacob Keller 12593a749623SJacob Keller /* Rx case */ 12603a749623SJacob Keller /* Read, modify, write */ 12613a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val); 12623a749623SJacob Keller if (err) { 12633a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n", 12643a749623SJacob Keller err); 12653a749623SJacob Keller return err; 12663a749623SJacob Keller } 12673a749623SJacob Keller 12683a749623SJacob Keller /* Modify necessary bits only and perform write */ 12693a749623SJacob Keller val &= ~TS_CMD_MASK; 12703a749623SJacob Keller val |= cmd_val; 12713a749623SJacob Keller 12723a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val); 12733a749623SJacob Keller if (err) { 12743a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n", 12753a749623SJacob Keller err); 12763a749623SJacob Keller return err; 12773a749623SJacob Keller } 12783a749623SJacob Keller 12793a749623SJacob Keller return 0; 12803a749623SJacob Keller } 12813a749623SJacob Keller 12823a749623SJacob Keller /** 12833a749623SJacob Keller * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command 12843a749623SJacob Keller * @hw: pointer to the HW struct 12853a749623SJacob Keller * @cmd: timer command to prepare 12863a749623SJacob Keller * 12873a749623SJacob Keller * Prepare all ports connected to this device for an upcoming timer sync 12883a749623SJacob Keller * command. 12893a749623SJacob Keller */ 12903a749623SJacob Keller static int 12913a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 12923a749623SJacob Keller { 12933a749623SJacob Keller u8 port; 12943a749623SJacob Keller 12953a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 12963a749623SJacob Keller int err; 12973a749623SJacob Keller 12983a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, cmd); 12993a749623SJacob Keller if (err) 13003a749623SJacob Keller return err; 13013a749623SJacob Keller } 13023a749623SJacob Keller 13033a749623SJacob Keller return 0; 13043a749623SJacob Keller } 13053a749623SJacob Keller 13063a749623SJacob Keller /* E822 Vernier calibration functions 13073a749623SJacob Keller * 13083a749623SJacob Keller * The following functions are used as part of the vernier calibration of 13093a749623SJacob Keller * a port. This calibration increases the precision of the timestamps on the 13103a749623SJacob Keller * port. 13113a749623SJacob Keller */ 13123a749623SJacob Keller 13133a749623SJacob Keller /** 13143a749623SJacob Keller * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode 13153a749623SJacob Keller * @hw: pointer to HW struct 13163a749623SJacob Keller * @port: the port to read from 13173a749623SJacob Keller * @link_out: if non-NULL, holds link speed on success 13183a749623SJacob Keller * @fec_out: if non-NULL, holds FEC algorithm on success 13193a749623SJacob Keller * 13203a749623SJacob Keller * Read the serdes data for the PHY port and extract the link speed and FEC 13213a749623SJacob Keller * algorithm. 13223a749623SJacob Keller */ 13233a749623SJacob Keller static int 13243a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, 13253a749623SJacob Keller enum ice_ptp_link_spd *link_out, 13263a749623SJacob Keller enum ice_ptp_fec_mode *fec_out) 13273a749623SJacob Keller { 13283a749623SJacob Keller enum ice_ptp_link_spd link; 13293a749623SJacob Keller enum ice_ptp_fec_mode fec; 13303a749623SJacob Keller u32 serdes; 13313a749623SJacob Keller int err; 13323a749623SJacob Keller 13333a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes); 13343a749623SJacob Keller if (err) { 13353a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n"); 13363a749623SJacob Keller return err; 13373a749623SJacob Keller } 13383a749623SJacob Keller 13393a749623SJacob Keller /* Determine the FEC algorithm */ 13403a749623SJacob Keller fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes); 13413a749623SJacob Keller 13423a749623SJacob Keller serdes &= P_REG_LINK_SPEED_SERDES_M; 13433a749623SJacob Keller 13443a749623SJacob Keller /* Determine the link speed */ 13453a749623SJacob Keller if (fec == ICE_PTP_FEC_MODE_RS_FEC) { 13463a749623SJacob Keller switch (serdes) { 13473a749623SJacob Keller case ICE_PTP_SERDES_25G: 13483a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G_RS; 13493a749623SJacob Keller break; 13503a749623SJacob Keller case ICE_PTP_SERDES_50G: 13513a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G_RS; 13523a749623SJacob Keller break; 13533a749623SJacob Keller case ICE_PTP_SERDES_100G: 13543a749623SJacob Keller link = ICE_PTP_LNK_SPD_100G_RS; 13553a749623SJacob Keller break; 13563a749623SJacob Keller default: 13573a749623SJacob Keller return -EIO; 13583a749623SJacob Keller } 13593a749623SJacob Keller } else { 13603a749623SJacob Keller switch (serdes) { 13613a749623SJacob Keller case ICE_PTP_SERDES_1G: 13623a749623SJacob Keller link = ICE_PTP_LNK_SPD_1G; 13633a749623SJacob Keller break; 13643a749623SJacob Keller case ICE_PTP_SERDES_10G: 13653a749623SJacob Keller link = ICE_PTP_LNK_SPD_10G; 13663a749623SJacob Keller break; 13673a749623SJacob Keller case ICE_PTP_SERDES_25G: 13683a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G; 13693a749623SJacob Keller break; 13703a749623SJacob Keller case ICE_PTP_SERDES_40G: 13713a749623SJacob Keller link = ICE_PTP_LNK_SPD_40G; 13723a749623SJacob Keller break; 13733a749623SJacob Keller case ICE_PTP_SERDES_50G: 13743a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G; 13753a749623SJacob Keller break; 13763a749623SJacob Keller default: 13773a749623SJacob Keller return -EIO; 13783a749623SJacob Keller } 13793a749623SJacob Keller } 13803a749623SJacob Keller 13813a749623SJacob Keller if (link_out) 13823a749623SJacob Keller *link_out = link; 13833a749623SJacob Keller if (fec_out) 13843a749623SJacob Keller *fec_out = fec; 13853a749623SJacob Keller 13863a749623SJacob Keller return 0; 13873a749623SJacob Keller } 13883a749623SJacob Keller 13893a749623SJacob Keller /** 13903a749623SJacob Keller * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp 13913a749623SJacob Keller * @hw: pointer to HW struct 13923a749623SJacob Keller * @port: to configure the quad for 13933a749623SJacob Keller */ 13943a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) 13953a749623SJacob Keller { 13963a749623SJacob Keller enum ice_ptp_link_spd link_spd; 13973a749623SJacob Keller int err; 13983a749623SJacob Keller u32 val; 13993a749623SJacob Keller u8 quad; 14003a749623SJacob Keller 14013a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL); 14023a749623SJacob Keller if (err) { 14033a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n", 14043a749623SJacob Keller err); 14053a749623SJacob Keller return; 14063a749623SJacob Keller } 14073a749623SJacob Keller 14083a749623SJacob Keller quad = port / ICE_PORTS_PER_QUAD; 14093a749623SJacob Keller 14103a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); 14113a749623SJacob Keller if (err) { 14123a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n", 14133a749623SJacob Keller err); 14143a749623SJacob Keller return; 14153a749623SJacob Keller } 14163a749623SJacob Keller 14173a749623SJacob Keller if (link_spd >= ICE_PTP_LNK_SPD_40G) 14183a749623SJacob Keller val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 14193a749623SJacob Keller else 14203a749623SJacob Keller val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 14213a749623SJacob Keller 14223a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); 14233a749623SJacob Keller if (err) { 14243a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n", 14253a749623SJacob Keller err); 14263a749623SJacob Keller return; 14273a749623SJacob Keller } 14283a749623SJacob Keller } 14293a749623SJacob Keller 14303a749623SJacob Keller /** 14313a749623SJacob Keller * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822 14323a749623SJacob Keller * @hw: pointer to the HW structure 14333a749623SJacob Keller * @port: the port to configure 14343a749623SJacob Keller * 14353a749623SJacob Keller * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC 14363a749623SJacob Keller * hardware clock time units (TUs). That is, determine the number of TUs per 14373a749623SJacob Keller * serdes unit interval, and program the UIX registers with this conversion. 14383a749623SJacob Keller * 14393a749623SJacob Keller * This conversion is used as part of the calibration process when determining 14403a749623SJacob Keller * the additional error of a timestamp vs the real time of transmission or 14413a749623SJacob Keller * receipt of the packet. 14423a749623SJacob Keller * 14433a749623SJacob Keller * Hardware uses the number of TUs per 66 UIs, written to the UIX registers 14443a749623SJacob Keller * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks. 14453a749623SJacob Keller * 14463a749623SJacob Keller * To calculate the conversion ratio, we use the following facts: 14473a749623SJacob Keller * 14483a749623SJacob Keller * a) the clock frequency in Hz (cycles per second) 14493a749623SJacob Keller * b) the number of TUs per cycle (the increment value of the clock) 14503a749623SJacob Keller * c) 1 second per 1 billion nanoseconds 14513a749623SJacob Keller * d) the duration of 66 UIs in nanoseconds 14523a749623SJacob Keller * 14533a749623SJacob Keller * Given these facts, we can use the following table to work out what ratios 14543a749623SJacob Keller * to multiply in order to get the number of TUs per 66 UIs: 14553a749623SJacob Keller * 14563a749623SJacob Keller * cycles | 1 second | incval (TUs) | nanoseconds 14573a749623SJacob Keller * -------+--------------+--------------+------------- 14583a749623SJacob Keller * second | 1 billion ns | cycle | 66 UIs 14593a749623SJacob Keller * 14603a749623SJacob Keller * To perform the multiplication using integers without too much loss of 14613a749623SJacob Keller * precision, we can take use the following equation: 14623a749623SJacob Keller * 14633a749623SJacob Keller * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion) 14643a749623SJacob Keller * 14653a749623SJacob Keller * We scale up to using 6600 UI instead of 66 in order to avoid fractional 14663a749623SJacob Keller * nanosecond UIs (66 UI at 10G/40G is 6.4 ns) 14673a749623SJacob Keller * 14683a749623SJacob Keller * The increment value has a maximum expected range of about 34 bits, while 14693a749623SJacob Keller * the frequency value is about 29 bits. Multiplying these values shouldn't 14703a749623SJacob Keller * overflow the 64 bits. However, we must then further multiply them again by 14713a749623SJacob Keller * the Serdes unit interval duration. To avoid overflow here, we split the 14723a749623SJacob Keller * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and 14733a749623SJacob Keller * a divide by 390,625,000. This does lose some precision, but avoids 14743a749623SJacob Keller * miscalculation due to arithmetic overflow. 14753a749623SJacob Keller */ 14763a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) 14773a749623SJacob Keller { 14783a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, uix; 14793a749623SJacob Keller int err; 14803a749623SJacob Keller 14813a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 14823a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 14833a749623SJacob Keller 14843a749623SJacob Keller /* Calculate TUs per second divided by 256 */ 14853a749623SJacob Keller tu_per_sec = (cur_freq * clk_incval) >> 8; 14863a749623SJacob Keller 14873a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */ 14883a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */ 14893a749623SJacob Keller 14903a749623SJacob Keller /* Program the 10Gb/40Gb conversion ratio */ 14913a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000); 14923a749623SJacob Keller 14933a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L, 14943a749623SJacob Keller uix); 14953a749623SJacob Keller if (err) { 14963a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n", 14973a749623SJacob Keller err); 14983a749623SJacob Keller return err; 14993a749623SJacob Keller } 15003a749623SJacob Keller 15013a749623SJacob Keller /* Program the 25Gb/100Gb conversion ratio */ 15023a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000); 15033a749623SJacob Keller 15043a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L, 15053a749623SJacob Keller uix); 15063a749623SJacob Keller if (err) { 15073a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n", 15083a749623SJacob Keller err); 15093a749623SJacob Keller return err; 15103a749623SJacob Keller } 15113a749623SJacob Keller 15123a749623SJacob Keller return 0; 15133a749623SJacob Keller } 15143a749623SJacob Keller 15153a749623SJacob Keller /** 15163a749623SJacob Keller * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle 15173a749623SJacob Keller * @hw: pointer to the HW struct 15183a749623SJacob Keller * @port: port to configure 15193a749623SJacob Keller * 15203a749623SJacob Keller * Configure the number of TUs for the PAR and PCS clocks used as part of the 15213a749623SJacob Keller * timestamp calibration process. This depends on the link speed, as the PHY 15223a749623SJacob Keller * uses different markers depending on the speed. 15233a749623SJacob Keller * 15243a749623SJacob Keller * 1Gb/10Gb/25Gb: 15253a749623SJacob Keller * - Tx/Rx PAR/PCS markers 15263a749623SJacob Keller * 15273a749623SJacob Keller * 25Gb RS: 15283a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 15293a749623SJacob Keller * 15303a749623SJacob Keller * 40Gb/50Gb: 15313a749623SJacob Keller * - Tx/Rx PAR/PCS markers 15323a749623SJacob Keller * - Rx Deskew PAR/PCS markers 15333a749623SJacob Keller * 15343a749623SJacob Keller * 50G RS and 100GB RS: 15353a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 15363a749623SJacob Keller * - Rx Deskew PAR/PCS markers 15373a749623SJacob Keller * - Tx PAR/PCS markers 15383a749623SJacob Keller * 15393a749623SJacob Keller * To calculate the conversion, we use the PHC clock frequency (cycles per 15403a749623SJacob Keller * second), the increment value (TUs per cycle), and the related PHY clock 15413a749623SJacob Keller * frequency to calculate the TUs per unit of the PHY link clock. The 15423a749623SJacob Keller * following table shows how the units convert: 15433a749623SJacob Keller * 15443a749623SJacob Keller * cycles | TUs | second 15453a749623SJacob Keller * -------+-------+-------- 15463a749623SJacob Keller * second | cycle | cycles 15473a749623SJacob Keller * 15483a749623SJacob Keller * For each conversion register, look up the appropriate frequency from the 15493a749623SJacob Keller * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program 15503a749623SJacob Keller * this to the appropriate register, preparing hardware to perform timestamp 15513a749623SJacob Keller * calibration to calculate the total Tx or Rx offset to adjust the timestamp 15523a749623SJacob Keller * in order to calibrate for the internal PHY delays. 15533a749623SJacob Keller * 15543a749623SJacob Keller * Note that the increment value ranges up to ~34 bits, and the clock 15553a749623SJacob Keller * frequency is ~29 bits, so multiplying them together should fit within the 15563a749623SJacob Keller * 64 bit arithmetic. 15573a749623SJacob Keller */ 15583a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) 15593a749623SJacob Keller { 15603a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, phy_tus; 15613a749623SJacob Keller enum ice_ptp_link_spd link_spd; 15623a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 15633a749623SJacob Keller int err; 15643a749623SJacob Keller 15653a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 15663a749623SJacob Keller if (err) 15673a749623SJacob Keller return err; 15683a749623SJacob Keller 15693a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 15703a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 15713a749623SJacob Keller 15723a749623SJacob Keller /* Calculate TUs per cycle of the PHC clock */ 15733a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 15743a749623SJacob Keller 15753a749623SJacob Keller /* For each PHY conversion register, look up the appropriate link 15763a749623SJacob Keller * speed frequency and determine the TUs per that clock's cycle time. 15773a749623SJacob Keller * Split this into a high and low value and then program the 15783a749623SJacob Keller * appropriate register. If that link speed does not use the 15793a749623SJacob Keller * associated register, write zeros to clear it instead. 15803a749623SJacob Keller */ 15813a749623SJacob Keller 15823a749623SJacob Keller /* P_REG_PAR_TX_TUS */ 15833a749623SJacob Keller if (e822_vernier[link_spd].tx_par_clk) 15843a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 15853a749623SJacob Keller e822_vernier[link_spd].tx_par_clk); 15863a749623SJacob Keller else 15873a749623SJacob Keller phy_tus = 0; 15883a749623SJacob Keller 15893a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L, 15903a749623SJacob Keller phy_tus); 15913a749623SJacob Keller if (err) 15923a749623SJacob Keller return err; 15933a749623SJacob Keller 15943a749623SJacob Keller /* P_REG_PAR_RX_TUS */ 15953a749623SJacob Keller if (e822_vernier[link_spd].rx_par_clk) 15963a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 15973a749623SJacob Keller e822_vernier[link_spd].rx_par_clk); 15983a749623SJacob Keller else 15993a749623SJacob Keller phy_tus = 0; 16003a749623SJacob Keller 16013a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L, 16023a749623SJacob Keller phy_tus); 16033a749623SJacob Keller if (err) 16043a749623SJacob Keller return err; 16053a749623SJacob Keller 16063a749623SJacob Keller /* P_REG_PCS_TX_TUS */ 16073a749623SJacob Keller if (e822_vernier[link_spd].tx_pcs_clk) 16083a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16093a749623SJacob Keller e822_vernier[link_spd].tx_pcs_clk); 16103a749623SJacob Keller else 16113a749623SJacob Keller phy_tus = 0; 16123a749623SJacob Keller 16133a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L, 16143a749623SJacob Keller phy_tus); 16153a749623SJacob Keller if (err) 16163a749623SJacob Keller return err; 16173a749623SJacob Keller 16183a749623SJacob Keller /* P_REG_PCS_RX_TUS */ 16193a749623SJacob Keller if (e822_vernier[link_spd].rx_pcs_clk) 16203a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16213a749623SJacob Keller e822_vernier[link_spd].rx_pcs_clk); 16223a749623SJacob Keller else 16233a749623SJacob Keller phy_tus = 0; 16243a749623SJacob Keller 16253a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L, 16263a749623SJacob Keller phy_tus); 16273a749623SJacob Keller if (err) 16283a749623SJacob Keller return err; 16293a749623SJacob Keller 16303a749623SJacob Keller /* P_REG_DESK_PAR_TX_TUS */ 16313a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_par) 16323a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16333a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_par); 16343a749623SJacob Keller else 16353a749623SJacob Keller phy_tus = 0; 16363a749623SJacob Keller 16373a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L, 16383a749623SJacob Keller phy_tus); 16393a749623SJacob Keller if (err) 16403a749623SJacob Keller return err; 16413a749623SJacob Keller 16423a749623SJacob Keller /* P_REG_DESK_PAR_RX_TUS */ 16433a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_par) 16443a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16453a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_par); 16463a749623SJacob Keller else 16473a749623SJacob Keller phy_tus = 0; 16483a749623SJacob Keller 16493a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L, 16503a749623SJacob Keller phy_tus); 16513a749623SJacob Keller if (err) 16523a749623SJacob Keller return err; 16533a749623SJacob Keller 16543a749623SJacob Keller /* P_REG_DESK_PCS_TX_TUS */ 16553a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_pcs) 16563a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16573a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_pcs); 16583a749623SJacob Keller else 16593a749623SJacob Keller phy_tus = 0; 16603a749623SJacob Keller 16613a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L, 16623a749623SJacob Keller phy_tus); 16633a749623SJacob Keller if (err) 16643a749623SJacob Keller return err; 16653a749623SJacob Keller 16663a749623SJacob Keller /* P_REG_DESK_PCS_RX_TUS */ 16673a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_pcs) 16683a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 16693a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_pcs); 16703a749623SJacob Keller else 16713a749623SJacob Keller phy_tus = 0; 16723a749623SJacob Keller 16733a749623SJacob Keller return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L, 16743a749623SJacob Keller phy_tus); 16753a749623SJacob Keller } 16763a749623SJacob Keller 16773a749623SJacob Keller /** 16783a749623SJacob Keller * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port 16793a749623SJacob Keller * @hw: pointer to the HW struct 16803a749623SJacob Keller * @link_spd: the Link speed to calculate for 16813a749623SJacob Keller * 16823a749623SJacob Keller * Calculate the fixed offset due to known static latency data. 16833a749623SJacob Keller */ 16843a749623SJacob Keller static u64 16853a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 16863a749623SJacob Keller { 16873a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 16883a749623SJacob Keller 16893a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 16903a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 16913a749623SJacob Keller 16923a749623SJacob Keller /* Calculate TUs per second */ 16933a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 16943a749623SJacob Keller 16953a749623SJacob Keller /* Calculate number of TUs to add for the fixed Tx latency. Since the 16963a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 16973a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 16983a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 16993a749623SJacob Keller * divisions by 1e4 first then by 1e7. 17003a749623SJacob Keller */ 17013a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 17023a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].tx_fixed_delay; 17033a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 17043a749623SJacob Keller 17053a749623SJacob Keller return fixed_offset; 17063a749623SJacob Keller } 17073a749623SJacob Keller 17083a749623SJacob Keller /** 1709a69f1cb6SJacob Keller * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset 1710a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1711a69f1cb6SJacob Keller * @port: the PHY port to configure 1712a69f1cb6SJacob Keller * 1713a69f1cb6SJacob Keller * Program the P_REG_TOTAL_TX_OFFSET register with the total number of TUs to 1714a69f1cb6SJacob Keller * adjust Tx timestamps by. This is calculated by combining some known static 1715a69f1cb6SJacob Keller * latency along with the Vernier offset computations done by hardware. 1716a69f1cb6SJacob Keller * 1717a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 1718a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 1719a69f1cb6SJacob Keller * has measured the offset. 1720a69f1cb6SJacob Keller * 1721a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 1722a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 1723a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 1724a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 1725a69f1cb6SJacob Keller */ 1726a69f1cb6SJacob Keller static int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port) 1727a69f1cb6SJacob Keller { 1728a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 1729a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 1730a69f1cb6SJacob Keller u64 total_offset, val; 1731a69f1cb6SJacob Keller int err; 1732a69f1cb6SJacob Keller 1733a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1734a69f1cb6SJacob Keller if (err) 1735a69f1cb6SJacob Keller return err; 1736a69f1cb6SJacob Keller 1737a69f1cb6SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 1738a69f1cb6SJacob Keller 1739a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 1740a69f1cb6SJacob Keller * the total offset. 1741a69f1cb6SJacob Keller */ 1742a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G || 1743a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_10G || 1744a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1745a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G_RS || 1746a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1747a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1748a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1749a69f1cb6SJacob Keller P_REG_PAR_PCS_TX_OFFSET_L, 1750a69f1cb6SJacob Keller &val); 1751a69f1cb6SJacob Keller if (err) 1752a69f1cb6SJacob Keller return err; 1753a69f1cb6SJacob Keller 1754a69f1cb6SJacob Keller total_offset += val; 1755a69f1cb6SJacob Keller } 1756a69f1cb6SJacob Keller 1757a69f1cb6SJacob Keller /* For Tx, we only need to use the second Vernier offset for 1758a69f1cb6SJacob Keller * multi-lane link speeds with RS-FEC. The lanes will always be 1759a69f1cb6SJacob Keller * aligned. 1760a69f1cb6SJacob Keller */ 1761a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_50G_RS || 1762a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1763a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 1764a69f1cb6SJacob Keller P_REG_PAR_TX_TIME_L, 1765a69f1cb6SJacob Keller &val); 1766a69f1cb6SJacob Keller if (err) 1767a69f1cb6SJacob Keller return err; 1768a69f1cb6SJacob Keller 1769a69f1cb6SJacob Keller total_offset += val; 1770a69f1cb6SJacob Keller } 1771a69f1cb6SJacob Keller 1772a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 1773a69f1cb6SJacob Keller * PHY and indicate that the Tx offset is ready. After this, 1774a69f1cb6SJacob Keller * timestamps will be enabled. 1775a69f1cb6SJacob Keller */ 1776a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 1777a69f1cb6SJacob Keller total_offset); 1778a69f1cb6SJacob Keller if (err) 1779a69f1cb6SJacob Keller return err; 1780a69f1cb6SJacob Keller 1781a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 1782a69f1cb6SJacob Keller if (err) 1783a69f1cb6SJacob Keller return err; 1784a69f1cb6SJacob Keller 1785a69f1cb6SJacob Keller return 0; 1786a69f1cb6SJacob Keller } 1787a69f1cb6SJacob Keller 1788a69f1cb6SJacob Keller /** 17893a749623SJacob Keller * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode 17903a749623SJacob Keller * @hw: pointer to the HW struct 17913a749623SJacob Keller * @port: the PHY port to configure 17923a749623SJacob Keller * 17933a749623SJacob Keller * Calculate and program the fixed Tx offset, and indicate that the offset is 17943a749623SJacob Keller * ready. This can be used when operating in bypass mode. 17953a749623SJacob Keller */ 17963a749623SJacob Keller static int 17973a749623SJacob Keller ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port) 17983a749623SJacob Keller { 17993a749623SJacob Keller enum ice_ptp_link_spd link_spd; 18003a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 18013a749623SJacob Keller u64 total_offset; 18023a749623SJacob Keller int err; 18033a749623SJacob Keller 18043a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 18053a749623SJacob Keller if (err) 18063a749623SJacob Keller return err; 18073a749623SJacob Keller 18083a749623SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 18093a749623SJacob Keller 18103a749623SJacob Keller /* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L 18113a749623SJacob Keller * register, then indicate that the Tx offset is ready. After this, 18123a749623SJacob Keller * timestamps will be enabled. 18133a749623SJacob Keller * 18143a749623SJacob Keller * Note that this skips including the more precise offsets generated 18153a749623SJacob Keller * by the Vernier calibration. 18163a749623SJacob Keller */ 18173a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 18183a749623SJacob Keller total_offset); 18193a749623SJacob Keller if (err) 18203a749623SJacob Keller return err; 18213a749623SJacob Keller 18223a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 18233a749623SJacob Keller if (err) 18243a749623SJacob Keller return err; 18253a749623SJacob Keller 18263a749623SJacob Keller return 0; 18273a749623SJacob Keller } 18283a749623SJacob Keller 18293a749623SJacob Keller /** 1830a69f1cb6SJacob Keller * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx 1831a69f1cb6SJacob Keller * @hw: pointer to the HW struct 1832a69f1cb6SJacob Keller * @port: the PHY port to adjust for 1833a69f1cb6SJacob Keller * @link_spd: the current link speed of the PHY 1834a69f1cb6SJacob Keller * @fec_mode: the current FEC mode of the PHY 1835a69f1cb6SJacob Keller * @pmd_adj: on return, the amount to adjust the Rx total offset by 1836a69f1cb6SJacob Keller * 1837a69f1cb6SJacob Keller * Calculates the adjustment to Rx timestamps due to PMD alignment in the PHY. 1838a69f1cb6SJacob Keller * This varies by link speed and FEC mode. The value calculated accounts for 1839a69f1cb6SJacob Keller * various delays caused when receiving a packet. 1840a69f1cb6SJacob Keller */ 1841a69f1cb6SJacob Keller static int 1842a69f1cb6SJacob Keller ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port, 1843a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd, 1844a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj) 1845a69f1cb6SJacob Keller { 1846a69f1cb6SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, mult, adj; 1847a69f1cb6SJacob Keller u8 pmd_align; 1848a69f1cb6SJacob Keller u32 val; 1849a69f1cb6SJacob Keller int err; 1850a69f1cb6SJacob Keller 1851a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val); 1852a69f1cb6SJacob Keller if (err) { 1853a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n", 1854a69f1cb6SJacob Keller err); 1855a69f1cb6SJacob Keller return err; 1856a69f1cb6SJacob Keller } 1857a69f1cb6SJacob Keller 1858a69f1cb6SJacob Keller pmd_align = (u8)val; 1859a69f1cb6SJacob Keller 1860a69f1cb6SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1861a69f1cb6SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1862a69f1cb6SJacob Keller 1863a69f1cb6SJacob Keller /* Calculate TUs per second */ 1864a69f1cb6SJacob Keller tu_per_sec = cur_freq * clk_incval; 1865a69f1cb6SJacob Keller 1866a69f1cb6SJacob Keller /* The PMD alignment adjustment measurement depends on the link speed, 1867a69f1cb6SJacob Keller * and whether FEC is enabled. For each link speed, the alignment 1868a69f1cb6SJacob Keller * adjustment is calculated by dividing a value by the length of 1869a69f1cb6SJacob Keller * a Time Unit in nanoseconds. 1870a69f1cb6SJacob Keller * 1871a69f1cb6SJacob Keller * 1G: align == 4 ? 10 * 0.8 : (align + 6 % 10) * 0.8 1872a69f1cb6SJacob Keller * 10G: align == 65 ? 0 : (align * 0.1 * 32/33) 1873a69f1cb6SJacob Keller * 10G w/FEC: align * 0.1 * 32/33 1874a69f1cb6SJacob Keller * 25G: align == 65 ? 0 : (align * 0.4 * 32/33) 1875a69f1cb6SJacob Keller * 25G w/FEC: align * 0.4 * 32/33 1876a69f1cb6SJacob Keller * 40G: align == 65 ? 0 : (align * 0.1 * 32/33) 1877a69f1cb6SJacob Keller * 40G w/FEC: align * 0.1 * 32/33 1878a69f1cb6SJacob Keller * 50G: align == 65 ? 0 : (align * 0.4 * 32/33) 1879a69f1cb6SJacob Keller * 50G w/FEC: align * 0.8 * 32/33 1880a69f1cb6SJacob Keller * 1881a69f1cb6SJacob Keller * For RS-FEC, if align is < 17 then we must also add 1.6 * 32/33. 1882a69f1cb6SJacob Keller * 1883a69f1cb6SJacob Keller * To allow for calculating this value using integer arithmetic, we 1884a69f1cb6SJacob Keller * instead start with the number of TUs per second, (inverse of the 1885a69f1cb6SJacob Keller * length of a Time Unit in nanoseconds), multiply by a value based 1886a69f1cb6SJacob Keller * on the PMD alignment register, and then divide by the right value 1887a69f1cb6SJacob Keller * calculated based on the table above. To avoid integer overflow this 1888a69f1cb6SJacob Keller * division is broken up into a step of dividing by 125 first. 1889a69f1cb6SJacob Keller */ 1890a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_1G) { 1891a69f1cb6SJacob Keller if (pmd_align == 4) 1892a69f1cb6SJacob Keller mult = 10; 1893a69f1cb6SJacob Keller else 1894a69f1cb6SJacob Keller mult = (pmd_align + 6) % 10; 1895a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_10G || 1896a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_25G || 1897a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_40G || 1898a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G) { 1899a69f1cb6SJacob Keller /* If Clause 74 FEC, always calculate PMD adjust */ 1900a69f1cb6SJacob Keller if (pmd_align != 65 || fec_mode == ICE_PTP_FEC_MODE_CLAUSE74) 1901a69f1cb6SJacob Keller mult = pmd_align; 1902a69f1cb6SJacob Keller else 1903a69f1cb6SJacob Keller mult = 0; 1904a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_25G_RS || 1905a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 1906a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 1907a69f1cb6SJacob Keller if (pmd_align < 17) 1908a69f1cb6SJacob Keller mult = pmd_align + 40; 1909a69f1cb6SJacob Keller else 1910a69f1cb6SJacob Keller mult = pmd_align; 1911a69f1cb6SJacob Keller } else { 1912a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Unknown link speed %d, skipping PMD adjustment\n", 1913a69f1cb6SJacob Keller link_spd); 1914a69f1cb6SJacob Keller mult = 0; 1915a69f1cb6SJacob Keller } 1916a69f1cb6SJacob Keller 1917a69f1cb6SJacob Keller /* In some cases, there's no need to adjust for the PMD alignment */ 1918a69f1cb6SJacob Keller if (!mult) { 1919a69f1cb6SJacob Keller *pmd_adj = 0; 1920a69f1cb6SJacob Keller return 0; 1921a69f1cb6SJacob Keller } 1922a69f1cb6SJacob Keller 1923a69f1cb6SJacob Keller /* Calculate the adjustment by multiplying TUs per second by the 1924a69f1cb6SJacob Keller * appropriate multiplier and divisor. To avoid overflow, we first 1925a69f1cb6SJacob Keller * divide by 125, and then handle remaining divisor based on the link 1926a69f1cb6SJacob Keller * speed pmd_adj_divisor value. 1927a69f1cb6SJacob Keller */ 1928a69f1cb6SJacob Keller adj = div_u64(tu_per_sec, 125); 1929a69f1cb6SJacob Keller adj *= mult; 1930a69f1cb6SJacob Keller adj = div_u64(adj, e822_vernier[link_spd].pmd_adj_divisor); 1931a69f1cb6SJacob Keller 1932a69f1cb6SJacob Keller /* Finally, for 25G-RS and 50G-RS, a further adjustment for the Rx 1933a69f1cb6SJacob Keller * cycle count is necessary. 1934a69f1cb6SJacob Keller */ 1935a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_25G_RS) { 1936a69f1cb6SJacob Keller u64 cycle_adj; 1937a69f1cb6SJacob Keller u8 rx_cycle; 1938a69f1cb6SJacob Keller 1939a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT, 1940a69f1cb6SJacob Keller &val); 1941a69f1cb6SJacob Keller if (err) { 1942a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n", 1943a69f1cb6SJacob Keller err); 1944a69f1cb6SJacob Keller return err; 1945a69f1cb6SJacob Keller } 1946a69f1cb6SJacob Keller 1947a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_40_TO_160_CNT_RXCYC_M; 1948a69f1cb6SJacob Keller if (rx_cycle) { 1949a69f1cb6SJacob Keller mult = (4 - rx_cycle) * 40; 1950a69f1cb6SJacob Keller 1951a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1952a69f1cb6SJacob Keller cycle_adj *= mult; 1953a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1954a69f1cb6SJacob Keller 1955a69f1cb6SJacob Keller adj += cycle_adj; 1956a69f1cb6SJacob Keller } 1957a69f1cb6SJacob Keller } else if (link_spd == ICE_PTP_LNK_SPD_50G_RS) { 1958a69f1cb6SJacob Keller u64 cycle_adj; 1959a69f1cb6SJacob Keller u8 rx_cycle; 1960a69f1cb6SJacob Keller 1961a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT, 1962a69f1cb6SJacob Keller &val); 1963a69f1cb6SJacob Keller if (err) { 1964a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n", 1965a69f1cb6SJacob Keller err); 1966a69f1cb6SJacob Keller return err; 1967a69f1cb6SJacob Keller } 1968a69f1cb6SJacob Keller 1969a69f1cb6SJacob Keller rx_cycle = val & P_REG_RX_80_TO_160_CNT_RXCYC_M; 1970a69f1cb6SJacob Keller if (rx_cycle) { 1971a69f1cb6SJacob Keller mult = rx_cycle * 40; 1972a69f1cb6SJacob Keller 1973a69f1cb6SJacob Keller cycle_adj = div_u64(tu_per_sec, 125); 1974a69f1cb6SJacob Keller cycle_adj *= mult; 1975a69f1cb6SJacob Keller cycle_adj = div_u64(cycle_adj, e822_vernier[link_spd].pmd_adj_divisor); 1976a69f1cb6SJacob Keller 1977a69f1cb6SJacob Keller adj += cycle_adj; 1978a69f1cb6SJacob Keller } 1979a69f1cb6SJacob Keller } 1980a69f1cb6SJacob Keller 1981a69f1cb6SJacob Keller /* Return the calculated adjustment */ 1982a69f1cb6SJacob Keller *pmd_adj = adj; 1983a69f1cb6SJacob Keller 1984a69f1cb6SJacob Keller return 0; 1985a69f1cb6SJacob Keller } 1986a69f1cb6SJacob Keller 1987a69f1cb6SJacob Keller /** 19883a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 19893a749623SJacob Keller * @hw: pointer to HW struct 19903a749623SJacob Keller * @link_spd: The Link speed to calculate for 19913a749623SJacob Keller * 19923a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 19933a749623SJacob Keller */ 19943a749623SJacob Keller static u64 19953a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 19963a749623SJacob Keller { 19973a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 19983a749623SJacob Keller 19993a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 20003a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 20013a749623SJacob Keller 20023a749623SJacob Keller /* Calculate TUs per second */ 20033a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 20043a749623SJacob Keller 20053a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 20063a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 20073a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 20083a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 20093a749623SJacob Keller * divisions by 1e4 first then by 1e7. 20103a749623SJacob Keller */ 20113a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 20123a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 20133a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 20143a749623SJacob Keller 20153a749623SJacob Keller return fixed_offset; 20163a749623SJacob Keller } 20173a749623SJacob Keller 20183a749623SJacob Keller /** 2019a69f1cb6SJacob Keller * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset 2020a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2021a69f1cb6SJacob Keller * @port: the PHY port to configure 2022a69f1cb6SJacob Keller * 2023a69f1cb6SJacob Keller * Program the P_REG_TOTAL_RX_OFFSET register with the number of Time Units to 2024a69f1cb6SJacob Keller * adjust Rx timestamps by. This combines calculations from the Vernier offset 2025a69f1cb6SJacob Keller * measurements taken in hardware with some data about known fixed delay as 2026a69f1cb6SJacob Keller * well as adjusting for multi-lane alignment delay. 2027a69f1cb6SJacob Keller * 2028a69f1cb6SJacob Keller * This function must be called only after the offset registers are valid, 2029a69f1cb6SJacob Keller * i.e. after the Vernier calibration wait has passed, to ensure that the PHY 2030a69f1cb6SJacob Keller * has measured the offset. 2031a69f1cb6SJacob Keller * 2032a69f1cb6SJacob Keller * To avoid overflow, when calculating the offset based on the known static 2033a69f1cb6SJacob Keller * latency values, we use measurements in 1/100th of a nanosecond, and divide 2034a69f1cb6SJacob Keller * the TUs per second up front. This avoids overflow while allowing 2035a69f1cb6SJacob Keller * calculation of the adjustment using integer arithmetic. 2036a69f1cb6SJacob Keller */ 2037a69f1cb6SJacob Keller static int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port) 2038a69f1cb6SJacob Keller { 2039a69f1cb6SJacob Keller enum ice_ptp_link_spd link_spd; 2040a69f1cb6SJacob Keller enum ice_ptp_fec_mode fec_mode; 2041a69f1cb6SJacob Keller u64 total_offset, pmd, val; 2042a69f1cb6SJacob Keller int err; 2043a69f1cb6SJacob Keller 2044a69f1cb6SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 2045a69f1cb6SJacob Keller if (err) 2046a69f1cb6SJacob Keller return err; 2047a69f1cb6SJacob Keller 2048a69f1cb6SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 2049a69f1cb6SJacob Keller 2050a69f1cb6SJacob Keller /* Read the first Vernier offset from the PHY register and add it to 2051a69f1cb6SJacob Keller * the total offset. 2052a69f1cb6SJacob Keller */ 2053a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2054a69f1cb6SJacob Keller P_REG_PAR_PCS_RX_OFFSET_L, 2055a69f1cb6SJacob Keller &val); 2056a69f1cb6SJacob Keller if (err) 2057a69f1cb6SJacob Keller return err; 2058a69f1cb6SJacob Keller 2059a69f1cb6SJacob Keller total_offset += val; 2060a69f1cb6SJacob Keller 2061a69f1cb6SJacob Keller /* For Rx, all multi-lane link speeds include a second Vernier 2062a69f1cb6SJacob Keller * calibration, because the lanes might not be aligned. 2063a69f1cb6SJacob Keller */ 2064a69f1cb6SJacob Keller if (link_spd == ICE_PTP_LNK_SPD_40G || 2065a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G || 2066a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_50G_RS || 2067a69f1cb6SJacob Keller link_spd == ICE_PTP_LNK_SPD_100G_RS) { 2068a69f1cb6SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, 2069a69f1cb6SJacob Keller P_REG_PAR_RX_TIME_L, 2070a69f1cb6SJacob Keller &val); 2071a69f1cb6SJacob Keller if (err) 2072a69f1cb6SJacob Keller return err; 2073a69f1cb6SJacob Keller 2074a69f1cb6SJacob Keller total_offset += val; 2075a69f1cb6SJacob Keller } 2076a69f1cb6SJacob Keller 2077a69f1cb6SJacob Keller /* In addition, Rx must account for the PMD alignment */ 2078a69f1cb6SJacob Keller err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd); 2079a69f1cb6SJacob Keller if (err) 2080a69f1cb6SJacob Keller return err; 2081a69f1cb6SJacob Keller 2082a69f1cb6SJacob Keller /* For RS-FEC, this adjustment adds delay, but for other modes, it 2083a69f1cb6SJacob Keller * subtracts delay. 2084a69f1cb6SJacob Keller */ 2085a69f1cb6SJacob Keller if (fec_mode == ICE_PTP_FEC_MODE_RS_FEC) 2086a69f1cb6SJacob Keller total_offset += pmd; 2087a69f1cb6SJacob Keller else 2088a69f1cb6SJacob Keller total_offset -= pmd; 2089a69f1cb6SJacob Keller 2090a69f1cb6SJacob Keller /* Now that the total offset has been calculated, program it to the 2091a69f1cb6SJacob Keller * PHY and indicate that the Rx offset is ready. After this, 2092a69f1cb6SJacob Keller * timestamps will be enabled. 2093a69f1cb6SJacob Keller */ 2094a69f1cb6SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 2095a69f1cb6SJacob Keller total_offset); 2096a69f1cb6SJacob Keller if (err) 2097a69f1cb6SJacob Keller return err; 2098a69f1cb6SJacob Keller 2099a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 2100a69f1cb6SJacob Keller if (err) 2101a69f1cb6SJacob Keller return err; 2102a69f1cb6SJacob Keller 2103a69f1cb6SJacob Keller return 0; 2104a69f1cb6SJacob Keller } 2105a69f1cb6SJacob Keller 2106a69f1cb6SJacob Keller /** 21073a749623SJacob Keller * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode 21083a749623SJacob Keller * @hw: pointer to the HW struct 21093a749623SJacob Keller * @port: the PHY port to configure 21103a749623SJacob Keller * 21113a749623SJacob Keller * Calculate and program the fixed Rx offset, and indicate that the offset is 21123a749623SJacob Keller * ready. This can be used when operating in bypass mode. 21133a749623SJacob Keller */ 21143a749623SJacob Keller static int 21153a749623SJacob Keller ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port) 21163a749623SJacob Keller { 21173a749623SJacob Keller enum ice_ptp_link_spd link_spd; 21183a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 21193a749623SJacob Keller u64 total_offset; 21203a749623SJacob Keller int err; 21213a749623SJacob Keller 21223a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 21233a749623SJacob Keller if (err) 21243a749623SJacob Keller return err; 21253a749623SJacob Keller 21263a749623SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 21273a749623SJacob Keller 21283a749623SJacob Keller /* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L 21293a749623SJacob Keller * register, then indicate that the Rx offset is ready. After this, 21303a749623SJacob Keller * timestamps will be enabled. 21313a749623SJacob Keller * 21323a749623SJacob Keller * Note that this skips including the more precise offsets generated 21333a749623SJacob Keller * by Vernier calibration. 21343a749623SJacob Keller */ 21353a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 21363a749623SJacob Keller total_offset); 21373a749623SJacob Keller if (err) 21383a749623SJacob Keller return err; 21393a749623SJacob Keller 21403a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 21413a749623SJacob Keller if (err) 21423a749623SJacob Keller return err; 21433a749623SJacob Keller 21443a749623SJacob Keller return 0; 21453a749623SJacob Keller } 21463a749623SJacob Keller 21473a749623SJacob Keller /** 21483a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 21493a749623SJacob Keller * @hw: pointer to the HW struct 21503a749623SJacob Keller * @port: the PHY port to read 21513a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 21523a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 21533a749623SJacob Keller * 21543a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 21553a749623SJacob Keller * timer values. 21563a749623SJacob Keller */ 21573a749623SJacob Keller static int 21583a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 21593a749623SJacob Keller u64 *phc_time) 21603a749623SJacob Keller { 21613a749623SJacob Keller u64 tx_time, rx_time; 21623a749623SJacob Keller u32 zo, lo; 21633a749623SJacob Keller u8 tmr_idx; 21643a749623SJacob Keller int err; 21653a749623SJacob Keller 21663a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 21673a749623SJacob Keller 21683a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 21693a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 21703a749623SJacob Keller 21713a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 21723a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 21733a749623SJacob Keller if (err) 21743a749623SJacob Keller return err; 21753a749623SJacob Keller 21763a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 21773a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 21783a749623SJacob Keller 21793a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 21803a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 21813a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 21823a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 21833a749623SJacob Keller 21843a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 21853a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 21863a749623SJacob Keller if (err) 21873a749623SJacob Keller return err; 21883a749623SJacob Keller 21893a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 21903a749623SJacob Keller * Note that this should not happen in normal circumstances since the 21913a749623SJacob Keller * driver always programs them together. 21923a749623SJacob Keller */ 21933a749623SJacob Keller if (tx_time != rx_time) 21943a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 21953a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 21963a749623SJacob Keller port, (unsigned long long)tx_time, 21973a749623SJacob Keller (unsigned long long)rx_time); 21983a749623SJacob Keller 21993a749623SJacob Keller *phy_time = tx_time; 22003a749623SJacob Keller 22013a749623SJacob Keller return 0; 22023a749623SJacob Keller } 22033a749623SJacob Keller 22043a749623SJacob Keller /** 22053a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 22063a749623SJacob Keller * @hw: pointer to the HW struct 22073a749623SJacob Keller * @port: the PHY port to synchronize 22083a749623SJacob Keller * 22093a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 22103a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 22113a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 22123a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 22133a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 22143a749623SJacob Keller */ 22153a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 22163a749623SJacob Keller { 22173a749623SJacob Keller u64 phc_time, phy_time, difference; 22183a749623SJacob Keller int err; 22193a749623SJacob Keller 22203a749623SJacob Keller if (!ice_ptp_lock(hw)) { 22213a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 22223a749623SJacob Keller return -EBUSY; 22233a749623SJacob Keller } 22243a749623SJacob Keller 22253a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 22263a749623SJacob Keller if (err) 22273a749623SJacob Keller goto err_unlock; 22283a749623SJacob Keller 22293a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 22303a749623SJacob Keller * it to match the PHC time. 22313a749623SJacob Keller * 22323a749623SJacob Keller * Note that the port adjustment is done using 2s complement 22333a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 22343a749623SJacob Keller * calculate the difference between the PHC time and the port time, 22353a749623SJacob Keller * and it will be interpreted correctly. 22363a749623SJacob Keller */ 22373a749623SJacob Keller difference = phc_time - phy_time; 22383a749623SJacob Keller 22393a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 22403a749623SJacob Keller if (err) 22413a749623SJacob Keller goto err_unlock; 22423a749623SJacob Keller 22433a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 22443a749623SJacob Keller if (err) 22453a749623SJacob Keller goto err_unlock; 22463a749623SJacob Keller 22473a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 22483a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 22493a749623SJacob Keller 22503a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 22513a749623SJacob Keller * verify that the time was properly adjusted. 22523a749623SJacob Keller */ 22533a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 22543a749623SJacob Keller if (err) 22553a749623SJacob Keller goto err_unlock; 22563a749623SJacob Keller 22573a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 22583a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 22593a749623SJacob Keller port, (unsigned long long)phy_time, 22603a749623SJacob Keller (unsigned long long)phc_time); 22613a749623SJacob Keller 22623a749623SJacob Keller ice_ptp_unlock(hw); 22633a749623SJacob Keller 22643a749623SJacob Keller return 0; 22653a749623SJacob Keller 22663a749623SJacob Keller err_unlock: 22673a749623SJacob Keller ice_ptp_unlock(hw); 22683a749623SJacob Keller return err; 22693a749623SJacob Keller } 22703a749623SJacob Keller 22713a749623SJacob Keller /** 22723a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 22733a749623SJacob Keller * @hw: pointer to the HW struct 22743a749623SJacob Keller * @port: the PHY port to stop 22753a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 22763a749623SJacob Keller * 22773a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 22783a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 22793a749623SJacob Keller * initialized or when link speed changes. 22803a749623SJacob Keller */ 22813a749623SJacob Keller int 22823a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 22833a749623SJacob Keller { 22843a749623SJacob Keller int err; 22853a749623SJacob Keller u32 val; 22863a749623SJacob Keller 22873a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 22883a749623SJacob Keller if (err) 22893a749623SJacob Keller return err; 22903a749623SJacob Keller 22913a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 22923a749623SJacob Keller if (err) 22933a749623SJacob Keller return err; 22943a749623SJacob Keller 22953a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 22963a749623SJacob Keller if (err) 22973a749623SJacob Keller return err; 22983a749623SJacob Keller 22993a749623SJacob Keller val &= ~P_REG_PS_START_M; 23003a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23013a749623SJacob Keller if (err) 23023a749623SJacob Keller return err; 23033a749623SJacob Keller 23043a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 23053a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23063a749623SJacob Keller if (err) 23073a749623SJacob Keller return err; 23083a749623SJacob Keller 23093a749623SJacob Keller if (soft_reset) { 23103a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 23113a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23123a749623SJacob Keller if (err) 23133a749623SJacob Keller return err; 23143a749623SJacob Keller } 23153a749623SJacob Keller 23163a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 23173a749623SJacob Keller 23183a749623SJacob Keller return 0; 23193a749623SJacob Keller } 23203a749623SJacob Keller 23213a749623SJacob Keller /** 23223a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 23233a749623SJacob Keller * @hw: pointer to the HW struct 23243a749623SJacob Keller * @port: the PHY port to start 23253a749623SJacob Keller * @bypass: if true, start the PHY in bypass mode 23263a749623SJacob Keller * 23273a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 23283a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 23293a749623SJacob Keller * initialized or when link speed changes. 23303a749623SJacob Keller * 23313a749623SJacob Keller * Bypass mode enables timestamps immediately without waiting for Vernier 23323a749623SJacob Keller * calibration to complete. Hardware will still continue taking Vernier 23333a749623SJacob Keller * measurements on Tx or Rx of packets, but they will not be applied to 23343a749623SJacob Keller * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware 23353a749623SJacob Keller * has completed offset calculation. 23363a749623SJacob Keller */ 23373a749623SJacob Keller int 23383a749623SJacob Keller ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass) 23393a749623SJacob Keller { 23403a749623SJacob Keller u32 lo, hi, val; 23413a749623SJacob Keller u64 incval; 23423a749623SJacob Keller u8 tmr_idx; 23433a749623SJacob Keller int err; 23443a749623SJacob Keller 23453a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 23463a749623SJacob Keller 23473a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 23483a749623SJacob Keller if (err) 23493a749623SJacob Keller return err; 23503a749623SJacob Keller 23513a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 23523a749623SJacob Keller 23533a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 23543a749623SJacob Keller if (err) 23553a749623SJacob Keller return err; 23563a749623SJacob Keller 23573a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 23583a749623SJacob Keller if (err) 23593a749623SJacob Keller return err; 23603a749623SJacob Keller 23613a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 23623a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 23633a749623SJacob Keller incval = (u64)hi << 32 | lo; 23643a749623SJacob Keller 23653a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 23663a749623SJacob Keller if (err) 23673a749623SJacob Keller return err; 23683a749623SJacob Keller 23693a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23703a749623SJacob Keller if (err) 23713a749623SJacob Keller return err; 23723a749623SJacob Keller 23733a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23743a749623SJacob Keller 23753a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 23763a749623SJacob Keller if (err) 23773a749623SJacob Keller return err; 23783a749623SJacob Keller 23793a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 23803a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23813a749623SJacob Keller if (err) 23823a749623SJacob Keller return err; 23833a749623SJacob Keller 23843a749623SJacob Keller val |= P_REG_PS_START_M; 23853a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23863a749623SJacob Keller if (err) 23873a749623SJacob Keller return err; 23883a749623SJacob Keller 23893a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 23903a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 23913a749623SJacob Keller if (err) 23923a749623SJacob Keller return err; 23933a749623SJacob Keller 23943a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 23953a749623SJacob Keller if (err) 23963a749623SJacob Keller return err; 23973a749623SJacob Keller 23983a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 23993a749623SJacob Keller 24003a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 24013a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24023a749623SJacob Keller if (err) 24033a749623SJacob Keller return err; 24043a749623SJacob Keller 24053a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 24063a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24073a749623SJacob Keller if (err) 24083a749623SJacob Keller return err; 24093a749623SJacob Keller 24103a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 24113a749623SJacob Keller 24123a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 24133a749623SJacob Keller if (err) 24143a749623SJacob Keller return err; 24153a749623SJacob Keller 24163a749623SJacob Keller if (bypass) { 24173a749623SJacob Keller val |= P_REG_PS_BYPASS_MODE_M; 24183a749623SJacob Keller /* Enter BYPASS mode, enabling timestamps immediately. */ 24193a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 24203a749623SJacob Keller if (err) 24213a749623SJacob Keller return err; 24223a749623SJacob Keller 24233a749623SJacob Keller /* Program the fixed Tx offset */ 24243a749623SJacob Keller err = ice_phy_cfg_fixed_tx_offset_e822(hw, port); 24253a749623SJacob Keller if (err) 24263a749623SJacob Keller return err; 24273a749623SJacob Keller 24283a749623SJacob Keller /* Program the fixed Rx offset */ 24293a749623SJacob Keller err = ice_phy_cfg_fixed_rx_offset_e822(hw, port); 24303a749623SJacob Keller if (err) 24313a749623SJacob Keller return err; 24323a749623SJacob Keller } 24333a749623SJacob Keller 24343a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 24353a749623SJacob Keller 24363a749623SJacob Keller return 0; 24373a749623SJacob Keller } 24383a749623SJacob Keller 2439a69f1cb6SJacob Keller /** 2440a69f1cb6SJacob Keller * ice_phy_exit_bypass_e822 - Exit bypass mode, after vernier calculations 2441a69f1cb6SJacob Keller * @hw: pointer to the HW struct 2442a69f1cb6SJacob Keller * @port: the PHY port to configure 2443a69f1cb6SJacob Keller * 2444a69f1cb6SJacob Keller * After hardware finishes vernier calculations for the Tx and Rx offset, this 2445a69f1cb6SJacob Keller * function can be used to exit bypass mode by updating the total Tx and Rx 2446a69f1cb6SJacob Keller * offsets, and then disabling bypass. This will enable hardware to include 2447a69f1cb6SJacob Keller * the more precise offset calibrations, increasing precision of the generated 2448a69f1cb6SJacob Keller * timestamps. 2449a69f1cb6SJacob Keller * 2450a69f1cb6SJacob Keller * This cannot be done until hardware has measured the offsets, which requires 2451a69f1cb6SJacob Keller * waiting until at least one packet has been sent and received by the device. 2452a69f1cb6SJacob Keller */ 2453a69f1cb6SJacob Keller int ice_phy_exit_bypass_e822(struct ice_hw *hw, u8 port) 2454a69f1cb6SJacob Keller { 2455a69f1cb6SJacob Keller int err; 2456a69f1cb6SJacob Keller u32 val; 2457a69f1cb6SJacob Keller 2458a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &val); 2459a69f1cb6SJacob Keller if (err) { 2460a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n", 2461a69f1cb6SJacob Keller port, err); 2462a69f1cb6SJacob Keller return err; 2463a69f1cb6SJacob Keller } 2464a69f1cb6SJacob Keller 2465a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2466a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Tx offset is not yet valid for port %u\n", 2467a69f1cb6SJacob Keller port); 2468a69f1cb6SJacob Keller return -EBUSY; 2469a69f1cb6SJacob Keller } 2470a69f1cb6SJacob Keller 2471a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &val); 2472a69f1cb6SJacob Keller if (err) { 2473a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n", 2474a69f1cb6SJacob Keller port, err); 2475a69f1cb6SJacob Keller return err; 2476a69f1cb6SJacob Keller } 2477a69f1cb6SJacob Keller 2478a69f1cb6SJacob Keller if (!(val & P_REG_TX_OV_STATUS_OV_M)) { 2479a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Rx offset is not yet valid for port %u\n", 2480a69f1cb6SJacob Keller port); 2481a69f1cb6SJacob Keller return -EBUSY; 2482a69f1cb6SJacob Keller } 2483a69f1cb6SJacob Keller 2484a69f1cb6SJacob Keller err = ice_phy_cfg_tx_offset_e822(hw, port); 2485a69f1cb6SJacob Keller if (err) { 2486a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Tx offset for port %u, err %d\n", 2487a69f1cb6SJacob Keller port, err); 2488a69f1cb6SJacob Keller return err; 2489a69f1cb6SJacob Keller } 2490a69f1cb6SJacob Keller 2491a69f1cb6SJacob Keller err = ice_phy_cfg_rx_offset_e822(hw, port); 2492a69f1cb6SJacob Keller if (err) { 2493a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to program total Rx offset for port %u, err %d\n", 2494a69f1cb6SJacob Keller port, err); 2495a69f1cb6SJacob Keller return err; 2496a69f1cb6SJacob Keller } 2497a69f1cb6SJacob Keller 2498a69f1cb6SJacob Keller /* Exit bypass mode now that the offset has been updated */ 2499a69f1cb6SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 2500a69f1cb6SJacob Keller if (err) { 2501a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read P_REG_PS for port %u, err %d\n", 2502a69f1cb6SJacob Keller port, err); 2503a69f1cb6SJacob Keller return err; 2504a69f1cb6SJacob Keller } 2505a69f1cb6SJacob Keller 2506a69f1cb6SJacob Keller if (!(val & P_REG_PS_BYPASS_MODE_M)) 2507a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Port %u not in bypass mode\n", 2508a69f1cb6SJacob Keller port); 2509a69f1cb6SJacob Keller 2510a69f1cb6SJacob Keller val &= ~P_REG_PS_BYPASS_MODE_M; 2511a69f1cb6SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 2512a69f1cb6SJacob Keller if (err) { 2513a69f1cb6SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to disable bypass for port %u, err %d\n", 2514a69f1cb6SJacob Keller port, err); 2515a69f1cb6SJacob Keller return err; 2516a69f1cb6SJacob Keller } 2517a69f1cb6SJacob Keller 2518a69f1cb6SJacob Keller dev_info(ice_hw_to_dev(hw), "Exiting bypass mode on PHY port %u\n", 2519a69f1cb6SJacob Keller port); 2520a69f1cb6SJacob Keller 2521a69f1cb6SJacob Keller return 0; 2522a69f1cb6SJacob Keller } 2523a69f1cb6SJacob Keller 252403cb4473SJacob Keller /* E810 functions 252503cb4473SJacob Keller * 252603cb4473SJacob Keller * The following functions operate on the E810 series devices which use 252703cb4473SJacob Keller * a separate external PHY. 252803cb4473SJacob Keller */ 252903cb4473SJacob Keller 253003cb4473SJacob Keller /** 253103cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 253203cb4473SJacob Keller * @hw: pointer to the HW struct 253303cb4473SJacob Keller * @addr: the address to read from 253403cb4473SJacob Keller * @val: On return, the value read from the PHY 253503cb4473SJacob Keller * 253603cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 253703cb4473SJacob Keller */ 253803cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 253903cb4473SJacob Keller { 254003cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 254139b28106SJacob Keller int err; 254203cb4473SJacob Keller 254303cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 254403cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 254503cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 254603cb4473SJacob Keller msg.dest_dev = rmn_0; 254703cb4473SJacob Keller 254839b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 254939b28106SJacob Keller if (err) { 255039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 255139b28106SJacob Keller err); 255239b28106SJacob Keller return err; 255303cb4473SJacob Keller } 255403cb4473SJacob Keller 255503cb4473SJacob Keller *val = msg.data; 255603cb4473SJacob Keller 255703cb4473SJacob Keller return 0; 255803cb4473SJacob Keller } 255903cb4473SJacob Keller 256003cb4473SJacob Keller /** 256103cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 256203cb4473SJacob Keller * @hw: pointer to the HW struct 256303cb4473SJacob Keller * @addr: the address to writem to 256403cb4473SJacob Keller * @val: the value to write to the PHY 256503cb4473SJacob Keller * 256603cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 256703cb4473SJacob Keller */ 256803cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 256903cb4473SJacob Keller { 257003cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 257139b28106SJacob Keller int err; 257203cb4473SJacob Keller 257303cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 257403cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 257503cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 257603cb4473SJacob Keller msg.dest_dev = rmn_0; 257703cb4473SJacob Keller msg.data = val; 257803cb4473SJacob Keller 257939b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 258039b28106SJacob Keller if (err) { 258139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 258239b28106SJacob Keller err); 258339b28106SJacob Keller return err; 258403cb4473SJacob Keller } 258503cb4473SJacob Keller 258603cb4473SJacob Keller return 0; 258703cb4473SJacob Keller } 258803cb4473SJacob Keller 258903cb4473SJacob Keller /** 259003cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 259103cb4473SJacob Keller * @hw: pointer to the HW struct 259203cb4473SJacob Keller * @lport: the lport to read from 259303cb4473SJacob Keller * @idx: the timestamp index to read 259403cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 259503cb4473SJacob Keller * 259603cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 259703cb4473SJacob Keller * on the E810 device. 259803cb4473SJacob Keller */ 259903cb4473SJacob Keller static int 260003cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 260103cb4473SJacob Keller { 260203cb4473SJacob Keller u32 lo_addr, hi_addr, lo, hi; 260339b28106SJacob Keller int err; 260403cb4473SJacob Keller 260503cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 260603cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 260703cb4473SJacob Keller 260839b28106SJacob Keller err = ice_read_phy_reg_e810(hw, lo_addr, &lo); 260939b28106SJacob Keller if (err) { 261039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 261139b28106SJacob Keller err); 261239b28106SJacob Keller return err; 261303cb4473SJacob Keller } 261403cb4473SJacob Keller 261539b28106SJacob Keller err = ice_read_phy_reg_e810(hw, hi_addr, &hi); 261639b28106SJacob Keller if (err) { 261739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 261839b28106SJacob Keller err); 261939b28106SJacob Keller return err; 262003cb4473SJacob Keller } 262103cb4473SJacob Keller 262203cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 262303cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 262403cb4473SJacob Keller */ 262503cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 262603cb4473SJacob Keller 262703cb4473SJacob Keller return 0; 262803cb4473SJacob Keller } 262903cb4473SJacob Keller 263003cb4473SJacob Keller /** 263103cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 263203cb4473SJacob Keller * @hw: pointer to the HW struct 263303cb4473SJacob Keller * @lport: the lport to read from 263403cb4473SJacob Keller * @idx: the timestamp index to reset 263503cb4473SJacob Keller * 263603cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 263703cb4473SJacob Keller * external PHY on the E810 device. 263803cb4473SJacob Keller */ 263903cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 264003cb4473SJacob Keller { 264103cb4473SJacob Keller u32 lo_addr, hi_addr; 264239b28106SJacob Keller int err; 264303cb4473SJacob Keller 264403cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 264503cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 264603cb4473SJacob Keller 264739b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 264839b28106SJacob Keller if (err) { 264939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 265039b28106SJacob Keller err); 265139b28106SJacob Keller return err; 265203cb4473SJacob Keller } 265303cb4473SJacob Keller 265439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 265539b28106SJacob Keller if (err) { 265639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 265739b28106SJacob Keller err); 265839b28106SJacob Keller return err; 265903cb4473SJacob Keller } 266003cb4473SJacob Keller 266103cb4473SJacob Keller return 0; 266203cb4473SJacob Keller } 266303cb4473SJacob Keller 266403cb4473SJacob Keller /** 266503cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 266603cb4473SJacob Keller * @hw: pointer to HW struct 266703cb4473SJacob Keller * 266803cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 266903cb4473SJacob Keller * this function. 267003cb4473SJacob Keller */ 267103cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 267203cb4473SJacob Keller { 267303cb4473SJacob Keller u8 tmr_idx; 267439b28106SJacob Keller int err; 267503cb4473SJacob Keller 267603cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 267739b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 267803cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 267939b28106SJacob Keller if (err) 268003cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 268139b28106SJacob Keller err); 268203cb4473SJacob Keller 268339b28106SJacob Keller return err; 268403cb4473SJacob Keller } 268503cb4473SJacob Keller 268603cb4473SJacob Keller /** 2687b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 2688b2ee7256SJacob Keller * @hw: pointer to HW struct 2689b2ee7256SJacob Keller * 2690b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 2691b2ee7256SJacob Keller */ 2692b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 2693b2ee7256SJacob Keller { 2694b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 2695b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 2696b2ee7256SJacob Keller 2697b2ee7256SJacob Keller /* Initialize the PHY */ 2698b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 2699b2ee7256SJacob Keller } 2700b2ee7256SJacob Keller 2701b2ee7256SJacob Keller /** 270203cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 270303cb4473SJacob Keller * @hw: Board private structure 270403cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 270503cb4473SJacob Keller * 270603cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 270703cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 270803cb4473SJacob Keller * driver issues an INIT_TIME command. 270903cb4473SJacob Keller * 271003cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 271103cb4473SJacob Keller * nominal nanoseconds. 271203cb4473SJacob Keller */ 271303cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 271403cb4473SJacob Keller { 271503cb4473SJacob Keller u8 tmr_idx; 271639b28106SJacob Keller int err; 271703cb4473SJacob Keller 271803cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 271939b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 272039b28106SJacob Keller if (err) { 272139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 272239b28106SJacob Keller err); 272339b28106SJacob Keller return err; 272403cb4473SJacob Keller } 272503cb4473SJacob Keller 272639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 272739b28106SJacob Keller if (err) { 272839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 272939b28106SJacob Keller err); 273039b28106SJacob Keller return err; 273103cb4473SJacob Keller } 273203cb4473SJacob Keller 273303cb4473SJacob Keller return 0; 273403cb4473SJacob Keller } 273503cb4473SJacob Keller 273603cb4473SJacob Keller /** 273703cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 273803cb4473SJacob Keller * @hw: pointer to HW struct 273903cb4473SJacob Keller * @adj: adjustment value to program 274003cb4473SJacob Keller * 274103cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 274203cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 274303cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 274403cb4473SJacob Keller * 274503cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 274603cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 274703cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 274803cb4473SJacob Keller */ 274903cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 275003cb4473SJacob Keller { 275103cb4473SJacob Keller u8 tmr_idx; 275239b28106SJacob Keller int err; 275303cb4473SJacob Keller 275403cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 275503cb4473SJacob Keller 275603cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 275703cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 275803cb4473SJacob Keller */ 275939b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 276039b28106SJacob Keller if (err) { 276139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 276239b28106SJacob Keller err); 276339b28106SJacob Keller return err; 276403cb4473SJacob Keller } 276503cb4473SJacob Keller 276639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 276739b28106SJacob Keller if (err) { 276839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 276939b28106SJacob Keller err); 277039b28106SJacob Keller return err; 277103cb4473SJacob Keller } 277203cb4473SJacob Keller 277303cb4473SJacob Keller return 0; 277403cb4473SJacob Keller } 277503cb4473SJacob Keller 277603cb4473SJacob Keller /** 277703cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 277803cb4473SJacob Keller * @hw: pointer to HW struct 277903cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 278003cb4473SJacob Keller * 278103cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 278203cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 278303cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 278403cb4473SJacob Keller */ 278503cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 278603cb4473SJacob Keller { 278703cb4473SJacob Keller u32 high, low; 278803cb4473SJacob Keller u8 tmr_idx; 278939b28106SJacob Keller int err; 279003cb4473SJacob Keller 279103cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 279203cb4473SJacob Keller low = lower_32_bits(incval); 279303cb4473SJacob Keller high = upper_32_bits(incval); 279403cb4473SJacob Keller 279539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 279639b28106SJacob Keller if (err) { 279739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 279839b28106SJacob Keller err); 279939b28106SJacob Keller return err; 280003cb4473SJacob Keller } 280103cb4473SJacob Keller 280239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 280339b28106SJacob Keller if (err) { 280439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 280539b28106SJacob Keller err); 280639b28106SJacob Keller return err; 280703cb4473SJacob Keller } 280803cb4473SJacob Keller 280903cb4473SJacob Keller return 0; 281003cb4473SJacob Keller } 281103cb4473SJacob Keller 281203cb4473SJacob Keller /** 281303cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 281403cb4473SJacob Keller * @hw: pointer to HW struct 281503cb4473SJacob Keller * @cmd: Command to be sent to the port 281603cb4473SJacob Keller * 281703cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 281803cb4473SJacob Keller * command. 281903cb4473SJacob Keller */ 282003cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 282103cb4473SJacob Keller { 282203cb4473SJacob Keller u32 cmd_val, val; 282339b28106SJacob Keller int err; 282403cb4473SJacob Keller 282503cb4473SJacob Keller switch (cmd) { 282603cb4473SJacob Keller case INIT_TIME: 282703cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 282803cb4473SJacob Keller break; 282903cb4473SJacob Keller case INIT_INCVAL: 283003cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 283103cb4473SJacob Keller break; 283203cb4473SJacob Keller case ADJ_TIME: 283303cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 283403cb4473SJacob Keller break; 283503cb4473SJacob Keller case READ_TIME: 283603cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 283703cb4473SJacob Keller break; 283803cb4473SJacob Keller case ADJ_TIME_AT_TIME: 283903cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 284003cb4473SJacob Keller break; 284103cb4473SJacob Keller } 284203cb4473SJacob Keller 284303cb4473SJacob Keller /* Read, modify, write */ 284439b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 284539b28106SJacob Keller if (err) { 284639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 284739b28106SJacob Keller return err; 284803cb4473SJacob Keller } 284903cb4473SJacob Keller 285003cb4473SJacob Keller /* Modify necessary bits only and perform write */ 285103cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 285203cb4473SJacob Keller val |= cmd_val; 285303cb4473SJacob Keller 285439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 285539b28106SJacob Keller if (err) { 285639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 285739b28106SJacob Keller return err; 285803cb4473SJacob Keller } 285903cb4473SJacob Keller 286003cb4473SJacob Keller return 0; 286103cb4473SJacob Keller } 286203cb4473SJacob Keller 286303cb4473SJacob Keller /* Device agnostic functions 286403cb4473SJacob Keller * 28653a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 28663a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 28673a749623SJacob Keller * necessary. 286803cb4473SJacob Keller */ 286903cb4473SJacob Keller 287003cb4473SJacob Keller /** 287103cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 287203cb4473SJacob Keller * @hw: pointer to the HW struct 287303cb4473SJacob Keller * 287403cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 287503cb4473SJacob Keller * was acquired, false otherwise. 287603cb4473SJacob Keller * 287703cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 287803cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 287903cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 288003cb4473SJacob Keller * bit set, it means that another function acquired the lock. 288103cb4473SJacob Keller * 288203cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 288303cb4473SJacob Keller * functions when done. 288403cb4473SJacob Keller */ 288503cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 288603cb4473SJacob Keller { 288703cb4473SJacob Keller u32 hw_lock; 288803cb4473SJacob Keller int i; 288903cb4473SJacob Keller 289003cb4473SJacob Keller #define MAX_TRIES 5 289103cb4473SJacob Keller 289203cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 289303cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 289403cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2895587b839dSColin Ian King if (!hw_lock) 2896587b839dSColin Ian King break; 2897587b839dSColin Ian King 289803cb4473SJacob Keller /* Somebody is holding the lock */ 289903cb4473SJacob Keller usleep_range(10000, 20000); 290003cb4473SJacob Keller } 290103cb4473SJacob Keller 290203cb4473SJacob Keller return !hw_lock; 290303cb4473SJacob Keller } 290403cb4473SJacob Keller 290503cb4473SJacob Keller /** 290603cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 290703cb4473SJacob Keller * @hw: pointer to the HW struct 290803cb4473SJacob Keller * 290903cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 291003cb4473SJacob Keller * the PFTSYN_SEM register. 291103cb4473SJacob Keller */ 291203cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 291303cb4473SJacob Keller { 291403cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 291503cb4473SJacob Keller } 291603cb4473SJacob Keller 291703cb4473SJacob Keller /** 291803cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 291903cb4473SJacob Keller * @hw: pointer to HW struct 292003cb4473SJacob Keller * @cmd: the command to issue 292103cb4473SJacob Keller * 292203cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 292303cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 292403cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 292503cb4473SJacob Keller * timers. 292603cb4473SJacob Keller */ 292703cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 292803cb4473SJacob Keller { 292939b28106SJacob Keller int err; 293003cb4473SJacob Keller 293103cb4473SJacob Keller /* First, prepare the source timer */ 293203cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 293303cb4473SJacob Keller 293403cb4473SJacob Keller /* Next, prepare the ports */ 29353a749623SJacob Keller if (ice_is_e810(hw)) 293639b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 29373a749623SJacob Keller else 29383a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 293939b28106SJacob Keller if (err) { 294039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 294139b28106SJacob Keller cmd, err); 294239b28106SJacob Keller return err; 294303cb4473SJacob Keller } 294403cb4473SJacob Keller 29453a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 29463a749623SJacob Keller * commands synchronously 294703cb4473SJacob Keller */ 29483a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 294903cb4473SJacob Keller 295003cb4473SJacob Keller return 0; 295103cb4473SJacob Keller } 295203cb4473SJacob Keller 295303cb4473SJacob Keller /** 295403cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 295503cb4473SJacob Keller * @hw: pointer to HW struct 295603cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 295703cb4473SJacob Keller * 295803cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 295903cb4473SJacob Keller * step process: 296003cb4473SJacob Keller * 296103cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 296203cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 296303cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 296403cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 296503cb4473SJacob Keller */ 296603cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 296703cb4473SJacob Keller { 296803cb4473SJacob Keller u8 tmr_idx; 296939b28106SJacob Keller int err; 297003cb4473SJacob Keller 297103cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 297203cb4473SJacob Keller 297303cb4473SJacob Keller /* Source timers */ 297403cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 297503cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 297603cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 297703cb4473SJacob Keller 297803cb4473SJacob Keller /* PHY timers */ 297903cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 29803a749623SJacob Keller if (ice_is_e810(hw)) 298139b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 29823a749623SJacob Keller else 29833a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 298439b28106SJacob Keller if (err) 298539b28106SJacob Keller return err; 298603cb4473SJacob Keller 298703cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 298803cb4473SJacob Keller } 298903cb4473SJacob Keller 299003cb4473SJacob Keller /** 299103cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 299203cb4473SJacob Keller * @hw: pointer to HW struct 299303cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 299403cb4473SJacob Keller * 299503cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 299603cb4473SJacob Keller * process: 299703cb4473SJacob Keller * 299803cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 299903cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 300003cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 300103cb4473SJacob Keller * source and port timers to the new increment value at the next clock 300203cb4473SJacob Keller * cycle. 300303cb4473SJacob Keller */ 300403cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 300503cb4473SJacob Keller { 300603cb4473SJacob Keller u8 tmr_idx; 300739b28106SJacob Keller int err; 300803cb4473SJacob Keller 300903cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 301003cb4473SJacob Keller 301103cb4473SJacob Keller /* Shadow Adjust */ 301203cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 301303cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 301403cb4473SJacob Keller 30153a749623SJacob Keller if (ice_is_e810(hw)) 301639b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 30173a749623SJacob Keller else 30183a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 301939b28106SJacob Keller if (err) 302039b28106SJacob Keller return err; 302103cb4473SJacob Keller 302203cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 302303cb4473SJacob Keller } 302403cb4473SJacob Keller 302503cb4473SJacob Keller /** 302603cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 302703cb4473SJacob Keller * @hw: pointer to HW struct 302803cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 302903cb4473SJacob Keller * 303003cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 303103cb4473SJacob Keller */ 303203cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 303303cb4473SJacob Keller { 303439b28106SJacob Keller int err; 303503cb4473SJacob Keller 303603cb4473SJacob Keller if (!ice_ptp_lock(hw)) 303703cb4473SJacob Keller return -EBUSY; 303803cb4473SJacob Keller 303939b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 304003cb4473SJacob Keller 304103cb4473SJacob Keller ice_ptp_unlock(hw); 304203cb4473SJacob Keller 304339b28106SJacob Keller return err; 304403cb4473SJacob Keller } 304503cb4473SJacob Keller 304603cb4473SJacob Keller /** 304703cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 304803cb4473SJacob Keller * @hw: pointer to HW struct 304903cb4473SJacob Keller * @adj: Adjustment in nanoseconds 305003cb4473SJacob Keller * 305103cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 305203cb4473SJacob Keller * nanoseconds. This requires a three-step process: 305303cb4473SJacob Keller * 305403cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 305503cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 305603cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 305703cb4473SJacob Keller * both the source and port timers at the next clock cycle. 305803cb4473SJacob Keller */ 305903cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 306003cb4473SJacob Keller { 306103cb4473SJacob Keller u8 tmr_idx; 306239b28106SJacob Keller int err; 306303cb4473SJacob Keller 306403cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 306503cb4473SJacob Keller 306603cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 306703cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 306803cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 306903cb4473SJacob Keller * the value as a 2's complement integer. 307003cb4473SJacob Keller */ 307103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 307203cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 307303cb4473SJacob Keller 30743a749623SJacob Keller if (ice_is_e810(hw)) 307539b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 30763a749623SJacob Keller else 30773a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 307839b28106SJacob Keller if (err) 307939b28106SJacob Keller return err; 308003cb4473SJacob Keller 308103cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 308203cb4473SJacob Keller } 308303cb4473SJacob Keller 308403cb4473SJacob Keller /** 308503cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 308603cb4473SJacob Keller * @hw: pointer to the HW struct 308703cb4473SJacob Keller * @block: the block to read from 308803cb4473SJacob Keller * @idx: the timestamp index to read 308903cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 309003cb4473SJacob Keller * 30913a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 30923a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 30933a749623SJacob Keller * logical port to read from. 309403cb4473SJacob Keller */ 309503cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 309603cb4473SJacob Keller { 30973a749623SJacob Keller if (ice_is_e810(hw)) 309803cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 30993a749623SJacob Keller else 31003a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 310103cb4473SJacob Keller } 310203cb4473SJacob Keller 310303cb4473SJacob Keller /** 310403cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 310503cb4473SJacob Keller * @hw: pointer to the HW struct 310603cb4473SJacob Keller * @block: the block to read from 310703cb4473SJacob Keller * @idx: the timestamp index to reset 310803cb4473SJacob Keller * 31093a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 31103a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 31113a749623SJacob Keller * block is the logical port to clear from. 311203cb4473SJacob Keller */ 311303cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 311403cb4473SJacob Keller { 31153a749623SJacob Keller if (ice_is_e810(hw)) 311603cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 31173a749623SJacob Keller else 31183a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 311903cb4473SJacob Keller } 3120885fe693SMaciej Machnikowski 3121885fe693SMaciej Machnikowski /* E810T SMA functions 3122885fe693SMaciej Machnikowski * 3123885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 3124885fe693SMaciej Machnikowski * to access the extended GPIOs available. 3125885fe693SMaciej Machnikowski */ 3126885fe693SMaciej Machnikowski 3127885fe693SMaciej Machnikowski /** 3128885fe693SMaciej Machnikowski * ice_get_pca9575_handle 3129885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3130885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 3131885fe693SMaciej Machnikowski * 3132885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 3133885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 3134885fe693SMaciej Machnikowski * will return cached value 3135885fe693SMaciej Machnikowski */ 3136885fe693SMaciej Machnikowski static int 3137885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 3138885fe693SMaciej Machnikowski { 3139885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 3140885fe693SMaciej Machnikowski struct ice_aq_desc desc; 3141885fe693SMaciej Machnikowski int status; 3142885fe693SMaciej Machnikowski u8 idx; 3143885fe693SMaciej Machnikowski 3144885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 3145885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 3146885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3147885fe693SMaciej Machnikowski return 0; 3148885fe693SMaciej Machnikowski } 3149885fe693SMaciej Machnikowski 3150885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 3151885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 3152885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 3153885fe693SMaciej Machnikowski 3154885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 3155885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 3156885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 3157885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 3158885fe693SMaciej Machnikowski 3159885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 3160885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 3161885fe693SMaciej Machnikowski 3162885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 3163885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 3164885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 3165885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 3166885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 3167885fe693SMaciej Machnikowski else 3168885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3169885fe693SMaciej Machnikowski 3170885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 3171885fe693SMaciej Machnikowski 3172885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 3173885fe693SMaciej Machnikowski if (status) 3174885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3175885fe693SMaciej Machnikowski 3176885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 3177885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 3178885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 3179885fe693SMaciej Machnikowski return -EOPNOTSUPP; 3180885fe693SMaciej Machnikowski 3181885fe693SMaciej Machnikowski /* If present save the handle and return it */ 3182885fe693SMaciej Machnikowski hw->io_expander_handle = 3183885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 3184885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 3185885fe693SMaciej Machnikowski 3186885fe693SMaciej Machnikowski return 0; 3187885fe693SMaciej Machnikowski } 3188885fe693SMaciej Machnikowski 3189885fe693SMaciej Machnikowski /** 3190885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 3191885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3192885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 3193885fe693SMaciej Machnikowski * 3194885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 3195885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 3196885fe693SMaciej Machnikowski */ 3197885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 3198885fe693SMaciej Machnikowski { 3199885fe693SMaciej Machnikowski int status; 3200885fe693SMaciej Machnikowski u16 handle; 3201885fe693SMaciej Machnikowski u8 i; 3202885fe693SMaciej Machnikowski 3203885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3204885fe693SMaciej Machnikowski if (status) 3205885fe693SMaciej Machnikowski return status; 3206885fe693SMaciej Machnikowski 3207885fe693SMaciej Machnikowski *data = 0; 3208885fe693SMaciej Machnikowski 3209885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3210885fe693SMaciej Machnikowski bool pin; 3211885fe693SMaciej Machnikowski 3212885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3213885fe693SMaciej Machnikowski &pin, NULL); 3214885fe693SMaciej Machnikowski if (status) 3215885fe693SMaciej Machnikowski break; 3216885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 3217885fe693SMaciej Machnikowski } 3218885fe693SMaciej Machnikowski 3219885fe693SMaciej Machnikowski return status; 3220885fe693SMaciej Machnikowski } 3221885fe693SMaciej Machnikowski 3222885fe693SMaciej Machnikowski /** 3223885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 3224885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3225885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 3226885fe693SMaciej Machnikowski * 3227885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 3228885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 3229885fe693SMaciej Machnikowski */ 3230885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 3231885fe693SMaciej Machnikowski { 3232885fe693SMaciej Machnikowski int status; 3233885fe693SMaciej Machnikowski u16 handle; 3234885fe693SMaciej Machnikowski u8 i; 3235885fe693SMaciej Machnikowski 3236885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3237885fe693SMaciej Machnikowski if (status) 3238885fe693SMaciej Machnikowski return status; 3239885fe693SMaciej Machnikowski 3240885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 3241885fe693SMaciej Machnikowski bool pin; 3242885fe693SMaciej Machnikowski 3243885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 3244885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 3245885fe693SMaciej Machnikowski pin, NULL); 3246885fe693SMaciej Machnikowski if (status) 3247885fe693SMaciej Machnikowski break; 3248885fe693SMaciej Machnikowski } 3249885fe693SMaciej Machnikowski 3250885fe693SMaciej Machnikowski return status; 3251885fe693SMaciej Machnikowski } 3252885fe693SMaciej Machnikowski 3253885fe693SMaciej Machnikowski /** 3254*43113ff7SKarol Kolacinski * ice_read_pca9575_reg_e810t 3255*43113ff7SKarol Kolacinski * @hw: pointer to the hw struct 3256*43113ff7SKarol Kolacinski * @offset: GPIO controller register offset 3257*43113ff7SKarol Kolacinski * @data: pointer to data to be read from the GPIO controller 3258*43113ff7SKarol Kolacinski * 3259*43113ff7SKarol Kolacinski * Read the register from the GPIO controller 3260*43113ff7SKarol Kolacinski */ 3261*43113ff7SKarol Kolacinski int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) 3262*43113ff7SKarol Kolacinski { 3263*43113ff7SKarol Kolacinski struct ice_aqc_link_topo_addr link_topo; 3264*43113ff7SKarol Kolacinski __le16 addr; 3265*43113ff7SKarol Kolacinski u16 handle; 3266*43113ff7SKarol Kolacinski int err; 3267*43113ff7SKarol Kolacinski 3268*43113ff7SKarol Kolacinski memset(&link_topo, 0, sizeof(link_topo)); 3269*43113ff7SKarol Kolacinski 3270*43113ff7SKarol Kolacinski err = ice_get_pca9575_handle(hw, &handle); 3271*43113ff7SKarol Kolacinski if (err) 3272*43113ff7SKarol Kolacinski return err; 3273*43113ff7SKarol Kolacinski 3274*43113ff7SKarol Kolacinski link_topo.handle = cpu_to_le16(handle); 3275*43113ff7SKarol Kolacinski link_topo.topo_params.node_type_ctx = 3276*43113ff7SKarol Kolacinski FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, 3277*43113ff7SKarol Kolacinski ICE_AQC_LINK_TOPO_NODE_CTX_PROVIDED); 3278*43113ff7SKarol Kolacinski 3279*43113ff7SKarol Kolacinski addr = cpu_to_le16((u16)offset); 3280*43113ff7SKarol Kolacinski 3281*43113ff7SKarol Kolacinski return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL); 3282*43113ff7SKarol Kolacinski } 3283*43113ff7SKarol Kolacinski 3284*43113ff7SKarol Kolacinski /** 3285885fe693SMaciej Machnikowski * ice_is_pca9575_present 3286885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 3287885fe693SMaciej Machnikowski * 3288885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 3289885fe693SMaciej Machnikowski */ 3290885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 3291885fe693SMaciej Machnikowski { 3292885fe693SMaciej Machnikowski u16 handle = 0; 3293885fe693SMaciej Machnikowski int status; 3294885fe693SMaciej Machnikowski 3295885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 3296885fe693SMaciej Machnikowski return false; 3297885fe693SMaciej Machnikowski 3298885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 3299885fe693SMaciej Machnikowski 3300885fe693SMaciej Machnikowski return !status && handle; 3301885fe693SMaciej Machnikowski } 3302b2ee7256SJacob Keller 3303b2ee7256SJacob Keller /** 3304b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 3305b2ee7256SJacob Keller * @hw: pointer to the HW struct 3306b2ee7256SJacob Keller * 3307b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 3308b2ee7256SJacob Keller */ 3309b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 3310b2ee7256SJacob Keller { 3311b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 3312b2ee7256SJacob Keller 3313b2ee7256SJacob Keller /* Enable source clocks */ 3314b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 3315b2ee7256SJacob Keller 3316b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 3317b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 3318b2ee7256SJacob Keller 33193a749623SJacob Keller if (ice_is_e810(hw)) 3320b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 33213a749623SJacob Keller else 33223a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 3323b2ee7256SJacob Keller } 3324