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" 7*b111ab5aSJacob 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 /** 658*b111ab5aSJacob Keller * ice_read_cgu_reg_e822 - Read a CGU register 659*b111ab5aSJacob Keller * @hw: pointer to the HW struct 660*b111ab5aSJacob Keller * @addr: Register address to read 661*b111ab5aSJacob Keller * @val: storage for register value read 662*b111ab5aSJacob Keller * 663*b111ab5aSJacob Keller * Read the contents of a register of the Clock Generation Unit. Only 664*b111ab5aSJacob Keller * applicable to E822 devices. 665*b111ab5aSJacob Keller */ 666*b111ab5aSJacob Keller static int 667*b111ab5aSJacob Keller ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val) 668*b111ab5aSJacob Keller { 669*b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 670*b111ab5aSJacob Keller int err; 671*b111ab5aSJacob Keller 672*b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_rd; 673*b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 674*b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 675*b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 676*b111ab5aSJacob Keller 677*b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 678*b111ab5aSJacob Keller if (err) { 679*b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read CGU register 0x%04x, err %d\n", 680*b111ab5aSJacob Keller addr, err); 681*b111ab5aSJacob Keller return err; 682*b111ab5aSJacob Keller } 683*b111ab5aSJacob Keller 684*b111ab5aSJacob Keller *val = cgu_msg.data; 685*b111ab5aSJacob Keller 686*b111ab5aSJacob Keller return err; 687*b111ab5aSJacob Keller } 688*b111ab5aSJacob Keller 689*b111ab5aSJacob Keller /** 690*b111ab5aSJacob Keller * ice_write_cgu_reg_e822 - Write a CGU register 691*b111ab5aSJacob Keller * @hw: pointer to the HW struct 692*b111ab5aSJacob Keller * @addr: Register address to write 693*b111ab5aSJacob Keller * @val: value to write into the register 694*b111ab5aSJacob Keller * 695*b111ab5aSJacob Keller * Write the specified value to a register of the Clock Generation Unit. Only 696*b111ab5aSJacob Keller * applicable to E822 devices. 697*b111ab5aSJacob Keller */ 698*b111ab5aSJacob Keller static int 699*b111ab5aSJacob Keller ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val) 700*b111ab5aSJacob Keller { 701*b111ab5aSJacob Keller struct ice_sbq_msg_input cgu_msg; 702*b111ab5aSJacob Keller int err; 703*b111ab5aSJacob Keller 704*b111ab5aSJacob Keller cgu_msg.opcode = ice_sbq_msg_wr; 705*b111ab5aSJacob Keller cgu_msg.dest_dev = cgu; 706*b111ab5aSJacob Keller cgu_msg.msg_addr_low = addr; 707*b111ab5aSJacob Keller cgu_msg.msg_addr_high = 0x0; 708*b111ab5aSJacob Keller cgu_msg.data = val; 709*b111ab5aSJacob Keller 710*b111ab5aSJacob Keller err = ice_sbq_rw_reg(hw, &cgu_msg); 711*b111ab5aSJacob Keller if (err) { 712*b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write CGU register 0x%04x, err %d\n", 713*b111ab5aSJacob Keller addr, err); 714*b111ab5aSJacob Keller return err; 715*b111ab5aSJacob Keller } 716*b111ab5aSJacob Keller 717*b111ab5aSJacob Keller return err; 718*b111ab5aSJacob Keller } 719*b111ab5aSJacob Keller 720*b111ab5aSJacob Keller /** 721*b111ab5aSJacob Keller * ice_clk_freq_str - Convert time_ref_freq to string 722*b111ab5aSJacob Keller * @clk_freq: Clock frequency 723*b111ab5aSJacob Keller * 724*b111ab5aSJacob Keller * Convert the specified TIME_REF clock frequency to a string. 725*b111ab5aSJacob Keller */ 726*b111ab5aSJacob Keller static const char *ice_clk_freq_str(u8 clk_freq) 727*b111ab5aSJacob Keller { 728*b111ab5aSJacob Keller switch ((enum ice_time_ref_freq)clk_freq) { 729*b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_25_000: 730*b111ab5aSJacob Keller return "25 MHz"; 731*b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_122_880: 732*b111ab5aSJacob Keller return "122.88 MHz"; 733*b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_125_000: 734*b111ab5aSJacob Keller return "125 MHz"; 735*b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_153_600: 736*b111ab5aSJacob Keller return "153.6 MHz"; 737*b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_156_250: 738*b111ab5aSJacob Keller return "156.25 MHz"; 739*b111ab5aSJacob Keller case ICE_TIME_REF_FREQ_245_760: 740*b111ab5aSJacob Keller return "245.76 MHz"; 741*b111ab5aSJacob Keller default: 742*b111ab5aSJacob Keller return "Unknown"; 743*b111ab5aSJacob Keller } 744*b111ab5aSJacob Keller } 745*b111ab5aSJacob Keller 746*b111ab5aSJacob Keller /** 747*b111ab5aSJacob Keller * ice_clk_src_str - Convert time_ref_src to string 748*b111ab5aSJacob Keller * @clk_src: Clock source 749*b111ab5aSJacob Keller * 750*b111ab5aSJacob Keller * Convert the specified clock source to its string name. 751*b111ab5aSJacob Keller */ 752*b111ab5aSJacob Keller static const char *ice_clk_src_str(u8 clk_src) 753*b111ab5aSJacob Keller { 754*b111ab5aSJacob Keller switch ((enum ice_clk_src)clk_src) { 755*b111ab5aSJacob Keller case ICE_CLK_SRC_TCX0: 756*b111ab5aSJacob Keller return "TCX0"; 757*b111ab5aSJacob Keller case ICE_CLK_SRC_TIME_REF: 758*b111ab5aSJacob Keller return "TIME_REF"; 759*b111ab5aSJacob Keller default: 760*b111ab5aSJacob Keller return "Unknown"; 761*b111ab5aSJacob Keller } 762*b111ab5aSJacob Keller } 763*b111ab5aSJacob Keller 764*b111ab5aSJacob Keller /** 765*b111ab5aSJacob Keller * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit 766*b111ab5aSJacob Keller * @hw: pointer to the HW struct 767*b111ab5aSJacob Keller * @clk_freq: Clock frequency to program 768*b111ab5aSJacob Keller * @clk_src: Clock source to select (TIME_REF, or TCX0) 769*b111ab5aSJacob Keller * 770*b111ab5aSJacob Keller * Configure the Clock Generation Unit with the desired clock frequency and 771*b111ab5aSJacob Keller * time reference, enabling the PLL which drives the PTP hardware clock. 772*b111ab5aSJacob Keller */ 773*b111ab5aSJacob Keller static int 774*b111ab5aSJacob Keller ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq, 775*b111ab5aSJacob Keller enum ice_clk_src clk_src) 776*b111ab5aSJacob Keller { 777*b111ab5aSJacob Keller union tspll_ro_bwm_lf bwm_lf; 778*b111ab5aSJacob Keller union nac_cgu_dword19 dw19; 779*b111ab5aSJacob Keller union nac_cgu_dword22 dw22; 780*b111ab5aSJacob Keller union nac_cgu_dword24 dw24; 781*b111ab5aSJacob Keller union nac_cgu_dword9 dw9; 782*b111ab5aSJacob Keller int err; 783*b111ab5aSJacob Keller 784*b111ab5aSJacob Keller if (clk_freq >= NUM_ICE_TIME_REF_FREQ) { 785*b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid TIME_REF frequency %u\n", 786*b111ab5aSJacob Keller clk_freq); 787*b111ab5aSJacob Keller return -EINVAL; 788*b111ab5aSJacob Keller } 789*b111ab5aSJacob Keller 790*b111ab5aSJacob Keller if (clk_src >= NUM_ICE_CLK_SRC) { 791*b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "Invalid clock source %u\n", 792*b111ab5aSJacob Keller clk_src); 793*b111ab5aSJacob Keller return -EINVAL; 794*b111ab5aSJacob Keller } 795*b111ab5aSJacob Keller 796*b111ab5aSJacob Keller if (clk_src == ICE_CLK_SRC_TCX0 && 797*b111ab5aSJacob Keller clk_freq != ICE_TIME_REF_FREQ_25_000) { 798*b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), 799*b111ab5aSJacob Keller "TCX0 only supports 25 MHz frequency\n"); 800*b111ab5aSJacob Keller return -EINVAL; 801*b111ab5aSJacob Keller } 802*b111ab5aSJacob Keller 803*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val); 804*b111ab5aSJacob Keller if (err) 805*b111ab5aSJacob Keller return err; 806*b111ab5aSJacob Keller 807*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 808*b111ab5aSJacob Keller if (err) 809*b111ab5aSJacob Keller return err; 810*b111ab5aSJacob Keller 811*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 812*b111ab5aSJacob Keller if (err) 813*b111ab5aSJacob Keller return err; 814*b111ab5aSJacob Keller 815*b111ab5aSJacob Keller /* Log the current clock configuration */ 816*b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "Current CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 817*b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 818*b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 819*b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 820*b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 821*b111ab5aSJacob Keller 822*b111ab5aSJacob Keller /* Disable the PLL before changing the clock source or frequency */ 823*b111ab5aSJacob Keller if (dw24.field.ts_pll_enable) { 824*b111ab5aSJacob Keller dw24.field.ts_pll_enable = 0; 825*b111ab5aSJacob Keller 826*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 827*b111ab5aSJacob Keller if (err) 828*b111ab5aSJacob Keller return err; 829*b111ab5aSJacob Keller } 830*b111ab5aSJacob Keller 831*b111ab5aSJacob Keller /* Set the frequency */ 832*b111ab5aSJacob Keller dw9.field.time_ref_freq_sel = clk_freq; 833*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val); 834*b111ab5aSJacob Keller if (err) 835*b111ab5aSJacob Keller return err; 836*b111ab5aSJacob Keller 837*b111ab5aSJacob Keller /* Configure the TS PLL feedback divisor */ 838*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val); 839*b111ab5aSJacob Keller if (err) 840*b111ab5aSJacob Keller return err; 841*b111ab5aSJacob Keller 842*b111ab5aSJacob Keller dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div; 843*b111ab5aSJacob Keller dw19.field.tspll_ndivratio = 1; 844*b111ab5aSJacob Keller 845*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val); 846*b111ab5aSJacob Keller if (err) 847*b111ab5aSJacob Keller return err; 848*b111ab5aSJacob Keller 849*b111ab5aSJacob Keller /* Configure the TS PLL post divisor */ 850*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val); 851*b111ab5aSJacob Keller if (err) 852*b111ab5aSJacob Keller return err; 853*b111ab5aSJacob Keller 854*b111ab5aSJacob Keller dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div; 855*b111ab5aSJacob Keller dw22.field.time1588clk_sel_div2 = 0; 856*b111ab5aSJacob Keller 857*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val); 858*b111ab5aSJacob Keller if (err) 859*b111ab5aSJacob Keller return err; 860*b111ab5aSJacob Keller 861*b111ab5aSJacob Keller /* Configure the TS PLL pre divisor and clock source */ 862*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val); 863*b111ab5aSJacob Keller if (err) 864*b111ab5aSJacob Keller return err; 865*b111ab5aSJacob Keller 866*b111ab5aSJacob Keller dw24.field.ref1588_ck_div = e822_cgu_params[clk_freq].refclk_pre_div; 867*b111ab5aSJacob Keller dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div; 868*b111ab5aSJacob Keller dw24.field.time_ref_sel = clk_src; 869*b111ab5aSJacob Keller 870*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 871*b111ab5aSJacob Keller if (err) 872*b111ab5aSJacob Keller return err; 873*b111ab5aSJacob Keller 874*b111ab5aSJacob Keller /* Finally, enable the PLL */ 875*b111ab5aSJacob Keller dw24.field.ts_pll_enable = 1; 876*b111ab5aSJacob Keller 877*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val); 878*b111ab5aSJacob Keller if (err) 879*b111ab5aSJacob Keller return err; 880*b111ab5aSJacob Keller 881*b111ab5aSJacob Keller /* Wait to verify if the PLL locks */ 882*b111ab5aSJacob Keller usleep_range(1000, 5000); 883*b111ab5aSJacob Keller 884*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val); 885*b111ab5aSJacob Keller if (err) 886*b111ab5aSJacob Keller return err; 887*b111ab5aSJacob Keller 888*b111ab5aSJacob Keller if (!bwm_lf.field.plllock_true_lock_cri) { 889*b111ab5aSJacob Keller dev_warn(ice_hw_to_dev(hw), "CGU PLL failed to lock\n"); 890*b111ab5aSJacob Keller return -EBUSY; 891*b111ab5aSJacob Keller } 892*b111ab5aSJacob Keller 893*b111ab5aSJacob Keller /* Log the current clock configuration */ 894*b111ab5aSJacob Keller ice_debug(hw, ICE_DBG_PTP, "New CGU configuration -- %s, clk_src %s, clk_freq %s, PLL %s\n", 895*b111ab5aSJacob Keller dw24.field.ts_pll_enable ? "enabled" : "disabled", 896*b111ab5aSJacob Keller ice_clk_src_str(dw24.field.time_ref_sel), 897*b111ab5aSJacob Keller ice_clk_freq_str(dw9.field.time_ref_freq_sel), 898*b111ab5aSJacob Keller bwm_lf.field.plllock_true_lock_cri ? "locked" : "unlocked"); 899*b111ab5aSJacob Keller 900*b111ab5aSJacob Keller return 0; 901*b111ab5aSJacob Keller } 902*b111ab5aSJacob Keller 903*b111ab5aSJacob Keller /** 904*b111ab5aSJacob Keller * ice_init_cgu_e822 - Initialize CGU with settings from firmware 905*b111ab5aSJacob Keller * @hw: pointer to the HW structure 906*b111ab5aSJacob Keller * 907*b111ab5aSJacob Keller * Initialize the Clock Generation Unit of the E822 device. 908*b111ab5aSJacob Keller */ 909*b111ab5aSJacob Keller static int ice_init_cgu_e822(struct ice_hw *hw) 910*b111ab5aSJacob Keller { 911*b111ab5aSJacob Keller struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info; 912*b111ab5aSJacob Keller union tspll_cntr_bist_settings cntr_bist; 913*b111ab5aSJacob Keller int err; 914*b111ab5aSJacob Keller 915*b111ab5aSJacob Keller err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 916*b111ab5aSJacob Keller &cntr_bist.val); 917*b111ab5aSJacob Keller if (err) 918*b111ab5aSJacob Keller return err; 919*b111ab5aSJacob Keller 920*b111ab5aSJacob Keller /* Disable sticky lock detection so lock err reported is accurate */ 921*b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_0 = 0; 922*b111ab5aSJacob Keller cntr_bist.field.i_plllock_sel_1 = 0; 923*b111ab5aSJacob Keller 924*b111ab5aSJacob Keller err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS, 925*b111ab5aSJacob Keller cntr_bist.val); 926*b111ab5aSJacob Keller if (err) 927*b111ab5aSJacob Keller return err; 928*b111ab5aSJacob Keller 929*b111ab5aSJacob Keller /* Configure the CGU PLL using the parameters from the function 930*b111ab5aSJacob Keller * capabilities. 931*b111ab5aSJacob Keller */ 932*b111ab5aSJacob Keller err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref, 933*b111ab5aSJacob Keller (enum ice_clk_src)ts_info->clk_src); 934*b111ab5aSJacob Keller if (err) 935*b111ab5aSJacob Keller return err; 936*b111ab5aSJacob Keller 937*b111ab5aSJacob Keller return 0; 938*b111ab5aSJacob Keller } 939*b111ab5aSJacob Keller 940*b111ab5aSJacob 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 { 973*b111ab5aSJacob 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 984*b111ab5aSJacob Keller /* Initialize the Clock Generation Unit */ 985*b111ab5aSJacob Keller err = ice_init_cgu_e822(hw); 986*b111ab5aSJacob Keller if (err) 987*b111ab5aSJacob Keller return err; 988*b111ab5aSJacob 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 /** 17093a749623SJacob Keller * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode 17103a749623SJacob Keller * @hw: pointer to the HW struct 17113a749623SJacob Keller * @port: the PHY port to configure 17123a749623SJacob Keller * 17133a749623SJacob Keller * Calculate and program the fixed Tx offset, and indicate that the offset is 17143a749623SJacob Keller * ready. This can be used when operating in bypass mode. 17153a749623SJacob Keller */ 17163a749623SJacob Keller static int 17173a749623SJacob Keller ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port) 17183a749623SJacob Keller { 17193a749623SJacob Keller enum ice_ptp_link_spd link_spd; 17203a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 17213a749623SJacob Keller u64 total_offset; 17223a749623SJacob Keller int err; 17233a749623SJacob Keller 17243a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 17253a749623SJacob Keller if (err) 17263a749623SJacob Keller return err; 17273a749623SJacob Keller 17283a749623SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 17293a749623SJacob Keller 17303a749623SJacob Keller /* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L 17313a749623SJacob Keller * register, then indicate that the Tx offset is ready. After this, 17323a749623SJacob Keller * timestamps will be enabled. 17333a749623SJacob Keller * 17343a749623SJacob Keller * Note that this skips including the more precise offsets generated 17353a749623SJacob Keller * by the Vernier calibration. 17363a749623SJacob Keller */ 17373a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 17383a749623SJacob Keller total_offset); 17393a749623SJacob Keller if (err) 17403a749623SJacob Keller return err; 17413a749623SJacob Keller 17423a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 17433a749623SJacob Keller if (err) 17443a749623SJacob Keller return err; 17453a749623SJacob Keller 17463a749623SJacob Keller return 0; 17473a749623SJacob Keller } 17483a749623SJacob Keller 17493a749623SJacob Keller /** 17503a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 17513a749623SJacob Keller * @hw: pointer to HW struct 17523a749623SJacob Keller * @link_spd: The Link speed to calculate for 17533a749623SJacob Keller * 17543a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 17553a749623SJacob Keller */ 17563a749623SJacob Keller static u64 17573a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 17583a749623SJacob Keller { 17593a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 17603a749623SJacob Keller 17613a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 17623a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 17633a749623SJacob Keller 17643a749623SJacob Keller /* Calculate TUs per second */ 17653a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 17663a749623SJacob Keller 17673a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 17683a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 17693a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 17703a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 17713a749623SJacob Keller * divisions by 1e4 first then by 1e7. 17723a749623SJacob Keller */ 17733a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 17743a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 17753a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 17763a749623SJacob Keller 17773a749623SJacob Keller return fixed_offset; 17783a749623SJacob Keller } 17793a749623SJacob Keller 17803a749623SJacob Keller /** 17813a749623SJacob Keller * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode 17823a749623SJacob Keller * @hw: pointer to the HW struct 17833a749623SJacob Keller * @port: the PHY port to configure 17843a749623SJacob Keller * 17853a749623SJacob Keller * Calculate and program the fixed Rx offset, and indicate that the offset is 17863a749623SJacob Keller * ready. This can be used when operating in bypass mode. 17873a749623SJacob Keller */ 17883a749623SJacob Keller static int 17893a749623SJacob Keller ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port) 17903a749623SJacob Keller { 17913a749623SJacob Keller enum ice_ptp_link_spd link_spd; 17923a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 17933a749623SJacob Keller u64 total_offset; 17943a749623SJacob Keller int err; 17953a749623SJacob Keller 17963a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 17973a749623SJacob Keller if (err) 17983a749623SJacob Keller return err; 17993a749623SJacob Keller 18003a749623SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 18013a749623SJacob Keller 18023a749623SJacob Keller /* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L 18033a749623SJacob Keller * register, then indicate that the Rx offset is ready. After this, 18043a749623SJacob Keller * timestamps will be enabled. 18053a749623SJacob Keller * 18063a749623SJacob Keller * Note that this skips including the more precise offsets generated 18073a749623SJacob Keller * by Vernier calibration. 18083a749623SJacob Keller */ 18093a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 18103a749623SJacob Keller total_offset); 18113a749623SJacob Keller if (err) 18123a749623SJacob Keller return err; 18133a749623SJacob Keller 18143a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 18153a749623SJacob Keller if (err) 18163a749623SJacob Keller return err; 18173a749623SJacob Keller 18183a749623SJacob Keller return 0; 18193a749623SJacob Keller } 18203a749623SJacob Keller 18213a749623SJacob Keller /** 18223a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 18233a749623SJacob Keller * @hw: pointer to the HW struct 18243a749623SJacob Keller * @port: the PHY port to read 18253a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 18263a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 18273a749623SJacob Keller * 18283a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 18293a749623SJacob Keller * timer values. 18303a749623SJacob Keller */ 18313a749623SJacob Keller static int 18323a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 18333a749623SJacob Keller u64 *phc_time) 18343a749623SJacob Keller { 18353a749623SJacob Keller u64 tx_time, rx_time; 18363a749623SJacob Keller u32 zo, lo; 18373a749623SJacob Keller u8 tmr_idx; 18383a749623SJacob Keller int err; 18393a749623SJacob Keller 18403a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 18413a749623SJacob Keller 18423a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 18433a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 18443a749623SJacob Keller 18453a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 18463a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 18473a749623SJacob Keller if (err) 18483a749623SJacob Keller return err; 18493a749623SJacob Keller 18503a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 18513a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 18523a749623SJacob Keller 18533a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 18543a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 18553a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 18563a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 18573a749623SJacob Keller 18583a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 18593a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 18603a749623SJacob Keller if (err) 18613a749623SJacob Keller return err; 18623a749623SJacob Keller 18633a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 18643a749623SJacob Keller * Note that this should not happen in normal circumstances since the 18653a749623SJacob Keller * driver always programs them together. 18663a749623SJacob Keller */ 18673a749623SJacob Keller if (tx_time != rx_time) 18683a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 18693a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 18703a749623SJacob Keller port, (unsigned long long)tx_time, 18713a749623SJacob Keller (unsigned long long)rx_time); 18723a749623SJacob Keller 18733a749623SJacob Keller *phy_time = tx_time; 18743a749623SJacob Keller 18753a749623SJacob Keller return 0; 18763a749623SJacob Keller } 18773a749623SJacob Keller 18783a749623SJacob Keller /** 18793a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 18803a749623SJacob Keller * @hw: pointer to the HW struct 18813a749623SJacob Keller * @port: the PHY port to synchronize 18823a749623SJacob Keller * 18833a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 18843a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 18853a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 18863a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 18873a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 18883a749623SJacob Keller */ 18893a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 18903a749623SJacob Keller { 18913a749623SJacob Keller u64 phc_time, phy_time, difference; 18923a749623SJacob Keller int err; 18933a749623SJacob Keller 18943a749623SJacob Keller if (!ice_ptp_lock(hw)) { 18953a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 18963a749623SJacob Keller return -EBUSY; 18973a749623SJacob Keller } 18983a749623SJacob Keller 18993a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 19003a749623SJacob Keller if (err) 19013a749623SJacob Keller goto err_unlock; 19023a749623SJacob Keller 19033a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 19043a749623SJacob Keller * it to match the PHC time. 19053a749623SJacob Keller * 19063a749623SJacob Keller * Note that the port adjustment is done using 2s complement 19073a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 19083a749623SJacob Keller * calculate the difference between the PHC time and the port time, 19093a749623SJacob Keller * and it will be interpreted correctly. 19103a749623SJacob Keller */ 19113a749623SJacob Keller difference = phc_time - phy_time; 19123a749623SJacob Keller 19133a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 19143a749623SJacob Keller if (err) 19153a749623SJacob Keller goto err_unlock; 19163a749623SJacob Keller 19173a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 19183a749623SJacob Keller if (err) 19193a749623SJacob Keller goto err_unlock; 19203a749623SJacob Keller 19213a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 19223a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 19233a749623SJacob Keller 19243a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 19253a749623SJacob Keller * verify that the time was properly adjusted. 19263a749623SJacob Keller */ 19273a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 19283a749623SJacob Keller if (err) 19293a749623SJacob Keller goto err_unlock; 19303a749623SJacob Keller 19313a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 19323a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 19333a749623SJacob Keller port, (unsigned long long)phy_time, 19343a749623SJacob Keller (unsigned long long)phc_time); 19353a749623SJacob Keller 19363a749623SJacob Keller ice_ptp_unlock(hw); 19373a749623SJacob Keller 19383a749623SJacob Keller return 0; 19393a749623SJacob Keller 19403a749623SJacob Keller err_unlock: 19413a749623SJacob Keller ice_ptp_unlock(hw); 19423a749623SJacob Keller return err; 19433a749623SJacob Keller } 19443a749623SJacob Keller 19453a749623SJacob Keller /** 19463a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 19473a749623SJacob Keller * @hw: pointer to the HW struct 19483a749623SJacob Keller * @port: the PHY port to stop 19493a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 19503a749623SJacob Keller * 19513a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 19523a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 19533a749623SJacob Keller * initialized or when link speed changes. 19543a749623SJacob Keller */ 19553a749623SJacob Keller int 19563a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 19573a749623SJacob Keller { 19583a749623SJacob Keller int err; 19593a749623SJacob Keller u32 val; 19603a749623SJacob Keller 19613a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 19623a749623SJacob Keller if (err) 19633a749623SJacob Keller return err; 19643a749623SJacob Keller 19653a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 19663a749623SJacob Keller if (err) 19673a749623SJacob Keller return err; 19683a749623SJacob Keller 19693a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 19703a749623SJacob Keller if (err) 19713a749623SJacob Keller return err; 19723a749623SJacob Keller 19733a749623SJacob Keller val &= ~P_REG_PS_START_M; 19743a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 19753a749623SJacob Keller if (err) 19763a749623SJacob Keller return err; 19773a749623SJacob Keller 19783a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 19793a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 19803a749623SJacob Keller if (err) 19813a749623SJacob Keller return err; 19823a749623SJacob Keller 19833a749623SJacob Keller if (soft_reset) { 19843a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 19853a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 19863a749623SJacob Keller if (err) 19873a749623SJacob Keller return err; 19883a749623SJacob Keller } 19893a749623SJacob Keller 19903a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 19913a749623SJacob Keller 19923a749623SJacob Keller return 0; 19933a749623SJacob Keller } 19943a749623SJacob Keller 19953a749623SJacob Keller /** 19963a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 19973a749623SJacob Keller * @hw: pointer to the HW struct 19983a749623SJacob Keller * @port: the PHY port to start 19993a749623SJacob Keller * @bypass: if true, start the PHY in bypass mode 20003a749623SJacob Keller * 20013a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 20023a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 20033a749623SJacob Keller * initialized or when link speed changes. 20043a749623SJacob Keller * 20053a749623SJacob Keller * Bypass mode enables timestamps immediately without waiting for Vernier 20063a749623SJacob Keller * calibration to complete. Hardware will still continue taking Vernier 20073a749623SJacob Keller * measurements on Tx or Rx of packets, but they will not be applied to 20083a749623SJacob Keller * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware 20093a749623SJacob Keller * has completed offset calculation. 20103a749623SJacob Keller */ 20113a749623SJacob Keller int 20123a749623SJacob Keller ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass) 20133a749623SJacob Keller { 20143a749623SJacob Keller u32 lo, hi, val; 20153a749623SJacob Keller u64 incval; 20163a749623SJacob Keller u8 tmr_idx; 20173a749623SJacob Keller int err; 20183a749623SJacob Keller 20193a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 20203a749623SJacob Keller 20213a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 20223a749623SJacob Keller if (err) 20233a749623SJacob Keller return err; 20243a749623SJacob Keller 20253a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 20263a749623SJacob Keller 20273a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 20283a749623SJacob Keller if (err) 20293a749623SJacob Keller return err; 20303a749623SJacob Keller 20313a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 20323a749623SJacob Keller if (err) 20333a749623SJacob Keller return err; 20343a749623SJacob Keller 20353a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 20363a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 20373a749623SJacob Keller incval = (u64)hi << 32 | lo; 20383a749623SJacob Keller 20393a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 20403a749623SJacob Keller if (err) 20413a749623SJacob Keller return err; 20423a749623SJacob Keller 20433a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 20443a749623SJacob Keller if (err) 20453a749623SJacob Keller return err; 20463a749623SJacob Keller 20473a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 20483a749623SJacob Keller 20493a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 20503a749623SJacob Keller if (err) 20513a749623SJacob Keller return err; 20523a749623SJacob Keller 20533a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 20543a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 20553a749623SJacob Keller if (err) 20563a749623SJacob Keller return err; 20573a749623SJacob Keller 20583a749623SJacob Keller val |= P_REG_PS_START_M; 20593a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 20603a749623SJacob Keller if (err) 20613a749623SJacob Keller return err; 20623a749623SJacob Keller 20633a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 20643a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 20653a749623SJacob Keller if (err) 20663a749623SJacob Keller return err; 20673a749623SJacob Keller 20683a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 20693a749623SJacob Keller if (err) 20703a749623SJacob Keller return err; 20713a749623SJacob Keller 20723a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 20733a749623SJacob Keller 20743a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 20753a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 20763a749623SJacob Keller if (err) 20773a749623SJacob Keller return err; 20783a749623SJacob Keller 20793a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 20803a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 20813a749623SJacob Keller if (err) 20823a749623SJacob Keller return err; 20833a749623SJacob Keller 20843a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 20853a749623SJacob Keller 20863a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 20873a749623SJacob Keller if (err) 20883a749623SJacob Keller return err; 20893a749623SJacob Keller 20903a749623SJacob Keller if (bypass) { 20913a749623SJacob Keller val |= P_REG_PS_BYPASS_MODE_M; 20923a749623SJacob Keller /* Enter BYPASS mode, enabling timestamps immediately. */ 20933a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 20943a749623SJacob Keller if (err) 20953a749623SJacob Keller return err; 20963a749623SJacob Keller 20973a749623SJacob Keller /* Program the fixed Tx offset */ 20983a749623SJacob Keller err = ice_phy_cfg_fixed_tx_offset_e822(hw, port); 20993a749623SJacob Keller if (err) 21003a749623SJacob Keller return err; 21013a749623SJacob Keller 21023a749623SJacob Keller /* Program the fixed Rx offset */ 21033a749623SJacob Keller err = ice_phy_cfg_fixed_rx_offset_e822(hw, port); 21043a749623SJacob Keller if (err) 21053a749623SJacob Keller return err; 21063a749623SJacob Keller } 21073a749623SJacob Keller 21083a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 21093a749623SJacob Keller 21103a749623SJacob Keller return 0; 21113a749623SJacob Keller } 21123a749623SJacob Keller 211303cb4473SJacob Keller /* E810 functions 211403cb4473SJacob Keller * 211503cb4473SJacob Keller * The following functions operate on the E810 series devices which use 211603cb4473SJacob Keller * a separate external PHY. 211703cb4473SJacob Keller */ 211803cb4473SJacob Keller 211903cb4473SJacob Keller /** 212003cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 212103cb4473SJacob Keller * @hw: pointer to the HW struct 212203cb4473SJacob Keller * @addr: the address to read from 212303cb4473SJacob Keller * @val: On return, the value read from the PHY 212403cb4473SJacob Keller * 212503cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 212603cb4473SJacob Keller */ 212703cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 212803cb4473SJacob Keller { 212903cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 213039b28106SJacob Keller int err; 213103cb4473SJacob Keller 213203cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 213303cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 213403cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 213503cb4473SJacob Keller msg.dest_dev = rmn_0; 213603cb4473SJacob Keller 213739b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 213839b28106SJacob Keller if (err) { 213939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 214039b28106SJacob Keller err); 214139b28106SJacob Keller return err; 214203cb4473SJacob Keller } 214303cb4473SJacob Keller 214403cb4473SJacob Keller *val = msg.data; 214503cb4473SJacob Keller 214603cb4473SJacob Keller return 0; 214703cb4473SJacob Keller } 214803cb4473SJacob Keller 214903cb4473SJacob Keller /** 215003cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 215103cb4473SJacob Keller * @hw: pointer to the HW struct 215203cb4473SJacob Keller * @addr: the address to writem to 215303cb4473SJacob Keller * @val: the value to write to the PHY 215403cb4473SJacob Keller * 215503cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 215603cb4473SJacob Keller */ 215703cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 215803cb4473SJacob Keller { 215903cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 216039b28106SJacob Keller int err; 216103cb4473SJacob Keller 216203cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 216303cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 216403cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 216503cb4473SJacob Keller msg.dest_dev = rmn_0; 216603cb4473SJacob Keller msg.data = val; 216703cb4473SJacob Keller 216839b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 216939b28106SJacob Keller if (err) { 217039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 217139b28106SJacob Keller err); 217239b28106SJacob Keller return err; 217303cb4473SJacob Keller } 217403cb4473SJacob Keller 217503cb4473SJacob Keller return 0; 217603cb4473SJacob Keller } 217703cb4473SJacob Keller 217803cb4473SJacob Keller /** 217903cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 218003cb4473SJacob Keller * @hw: pointer to the HW struct 218103cb4473SJacob Keller * @lport: the lport to read from 218203cb4473SJacob Keller * @idx: the timestamp index to read 218303cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 218403cb4473SJacob Keller * 218503cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 218603cb4473SJacob Keller * on the E810 device. 218703cb4473SJacob Keller */ 218803cb4473SJacob Keller static int 218903cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 219003cb4473SJacob Keller { 219103cb4473SJacob Keller u32 lo_addr, hi_addr, lo, hi; 219239b28106SJacob Keller int err; 219303cb4473SJacob Keller 219403cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 219503cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 219603cb4473SJacob Keller 219739b28106SJacob Keller err = ice_read_phy_reg_e810(hw, lo_addr, &lo); 219839b28106SJacob Keller if (err) { 219939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 220039b28106SJacob Keller err); 220139b28106SJacob Keller return err; 220203cb4473SJacob Keller } 220303cb4473SJacob Keller 220439b28106SJacob Keller err = ice_read_phy_reg_e810(hw, hi_addr, &hi); 220539b28106SJacob Keller if (err) { 220639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 220739b28106SJacob Keller err); 220839b28106SJacob Keller return err; 220903cb4473SJacob Keller } 221003cb4473SJacob Keller 221103cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 221203cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 221303cb4473SJacob Keller */ 221403cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 221503cb4473SJacob Keller 221603cb4473SJacob Keller return 0; 221703cb4473SJacob Keller } 221803cb4473SJacob Keller 221903cb4473SJacob Keller /** 222003cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 222103cb4473SJacob Keller * @hw: pointer to the HW struct 222203cb4473SJacob Keller * @lport: the lport to read from 222303cb4473SJacob Keller * @idx: the timestamp index to reset 222403cb4473SJacob Keller * 222503cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 222603cb4473SJacob Keller * external PHY on the E810 device. 222703cb4473SJacob Keller */ 222803cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 222903cb4473SJacob Keller { 223003cb4473SJacob Keller u32 lo_addr, hi_addr; 223139b28106SJacob Keller int err; 223203cb4473SJacob Keller 223303cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 223403cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 223503cb4473SJacob Keller 223639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 223739b28106SJacob Keller if (err) { 223839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 223939b28106SJacob Keller err); 224039b28106SJacob Keller return err; 224103cb4473SJacob Keller } 224203cb4473SJacob Keller 224339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 224439b28106SJacob Keller if (err) { 224539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 224639b28106SJacob Keller err); 224739b28106SJacob Keller return err; 224803cb4473SJacob Keller } 224903cb4473SJacob Keller 225003cb4473SJacob Keller return 0; 225103cb4473SJacob Keller } 225203cb4473SJacob Keller 225303cb4473SJacob Keller /** 225403cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 225503cb4473SJacob Keller * @hw: pointer to HW struct 225603cb4473SJacob Keller * 225703cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 225803cb4473SJacob Keller * this function. 225903cb4473SJacob Keller */ 226003cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 226103cb4473SJacob Keller { 226203cb4473SJacob Keller u8 tmr_idx; 226339b28106SJacob Keller int err; 226403cb4473SJacob Keller 226503cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 226639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 226703cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 226839b28106SJacob Keller if (err) 226903cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 227039b28106SJacob Keller err); 227103cb4473SJacob Keller 227239b28106SJacob Keller return err; 227303cb4473SJacob Keller } 227403cb4473SJacob Keller 227503cb4473SJacob Keller /** 2276b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 2277b2ee7256SJacob Keller * @hw: pointer to HW struct 2278b2ee7256SJacob Keller * 2279b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 2280b2ee7256SJacob Keller */ 2281b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 2282b2ee7256SJacob Keller { 2283b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 2284b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 2285b2ee7256SJacob Keller 2286b2ee7256SJacob Keller /* Initialize the PHY */ 2287b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 2288b2ee7256SJacob Keller } 2289b2ee7256SJacob Keller 2290b2ee7256SJacob Keller /** 229103cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 229203cb4473SJacob Keller * @hw: Board private structure 229303cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 229403cb4473SJacob Keller * 229503cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 229603cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 229703cb4473SJacob Keller * driver issues an INIT_TIME command. 229803cb4473SJacob Keller * 229903cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 230003cb4473SJacob Keller * nominal nanoseconds. 230103cb4473SJacob Keller */ 230203cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 230303cb4473SJacob Keller { 230403cb4473SJacob Keller u8 tmr_idx; 230539b28106SJacob Keller int err; 230603cb4473SJacob Keller 230703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 230839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 230939b28106SJacob Keller if (err) { 231039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 231139b28106SJacob Keller err); 231239b28106SJacob Keller return err; 231303cb4473SJacob Keller } 231403cb4473SJacob Keller 231539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 231639b28106SJacob Keller if (err) { 231739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 231839b28106SJacob Keller err); 231939b28106SJacob Keller return err; 232003cb4473SJacob Keller } 232103cb4473SJacob Keller 232203cb4473SJacob Keller return 0; 232303cb4473SJacob Keller } 232403cb4473SJacob Keller 232503cb4473SJacob Keller /** 232603cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 232703cb4473SJacob Keller * @hw: pointer to HW struct 232803cb4473SJacob Keller * @adj: adjustment value to program 232903cb4473SJacob Keller * 233003cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 233103cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 233203cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 233303cb4473SJacob Keller * 233403cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 233503cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 233603cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 233703cb4473SJacob Keller */ 233803cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 233903cb4473SJacob Keller { 234003cb4473SJacob Keller u8 tmr_idx; 234139b28106SJacob Keller int err; 234203cb4473SJacob Keller 234303cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 234403cb4473SJacob Keller 234503cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 234603cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 234703cb4473SJacob Keller */ 234839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 234939b28106SJacob Keller if (err) { 235039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 235139b28106SJacob Keller err); 235239b28106SJacob Keller return err; 235303cb4473SJacob Keller } 235403cb4473SJacob Keller 235539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 235639b28106SJacob Keller if (err) { 235739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 235839b28106SJacob Keller err); 235939b28106SJacob Keller return err; 236003cb4473SJacob Keller } 236103cb4473SJacob Keller 236203cb4473SJacob Keller return 0; 236303cb4473SJacob Keller } 236403cb4473SJacob Keller 236503cb4473SJacob Keller /** 236603cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 236703cb4473SJacob Keller * @hw: pointer to HW struct 236803cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 236903cb4473SJacob Keller * 237003cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 237103cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 237203cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 237303cb4473SJacob Keller */ 237403cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 237503cb4473SJacob Keller { 237603cb4473SJacob Keller u32 high, low; 237703cb4473SJacob Keller u8 tmr_idx; 237839b28106SJacob Keller int err; 237903cb4473SJacob Keller 238003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 238103cb4473SJacob Keller low = lower_32_bits(incval); 238203cb4473SJacob Keller high = upper_32_bits(incval); 238303cb4473SJacob Keller 238439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 238539b28106SJacob Keller if (err) { 238639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 238739b28106SJacob Keller err); 238839b28106SJacob Keller return err; 238903cb4473SJacob Keller } 239003cb4473SJacob Keller 239139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 239239b28106SJacob Keller if (err) { 239339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 239439b28106SJacob Keller err); 239539b28106SJacob Keller return err; 239603cb4473SJacob Keller } 239703cb4473SJacob Keller 239803cb4473SJacob Keller return 0; 239903cb4473SJacob Keller } 240003cb4473SJacob Keller 240103cb4473SJacob Keller /** 240203cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 240303cb4473SJacob Keller * @hw: pointer to HW struct 240403cb4473SJacob Keller * @cmd: Command to be sent to the port 240503cb4473SJacob Keller * 240603cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 240703cb4473SJacob Keller * command. 240803cb4473SJacob Keller */ 240903cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 241003cb4473SJacob Keller { 241103cb4473SJacob Keller u32 cmd_val, val; 241239b28106SJacob Keller int err; 241303cb4473SJacob Keller 241403cb4473SJacob Keller switch (cmd) { 241503cb4473SJacob Keller case INIT_TIME: 241603cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 241703cb4473SJacob Keller break; 241803cb4473SJacob Keller case INIT_INCVAL: 241903cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 242003cb4473SJacob Keller break; 242103cb4473SJacob Keller case ADJ_TIME: 242203cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 242303cb4473SJacob Keller break; 242403cb4473SJacob Keller case READ_TIME: 242503cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 242603cb4473SJacob Keller break; 242703cb4473SJacob Keller case ADJ_TIME_AT_TIME: 242803cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 242903cb4473SJacob Keller break; 243003cb4473SJacob Keller } 243103cb4473SJacob Keller 243203cb4473SJacob Keller /* Read, modify, write */ 243339b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 243439b28106SJacob Keller if (err) { 243539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 243639b28106SJacob Keller return err; 243703cb4473SJacob Keller } 243803cb4473SJacob Keller 243903cb4473SJacob Keller /* Modify necessary bits only and perform write */ 244003cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 244103cb4473SJacob Keller val |= cmd_val; 244203cb4473SJacob Keller 244339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 244439b28106SJacob Keller if (err) { 244539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 244639b28106SJacob Keller return err; 244703cb4473SJacob Keller } 244803cb4473SJacob Keller 244903cb4473SJacob Keller return 0; 245003cb4473SJacob Keller } 245103cb4473SJacob Keller 245203cb4473SJacob Keller /* Device agnostic functions 245303cb4473SJacob Keller * 24543a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 24553a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 24563a749623SJacob Keller * necessary. 245703cb4473SJacob Keller */ 245803cb4473SJacob Keller 245903cb4473SJacob Keller /** 246003cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 246103cb4473SJacob Keller * @hw: pointer to the HW struct 246203cb4473SJacob Keller * 246303cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 246403cb4473SJacob Keller * was acquired, false otherwise. 246503cb4473SJacob Keller * 246603cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 246703cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 246803cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 246903cb4473SJacob Keller * bit set, it means that another function acquired the lock. 247003cb4473SJacob Keller * 247103cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 247203cb4473SJacob Keller * functions when done. 247303cb4473SJacob Keller */ 247403cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 247503cb4473SJacob Keller { 247603cb4473SJacob Keller u32 hw_lock; 247703cb4473SJacob Keller int i; 247803cb4473SJacob Keller 247903cb4473SJacob Keller #define MAX_TRIES 5 248003cb4473SJacob Keller 248103cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 248203cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 248303cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2484587b839dSColin Ian King if (!hw_lock) 2485587b839dSColin Ian King break; 2486587b839dSColin Ian King 248703cb4473SJacob Keller /* Somebody is holding the lock */ 248803cb4473SJacob Keller usleep_range(10000, 20000); 248903cb4473SJacob Keller } 249003cb4473SJacob Keller 249103cb4473SJacob Keller return !hw_lock; 249203cb4473SJacob Keller } 249303cb4473SJacob Keller 249403cb4473SJacob Keller /** 249503cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 249603cb4473SJacob Keller * @hw: pointer to the HW struct 249703cb4473SJacob Keller * 249803cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 249903cb4473SJacob Keller * the PFTSYN_SEM register. 250003cb4473SJacob Keller */ 250103cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 250203cb4473SJacob Keller { 250303cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 250403cb4473SJacob Keller } 250503cb4473SJacob Keller 250603cb4473SJacob Keller /** 250703cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 250803cb4473SJacob Keller * @hw: pointer to HW struct 250903cb4473SJacob Keller * @cmd: the command to issue 251003cb4473SJacob Keller * 251103cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 251203cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 251303cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 251403cb4473SJacob Keller * timers. 251503cb4473SJacob Keller */ 251603cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 251703cb4473SJacob Keller { 251839b28106SJacob Keller int err; 251903cb4473SJacob Keller 252003cb4473SJacob Keller /* First, prepare the source timer */ 252103cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 252203cb4473SJacob Keller 252303cb4473SJacob Keller /* Next, prepare the ports */ 25243a749623SJacob Keller if (ice_is_e810(hw)) 252539b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 25263a749623SJacob Keller else 25273a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 252839b28106SJacob Keller if (err) { 252939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 253039b28106SJacob Keller cmd, err); 253139b28106SJacob Keller return err; 253203cb4473SJacob Keller } 253303cb4473SJacob Keller 25343a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 25353a749623SJacob Keller * commands synchronously 253603cb4473SJacob Keller */ 25373a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 253803cb4473SJacob Keller 253903cb4473SJacob Keller return 0; 254003cb4473SJacob Keller } 254103cb4473SJacob Keller 254203cb4473SJacob Keller /** 254303cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 254403cb4473SJacob Keller * @hw: pointer to HW struct 254503cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 254603cb4473SJacob Keller * 254703cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 254803cb4473SJacob Keller * step process: 254903cb4473SJacob Keller * 255003cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 255103cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 255203cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 255303cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 255403cb4473SJacob Keller */ 255503cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 255603cb4473SJacob Keller { 255703cb4473SJacob Keller u8 tmr_idx; 255839b28106SJacob Keller int err; 255903cb4473SJacob Keller 256003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 256103cb4473SJacob Keller 256203cb4473SJacob Keller /* Source timers */ 256303cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 256403cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 256503cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 256603cb4473SJacob Keller 256703cb4473SJacob Keller /* PHY timers */ 256803cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 25693a749623SJacob Keller if (ice_is_e810(hw)) 257039b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 25713a749623SJacob Keller else 25723a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 257339b28106SJacob Keller if (err) 257439b28106SJacob Keller return err; 257503cb4473SJacob Keller 257603cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 257703cb4473SJacob Keller } 257803cb4473SJacob Keller 257903cb4473SJacob Keller /** 258003cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 258103cb4473SJacob Keller * @hw: pointer to HW struct 258203cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 258303cb4473SJacob Keller * 258403cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 258503cb4473SJacob Keller * process: 258603cb4473SJacob Keller * 258703cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 258803cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 258903cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 259003cb4473SJacob Keller * source and port timers to the new increment value at the next clock 259103cb4473SJacob Keller * cycle. 259203cb4473SJacob Keller */ 259303cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 259403cb4473SJacob Keller { 259503cb4473SJacob Keller u8 tmr_idx; 259639b28106SJacob Keller int err; 259703cb4473SJacob Keller 259803cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 259903cb4473SJacob Keller 260003cb4473SJacob Keller /* Shadow Adjust */ 260103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 260203cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 260303cb4473SJacob Keller 26043a749623SJacob Keller if (ice_is_e810(hw)) 260539b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 26063a749623SJacob Keller else 26073a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 260839b28106SJacob Keller if (err) 260939b28106SJacob Keller return err; 261003cb4473SJacob Keller 261103cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 261203cb4473SJacob Keller } 261303cb4473SJacob Keller 261403cb4473SJacob Keller /** 261503cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 261603cb4473SJacob Keller * @hw: pointer to HW struct 261703cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 261803cb4473SJacob Keller * 261903cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 262003cb4473SJacob Keller */ 262103cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 262203cb4473SJacob Keller { 262339b28106SJacob Keller int err; 262403cb4473SJacob Keller 262503cb4473SJacob Keller if (!ice_ptp_lock(hw)) 262603cb4473SJacob Keller return -EBUSY; 262703cb4473SJacob Keller 262839b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 262903cb4473SJacob Keller 263003cb4473SJacob Keller ice_ptp_unlock(hw); 263103cb4473SJacob Keller 263239b28106SJacob Keller return err; 263303cb4473SJacob Keller } 263403cb4473SJacob Keller 263503cb4473SJacob Keller /** 263603cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 263703cb4473SJacob Keller * @hw: pointer to HW struct 263803cb4473SJacob Keller * @adj: Adjustment in nanoseconds 263903cb4473SJacob Keller * 264003cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 264103cb4473SJacob Keller * nanoseconds. This requires a three-step process: 264203cb4473SJacob Keller * 264303cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 264403cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 264503cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 264603cb4473SJacob Keller * both the source and port timers at the next clock cycle. 264703cb4473SJacob Keller */ 264803cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 264903cb4473SJacob Keller { 265003cb4473SJacob Keller u8 tmr_idx; 265139b28106SJacob Keller int err; 265203cb4473SJacob Keller 265303cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 265403cb4473SJacob Keller 265503cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 265603cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 265703cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 265803cb4473SJacob Keller * the value as a 2's complement integer. 265903cb4473SJacob Keller */ 266003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 266103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 266203cb4473SJacob Keller 26633a749623SJacob Keller if (ice_is_e810(hw)) 266439b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 26653a749623SJacob Keller else 26663a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 266739b28106SJacob Keller if (err) 266839b28106SJacob Keller return err; 266903cb4473SJacob Keller 267003cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 267103cb4473SJacob Keller } 267203cb4473SJacob Keller 267303cb4473SJacob Keller /** 267403cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 267503cb4473SJacob Keller * @hw: pointer to the HW struct 267603cb4473SJacob Keller * @block: the block to read from 267703cb4473SJacob Keller * @idx: the timestamp index to read 267803cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 267903cb4473SJacob Keller * 26803a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 26813a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 26823a749623SJacob Keller * logical port to read from. 268303cb4473SJacob Keller */ 268403cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 268503cb4473SJacob Keller { 26863a749623SJacob Keller if (ice_is_e810(hw)) 268703cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 26883a749623SJacob Keller else 26893a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 269003cb4473SJacob Keller } 269103cb4473SJacob Keller 269203cb4473SJacob Keller /** 269303cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 269403cb4473SJacob Keller * @hw: pointer to the HW struct 269503cb4473SJacob Keller * @block: the block to read from 269603cb4473SJacob Keller * @idx: the timestamp index to reset 269703cb4473SJacob Keller * 26983a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 26993a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 27003a749623SJacob Keller * block is the logical port to clear from. 270103cb4473SJacob Keller */ 270203cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 270303cb4473SJacob Keller { 27043a749623SJacob Keller if (ice_is_e810(hw)) 270503cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 27063a749623SJacob Keller else 27073a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 270803cb4473SJacob Keller } 2709885fe693SMaciej Machnikowski 2710885fe693SMaciej Machnikowski /* E810T SMA functions 2711885fe693SMaciej Machnikowski * 2712885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 2713885fe693SMaciej Machnikowski * to access the extended GPIOs available. 2714885fe693SMaciej Machnikowski */ 2715885fe693SMaciej Machnikowski 2716885fe693SMaciej Machnikowski /** 2717885fe693SMaciej Machnikowski * ice_get_pca9575_handle 2718885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2719885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 2720885fe693SMaciej Machnikowski * 2721885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 2722885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 2723885fe693SMaciej Machnikowski * will return cached value 2724885fe693SMaciej Machnikowski */ 2725885fe693SMaciej Machnikowski static int 2726885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 2727885fe693SMaciej Machnikowski { 2728885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 2729885fe693SMaciej Machnikowski struct ice_aq_desc desc; 2730885fe693SMaciej Machnikowski int status; 2731885fe693SMaciej Machnikowski u8 idx; 2732885fe693SMaciej Machnikowski 2733885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 2734885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 2735885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 2736885fe693SMaciej Machnikowski return 0; 2737885fe693SMaciej Machnikowski } 2738885fe693SMaciej Machnikowski 2739885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 2740885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 2741885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 2742885fe693SMaciej Machnikowski 2743885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 2744885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 2745885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 2746885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 2747885fe693SMaciej Machnikowski 2748885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 2749885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 2750885fe693SMaciej Machnikowski 2751885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 2752885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 2753885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 2754885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 2755885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 2756885fe693SMaciej Machnikowski else 2757885fe693SMaciej Machnikowski return -EOPNOTSUPP; 2758885fe693SMaciej Machnikowski 2759885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 2760885fe693SMaciej Machnikowski 2761885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 2762885fe693SMaciej Machnikowski if (status) 2763885fe693SMaciej Machnikowski return -EOPNOTSUPP; 2764885fe693SMaciej Machnikowski 2765885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 2766885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 2767885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 2768885fe693SMaciej Machnikowski return -EOPNOTSUPP; 2769885fe693SMaciej Machnikowski 2770885fe693SMaciej Machnikowski /* If present save the handle and return it */ 2771885fe693SMaciej Machnikowski hw->io_expander_handle = 2772885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 2773885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 2774885fe693SMaciej Machnikowski 2775885fe693SMaciej Machnikowski return 0; 2776885fe693SMaciej Machnikowski } 2777885fe693SMaciej Machnikowski 2778885fe693SMaciej Machnikowski /** 2779885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 2780885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2781885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 2782885fe693SMaciej Machnikowski * 2783885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 2784885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 2785885fe693SMaciej Machnikowski */ 2786885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 2787885fe693SMaciej Machnikowski { 2788885fe693SMaciej Machnikowski int status; 2789885fe693SMaciej Machnikowski u16 handle; 2790885fe693SMaciej Machnikowski u8 i; 2791885fe693SMaciej Machnikowski 2792885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 2793885fe693SMaciej Machnikowski if (status) 2794885fe693SMaciej Machnikowski return status; 2795885fe693SMaciej Machnikowski 2796885fe693SMaciej Machnikowski *data = 0; 2797885fe693SMaciej Machnikowski 2798885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 2799885fe693SMaciej Machnikowski bool pin; 2800885fe693SMaciej Machnikowski 2801885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 2802885fe693SMaciej Machnikowski &pin, NULL); 2803885fe693SMaciej Machnikowski if (status) 2804885fe693SMaciej Machnikowski break; 2805885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 2806885fe693SMaciej Machnikowski } 2807885fe693SMaciej Machnikowski 2808885fe693SMaciej Machnikowski return status; 2809885fe693SMaciej Machnikowski } 2810885fe693SMaciej Machnikowski 2811885fe693SMaciej Machnikowski /** 2812885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 2813885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2814885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 2815885fe693SMaciej Machnikowski * 2816885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 2817885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 2818885fe693SMaciej Machnikowski */ 2819885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 2820885fe693SMaciej Machnikowski { 2821885fe693SMaciej Machnikowski int status; 2822885fe693SMaciej Machnikowski u16 handle; 2823885fe693SMaciej Machnikowski u8 i; 2824885fe693SMaciej Machnikowski 2825885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 2826885fe693SMaciej Machnikowski if (status) 2827885fe693SMaciej Machnikowski return status; 2828885fe693SMaciej Machnikowski 2829885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 2830885fe693SMaciej Machnikowski bool pin; 2831885fe693SMaciej Machnikowski 2832885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 2833885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 2834885fe693SMaciej Machnikowski pin, NULL); 2835885fe693SMaciej Machnikowski if (status) 2836885fe693SMaciej Machnikowski break; 2837885fe693SMaciej Machnikowski } 2838885fe693SMaciej Machnikowski 2839885fe693SMaciej Machnikowski return status; 2840885fe693SMaciej Machnikowski } 2841885fe693SMaciej Machnikowski 2842885fe693SMaciej Machnikowski /** 2843885fe693SMaciej Machnikowski * ice_is_pca9575_present 2844885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2845885fe693SMaciej Machnikowski * 2846885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 2847885fe693SMaciej Machnikowski */ 2848885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 2849885fe693SMaciej Machnikowski { 2850885fe693SMaciej Machnikowski u16 handle = 0; 2851885fe693SMaciej Machnikowski int status; 2852885fe693SMaciej Machnikowski 2853885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 2854885fe693SMaciej Machnikowski return false; 2855885fe693SMaciej Machnikowski 2856885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 2857885fe693SMaciej Machnikowski 2858885fe693SMaciej Machnikowski return !status && handle; 2859885fe693SMaciej Machnikowski } 2860b2ee7256SJacob Keller 2861b2ee7256SJacob Keller /** 2862b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 2863b2ee7256SJacob Keller * @hw: pointer to the HW struct 2864b2ee7256SJacob Keller * 2865b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 2866b2ee7256SJacob Keller */ 2867b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 2868b2ee7256SJacob Keller { 2869b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 2870b2ee7256SJacob Keller 2871b2ee7256SJacob Keller /* Enable source clocks */ 2872b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 2873b2ee7256SJacob Keller 2874b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 2875b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 2876b2ee7256SJacob Keller 28773a749623SJacob Keller if (ice_is_e810(hw)) 2878b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 28793a749623SJacob Keller else 28803a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 2881b2ee7256SJacob Keller } 2882