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" 6*3a749623SJacob Keller #include "ice_ptp_consts.h" 703cb4473SJacob Keller 803cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used 903cb4473SJacob Keller * for the Precision Time Protocol. 1003cb4473SJacob Keller * 1103cb4473SJacob Keller * The ice hardware represents the current time using three registers: 1203cb4473SJacob Keller * 1303cb4473SJacob Keller * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R 1403cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1503cb4473SJacob Keller * | 32 bits | | 32 bits | | 32 bits | 1603cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1703cb4473SJacob Keller * 1803cb4473SJacob Keller * The registers are incremented every clock tick using a 40bit increment 1903cb4473SJacob Keller * value defined over two registers: 2003cb4473SJacob Keller * 2103cb4473SJacob Keller * GLTSYN_INCVAL_H GLTSYN_INCVAL_L 2203cb4473SJacob Keller * +---------------+ +---------------+ 2303cb4473SJacob Keller * | 8 bit s | | 32 bits | 2403cb4473SJacob Keller * +---------------+ +---------------+ 2503cb4473SJacob Keller * 2603cb4473SJacob Keller * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L 2703cb4473SJacob Keller * registers every clock source tick. Depending on the specific device 2803cb4473SJacob Keller * configuration, the clock source frequency could be one of a number of 2903cb4473SJacob Keller * values. 3003cb4473SJacob Keller * 3103cb4473SJacob Keller * For E810 devices, the increment frequency is 812.5 MHz 3203cb4473SJacob Keller * 33*3a749623SJacob Keller * For E822 devices the clock can be derived from different sources, and the 34*3a749623SJacob Keller * increment has an effective frequency of one of the following: 35*3a749623SJacob Keller * - 823.4375 MHz 36*3a749623SJacob Keller * - 783.36 MHz 37*3a749623SJacob Keller * - 796.875 MHz 38*3a749623SJacob Keller * - 816 MHz 39*3a749623SJacob Keller * - 830.078125 MHz 40*3a749623SJacob Keller * - 783.36 MHz 41*3a749623SJacob Keller * 4203cb4473SJacob Keller * The hardware captures timestamps in the PHY for incoming packets, and for 4303cb4473SJacob Keller * outgoing packets on request. To support this, the PHY maintains a timer 4403cb4473SJacob Keller * that matches the lower 64 bits of the global source timer. 4503cb4473SJacob Keller * 4603cb4473SJacob Keller * In order to ensure that the PHY timers and the source timer are equivalent, 4703cb4473SJacob Keller * shadow registers are used to prepare the desired initial values. A special 4803cb4473SJacob Keller * sync command is issued to trigger copying from the shadow registers into 4903cb4473SJacob Keller * the appropriate source and PHY registers simultaneously. 50*3a749623SJacob Keller * 51*3a749623SJacob Keller * The driver supports devices which have different PHYs with subtly different 52*3a749623SJacob Keller * mechanisms to program and control the timers. We divide the devices into 53*3a749623SJacob Keller * families named after the first major device, E810 and similar devices, and 54*3a749623SJacob Keller * E822 and similar devices. 55*3a749623SJacob Keller * 56*3a749623SJacob Keller * - E822 based devices have additional support for fine grained Vernier 57*3a749623SJacob Keller * calibration which requires significant setup 58*3a749623SJacob Keller * - The layout of timestamp data in the PHY register blocks is different 59*3a749623SJacob Keller * - The way timer synchronization commands are issued is different. 60*3a749623SJacob Keller * 61*3a749623SJacob Keller * To support this, very low level functions have an e810 or e822 suffix 62*3a749623SJacob Keller * indicating what type of device they work on. Higher level abstractions for 63*3a749623SJacob Keller * tasks that can be done on both devices do not have the suffix and will 64*3a749623SJacob Keller * correctly look up the appropriate low level function when running. 65*3a749623SJacob Keller * 66*3a749623SJacob Keller * Functions which only make sense on a single device family may not have 67*3a749623SJacob Keller * a suitable generic implementation 6803cb4473SJacob Keller */ 6903cb4473SJacob Keller 7003cb4473SJacob Keller /** 7103cb4473SJacob Keller * ice_get_ptp_src_clock_index - determine source clock index 7203cb4473SJacob Keller * @hw: pointer to HW struct 7303cb4473SJacob Keller * 7403cb4473SJacob Keller * Determine the source clock index currently in use, based on device 7503cb4473SJacob Keller * capabilities reported during initialization. 7603cb4473SJacob Keller */ 7703cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw) 7803cb4473SJacob Keller { 7903cb4473SJacob Keller return hw->func_caps.ts_func_info.tmr_index_assoc; 8003cb4473SJacob Keller } 8103cb4473SJacob Keller 82*3a749623SJacob Keller /** 83*3a749623SJacob Keller * ice_ptp_read_src_incval - Read source timer increment value 84*3a749623SJacob Keller * @hw: pointer to HW struct 85*3a749623SJacob Keller * 86*3a749623SJacob Keller * Read the increment value of the source timer and return it. 87*3a749623SJacob Keller */ 88*3a749623SJacob Keller static u64 ice_ptp_read_src_incval(struct ice_hw *hw) 89*3a749623SJacob Keller { 90*3a749623SJacob Keller u32 lo, hi; 91*3a749623SJacob Keller u8 tmr_idx; 92*3a749623SJacob Keller 93*3a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 94*3a749623SJacob Keller 95*3a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 96*3a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 97*3a749623SJacob Keller 98*3a749623SJacob Keller return ((u64)(hi & INCVAL_HIGH_M) << 32) | lo; 99*3a749623SJacob Keller } 100*3a749623SJacob Keller 101*3a749623SJacob Keller /** 102*3a749623SJacob Keller * ice_ptp_src_cmd - Prepare source timer for a timer command 103*3a749623SJacob Keller * @hw: pointer to HW structure 104*3a749623SJacob Keller * @cmd: Timer command 105*3a749623SJacob Keller * 106*3a749623SJacob Keller * Prepare the source timer for an upcoming timer sync command. 107*3a749623SJacob Keller */ 108*3a749623SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 109*3a749623SJacob Keller { 110*3a749623SJacob Keller u32 cmd_val; 111*3a749623SJacob Keller u8 tmr_idx; 112*3a749623SJacob Keller 113*3a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 114*3a749623SJacob Keller cmd_val = tmr_idx << SEL_CPK_SRC; 115*3a749623SJacob Keller 116*3a749623SJacob Keller switch (cmd) { 117*3a749623SJacob Keller case INIT_TIME: 118*3a749623SJacob Keller cmd_val |= GLTSYN_CMD_INIT_TIME; 119*3a749623SJacob Keller break; 120*3a749623SJacob Keller case INIT_INCVAL: 121*3a749623SJacob Keller cmd_val |= GLTSYN_CMD_INIT_INCVAL; 122*3a749623SJacob Keller break; 123*3a749623SJacob Keller case ADJ_TIME: 124*3a749623SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_TIME; 125*3a749623SJacob Keller break; 126*3a749623SJacob Keller case ADJ_TIME_AT_TIME: 127*3a749623SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME; 128*3a749623SJacob Keller break; 129*3a749623SJacob Keller case READ_TIME: 130*3a749623SJacob Keller cmd_val |= GLTSYN_CMD_READ_TIME; 131*3a749623SJacob Keller break; 132*3a749623SJacob Keller } 133*3a749623SJacob Keller 134*3a749623SJacob Keller wr32(hw, GLTSYN_CMD, cmd_val); 135*3a749623SJacob Keller } 136*3a749623SJacob Keller 137*3a749623SJacob Keller /** 138*3a749623SJacob Keller * ice_ptp_exec_tmr_cmd - Execute all prepared timer commands 139*3a749623SJacob Keller * @hw: pointer to HW struct 140*3a749623SJacob Keller * 141*3a749623SJacob Keller * Write the SYNC_EXEC_CMD bit to the GLTSYN_CMD_SYNC register, and flush the 142*3a749623SJacob Keller * write immediately. This triggers the hardware to begin executing all of the 143*3a749623SJacob Keller * source and PHY timer commands synchronously. 144*3a749623SJacob Keller */ 145*3a749623SJacob Keller static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw) 146*3a749623SJacob Keller { 147*3a749623SJacob Keller wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD); 148*3a749623SJacob Keller ice_flush(hw); 149*3a749623SJacob Keller } 150*3a749623SJacob Keller 151*3a749623SJacob Keller /* E822 family functions 152*3a749623SJacob Keller * 153*3a749623SJacob Keller * The following functions operate on the E822 family of devices. 154*3a749623SJacob Keller */ 155*3a749623SJacob Keller 156*3a749623SJacob Keller /** 157*3a749623SJacob Keller * ice_fill_phy_msg_e822 - Fill message data for a PHY register access 158*3a749623SJacob Keller * @msg: the PHY message buffer to fill in 159*3a749623SJacob Keller * @port: the port to access 160*3a749623SJacob Keller * @offset: the register offset 161*3a749623SJacob Keller */ 162*3a749623SJacob Keller static void 163*3a749623SJacob Keller ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset) 164*3a749623SJacob Keller { 165*3a749623SJacob Keller int phy_port, phy, quadtype; 166*3a749623SJacob Keller 167*3a749623SJacob Keller phy_port = port % ICE_PORTS_PER_PHY; 168*3a749623SJacob Keller phy = port / ICE_PORTS_PER_PHY; 169*3a749623SJacob Keller quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_NUM_QUAD_TYPE; 170*3a749623SJacob Keller 171*3a749623SJacob Keller if (quadtype == 0) { 172*3a749623SJacob Keller msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port); 173*3a749623SJacob Keller msg->msg_addr_high = P_Q0_H(P_0_BASE + offset, phy_port); 174*3a749623SJacob Keller } else { 175*3a749623SJacob Keller msg->msg_addr_low = P_Q1_L(P_4_BASE + offset, phy_port); 176*3a749623SJacob Keller msg->msg_addr_high = P_Q1_H(P_4_BASE + offset, phy_port); 177*3a749623SJacob Keller } 178*3a749623SJacob Keller 179*3a749623SJacob Keller if (phy == 0) 180*3a749623SJacob Keller msg->dest_dev = rmn_0; 181*3a749623SJacob Keller else if (phy == 1) 182*3a749623SJacob Keller msg->dest_dev = rmn_1; 183*3a749623SJacob Keller else 184*3a749623SJacob Keller msg->dest_dev = rmn_2; 185*3a749623SJacob Keller } 186*3a749623SJacob Keller 187*3a749623SJacob Keller /** 188*3a749623SJacob Keller * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register 189*3a749623SJacob Keller * @low_addr: the low address to check 190*3a749623SJacob Keller * @high_addr: on return, contains the high address of the 64bit register 191*3a749623SJacob Keller * 192*3a749623SJacob Keller * Checks if the provided low address is one of the known 64bit PHY values 193*3a749623SJacob Keller * represented as two 32bit registers. If it is, return the appropriate high 194*3a749623SJacob Keller * register offset to use. 195*3a749623SJacob Keller */ 196*3a749623SJacob Keller static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr) 197*3a749623SJacob Keller { 198*3a749623SJacob Keller switch (low_addr) { 199*3a749623SJacob Keller case P_REG_PAR_PCS_TX_OFFSET_L: 200*3a749623SJacob Keller *high_addr = P_REG_PAR_PCS_TX_OFFSET_U; 201*3a749623SJacob Keller return true; 202*3a749623SJacob Keller case P_REG_PAR_PCS_RX_OFFSET_L: 203*3a749623SJacob Keller *high_addr = P_REG_PAR_PCS_RX_OFFSET_U; 204*3a749623SJacob Keller return true; 205*3a749623SJacob Keller case P_REG_PAR_TX_TIME_L: 206*3a749623SJacob Keller *high_addr = P_REG_PAR_TX_TIME_U; 207*3a749623SJacob Keller return true; 208*3a749623SJacob Keller case P_REG_PAR_RX_TIME_L: 209*3a749623SJacob Keller *high_addr = P_REG_PAR_RX_TIME_U; 210*3a749623SJacob Keller return true; 211*3a749623SJacob Keller case P_REG_TOTAL_TX_OFFSET_L: 212*3a749623SJacob Keller *high_addr = P_REG_TOTAL_TX_OFFSET_U; 213*3a749623SJacob Keller return true; 214*3a749623SJacob Keller case P_REG_TOTAL_RX_OFFSET_L: 215*3a749623SJacob Keller *high_addr = P_REG_TOTAL_RX_OFFSET_U; 216*3a749623SJacob Keller return true; 217*3a749623SJacob Keller case P_REG_UIX66_10G_40G_L: 218*3a749623SJacob Keller *high_addr = P_REG_UIX66_10G_40G_U; 219*3a749623SJacob Keller return true; 220*3a749623SJacob Keller case P_REG_UIX66_25G_100G_L: 221*3a749623SJacob Keller *high_addr = P_REG_UIX66_25G_100G_U; 222*3a749623SJacob Keller return true; 223*3a749623SJacob Keller case P_REG_TX_CAPTURE_L: 224*3a749623SJacob Keller *high_addr = P_REG_TX_CAPTURE_U; 225*3a749623SJacob Keller return true; 226*3a749623SJacob Keller case P_REG_RX_CAPTURE_L: 227*3a749623SJacob Keller *high_addr = P_REG_RX_CAPTURE_U; 228*3a749623SJacob Keller return true; 229*3a749623SJacob Keller case P_REG_TX_TIMER_INC_PRE_L: 230*3a749623SJacob Keller *high_addr = P_REG_TX_TIMER_INC_PRE_U; 231*3a749623SJacob Keller return true; 232*3a749623SJacob Keller case P_REG_RX_TIMER_INC_PRE_L: 233*3a749623SJacob Keller *high_addr = P_REG_RX_TIMER_INC_PRE_U; 234*3a749623SJacob Keller return true; 235*3a749623SJacob Keller default: 236*3a749623SJacob Keller return false; 237*3a749623SJacob Keller } 238*3a749623SJacob Keller } 239*3a749623SJacob Keller 240*3a749623SJacob Keller /** 241*3a749623SJacob Keller * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register 242*3a749623SJacob Keller * @low_addr: the low address to check 243*3a749623SJacob Keller * @high_addr: on return, contains the high address of the 40bit value 244*3a749623SJacob Keller * 245*3a749623SJacob Keller * Checks if the provided low address is one of the known 40bit PHY values 246*3a749623SJacob Keller * split into two registers with the lower 8 bits in the low register and the 247*3a749623SJacob Keller * upper 32 bits in the high register. If it is, return the appropriate high 248*3a749623SJacob Keller * register offset to use. 249*3a749623SJacob Keller */ 250*3a749623SJacob Keller static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr) 251*3a749623SJacob Keller { 252*3a749623SJacob Keller switch (low_addr) { 253*3a749623SJacob Keller case P_REG_TIMETUS_L: 254*3a749623SJacob Keller *high_addr = P_REG_TIMETUS_U; 255*3a749623SJacob Keller return true; 256*3a749623SJacob Keller case P_REG_PAR_RX_TUS_L: 257*3a749623SJacob Keller *high_addr = P_REG_PAR_RX_TUS_U; 258*3a749623SJacob Keller return true; 259*3a749623SJacob Keller case P_REG_PAR_TX_TUS_L: 260*3a749623SJacob Keller *high_addr = P_REG_PAR_TX_TUS_U; 261*3a749623SJacob Keller return true; 262*3a749623SJacob Keller case P_REG_PCS_RX_TUS_L: 263*3a749623SJacob Keller *high_addr = P_REG_PCS_RX_TUS_U; 264*3a749623SJacob Keller return true; 265*3a749623SJacob Keller case P_REG_PCS_TX_TUS_L: 266*3a749623SJacob Keller *high_addr = P_REG_PCS_TX_TUS_U; 267*3a749623SJacob Keller return true; 268*3a749623SJacob Keller case P_REG_DESK_PAR_RX_TUS_L: 269*3a749623SJacob Keller *high_addr = P_REG_DESK_PAR_RX_TUS_U; 270*3a749623SJacob Keller return true; 271*3a749623SJacob Keller case P_REG_DESK_PAR_TX_TUS_L: 272*3a749623SJacob Keller *high_addr = P_REG_DESK_PAR_TX_TUS_U; 273*3a749623SJacob Keller return true; 274*3a749623SJacob Keller case P_REG_DESK_PCS_RX_TUS_L: 275*3a749623SJacob Keller *high_addr = P_REG_DESK_PCS_RX_TUS_U; 276*3a749623SJacob Keller return true; 277*3a749623SJacob Keller case P_REG_DESK_PCS_TX_TUS_L: 278*3a749623SJacob Keller *high_addr = P_REG_DESK_PCS_TX_TUS_U; 279*3a749623SJacob Keller return true; 280*3a749623SJacob Keller default: 281*3a749623SJacob Keller return false; 282*3a749623SJacob Keller } 283*3a749623SJacob Keller } 284*3a749623SJacob Keller 285*3a749623SJacob Keller /** 286*3a749623SJacob Keller * ice_read_phy_reg_e822 - Read a PHY register 287*3a749623SJacob Keller * @hw: pointer to the HW struct 288*3a749623SJacob Keller * @port: PHY port to read from 289*3a749623SJacob Keller * @offset: PHY register offset to read 290*3a749623SJacob Keller * @val: on return, the contents read from the PHY 291*3a749623SJacob Keller * 292*3a749623SJacob Keller * Read a PHY register for the given port over the device sideband queue. 293*3a749623SJacob Keller */ 294*3a749623SJacob Keller int 295*3a749623SJacob Keller ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val) 296*3a749623SJacob Keller { 297*3a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 298*3a749623SJacob Keller int err; 299*3a749623SJacob Keller 300*3a749623SJacob Keller ice_fill_phy_msg_e822(&msg, port, offset); 301*3a749623SJacob Keller msg.opcode = ice_sbq_msg_rd; 302*3a749623SJacob Keller 303*3a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 304*3a749623SJacob Keller if (err) { 305*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 306*3a749623SJacob Keller err); 307*3a749623SJacob Keller return err; 308*3a749623SJacob Keller } 309*3a749623SJacob Keller 310*3a749623SJacob Keller *val = msg.data; 311*3a749623SJacob Keller 312*3a749623SJacob Keller return 0; 313*3a749623SJacob Keller } 314*3a749623SJacob Keller 315*3a749623SJacob Keller /** 316*3a749623SJacob Keller * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers 317*3a749623SJacob Keller * @hw: pointer to the HW struct 318*3a749623SJacob Keller * @port: PHY port to read from 319*3a749623SJacob Keller * @low_addr: offset of the lower register to read from 320*3a749623SJacob Keller * @val: on return, the contents of the 64bit value from the PHY registers 321*3a749623SJacob Keller * 322*3a749623SJacob Keller * Reads the two registers associated with a 64bit value and returns it in the 323*3a749623SJacob Keller * val pointer. The offset always specifies the lower register offset to use. 324*3a749623SJacob Keller * The high offset is looked up. This function only operates on registers 325*3a749623SJacob Keller * known to be two parts of a 64bit value. 326*3a749623SJacob Keller */ 327*3a749623SJacob Keller static int 328*3a749623SJacob Keller ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val) 329*3a749623SJacob Keller { 330*3a749623SJacob Keller u32 low, high; 331*3a749623SJacob Keller u16 high_addr; 332*3a749623SJacob Keller int err; 333*3a749623SJacob Keller 334*3a749623SJacob Keller /* Only operate on registers known to be split into two 32bit 335*3a749623SJacob Keller * registers. 336*3a749623SJacob Keller */ 337*3a749623SJacob Keller if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { 338*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", 339*3a749623SJacob Keller low_addr); 340*3a749623SJacob Keller return -EINVAL; 341*3a749623SJacob Keller } 342*3a749623SJacob Keller 343*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, low_addr, &low); 344*3a749623SJacob Keller if (err) { 345*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d", 346*3a749623SJacob Keller low_addr, err); 347*3a749623SJacob Keller return err; 348*3a749623SJacob Keller } 349*3a749623SJacob Keller 350*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, high_addr, &high); 351*3a749623SJacob Keller if (err) { 352*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d", 353*3a749623SJacob Keller high_addr, err); 354*3a749623SJacob Keller return err; 355*3a749623SJacob Keller } 356*3a749623SJacob Keller 357*3a749623SJacob Keller *val = (u64)high << 32 | low; 358*3a749623SJacob Keller 359*3a749623SJacob Keller return 0; 360*3a749623SJacob Keller } 361*3a749623SJacob Keller 362*3a749623SJacob Keller /** 363*3a749623SJacob Keller * ice_write_phy_reg_e822 - Write a PHY register 364*3a749623SJacob Keller * @hw: pointer to the HW struct 365*3a749623SJacob Keller * @port: PHY port to write to 366*3a749623SJacob Keller * @offset: PHY register offset to write 367*3a749623SJacob Keller * @val: The value to write to the register 368*3a749623SJacob Keller * 369*3a749623SJacob Keller * Write a PHY register for the given port over the device sideband queue. 370*3a749623SJacob Keller */ 371*3a749623SJacob Keller int 372*3a749623SJacob Keller ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val) 373*3a749623SJacob Keller { 374*3a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 375*3a749623SJacob Keller int err; 376*3a749623SJacob Keller 377*3a749623SJacob Keller ice_fill_phy_msg_e822(&msg, port, offset); 378*3a749623SJacob Keller msg.opcode = ice_sbq_msg_wr; 379*3a749623SJacob Keller msg.data = val; 380*3a749623SJacob Keller 381*3a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 382*3a749623SJacob Keller if (err) { 383*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 384*3a749623SJacob Keller err); 385*3a749623SJacob Keller return err; 386*3a749623SJacob Keller } 387*3a749623SJacob Keller 388*3a749623SJacob Keller return 0; 389*3a749623SJacob Keller } 390*3a749623SJacob Keller 391*3a749623SJacob Keller /** 392*3a749623SJacob Keller * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY 393*3a749623SJacob Keller * @hw: pointer to the HW struct 394*3a749623SJacob Keller * @port: port to write to 395*3a749623SJacob Keller * @low_addr: offset of the low register 396*3a749623SJacob Keller * @val: 40b value to write 397*3a749623SJacob Keller * 398*3a749623SJacob Keller * Write the provided 40b value to the two associated registers by splitting 399*3a749623SJacob Keller * it up into two chunks, the lower 8 bits and the upper 32 bits. 400*3a749623SJacob Keller */ 401*3a749623SJacob Keller static int 402*3a749623SJacob Keller ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) 403*3a749623SJacob Keller { 404*3a749623SJacob Keller u32 low, high; 405*3a749623SJacob Keller u16 high_addr; 406*3a749623SJacob Keller int err; 407*3a749623SJacob Keller 408*3a749623SJacob Keller /* Only operate on registers known to be split into a lower 8 bit 409*3a749623SJacob Keller * register and an upper 32 bit register. 410*3a749623SJacob Keller */ 411*3a749623SJacob Keller if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) { 412*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n", 413*3a749623SJacob Keller low_addr); 414*3a749623SJacob Keller return -EINVAL; 415*3a749623SJacob Keller } 416*3a749623SJacob Keller 417*3a749623SJacob Keller low = (u32)(val & P_REG_40B_LOW_M); 418*3a749623SJacob Keller high = (u32)(val >> P_REG_40B_HIGH_S); 419*3a749623SJacob Keller 420*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, low_addr, low); 421*3a749623SJacob Keller if (err) { 422*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", 423*3a749623SJacob Keller low_addr, err); 424*3a749623SJacob Keller return err; 425*3a749623SJacob Keller } 426*3a749623SJacob Keller 427*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, high_addr, high); 428*3a749623SJacob Keller if (err) { 429*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", 430*3a749623SJacob Keller high_addr, err); 431*3a749623SJacob Keller return err; 432*3a749623SJacob Keller } 433*3a749623SJacob Keller 434*3a749623SJacob Keller return 0; 435*3a749623SJacob Keller } 436*3a749623SJacob Keller 437*3a749623SJacob Keller /** 438*3a749623SJacob Keller * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers 439*3a749623SJacob Keller * @hw: pointer to the HW struct 440*3a749623SJacob Keller * @port: PHY port to read from 441*3a749623SJacob Keller * @low_addr: offset of the lower register to read from 442*3a749623SJacob Keller * @val: the contents of the 64bit value to write to PHY 443*3a749623SJacob Keller * 444*3a749623SJacob Keller * Write the 64bit value to the two associated 32bit PHY registers. The offset 445*3a749623SJacob Keller * is always specified as the lower register, and the high address is looked 446*3a749623SJacob Keller * up. This function only operates on registers known to be two parts of 447*3a749623SJacob Keller * a 64bit value. 448*3a749623SJacob Keller */ 449*3a749623SJacob Keller static int 450*3a749623SJacob Keller ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val) 451*3a749623SJacob Keller { 452*3a749623SJacob Keller u32 low, high; 453*3a749623SJacob Keller u16 high_addr; 454*3a749623SJacob Keller int err; 455*3a749623SJacob Keller 456*3a749623SJacob Keller /* Only operate on registers known to be split into two 32bit 457*3a749623SJacob Keller * registers. 458*3a749623SJacob Keller */ 459*3a749623SJacob Keller if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) { 460*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n", 461*3a749623SJacob Keller low_addr); 462*3a749623SJacob Keller return -EINVAL; 463*3a749623SJacob Keller } 464*3a749623SJacob Keller 465*3a749623SJacob Keller low = lower_32_bits(val); 466*3a749623SJacob Keller high = upper_32_bits(val); 467*3a749623SJacob Keller 468*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, low_addr, low); 469*3a749623SJacob Keller if (err) { 470*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d", 471*3a749623SJacob Keller low_addr, err); 472*3a749623SJacob Keller return err; 473*3a749623SJacob Keller } 474*3a749623SJacob Keller 475*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, high_addr, high); 476*3a749623SJacob Keller if (err) { 477*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d", 478*3a749623SJacob Keller high_addr, err); 479*3a749623SJacob Keller return err; 480*3a749623SJacob Keller } 481*3a749623SJacob Keller 482*3a749623SJacob Keller return 0; 483*3a749623SJacob Keller } 484*3a749623SJacob Keller 485*3a749623SJacob Keller /** 486*3a749623SJacob Keller * ice_fill_quad_msg_e822 - Fill message data for quad register access 487*3a749623SJacob Keller * @msg: the PHY message buffer to fill in 488*3a749623SJacob Keller * @quad: the quad to access 489*3a749623SJacob Keller * @offset: the register offset 490*3a749623SJacob Keller * 491*3a749623SJacob Keller * Fill a message buffer for accessing a register in a quad shared between 492*3a749623SJacob Keller * multiple PHYs. 493*3a749623SJacob Keller */ 494*3a749623SJacob Keller static void 495*3a749623SJacob Keller ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset) 496*3a749623SJacob Keller { 497*3a749623SJacob Keller u32 addr; 498*3a749623SJacob Keller 499*3a749623SJacob Keller msg->dest_dev = rmn_0; 500*3a749623SJacob Keller 501*3a749623SJacob Keller if ((quad % ICE_NUM_QUAD_TYPE) == 0) 502*3a749623SJacob Keller addr = Q_0_BASE + offset; 503*3a749623SJacob Keller else 504*3a749623SJacob Keller addr = Q_1_BASE + offset; 505*3a749623SJacob Keller 506*3a749623SJacob Keller msg->msg_addr_low = lower_16_bits(addr); 507*3a749623SJacob Keller msg->msg_addr_high = upper_16_bits(addr); 508*3a749623SJacob Keller } 509*3a749623SJacob Keller 510*3a749623SJacob Keller /** 511*3a749623SJacob Keller * ice_read_quad_reg_e822 - Read a PHY quad register 512*3a749623SJacob Keller * @hw: pointer to the HW struct 513*3a749623SJacob Keller * @quad: quad to read from 514*3a749623SJacob Keller * @offset: quad register offset to read 515*3a749623SJacob Keller * @val: on return, the contents read from the quad 516*3a749623SJacob Keller * 517*3a749623SJacob Keller * Read a quad register over the device sideband queue. Quad registers are 518*3a749623SJacob Keller * shared between multiple PHYs. 519*3a749623SJacob Keller */ 520*3a749623SJacob Keller int 521*3a749623SJacob Keller ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val) 522*3a749623SJacob Keller { 523*3a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 524*3a749623SJacob Keller int err; 525*3a749623SJacob Keller 526*3a749623SJacob Keller if (quad >= ICE_MAX_QUAD) 527*3a749623SJacob Keller return -EINVAL; 528*3a749623SJacob Keller 529*3a749623SJacob Keller ice_fill_quad_msg_e822(&msg, quad, offset); 530*3a749623SJacob Keller msg.opcode = ice_sbq_msg_rd; 531*3a749623SJacob Keller 532*3a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 533*3a749623SJacob Keller if (err) { 534*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 535*3a749623SJacob Keller err); 536*3a749623SJacob Keller return err; 537*3a749623SJacob Keller } 538*3a749623SJacob Keller 539*3a749623SJacob Keller *val = msg.data; 540*3a749623SJacob Keller 541*3a749623SJacob Keller return 0; 542*3a749623SJacob Keller } 543*3a749623SJacob Keller 544*3a749623SJacob Keller /** 545*3a749623SJacob Keller * ice_write_quad_reg_e822 - Write a PHY quad register 546*3a749623SJacob Keller * @hw: pointer to the HW struct 547*3a749623SJacob Keller * @quad: quad to write to 548*3a749623SJacob Keller * @offset: quad register offset to write 549*3a749623SJacob Keller * @val: The value to write to the register 550*3a749623SJacob Keller * 551*3a749623SJacob Keller * Write a quad register over the device sideband queue. Quad registers are 552*3a749623SJacob Keller * shared between multiple PHYs. 553*3a749623SJacob Keller */ 554*3a749623SJacob Keller int 555*3a749623SJacob Keller ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val) 556*3a749623SJacob Keller { 557*3a749623SJacob Keller struct ice_sbq_msg_input msg = {0}; 558*3a749623SJacob Keller int err; 559*3a749623SJacob Keller 560*3a749623SJacob Keller if (quad >= ICE_MAX_QUAD) 561*3a749623SJacob Keller return -EINVAL; 562*3a749623SJacob Keller 563*3a749623SJacob Keller ice_fill_quad_msg_e822(&msg, quad, offset); 564*3a749623SJacob Keller msg.opcode = ice_sbq_msg_wr; 565*3a749623SJacob Keller msg.data = val; 566*3a749623SJacob Keller 567*3a749623SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 568*3a749623SJacob Keller if (err) { 569*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 570*3a749623SJacob Keller err); 571*3a749623SJacob Keller return err; 572*3a749623SJacob Keller } 573*3a749623SJacob Keller 574*3a749623SJacob Keller return 0; 575*3a749623SJacob Keller } 576*3a749623SJacob Keller 577*3a749623SJacob Keller /** 578*3a749623SJacob Keller * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block 579*3a749623SJacob Keller * @hw: pointer to the HW struct 580*3a749623SJacob Keller * @quad: the quad to read from 581*3a749623SJacob Keller * @idx: the timestamp index to read 582*3a749623SJacob Keller * @tstamp: on return, the 40bit timestamp value 583*3a749623SJacob Keller * 584*3a749623SJacob Keller * Read a 40bit timestamp value out of the two associated registers in the 585*3a749623SJacob Keller * quad memory block that is shared between the internal PHYs of the E822 586*3a749623SJacob Keller * family of devices. 587*3a749623SJacob Keller */ 588*3a749623SJacob Keller static int 589*3a749623SJacob Keller ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp) 590*3a749623SJacob Keller { 591*3a749623SJacob Keller u16 lo_addr, hi_addr; 592*3a749623SJacob Keller u32 lo, hi; 593*3a749623SJacob Keller int err; 594*3a749623SJacob Keller 595*3a749623SJacob Keller lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); 596*3a749623SJacob Keller hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); 597*3a749623SJacob Keller 598*3a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo); 599*3a749623SJacob Keller if (err) { 600*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 601*3a749623SJacob Keller err); 602*3a749623SJacob Keller return err; 603*3a749623SJacob Keller } 604*3a749623SJacob Keller 605*3a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi); 606*3a749623SJacob Keller if (err) { 607*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 608*3a749623SJacob Keller err); 609*3a749623SJacob Keller return err; 610*3a749623SJacob Keller } 611*3a749623SJacob Keller 612*3a749623SJacob Keller /* For E822 based internal PHYs, the timestamp is reported with the 613*3a749623SJacob Keller * lower 8 bits in the low register, and the upper 32 bits in the high 614*3a749623SJacob Keller * register. 615*3a749623SJacob Keller */ 616*3a749623SJacob Keller *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M); 617*3a749623SJacob Keller 618*3a749623SJacob Keller return 0; 619*3a749623SJacob Keller } 620*3a749623SJacob Keller 621*3a749623SJacob Keller /** 622*3a749623SJacob Keller * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block 623*3a749623SJacob Keller * @hw: pointer to the HW struct 624*3a749623SJacob Keller * @quad: the quad to read from 625*3a749623SJacob Keller * @idx: the timestamp index to reset 626*3a749623SJacob Keller * 627*3a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the PHY quad block that is 628*3a749623SJacob Keller * shared between the internal PHYs on the E822 devices. 629*3a749623SJacob Keller */ 630*3a749623SJacob Keller static int 631*3a749623SJacob Keller ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx) 632*3a749623SJacob Keller { 633*3a749623SJacob Keller u16 lo_addr, hi_addr; 634*3a749623SJacob Keller int err; 635*3a749623SJacob Keller 636*3a749623SJacob Keller lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx); 637*3a749623SJacob Keller hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx); 638*3a749623SJacob Keller 639*3a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, lo_addr, 0); 640*3a749623SJacob Keller if (err) { 641*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 642*3a749623SJacob Keller err); 643*3a749623SJacob Keller return err; 644*3a749623SJacob Keller } 645*3a749623SJacob Keller 646*3a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, hi_addr, 0); 647*3a749623SJacob Keller if (err) { 648*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 649*3a749623SJacob Keller err); 650*3a749623SJacob Keller return err; 651*3a749623SJacob Keller } 652*3a749623SJacob Keller 653*3a749623SJacob Keller return 0; 654*3a749623SJacob Keller } 655*3a749623SJacob Keller 656*3a749623SJacob Keller /** 657*3a749623SJacob Keller * ice_ptp_set_vernier_wl - Set the window length for vernier calibration 658*3a749623SJacob Keller * @hw: pointer to the HW struct 659*3a749623SJacob Keller * 660*3a749623SJacob Keller * Set the window length used for the vernier port calibration process. 661*3a749623SJacob Keller */ 662*3a749623SJacob Keller static int ice_ptp_set_vernier_wl(struct ice_hw *hw) 663*3a749623SJacob Keller { 664*3a749623SJacob Keller u8 port; 665*3a749623SJacob Keller 666*3a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 667*3a749623SJacob Keller int err; 668*3a749623SJacob Keller 669*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_WL, 670*3a749623SJacob Keller PTP_VERNIER_WL); 671*3a749623SJacob Keller if (err) { 672*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n", 673*3a749623SJacob Keller port, err); 674*3a749623SJacob Keller return err; 675*3a749623SJacob Keller } 676*3a749623SJacob Keller } 677*3a749623SJacob Keller 678*3a749623SJacob Keller return 0; 679*3a749623SJacob Keller } 680*3a749623SJacob Keller 681*3a749623SJacob Keller /** 682*3a749623SJacob Keller * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization 683*3a749623SJacob Keller * @hw: pointer to HW struct 684*3a749623SJacob Keller * 685*3a749623SJacob Keller * Perform PHC initialization steps specific to E822 devices. 686*3a749623SJacob Keller */ 687*3a749623SJacob Keller static int ice_ptp_init_phc_e822(struct ice_hw *hw) 688*3a749623SJacob Keller { 689*3a749623SJacob Keller u32 regval; 690*3a749623SJacob Keller 691*3a749623SJacob Keller /* Enable reading switch and PHY registers over the sideband queue */ 692*3a749623SJacob Keller #define PF_SB_REM_DEV_CTL_SWITCH_READ BIT(1) 693*3a749623SJacob Keller #define PF_SB_REM_DEV_CTL_PHY0 BIT(2) 694*3a749623SJacob Keller regval = rd32(hw, PF_SB_REM_DEV_CTL); 695*3a749623SJacob Keller regval |= (PF_SB_REM_DEV_CTL_SWITCH_READ | 696*3a749623SJacob Keller PF_SB_REM_DEV_CTL_PHY0); 697*3a749623SJacob Keller wr32(hw, PF_SB_REM_DEV_CTL, regval); 698*3a749623SJacob Keller 699*3a749623SJacob Keller /* Set window length for all the ports */ 700*3a749623SJacob Keller return ice_ptp_set_vernier_wl(hw); 701*3a749623SJacob Keller } 702*3a749623SJacob Keller 703*3a749623SJacob Keller /** 704*3a749623SJacob Keller * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time 705*3a749623SJacob Keller * @hw: pointer to the HW struct 706*3a749623SJacob Keller * @time: Time to initialize the PHY port clocks to 707*3a749623SJacob Keller * 708*3a749623SJacob Keller * Program the PHY port registers with a new initial time value. The port 709*3a749623SJacob Keller * clock will be initialized once the driver issues an INIT_TIME sync 710*3a749623SJacob Keller * command. The time value is the upper 32 bits of the PHY timer, usually in 711*3a749623SJacob Keller * units of nominal nanoseconds. 712*3a749623SJacob Keller */ 713*3a749623SJacob Keller static int 714*3a749623SJacob Keller ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time) 715*3a749623SJacob Keller { 716*3a749623SJacob Keller u64 phy_time; 717*3a749623SJacob Keller u8 port; 718*3a749623SJacob Keller int err; 719*3a749623SJacob Keller 720*3a749623SJacob Keller /* The time represents the upper 32 bits of the PHY timer, so we need 721*3a749623SJacob Keller * to shift to account for this when programming. 722*3a749623SJacob Keller */ 723*3a749623SJacob Keller phy_time = (u64)time << 32; 724*3a749623SJacob Keller 725*3a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 726*3a749623SJacob Keller /* Tx case */ 727*3a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 728*3a749623SJacob Keller P_REG_TX_TIMER_INC_PRE_L, 729*3a749623SJacob Keller phy_time); 730*3a749623SJacob Keller if (err) 731*3a749623SJacob Keller goto exit_err; 732*3a749623SJacob Keller 733*3a749623SJacob Keller /* Rx case */ 734*3a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, 735*3a749623SJacob Keller P_REG_RX_TIMER_INC_PRE_L, 736*3a749623SJacob Keller phy_time); 737*3a749623SJacob Keller if (err) 738*3a749623SJacob Keller goto exit_err; 739*3a749623SJacob Keller } 740*3a749623SJacob Keller 741*3a749623SJacob Keller return 0; 742*3a749623SJacob Keller 743*3a749623SJacob Keller exit_err: 744*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write init time for port %u, err %d\n", 745*3a749623SJacob Keller port, err); 746*3a749623SJacob Keller 747*3a749623SJacob Keller return err; 748*3a749623SJacob Keller } 749*3a749623SJacob Keller 750*3a749623SJacob Keller /** 751*3a749623SJacob Keller * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust 752*3a749623SJacob Keller * @hw: pointer to HW struct 753*3a749623SJacob Keller * @port: Port number to be programmed 754*3a749623SJacob Keller * @time: time in cycles to adjust the port Tx and Rx clocks 755*3a749623SJacob Keller * 756*3a749623SJacob Keller * Program the port for an atomic adjustment by writing the Tx and Rx timer 757*3a749623SJacob Keller * registers. The atomic adjustment won't be completed until the driver issues 758*3a749623SJacob Keller * an ADJ_TIME command. 759*3a749623SJacob Keller * 760*3a749623SJacob Keller * Note that time is not in units of nanoseconds. It is in clock time 761*3a749623SJacob Keller * including the lower sub-nanosecond portion of the port timer. 762*3a749623SJacob Keller * 763*3a749623SJacob Keller * Negative adjustments are supported using 2s complement arithmetic. 764*3a749623SJacob Keller */ 765*3a749623SJacob Keller int 766*3a749623SJacob Keller ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time) 767*3a749623SJacob Keller { 768*3a749623SJacob Keller u32 l_time, u_time; 769*3a749623SJacob Keller int err; 770*3a749623SJacob Keller 771*3a749623SJacob Keller l_time = lower_32_bits(time); 772*3a749623SJacob Keller u_time = upper_32_bits(time); 773*3a749623SJacob Keller 774*3a749623SJacob Keller /* Tx case */ 775*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L, 776*3a749623SJacob Keller l_time); 777*3a749623SJacob Keller if (err) 778*3a749623SJacob Keller goto exit_err; 779*3a749623SJacob Keller 780*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U, 781*3a749623SJacob Keller u_time); 782*3a749623SJacob Keller if (err) 783*3a749623SJacob Keller goto exit_err; 784*3a749623SJacob Keller 785*3a749623SJacob Keller /* Rx case */ 786*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L, 787*3a749623SJacob Keller l_time); 788*3a749623SJacob Keller if (err) 789*3a749623SJacob Keller goto exit_err; 790*3a749623SJacob Keller 791*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U, 792*3a749623SJacob Keller u_time); 793*3a749623SJacob Keller if (err) 794*3a749623SJacob Keller goto exit_err; 795*3a749623SJacob Keller 796*3a749623SJacob Keller return 0; 797*3a749623SJacob Keller 798*3a749623SJacob Keller exit_err: 799*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write time adjust for port %u, err %d\n", 800*3a749623SJacob Keller port, err); 801*3a749623SJacob Keller return err; 802*3a749623SJacob Keller } 803*3a749623SJacob Keller 804*3a749623SJacob Keller /** 805*3a749623SJacob Keller * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment 806*3a749623SJacob Keller * @hw: pointer to HW struct 807*3a749623SJacob Keller * @adj: adjustment in nanoseconds 808*3a749623SJacob Keller * 809*3a749623SJacob Keller * Prepare the PHY ports for an atomic time adjustment by programming the PHY 810*3a749623SJacob Keller * Tx and Rx port registers. The actual adjustment is completed by issuing an 811*3a749623SJacob Keller * ADJ_TIME or ADJ_TIME_AT_TIME sync command. 812*3a749623SJacob Keller */ 813*3a749623SJacob Keller static int 814*3a749623SJacob Keller ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj) 815*3a749623SJacob Keller { 816*3a749623SJacob Keller s64 cycles; 817*3a749623SJacob Keller u8 port; 818*3a749623SJacob Keller 819*3a749623SJacob Keller /* The port clock supports adjustment of the sub-nanosecond portion of 820*3a749623SJacob Keller * the clock. We shift the provided adjustment in nanoseconds to 821*3a749623SJacob Keller * calculate the appropriate adjustment to program into the PHY ports. 822*3a749623SJacob Keller */ 823*3a749623SJacob Keller if (adj > 0) 824*3a749623SJacob Keller cycles = (s64)adj << 32; 825*3a749623SJacob Keller else 826*3a749623SJacob Keller cycles = -(((s64)-adj) << 32); 827*3a749623SJacob Keller 828*3a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 829*3a749623SJacob Keller int err; 830*3a749623SJacob Keller 831*3a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, cycles); 832*3a749623SJacob Keller if (err) 833*3a749623SJacob Keller return err; 834*3a749623SJacob Keller } 835*3a749623SJacob Keller 836*3a749623SJacob Keller return 0; 837*3a749623SJacob Keller } 838*3a749623SJacob Keller 839*3a749623SJacob Keller /** 840*3a749623SJacob Keller * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment 841*3a749623SJacob Keller * @hw: pointer to HW struct 842*3a749623SJacob Keller * @incval: new increment value to prepare 843*3a749623SJacob Keller * 844*3a749623SJacob Keller * Prepare each of the PHY ports for a new increment value by programming the 845*3a749623SJacob Keller * port's TIMETUS registers. The new increment value will be updated after 846*3a749623SJacob Keller * issuing an INIT_INCVAL command. 847*3a749623SJacob Keller */ 848*3a749623SJacob Keller static int 849*3a749623SJacob Keller ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval) 850*3a749623SJacob Keller { 851*3a749623SJacob Keller int err; 852*3a749623SJacob Keller u8 port; 853*3a749623SJacob Keller 854*3a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 855*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, 856*3a749623SJacob Keller incval); 857*3a749623SJacob Keller if (err) 858*3a749623SJacob Keller goto exit_err; 859*3a749623SJacob Keller } 860*3a749623SJacob Keller 861*3a749623SJacob Keller return 0; 862*3a749623SJacob Keller 863*3a749623SJacob Keller exit_err: 864*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval for port %u, err %d\n", 865*3a749623SJacob Keller port, err); 866*3a749623SJacob Keller 867*3a749623SJacob Keller return err; 868*3a749623SJacob Keller } 869*3a749623SJacob Keller 870*3a749623SJacob Keller /** 871*3a749623SJacob Keller * ice_ptp_read_port_capture - Read a port's local time capture 872*3a749623SJacob Keller * @hw: pointer to HW struct 873*3a749623SJacob Keller * @port: Port number to read 874*3a749623SJacob Keller * @tx_ts: on return, the Tx port time capture 875*3a749623SJacob Keller * @rx_ts: on return, the Rx port time capture 876*3a749623SJacob Keller * 877*3a749623SJacob Keller * Read the port's Tx and Rx local time capture values. 878*3a749623SJacob Keller * 879*3a749623SJacob Keller * Note this has no equivalent for the E810 devices. 880*3a749623SJacob Keller */ 881*3a749623SJacob Keller static int 882*3a749623SJacob Keller ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts) 883*3a749623SJacob Keller { 884*3a749623SJacob Keller int err; 885*3a749623SJacob Keller 886*3a749623SJacob Keller /* Tx case */ 887*3a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts); 888*3a749623SJacob Keller if (err) { 889*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n", 890*3a749623SJacob Keller err); 891*3a749623SJacob Keller return err; 892*3a749623SJacob Keller } 893*3a749623SJacob Keller 894*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "tx_init = 0x%016llx\n", 895*3a749623SJacob Keller (unsigned long long)*tx_ts); 896*3a749623SJacob Keller 897*3a749623SJacob Keller /* Rx case */ 898*3a749623SJacob Keller err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts); 899*3a749623SJacob Keller if (err) { 900*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n", 901*3a749623SJacob Keller err); 902*3a749623SJacob Keller return err; 903*3a749623SJacob Keller } 904*3a749623SJacob Keller 905*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "rx_init = 0x%016llx\n", 906*3a749623SJacob Keller (unsigned long long)*rx_ts); 907*3a749623SJacob Keller 908*3a749623SJacob Keller return 0; 909*3a749623SJacob Keller } 910*3a749623SJacob Keller 911*3a749623SJacob Keller /** 912*3a749623SJacob Keller * ice_ptp_one_port_cmd - Prepare a single PHY port for a timer command 913*3a749623SJacob Keller * @hw: pointer to HW struct 914*3a749623SJacob Keller * @port: Port to which cmd has to be sent 915*3a749623SJacob Keller * @cmd: Command to be sent to the port 916*3a749623SJacob Keller * 917*3a749623SJacob Keller * Prepare the requested port for an upcoming timer sync command. 918*3a749623SJacob Keller * 919*3a749623SJacob Keller * Note there is no equivalent of this operation on E810, as that device 920*3a749623SJacob Keller * always handles all external PHYs internally. 921*3a749623SJacob Keller */ 922*3a749623SJacob Keller static int 923*3a749623SJacob Keller ice_ptp_one_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) 924*3a749623SJacob Keller { 925*3a749623SJacob Keller u32 cmd_val, val; 926*3a749623SJacob Keller u8 tmr_idx; 927*3a749623SJacob Keller int err; 928*3a749623SJacob Keller 929*3a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 930*3a749623SJacob Keller cmd_val = tmr_idx << SEL_PHY_SRC; 931*3a749623SJacob Keller switch (cmd) { 932*3a749623SJacob Keller case INIT_TIME: 933*3a749623SJacob Keller cmd_val |= PHY_CMD_INIT_TIME; 934*3a749623SJacob Keller break; 935*3a749623SJacob Keller case INIT_INCVAL: 936*3a749623SJacob Keller cmd_val |= PHY_CMD_INIT_INCVAL; 937*3a749623SJacob Keller break; 938*3a749623SJacob Keller case ADJ_TIME: 939*3a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME; 940*3a749623SJacob Keller break; 941*3a749623SJacob Keller case READ_TIME: 942*3a749623SJacob Keller cmd_val |= PHY_CMD_READ_TIME; 943*3a749623SJacob Keller break; 944*3a749623SJacob Keller case ADJ_TIME_AT_TIME: 945*3a749623SJacob Keller cmd_val |= PHY_CMD_ADJ_TIME_AT_TIME; 946*3a749623SJacob Keller break; 947*3a749623SJacob Keller } 948*3a749623SJacob Keller 949*3a749623SJacob Keller /* Tx case */ 950*3a749623SJacob Keller /* Read, modify, write */ 951*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val); 952*3a749623SJacob Keller if (err) { 953*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n", 954*3a749623SJacob Keller err); 955*3a749623SJacob Keller return err; 956*3a749623SJacob Keller } 957*3a749623SJacob Keller 958*3a749623SJacob Keller /* Modify necessary bits only and perform write */ 959*3a749623SJacob Keller val &= ~TS_CMD_MASK; 960*3a749623SJacob Keller val |= cmd_val; 961*3a749623SJacob Keller 962*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val); 963*3a749623SJacob Keller if (err) { 964*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n", 965*3a749623SJacob Keller err); 966*3a749623SJacob Keller return err; 967*3a749623SJacob Keller } 968*3a749623SJacob Keller 969*3a749623SJacob Keller /* Rx case */ 970*3a749623SJacob Keller /* Read, modify, write */ 971*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val); 972*3a749623SJacob Keller if (err) { 973*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n", 974*3a749623SJacob Keller err); 975*3a749623SJacob Keller return err; 976*3a749623SJacob Keller } 977*3a749623SJacob Keller 978*3a749623SJacob Keller /* Modify necessary bits only and perform write */ 979*3a749623SJacob Keller val &= ~TS_CMD_MASK; 980*3a749623SJacob Keller val |= cmd_val; 981*3a749623SJacob Keller 982*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val); 983*3a749623SJacob Keller if (err) { 984*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n", 985*3a749623SJacob Keller err); 986*3a749623SJacob Keller return err; 987*3a749623SJacob Keller } 988*3a749623SJacob Keller 989*3a749623SJacob Keller return 0; 990*3a749623SJacob Keller } 991*3a749623SJacob Keller 992*3a749623SJacob Keller /** 993*3a749623SJacob Keller * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command 994*3a749623SJacob Keller * @hw: pointer to the HW struct 995*3a749623SJacob Keller * @cmd: timer command to prepare 996*3a749623SJacob Keller * 997*3a749623SJacob Keller * Prepare all ports connected to this device for an upcoming timer sync 998*3a749623SJacob Keller * command. 999*3a749623SJacob Keller */ 1000*3a749623SJacob Keller static int 1001*3a749623SJacob Keller ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 1002*3a749623SJacob Keller { 1003*3a749623SJacob Keller u8 port; 1004*3a749623SJacob Keller 1005*3a749623SJacob Keller for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) { 1006*3a749623SJacob Keller int err; 1007*3a749623SJacob Keller 1008*3a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, cmd); 1009*3a749623SJacob Keller if (err) 1010*3a749623SJacob Keller return err; 1011*3a749623SJacob Keller } 1012*3a749623SJacob Keller 1013*3a749623SJacob Keller return 0; 1014*3a749623SJacob Keller } 1015*3a749623SJacob Keller 1016*3a749623SJacob Keller /* E822 Vernier calibration functions 1017*3a749623SJacob Keller * 1018*3a749623SJacob Keller * The following functions are used as part of the vernier calibration of 1019*3a749623SJacob Keller * a port. This calibration increases the precision of the timestamps on the 1020*3a749623SJacob Keller * port. 1021*3a749623SJacob Keller */ 1022*3a749623SJacob Keller 1023*3a749623SJacob Keller /** 1024*3a749623SJacob Keller * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode 1025*3a749623SJacob Keller * @hw: pointer to HW struct 1026*3a749623SJacob Keller * @port: the port to read from 1027*3a749623SJacob Keller * @link_out: if non-NULL, holds link speed on success 1028*3a749623SJacob Keller * @fec_out: if non-NULL, holds FEC algorithm on success 1029*3a749623SJacob Keller * 1030*3a749623SJacob Keller * Read the serdes data for the PHY port and extract the link speed and FEC 1031*3a749623SJacob Keller * algorithm. 1032*3a749623SJacob Keller */ 1033*3a749623SJacob Keller static int 1034*3a749623SJacob Keller ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port, 1035*3a749623SJacob Keller enum ice_ptp_link_spd *link_out, 1036*3a749623SJacob Keller enum ice_ptp_fec_mode *fec_out) 1037*3a749623SJacob Keller { 1038*3a749623SJacob Keller enum ice_ptp_link_spd link; 1039*3a749623SJacob Keller enum ice_ptp_fec_mode fec; 1040*3a749623SJacob Keller u32 serdes; 1041*3a749623SJacob Keller int err; 1042*3a749623SJacob Keller 1043*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes); 1044*3a749623SJacob Keller if (err) { 1045*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n"); 1046*3a749623SJacob Keller return err; 1047*3a749623SJacob Keller } 1048*3a749623SJacob Keller 1049*3a749623SJacob Keller /* Determine the FEC algorithm */ 1050*3a749623SJacob Keller fec = (enum ice_ptp_fec_mode)P_REG_LINK_SPEED_FEC_MODE(serdes); 1051*3a749623SJacob Keller 1052*3a749623SJacob Keller serdes &= P_REG_LINK_SPEED_SERDES_M; 1053*3a749623SJacob Keller 1054*3a749623SJacob Keller /* Determine the link speed */ 1055*3a749623SJacob Keller if (fec == ICE_PTP_FEC_MODE_RS_FEC) { 1056*3a749623SJacob Keller switch (serdes) { 1057*3a749623SJacob Keller case ICE_PTP_SERDES_25G: 1058*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G_RS; 1059*3a749623SJacob Keller break; 1060*3a749623SJacob Keller case ICE_PTP_SERDES_50G: 1061*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G_RS; 1062*3a749623SJacob Keller break; 1063*3a749623SJacob Keller case ICE_PTP_SERDES_100G: 1064*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_100G_RS; 1065*3a749623SJacob Keller break; 1066*3a749623SJacob Keller default: 1067*3a749623SJacob Keller return -EIO; 1068*3a749623SJacob Keller } 1069*3a749623SJacob Keller } else { 1070*3a749623SJacob Keller switch (serdes) { 1071*3a749623SJacob Keller case ICE_PTP_SERDES_1G: 1072*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_1G; 1073*3a749623SJacob Keller break; 1074*3a749623SJacob Keller case ICE_PTP_SERDES_10G: 1075*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_10G; 1076*3a749623SJacob Keller break; 1077*3a749623SJacob Keller case ICE_PTP_SERDES_25G: 1078*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_25G; 1079*3a749623SJacob Keller break; 1080*3a749623SJacob Keller case ICE_PTP_SERDES_40G: 1081*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_40G; 1082*3a749623SJacob Keller break; 1083*3a749623SJacob Keller case ICE_PTP_SERDES_50G: 1084*3a749623SJacob Keller link = ICE_PTP_LNK_SPD_50G; 1085*3a749623SJacob Keller break; 1086*3a749623SJacob Keller default: 1087*3a749623SJacob Keller return -EIO; 1088*3a749623SJacob Keller } 1089*3a749623SJacob Keller } 1090*3a749623SJacob Keller 1091*3a749623SJacob Keller if (link_out) 1092*3a749623SJacob Keller *link_out = link; 1093*3a749623SJacob Keller if (fec_out) 1094*3a749623SJacob Keller *fec_out = fec; 1095*3a749623SJacob Keller 1096*3a749623SJacob Keller return 0; 1097*3a749623SJacob Keller } 1098*3a749623SJacob Keller 1099*3a749623SJacob Keller /** 1100*3a749623SJacob Keller * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp 1101*3a749623SJacob Keller * @hw: pointer to HW struct 1102*3a749623SJacob Keller * @port: to configure the quad for 1103*3a749623SJacob Keller */ 1104*3a749623SJacob Keller static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port) 1105*3a749623SJacob Keller { 1106*3a749623SJacob Keller enum ice_ptp_link_spd link_spd; 1107*3a749623SJacob Keller int err; 1108*3a749623SJacob Keller u32 val; 1109*3a749623SJacob Keller u8 quad; 1110*3a749623SJacob Keller 1111*3a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL); 1112*3a749623SJacob Keller if (err) { 1113*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n", 1114*3a749623SJacob Keller err); 1115*3a749623SJacob Keller return; 1116*3a749623SJacob Keller } 1117*3a749623SJacob Keller 1118*3a749623SJacob Keller quad = port / ICE_PORTS_PER_QUAD; 1119*3a749623SJacob Keller 1120*3a749623SJacob Keller err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val); 1121*3a749623SJacob Keller if (err) { 1122*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n", 1123*3a749623SJacob Keller err); 1124*3a749623SJacob Keller return; 1125*3a749623SJacob Keller } 1126*3a749623SJacob Keller 1127*3a749623SJacob Keller if (link_spd >= ICE_PTP_LNK_SPD_40G) 1128*3a749623SJacob Keller val &= ~Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 1129*3a749623SJacob Keller else 1130*3a749623SJacob Keller val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M; 1131*3a749623SJacob Keller 1132*3a749623SJacob Keller err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val); 1133*3a749623SJacob Keller if (err) { 1134*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n", 1135*3a749623SJacob Keller err); 1136*3a749623SJacob Keller return; 1137*3a749623SJacob Keller } 1138*3a749623SJacob Keller } 1139*3a749623SJacob Keller 1140*3a749623SJacob Keller /** 1141*3a749623SJacob Keller * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822 1142*3a749623SJacob Keller * @hw: pointer to the HW structure 1143*3a749623SJacob Keller * @port: the port to configure 1144*3a749623SJacob Keller * 1145*3a749623SJacob Keller * Program the conversion ration of Serdes clock "unit intervals" (UIs) to PHC 1146*3a749623SJacob Keller * hardware clock time units (TUs). That is, determine the number of TUs per 1147*3a749623SJacob Keller * serdes unit interval, and program the UIX registers with this conversion. 1148*3a749623SJacob Keller * 1149*3a749623SJacob Keller * This conversion is used as part of the calibration process when determining 1150*3a749623SJacob Keller * the additional error of a timestamp vs the real time of transmission or 1151*3a749623SJacob Keller * receipt of the packet. 1152*3a749623SJacob Keller * 1153*3a749623SJacob Keller * Hardware uses the number of TUs per 66 UIs, written to the UIX registers 1154*3a749623SJacob Keller * for the two main serdes clock rates, 10G/40G and 25G/100G serdes clocks. 1155*3a749623SJacob Keller * 1156*3a749623SJacob Keller * To calculate the conversion ratio, we use the following facts: 1157*3a749623SJacob Keller * 1158*3a749623SJacob Keller * a) the clock frequency in Hz (cycles per second) 1159*3a749623SJacob Keller * b) the number of TUs per cycle (the increment value of the clock) 1160*3a749623SJacob Keller * c) 1 second per 1 billion nanoseconds 1161*3a749623SJacob Keller * d) the duration of 66 UIs in nanoseconds 1162*3a749623SJacob Keller * 1163*3a749623SJacob Keller * Given these facts, we can use the following table to work out what ratios 1164*3a749623SJacob Keller * to multiply in order to get the number of TUs per 66 UIs: 1165*3a749623SJacob Keller * 1166*3a749623SJacob Keller * cycles | 1 second | incval (TUs) | nanoseconds 1167*3a749623SJacob Keller * -------+--------------+--------------+------------- 1168*3a749623SJacob Keller * second | 1 billion ns | cycle | 66 UIs 1169*3a749623SJacob Keller * 1170*3a749623SJacob Keller * To perform the multiplication using integers without too much loss of 1171*3a749623SJacob Keller * precision, we can take use the following equation: 1172*3a749623SJacob Keller * 1173*3a749623SJacob Keller * (freq * incval * 6600 LINE_UI ) / ( 100 * 1 billion) 1174*3a749623SJacob Keller * 1175*3a749623SJacob Keller * We scale up to using 6600 UI instead of 66 in order to avoid fractional 1176*3a749623SJacob Keller * nanosecond UIs (66 UI at 10G/40G is 6.4 ns) 1177*3a749623SJacob Keller * 1178*3a749623SJacob Keller * The increment value has a maximum expected range of about 34 bits, while 1179*3a749623SJacob Keller * the frequency value is about 29 bits. Multiplying these values shouldn't 1180*3a749623SJacob Keller * overflow the 64 bits. However, we must then further multiply them again by 1181*3a749623SJacob Keller * the Serdes unit interval duration. To avoid overflow here, we split the 1182*3a749623SJacob Keller * overall divide by 1e11 into a divide by 256 (shift down by 8 bits) and 1183*3a749623SJacob Keller * a divide by 390,625,000. This does lose some precision, but avoids 1184*3a749623SJacob Keller * miscalculation due to arithmetic overflow. 1185*3a749623SJacob Keller */ 1186*3a749623SJacob Keller static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port) 1187*3a749623SJacob Keller { 1188*3a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, uix; 1189*3a749623SJacob Keller int err; 1190*3a749623SJacob Keller 1191*3a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1192*3a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1193*3a749623SJacob Keller 1194*3a749623SJacob Keller /* Calculate TUs per second divided by 256 */ 1195*3a749623SJacob Keller tu_per_sec = (cur_freq * clk_incval) >> 8; 1196*3a749623SJacob Keller 1197*3a749623SJacob Keller #define LINE_UI_10G_40G 640 /* 6600 UIs is 640 nanoseconds at 10Gb/40Gb */ 1198*3a749623SJacob Keller #define LINE_UI_25G_100G 256 /* 6600 UIs is 256 nanoseconds at 25Gb/100Gb */ 1199*3a749623SJacob Keller 1200*3a749623SJacob Keller /* Program the 10Gb/40Gb conversion ratio */ 1201*3a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000); 1202*3a749623SJacob Keller 1203*3a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L, 1204*3a749623SJacob Keller uix); 1205*3a749623SJacob Keller if (err) { 1206*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n", 1207*3a749623SJacob Keller err); 1208*3a749623SJacob Keller return err; 1209*3a749623SJacob Keller } 1210*3a749623SJacob Keller 1211*3a749623SJacob Keller /* Program the 25Gb/100Gb conversion ratio */ 1212*3a749623SJacob Keller uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000); 1213*3a749623SJacob Keller 1214*3a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L, 1215*3a749623SJacob Keller uix); 1216*3a749623SJacob Keller if (err) { 1217*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n", 1218*3a749623SJacob Keller err); 1219*3a749623SJacob Keller return err; 1220*3a749623SJacob Keller } 1221*3a749623SJacob Keller 1222*3a749623SJacob Keller return 0; 1223*3a749623SJacob Keller } 1224*3a749623SJacob Keller 1225*3a749623SJacob Keller /** 1226*3a749623SJacob Keller * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle 1227*3a749623SJacob Keller * @hw: pointer to the HW struct 1228*3a749623SJacob Keller * @port: port to configure 1229*3a749623SJacob Keller * 1230*3a749623SJacob Keller * Configure the number of TUs for the PAR and PCS clocks used as part of the 1231*3a749623SJacob Keller * timestamp calibration process. This depends on the link speed, as the PHY 1232*3a749623SJacob Keller * uses different markers depending on the speed. 1233*3a749623SJacob Keller * 1234*3a749623SJacob Keller * 1Gb/10Gb/25Gb: 1235*3a749623SJacob Keller * - Tx/Rx PAR/PCS markers 1236*3a749623SJacob Keller * 1237*3a749623SJacob Keller * 25Gb RS: 1238*3a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 1239*3a749623SJacob Keller * 1240*3a749623SJacob Keller * 40Gb/50Gb: 1241*3a749623SJacob Keller * - Tx/Rx PAR/PCS markers 1242*3a749623SJacob Keller * - Rx Deskew PAR/PCS markers 1243*3a749623SJacob Keller * 1244*3a749623SJacob Keller * 50G RS and 100GB RS: 1245*3a749623SJacob Keller * - Tx/Rx Reed Solomon gearbox PAR/PCS markers 1246*3a749623SJacob Keller * - Rx Deskew PAR/PCS markers 1247*3a749623SJacob Keller * - Tx PAR/PCS markers 1248*3a749623SJacob Keller * 1249*3a749623SJacob Keller * To calculate the conversion, we use the PHC clock frequency (cycles per 1250*3a749623SJacob Keller * second), the increment value (TUs per cycle), and the related PHY clock 1251*3a749623SJacob Keller * frequency to calculate the TUs per unit of the PHY link clock. The 1252*3a749623SJacob Keller * following table shows how the units convert: 1253*3a749623SJacob Keller * 1254*3a749623SJacob Keller * cycles | TUs | second 1255*3a749623SJacob Keller * -------+-------+-------- 1256*3a749623SJacob Keller * second | cycle | cycles 1257*3a749623SJacob Keller * 1258*3a749623SJacob Keller * For each conversion register, look up the appropriate frequency from the 1259*3a749623SJacob Keller * e822 PAR/PCS table and calculate the TUs per unit of that clock. Program 1260*3a749623SJacob Keller * this to the appropriate register, preparing hardware to perform timestamp 1261*3a749623SJacob Keller * calibration to calculate the total Tx or Rx offset to adjust the timestamp 1262*3a749623SJacob Keller * in order to calibrate for the internal PHY delays. 1263*3a749623SJacob Keller * 1264*3a749623SJacob Keller * Note that the increment value ranges up to ~34 bits, and the clock 1265*3a749623SJacob Keller * frequency is ~29 bits, so multiplying them together should fit within the 1266*3a749623SJacob Keller * 64 bit arithmetic. 1267*3a749623SJacob Keller */ 1268*3a749623SJacob Keller static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port) 1269*3a749623SJacob Keller { 1270*3a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, phy_tus; 1271*3a749623SJacob Keller enum ice_ptp_link_spd link_spd; 1272*3a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 1273*3a749623SJacob Keller int err; 1274*3a749623SJacob Keller 1275*3a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1276*3a749623SJacob Keller if (err) 1277*3a749623SJacob Keller return err; 1278*3a749623SJacob Keller 1279*3a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1280*3a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1281*3a749623SJacob Keller 1282*3a749623SJacob Keller /* Calculate TUs per cycle of the PHC clock */ 1283*3a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 1284*3a749623SJacob Keller 1285*3a749623SJacob Keller /* For each PHY conversion register, look up the appropriate link 1286*3a749623SJacob Keller * speed frequency and determine the TUs per that clock's cycle time. 1287*3a749623SJacob Keller * Split this into a high and low value and then program the 1288*3a749623SJacob Keller * appropriate register. If that link speed does not use the 1289*3a749623SJacob Keller * associated register, write zeros to clear it instead. 1290*3a749623SJacob Keller */ 1291*3a749623SJacob Keller 1292*3a749623SJacob Keller /* P_REG_PAR_TX_TUS */ 1293*3a749623SJacob Keller if (e822_vernier[link_spd].tx_par_clk) 1294*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1295*3a749623SJacob Keller e822_vernier[link_spd].tx_par_clk); 1296*3a749623SJacob Keller else 1297*3a749623SJacob Keller phy_tus = 0; 1298*3a749623SJacob Keller 1299*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L, 1300*3a749623SJacob Keller phy_tus); 1301*3a749623SJacob Keller if (err) 1302*3a749623SJacob Keller return err; 1303*3a749623SJacob Keller 1304*3a749623SJacob Keller /* P_REG_PAR_RX_TUS */ 1305*3a749623SJacob Keller if (e822_vernier[link_spd].rx_par_clk) 1306*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1307*3a749623SJacob Keller e822_vernier[link_spd].rx_par_clk); 1308*3a749623SJacob Keller else 1309*3a749623SJacob Keller phy_tus = 0; 1310*3a749623SJacob Keller 1311*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L, 1312*3a749623SJacob Keller phy_tus); 1313*3a749623SJacob Keller if (err) 1314*3a749623SJacob Keller return err; 1315*3a749623SJacob Keller 1316*3a749623SJacob Keller /* P_REG_PCS_TX_TUS */ 1317*3a749623SJacob Keller if (e822_vernier[link_spd].tx_pcs_clk) 1318*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1319*3a749623SJacob Keller e822_vernier[link_spd].tx_pcs_clk); 1320*3a749623SJacob Keller else 1321*3a749623SJacob Keller phy_tus = 0; 1322*3a749623SJacob Keller 1323*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L, 1324*3a749623SJacob Keller phy_tus); 1325*3a749623SJacob Keller if (err) 1326*3a749623SJacob Keller return err; 1327*3a749623SJacob Keller 1328*3a749623SJacob Keller /* P_REG_PCS_RX_TUS */ 1329*3a749623SJacob Keller if (e822_vernier[link_spd].rx_pcs_clk) 1330*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1331*3a749623SJacob Keller e822_vernier[link_spd].rx_pcs_clk); 1332*3a749623SJacob Keller else 1333*3a749623SJacob Keller phy_tus = 0; 1334*3a749623SJacob Keller 1335*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L, 1336*3a749623SJacob Keller phy_tus); 1337*3a749623SJacob Keller if (err) 1338*3a749623SJacob Keller return err; 1339*3a749623SJacob Keller 1340*3a749623SJacob Keller /* P_REG_DESK_PAR_TX_TUS */ 1341*3a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_par) 1342*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1343*3a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_par); 1344*3a749623SJacob Keller else 1345*3a749623SJacob Keller phy_tus = 0; 1346*3a749623SJacob Keller 1347*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L, 1348*3a749623SJacob Keller phy_tus); 1349*3a749623SJacob Keller if (err) 1350*3a749623SJacob Keller return err; 1351*3a749623SJacob Keller 1352*3a749623SJacob Keller /* P_REG_DESK_PAR_RX_TUS */ 1353*3a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_par) 1354*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1355*3a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_par); 1356*3a749623SJacob Keller else 1357*3a749623SJacob Keller phy_tus = 0; 1358*3a749623SJacob Keller 1359*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L, 1360*3a749623SJacob Keller phy_tus); 1361*3a749623SJacob Keller if (err) 1362*3a749623SJacob Keller return err; 1363*3a749623SJacob Keller 1364*3a749623SJacob Keller /* P_REG_DESK_PCS_TX_TUS */ 1365*3a749623SJacob Keller if (e822_vernier[link_spd].tx_desk_rsgb_pcs) 1366*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1367*3a749623SJacob Keller e822_vernier[link_spd].tx_desk_rsgb_pcs); 1368*3a749623SJacob Keller else 1369*3a749623SJacob Keller phy_tus = 0; 1370*3a749623SJacob Keller 1371*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L, 1372*3a749623SJacob Keller phy_tus); 1373*3a749623SJacob Keller if (err) 1374*3a749623SJacob Keller return err; 1375*3a749623SJacob Keller 1376*3a749623SJacob Keller /* P_REG_DESK_PCS_RX_TUS */ 1377*3a749623SJacob Keller if (e822_vernier[link_spd].rx_desk_rsgb_pcs) 1378*3a749623SJacob Keller phy_tus = div_u64(tu_per_sec, 1379*3a749623SJacob Keller e822_vernier[link_spd].rx_desk_rsgb_pcs); 1380*3a749623SJacob Keller else 1381*3a749623SJacob Keller phy_tus = 0; 1382*3a749623SJacob Keller 1383*3a749623SJacob Keller return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L, 1384*3a749623SJacob Keller phy_tus); 1385*3a749623SJacob Keller } 1386*3a749623SJacob Keller 1387*3a749623SJacob Keller /** 1388*3a749623SJacob Keller * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port 1389*3a749623SJacob Keller * @hw: pointer to the HW struct 1390*3a749623SJacob Keller * @link_spd: the Link speed to calculate for 1391*3a749623SJacob Keller * 1392*3a749623SJacob Keller * Calculate the fixed offset due to known static latency data. 1393*3a749623SJacob Keller */ 1394*3a749623SJacob Keller static u64 1395*3a749623SJacob Keller ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 1396*3a749623SJacob Keller { 1397*3a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 1398*3a749623SJacob Keller 1399*3a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1400*3a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1401*3a749623SJacob Keller 1402*3a749623SJacob Keller /* Calculate TUs per second */ 1403*3a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 1404*3a749623SJacob Keller 1405*3a749623SJacob Keller /* Calculate number of TUs to add for the fixed Tx latency. Since the 1406*3a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 1407*3a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 1408*3a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 1409*3a749623SJacob Keller * divisions by 1e4 first then by 1e7. 1410*3a749623SJacob Keller */ 1411*3a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 1412*3a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].tx_fixed_delay; 1413*3a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 1414*3a749623SJacob Keller 1415*3a749623SJacob Keller return fixed_offset; 1416*3a749623SJacob Keller } 1417*3a749623SJacob Keller 1418*3a749623SJacob Keller /** 1419*3a749623SJacob Keller * ice_phy_cfg_fixed_tx_offset_e822 - Configure Tx offset for bypass mode 1420*3a749623SJacob Keller * @hw: pointer to the HW struct 1421*3a749623SJacob Keller * @port: the PHY port to configure 1422*3a749623SJacob Keller * 1423*3a749623SJacob Keller * Calculate and program the fixed Tx offset, and indicate that the offset is 1424*3a749623SJacob Keller * ready. This can be used when operating in bypass mode. 1425*3a749623SJacob Keller */ 1426*3a749623SJacob Keller static int 1427*3a749623SJacob Keller ice_phy_cfg_fixed_tx_offset_e822(struct ice_hw *hw, u8 port) 1428*3a749623SJacob Keller { 1429*3a749623SJacob Keller enum ice_ptp_link_spd link_spd; 1430*3a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 1431*3a749623SJacob Keller u64 total_offset; 1432*3a749623SJacob Keller int err; 1433*3a749623SJacob Keller 1434*3a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1435*3a749623SJacob Keller if (err) 1436*3a749623SJacob Keller return err; 1437*3a749623SJacob Keller 1438*3a749623SJacob Keller total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd); 1439*3a749623SJacob Keller 1440*3a749623SJacob Keller /* Program the fixed Tx offset into the P_REG_TOTAL_TX_OFFSET_L 1441*3a749623SJacob Keller * register, then indicate that the Tx offset is ready. After this, 1442*3a749623SJacob Keller * timestamps will be enabled. 1443*3a749623SJacob Keller * 1444*3a749623SJacob Keller * Note that this skips including the more precise offsets generated 1445*3a749623SJacob Keller * by the Vernier calibration. 1446*3a749623SJacob Keller */ 1447*3a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L, 1448*3a749623SJacob Keller total_offset); 1449*3a749623SJacob Keller if (err) 1450*3a749623SJacob Keller return err; 1451*3a749623SJacob Keller 1452*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1); 1453*3a749623SJacob Keller if (err) 1454*3a749623SJacob Keller return err; 1455*3a749623SJacob Keller 1456*3a749623SJacob Keller return 0; 1457*3a749623SJacob Keller } 1458*3a749623SJacob Keller 1459*3a749623SJacob Keller /** 1460*3a749623SJacob Keller * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port 1461*3a749623SJacob Keller * @hw: pointer to HW struct 1462*3a749623SJacob Keller * @link_spd: The Link speed to calculate for 1463*3a749623SJacob Keller * 1464*3a749623SJacob Keller * Determine the fixed Rx latency for a given link speed. 1465*3a749623SJacob Keller */ 1466*3a749623SJacob Keller static u64 1467*3a749623SJacob Keller ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd) 1468*3a749623SJacob Keller { 1469*3a749623SJacob Keller u64 cur_freq, clk_incval, tu_per_sec, fixed_offset; 1470*3a749623SJacob Keller 1471*3a749623SJacob Keller cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw)); 1472*3a749623SJacob Keller clk_incval = ice_ptp_read_src_incval(hw); 1473*3a749623SJacob Keller 1474*3a749623SJacob Keller /* Calculate TUs per second */ 1475*3a749623SJacob Keller tu_per_sec = cur_freq * clk_incval; 1476*3a749623SJacob Keller 1477*3a749623SJacob Keller /* Calculate number of TUs to add for the fixed Rx latency. Since the 1478*3a749623SJacob Keller * latency measurement is in 1/100th of a nanosecond, we need to 1479*3a749623SJacob Keller * multiply by tu_per_sec and then divide by 1e11. This calculation 1480*3a749623SJacob Keller * overflows 64 bit integer arithmetic, so break it up into two 1481*3a749623SJacob Keller * divisions by 1e4 first then by 1e7. 1482*3a749623SJacob Keller */ 1483*3a749623SJacob Keller fixed_offset = div_u64(tu_per_sec, 10000); 1484*3a749623SJacob Keller fixed_offset *= e822_vernier[link_spd].rx_fixed_delay; 1485*3a749623SJacob Keller fixed_offset = div_u64(fixed_offset, 10000000); 1486*3a749623SJacob Keller 1487*3a749623SJacob Keller return fixed_offset; 1488*3a749623SJacob Keller } 1489*3a749623SJacob Keller 1490*3a749623SJacob Keller /** 1491*3a749623SJacob Keller * ice_phy_cfg_fixed_rx_offset_e822 - Configure fixed Rx offset for bypass mode 1492*3a749623SJacob Keller * @hw: pointer to the HW struct 1493*3a749623SJacob Keller * @port: the PHY port to configure 1494*3a749623SJacob Keller * 1495*3a749623SJacob Keller * Calculate and program the fixed Rx offset, and indicate that the offset is 1496*3a749623SJacob Keller * ready. This can be used when operating in bypass mode. 1497*3a749623SJacob Keller */ 1498*3a749623SJacob Keller static int 1499*3a749623SJacob Keller ice_phy_cfg_fixed_rx_offset_e822(struct ice_hw *hw, u8 port) 1500*3a749623SJacob Keller { 1501*3a749623SJacob Keller enum ice_ptp_link_spd link_spd; 1502*3a749623SJacob Keller enum ice_ptp_fec_mode fec_mode; 1503*3a749623SJacob Keller u64 total_offset; 1504*3a749623SJacob Keller int err; 1505*3a749623SJacob Keller 1506*3a749623SJacob Keller err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode); 1507*3a749623SJacob Keller if (err) 1508*3a749623SJacob Keller return err; 1509*3a749623SJacob Keller 1510*3a749623SJacob Keller total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd); 1511*3a749623SJacob Keller 1512*3a749623SJacob Keller /* Program the fixed Rx offset into the P_REG_TOTAL_RX_OFFSET_L 1513*3a749623SJacob Keller * register, then indicate that the Rx offset is ready. After this, 1514*3a749623SJacob Keller * timestamps will be enabled. 1515*3a749623SJacob Keller * 1516*3a749623SJacob Keller * Note that this skips including the more precise offsets generated 1517*3a749623SJacob Keller * by Vernier calibration. 1518*3a749623SJacob Keller */ 1519*3a749623SJacob Keller err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L, 1520*3a749623SJacob Keller total_offset); 1521*3a749623SJacob Keller if (err) 1522*3a749623SJacob Keller return err; 1523*3a749623SJacob Keller 1524*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1); 1525*3a749623SJacob Keller if (err) 1526*3a749623SJacob Keller return err; 1527*3a749623SJacob Keller 1528*3a749623SJacob Keller return 0; 1529*3a749623SJacob Keller } 1530*3a749623SJacob Keller 1531*3a749623SJacob Keller /** 1532*3a749623SJacob Keller * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time 1533*3a749623SJacob Keller * @hw: pointer to the HW struct 1534*3a749623SJacob Keller * @port: the PHY port to read 1535*3a749623SJacob Keller * @phy_time: on return, the 64bit PHY timer value 1536*3a749623SJacob Keller * @phc_time: on return, the lower 64bits of PHC time 1537*3a749623SJacob Keller * 1538*3a749623SJacob Keller * Issue a READ_TIME timer command to simultaneously capture the PHY and PHC 1539*3a749623SJacob Keller * timer values. 1540*3a749623SJacob Keller */ 1541*3a749623SJacob Keller static int 1542*3a749623SJacob Keller ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time, 1543*3a749623SJacob Keller u64 *phc_time) 1544*3a749623SJacob Keller { 1545*3a749623SJacob Keller u64 tx_time, rx_time; 1546*3a749623SJacob Keller u32 zo, lo; 1547*3a749623SJacob Keller u8 tmr_idx; 1548*3a749623SJacob Keller int err; 1549*3a749623SJacob Keller 1550*3a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 1551*3a749623SJacob Keller 1552*3a749623SJacob Keller /* Prepare the PHC timer for a READ_TIME capture command */ 1553*3a749623SJacob Keller ice_ptp_src_cmd(hw, READ_TIME); 1554*3a749623SJacob Keller 1555*3a749623SJacob Keller /* Prepare the PHY timer for a READ_TIME capture command */ 1556*3a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, READ_TIME); 1557*3a749623SJacob Keller if (err) 1558*3a749623SJacob Keller return err; 1559*3a749623SJacob Keller 1560*3a749623SJacob Keller /* Issue the sync to start the READ_TIME capture */ 1561*3a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 1562*3a749623SJacob Keller 1563*3a749623SJacob Keller /* Read the captured PHC time from the shadow time registers */ 1564*3a749623SJacob Keller zo = rd32(hw, GLTSYN_SHTIME_0(tmr_idx)); 1565*3a749623SJacob Keller lo = rd32(hw, GLTSYN_SHTIME_L(tmr_idx)); 1566*3a749623SJacob Keller *phc_time = (u64)lo << 32 | zo; 1567*3a749623SJacob Keller 1568*3a749623SJacob Keller /* Read the captured PHY time from the PHY shadow registers */ 1569*3a749623SJacob Keller err = ice_ptp_read_port_capture(hw, port, &tx_time, &rx_time); 1570*3a749623SJacob Keller if (err) 1571*3a749623SJacob Keller return err; 1572*3a749623SJacob Keller 1573*3a749623SJacob Keller /* If the PHY Tx and Rx timers don't match, log a warning message. 1574*3a749623SJacob Keller * Note that this should not happen in normal circumstances since the 1575*3a749623SJacob Keller * driver always programs them together. 1576*3a749623SJacob Keller */ 1577*3a749623SJacob Keller if (tx_time != rx_time) 1578*3a749623SJacob Keller dev_warn(ice_hw_to_dev(hw), 1579*3a749623SJacob Keller "PHY port %u Tx and Rx timers do not match, tx_time 0x%016llX, rx_time 0x%016llX\n", 1580*3a749623SJacob Keller port, (unsigned long long)tx_time, 1581*3a749623SJacob Keller (unsigned long long)rx_time); 1582*3a749623SJacob Keller 1583*3a749623SJacob Keller *phy_time = tx_time; 1584*3a749623SJacob Keller 1585*3a749623SJacob Keller return 0; 1586*3a749623SJacob Keller } 1587*3a749623SJacob Keller 1588*3a749623SJacob Keller /** 1589*3a749623SJacob Keller * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer 1590*3a749623SJacob Keller * @hw: pointer to the HW struct 1591*3a749623SJacob Keller * @port: the PHY port to synchronize 1592*3a749623SJacob Keller * 1593*3a749623SJacob Keller * Perform an adjustment to ensure that the PHY and PHC timers are in sync. 1594*3a749623SJacob Keller * This is done by issuing a READ_TIME command which triggers a simultaneous 1595*3a749623SJacob Keller * read of the PHY timer and PHC timer. Then we use the difference to 1596*3a749623SJacob Keller * calculate an appropriate 2s complement addition to add to the PHY timer in 1597*3a749623SJacob Keller * order to ensure it reads the same value as the primary PHC timer. 1598*3a749623SJacob Keller */ 1599*3a749623SJacob Keller static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port) 1600*3a749623SJacob Keller { 1601*3a749623SJacob Keller u64 phc_time, phy_time, difference; 1602*3a749623SJacob Keller int err; 1603*3a749623SJacob Keller 1604*3a749623SJacob Keller if (!ice_ptp_lock(hw)) { 1605*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to acquire PTP semaphore\n"); 1606*3a749623SJacob Keller return -EBUSY; 1607*3a749623SJacob Keller } 1608*3a749623SJacob Keller 1609*3a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 1610*3a749623SJacob Keller if (err) 1611*3a749623SJacob Keller goto err_unlock; 1612*3a749623SJacob Keller 1613*3a749623SJacob Keller /* Calculate the amount required to add to the port time in order for 1614*3a749623SJacob Keller * it to match the PHC time. 1615*3a749623SJacob Keller * 1616*3a749623SJacob Keller * Note that the port adjustment is done using 2s complement 1617*3a749623SJacob Keller * arithmetic. This is convenient since it means that we can simply 1618*3a749623SJacob Keller * calculate the difference between the PHC time and the port time, 1619*3a749623SJacob Keller * and it will be interpreted correctly. 1620*3a749623SJacob Keller */ 1621*3a749623SJacob Keller difference = phc_time - phy_time; 1622*3a749623SJacob Keller 1623*3a749623SJacob Keller err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference); 1624*3a749623SJacob Keller if (err) 1625*3a749623SJacob Keller goto err_unlock; 1626*3a749623SJacob Keller 1627*3a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, ADJ_TIME); 1628*3a749623SJacob Keller if (err) 1629*3a749623SJacob Keller goto err_unlock; 1630*3a749623SJacob Keller 1631*3a749623SJacob Keller /* Issue the sync to activate the time adjustment */ 1632*3a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 1633*3a749623SJacob Keller 1634*3a749623SJacob Keller /* Re-capture the timer values to flush the command registers and 1635*3a749623SJacob Keller * verify that the time was properly adjusted. 1636*3a749623SJacob Keller */ 1637*3a749623SJacob Keller err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time); 1638*3a749623SJacob Keller if (err) 1639*3a749623SJacob Keller goto err_unlock; 1640*3a749623SJacob Keller 1641*3a749623SJacob Keller dev_info(ice_hw_to_dev(hw), 1642*3a749623SJacob Keller "Port %u PHY time synced to PHC: 0x%016llX, 0x%016llX\n", 1643*3a749623SJacob Keller port, (unsigned long long)phy_time, 1644*3a749623SJacob Keller (unsigned long long)phc_time); 1645*3a749623SJacob Keller 1646*3a749623SJacob Keller ice_ptp_unlock(hw); 1647*3a749623SJacob Keller 1648*3a749623SJacob Keller return 0; 1649*3a749623SJacob Keller 1650*3a749623SJacob Keller err_unlock: 1651*3a749623SJacob Keller ice_ptp_unlock(hw); 1652*3a749623SJacob Keller return err; 1653*3a749623SJacob Keller } 1654*3a749623SJacob Keller 1655*3a749623SJacob Keller /** 1656*3a749623SJacob Keller * ice_stop_phy_timer_e822 - Stop the PHY clock timer 1657*3a749623SJacob Keller * @hw: pointer to the HW struct 1658*3a749623SJacob Keller * @port: the PHY port to stop 1659*3a749623SJacob Keller * @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS 1660*3a749623SJacob Keller * 1661*3a749623SJacob Keller * Stop the clock of a PHY port. This must be done as part of the flow to 1662*3a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 1663*3a749623SJacob Keller * initialized or when link speed changes. 1664*3a749623SJacob Keller */ 1665*3a749623SJacob Keller int 1666*3a749623SJacob Keller ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset) 1667*3a749623SJacob Keller { 1668*3a749623SJacob Keller int err; 1669*3a749623SJacob Keller u32 val; 1670*3a749623SJacob Keller 1671*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0); 1672*3a749623SJacob Keller if (err) 1673*3a749623SJacob Keller return err; 1674*3a749623SJacob Keller 1675*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0); 1676*3a749623SJacob Keller if (err) 1677*3a749623SJacob Keller return err; 1678*3a749623SJacob Keller 1679*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 1680*3a749623SJacob Keller if (err) 1681*3a749623SJacob Keller return err; 1682*3a749623SJacob Keller 1683*3a749623SJacob Keller val &= ~P_REG_PS_START_M; 1684*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1685*3a749623SJacob Keller if (err) 1686*3a749623SJacob Keller return err; 1687*3a749623SJacob Keller 1688*3a749623SJacob Keller val &= ~P_REG_PS_ENA_CLK_M; 1689*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1690*3a749623SJacob Keller if (err) 1691*3a749623SJacob Keller return err; 1692*3a749623SJacob Keller 1693*3a749623SJacob Keller if (soft_reset) { 1694*3a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 1695*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1696*3a749623SJacob Keller if (err) 1697*3a749623SJacob Keller return err; 1698*3a749623SJacob Keller } 1699*3a749623SJacob Keller 1700*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Disabled clock on PHY port %u\n", port); 1701*3a749623SJacob Keller 1702*3a749623SJacob Keller return 0; 1703*3a749623SJacob Keller } 1704*3a749623SJacob Keller 1705*3a749623SJacob Keller /** 1706*3a749623SJacob Keller * ice_start_phy_timer_e822 - Start the PHY clock timer 1707*3a749623SJacob Keller * @hw: pointer to the HW struct 1708*3a749623SJacob Keller * @port: the PHY port to start 1709*3a749623SJacob Keller * @bypass: if true, start the PHY in bypass mode 1710*3a749623SJacob Keller * 1711*3a749623SJacob Keller * Start the clock of a PHY port. This must be done as part of the flow to 1712*3a749623SJacob Keller * re-calibrate Tx and Rx timestamping offsets whenever the clock time is 1713*3a749623SJacob Keller * initialized or when link speed changes. 1714*3a749623SJacob Keller * 1715*3a749623SJacob Keller * Bypass mode enables timestamps immediately without waiting for Vernier 1716*3a749623SJacob Keller * calibration to complete. Hardware will still continue taking Vernier 1717*3a749623SJacob Keller * measurements on Tx or Rx of packets, but they will not be applied to 1718*3a749623SJacob Keller * timestamps. Use ice_phy_exit_bypass_e822 to exit bypass mode once hardware 1719*3a749623SJacob Keller * has completed offset calculation. 1720*3a749623SJacob Keller */ 1721*3a749623SJacob Keller int 1722*3a749623SJacob Keller ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass) 1723*3a749623SJacob Keller { 1724*3a749623SJacob Keller u32 lo, hi, val; 1725*3a749623SJacob Keller u64 incval; 1726*3a749623SJacob Keller u8 tmr_idx; 1727*3a749623SJacob Keller int err; 1728*3a749623SJacob Keller 1729*3a749623SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 1730*3a749623SJacob Keller 1731*3a749623SJacob Keller err = ice_stop_phy_timer_e822(hw, port, false); 1732*3a749623SJacob Keller if (err) 1733*3a749623SJacob Keller return err; 1734*3a749623SJacob Keller 1735*3a749623SJacob Keller ice_phy_cfg_lane_e822(hw, port); 1736*3a749623SJacob Keller 1737*3a749623SJacob Keller err = ice_phy_cfg_uix_e822(hw, port); 1738*3a749623SJacob Keller if (err) 1739*3a749623SJacob Keller return err; 1740*3a749623SJacob Keller 1741*3a749623SJacob Keller err = ice_phy_cfg_parpcs_e822(hw, port); 1742*3a749623SJacob Keller if (err) 1743*3a749623SJacob Keller return err; 1744*3a749623SJacob Keller 1745*3a749623SJacob Keller lo = rd32(hw, GLTSYN_INCVAL_L(tmr_idx)); 1746*3a749623SJacob Keller hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx)); 1747*3a749623SJacob Keller incval = (u64)hi << 32 | lo; 1748*3a749623SJacob Keller 1749*3a749623SJacob Keller err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval); 1750*3a749623SJacob Keller if (err) 1751*3a749623SJacob Keller return err; 1752*3a749623SJacob Keller 1753*3a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 1754*3a749623SJacob Keller if (err) 1755*3a749623SJacob Keller return err; 1756*3a749623SJacob Keller 1757*3a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 1758*3a749623SJacob Keller 1759*3a749623SJacob Keller err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val); 1760*3a749623SJacob Keller if (err) 1761*3a749623SJacob Keller return err; 1762*3a749623SJacob Keller 1763*3a749623SJacob Keller val |= P_REG_PS_SFT_RESET_M; 1764*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1765*3a749623SJacob Keller if (err) 1766*3a749623SJacob Keller return err; 1767*3a749623SJacob Keller 1768*3a749623SJacob Keller val |= P_REG_PS_START_M; 1769*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1770*3a749623SJacob Keller if (err) 1771*3a749623SJacob Keller return err; 1772*3a749623SJacob Keller 1773*3a749623SJacob Keller val &= ~P_REG_PS_SFT_RESET_M; 1774*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1775*3a749623SJacob Keller if (err) 1776*3a749623SJacob Keller return err; 1777*3a749623SJacob Keller 1778*3a749623SJacob Keller err = ice_ptp_one_port_cmd(hw, port, INIT_INCVAL); 1779*3a749623SJacob Keller if (err) 1780*3a749623SJacob Keller return err; 1781*3a749623SJacob Keller 1782*3a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 1783*3a749623SJacob Keller 1784*3a749623SJacob Keller val |= P_REG_PS_ENA_CLK_M; 1785*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1786*3a749623SJacob Keller if (err) 1787*3a749623SJacob Keller return err; 1788*3a749623SJacob Keller 1789*3a749623SJacob Keller val |= P_REG_PS_LOAD_OFFSET_M; 1790*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1791*3a749623SJacob Keller if (err) 1792*3a749623SJacob Keller return err; 1793*3a749623SJacob Keller 1794*3a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 1795*3a749623SJacob Keller 1796*3a749623SJacob Keller err = ice_sync_phy_timer_e822(hw, port); 1797*3a749623SJacob Keller if (err) 1798*3a749623SJacob Keller return err; 1799*3a749623SJacob Keller 1800*3a749623SJacob Keller if (bypass) { 1801*3a749623SJacob Keller val |= P_REG_PS_BYPASS_MODE_M; 1802*3a749623SJacob Keller /* Enter BYPASS mode, enabling timestamps immediately. */ 1803*3a749623SJacob Keller err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val); 1804*3a749623SJacob Keller if (err) 1805*3a749623SJacob Keller return err; 1806*3a749623SJacob Keller 1807*3a749623SJacob Keller /* Program the fixed Tx offset */ 1808*3a749623SJacob Keller err = ice_phy_cfg_fixed_tx_offset_e822(hw, port); 1809*3a749623SJacob Keller if (err) 1810*3a749623SJacob Keller return err; 1811*3a749623SJacob Keller 1812*3a749623SJacob Keller /* Program the fixed Rx offset */ 1813*3a749623SJacob Keller err = ice_phy_cfg_fixed_rx_offset_e822(hw, port); 1814*3a749623SJacob Keller if (err) 1815*3a749623SJacob Keller return err; 1816*3a749623SJacob Keller } 1817*3a749623SJacob Keller 1818*3a749623SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Enabled clock on PHY port %u\n", port); 1819*3a749623SJacob Keller 1820*3a749623SJacob Keller return 0; 1821*3a749623SJacob Keller } 1822*3a749623SJacob Keller 182303cb4473SJacob Keller /* E810 functions 182403cb4473SJacob Keller * 182503cb4473SJacob Keller * The following functions operate on the E810 series devices which use 182603cb4473SJacob Keller * a separate external PHY. 182703cb4473SJacob Keller */ 182803cb4473SJacob Keller 182903cb4473SJacob Keller /** 183003cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 183103cb4473SJacob Keller * @hw: pointer to the HW struct 183203cb4473SJacob Keller * @addr: the address to read from 183303cb4473SJacob Keller * @val: On return, the value read from the PHY 183403cb4473SJacob Keller * 183503cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 183603cb4473SJacob Keller */ 183703cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 183803cb4473SJacob Keller { 183903cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 184039b28106SJacob Keller int err; 184103cb4473SJacob Keller 184203cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 184303cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 184403cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 184503cb4473SJacob Keller msg.dest_dev = rmn_0; 184603cb4473SJacob Keller 184739b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 184839b28106SJacob Keller if (err) { 184939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 185039b28106SJacob Keller err); 185139b28106SJacob Keller return err; 185203cb4473SJacob Keller } 185303cb4473SJacob Keller 185403cb4473SJacob Keller *val = msg.data; 185503cb4473SJacob Keller 185603cb4473SJacob Keller return 0; 185703cb4473SJacob Keller } 185803cb4473SJacob Keller 185903cb4473SJacob Keller /** 186003cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 186103cb4473SJacob Keller * @hw: pointer to the HW struct 186203cb4473SJacob Keller * @addr: the address to writem to 186303cb4473SJacob Keller * @val: the value to write to the PHY 186403cb4473SJacob Keller * 186503cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 186603cb4473SJacob Keller */ 186703cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 186803cb4473SJacob Keller { 186903cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 187039b28106SJacob Keller int err; 187103cb4473SJacob Keller 187203cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 187303cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 187403cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 187503cb4473SJacob Keller msg.dest_dev = rmn_0; 187603cb4473SJacob Keller msg.data = val; 187703cb4473SJacob Keller 187839b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 187939b28106SJacob Keller if (err) { 188039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 188139b28106SJacob Keller err); 188239b28106SJacob Keller return err; 188303cb4473SJacob Keller } 188403cb4473SJacob Keller 188503cb4473SJacob Keller return 0; 188603cb4473SJacob Keller } 188703cb4473SJacob Keller 188803cb4473SJacob Keller /** 188903cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 189003cb4473SJacob Keller * @hw: pointer to the HW struct 189103cb4473SJacob Keller * @lport: the lport to read from 189203cb4473SJacob Keller * @idx: the timestamp index to read 189303cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 189403cb4473SJacob Keller * 189503cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 189603cb4473SJacob Keller * on the E810 device. 189703cb4473SJacob Keller */ 189803cb4473SJacob Keller static int 189903cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 190003cb4473SJacob Keller { 190103cb4473SJacob Keller u32 lo_addr, hi_addr, lo, hi; 190239b28106SJacob Keller int err; 190303cb4473SJacob Keller 190403cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 190503cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 190603cb4473SJacob Keller 190739b28106SJacob Keller err = ice_read_phy_reg_e810(hw, lo_addr, &lo); 190839b28106SJacob Keller if (err) { 190939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 191039b28106SJacob Keller err); 191139b28106SJacob Keller return err; 191203cb4473SJacob Keller } 191303cb4473SJacob Keller 191439b28106SJacob Keller err = ice_read_phy_reg_e810(hw, hi_addr, &hi); 191539b28106SJacob Keller if (err) { 191639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 191739b28106SJacob Keller err); 191839b28106SJacob Keller return err; 191903cb4473SJacob Keller } 192003cb4473SJacob Keller 192103cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 192203cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 192303cb4473SJacob Keller */ 192403cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 192503cb4473SJacob Keller 192603cb4473SJacob Keller return 0; 192703cb4473SJacob Keller } 192803cb4473SJacob Keller 192903cb4473SJacob Keller /** 193003cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 193103cb4473SJacob Keller * @hw: pointer to the HW struct 193203cb4473SJacob Keller * @lport: the lport to read from 193303cb4473SJacob Keller * @idx: the timestamp index to reset 193403cb4473SJacob Keller * 193503cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 193603cb4473SJacob Keller * external PHY on the E810 device. 193703cb4473SJacob Keller */ 193803cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 193903cb4473SJacob Keller { 194003cb4473SJacob Keller u32 lo_addr, hi_addr; 194139b28106SJacob Keller int err; 194203cb4473SJacob Keller 194303cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 194403cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 194503cb4473SJacob Keller 194639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 194739b28106SJacob Keller if (err) { 194839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 194939b28106SJacob Keller err); 195039b28106SJacob Keller return err; 195103cb4473SJacob Keller } 195203cb4473SJacob Keller 195339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 195439b28106SJacob Keller if (err) { 195539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 195639b28106SJacob Keller err); 195739b28106SJacob Keller return err; 195803cb4473SJacob Keller } 195903cb4473SJacob Keller 196003cb4473SJacob Keller return 0; 196103cb4473SJacob Keller } 196203cb4473SJacob Keller 196303cb4473SJacob Keller /** 196403cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 196503cb4473SJacob Keller * @hw: pointer to HW struct 196603cb4473SJacob Keller * 196703cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 196803cb4473SJacob Keller * this function. 196903cb4473SJacob Keller */ 197003cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 197103cb4473SJacob Keller { 197203cb4473SJacob Keller u8 tmr_idx; 197339b28106SJacob Keller int err; 197403cb4473SJacob Keller 197503cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 197639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 197703cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 197839b28106SJacob Keller if (err) 197903cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 198039b28106SJacob Keller err); 198103cb4473SJacob Keller 198239b28106SJacob Keller return err; 198303cb4473SJacob Keller } 198403cb4473SJacob Keller 198503cb4473SJacob Keller /** 1986b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 1987b2ee7256SJacob Keller * @hw: pointer to HW struct 1988b2ee7256SJacob Keller * 1989b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 1990b2ee7256SJacob Keller */ 1991b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 1992b2ee7256SJacob Keller { 1993b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 1994b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 1995b2ee7256SJacob Keller 1996b2ee7256SJacob Keller /* Initialize the PHY */ 1997b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 1998b2ee7256SJacob Keller } 1999b2ee7256SJacob Keller 2000b2ee7256SJacob Keller /** 200103cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 200203cb4473SJacob Keller * @hw: Board private structure 200303cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 200403cb4473SJacob Keller * 200503cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 200603cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 200703cb4473SJacob Keller * driver issues an INIT_TIME command. 200803cb4473SJacob Keller * 200903cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 201003cb4473SJacob Keller * nominal nanoseconds. 201103cb4473SJacob Keller */ 201203cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 201303cb4473SJacob Keller { 201403cb4473SJacob Keller u8 tmr_idx; 201539b28106SJacob Keller int err; 201603cb4473SJacob Keller 201703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 201839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 201939b28106SJacob Keller if (err) { 202039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 202139b28106SJacob Keller err); 202239b28106SJacob Keller return err; 202303cb4473SJacob Keller } 202403cb4473SJacob Keller 202539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 202639b28106SJacob Keller if (err) { 202739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 202839b28106SJacob Keller err); 202939b28106SJacob Keller return err; 203003cb4473SJacob Keller } 203103cb4473SJacob Keller 203203cb4473SJacob Keller return 0; 203303cb4473SJacob Keller } 203403cb4473SJacob Keller 203503cb4473SJacob Keller /** 203603cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 203703cb4473SJacob Keller * @hw: pointer to HW struct 203803cb4473SJacob Keller * @adj: adjustment value to program 203903cb4473SJacob Keller * 204003cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 204103cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 204203cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 204303cb4473SJacob Keller * 204403cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 204503cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 204603cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 204703cb4473SJacob Keller */ 204803cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 204903cb4473SJacob Keller { 205003cb4473SJacob Keller u8 tmr_idx; 205139b28106SJacob Keller int err; 205203cb4473SJacob Keller 205303cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 205403cb4473SJacob Keller 205503cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 205603cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 205703cb4473SJacob Keller */ 205839b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 205939b28106SJacob Keller if (err) { 206039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 206139b28106SJacob Keller err); 206239b28106SJacob Keller return err; 206303cb4473SJacob Keller } 206403cb4473SJacob Keller 206539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 206639b28106SJacob Keller if (err) { 206739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 206839b28106SJacob Keller err); 206939b28106SJacob Keller return err; 207003cb4473SJacob Keller } 207103cb4473SJacob Keller 207203cb4473SJacob Keller return 0; 207303cb4473SJacob Keller } 207403cb4473SJacob Keller 207503cb4473SJacob Keller /** 207603cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 207703cb4473SJacob Keller * @hw: pointer to HW struct 207803cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 207903cb4473SJacob Keller * 208003cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 208103cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 208203cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 208303cb4473SJacob Keller */ 208403cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 208503cb4473SJacob Keller { 208603cb4473SJacob Keller u32 high, low; 208703cb4473SJacob Keller u8 tmr_idx; 208839b28106SJacob Keller int err; 208903cb4473SJacob Keller 209003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 209103cb4473SJacob Keller low = lower_32_bits(incval); 209203cb4473SJacob Keller high = upper_32_bits(incval); 209303cb4473SJacob Keller 209439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 209539b28106SJacob Keller if (err) { 209639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 209739b28106SJacob Keller err); 209839b28106SJacob Keller return err; 209903cb4473SJacob Keller } 210003cb4473SJacob Keller 210139b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 210239b28106SJacob Keller if (err) { 210339b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 210439b28106SJacob Keller err); 210539b28106SJacob Keller return err; 210603cb4473SJacob Keller } 210703cb4473SJacob Keller 210803cb4473SJacob Keller return 0; 210903cb4473SJacob Keller } 211003cb4473SJacob Keller 211103cb4473SJacob Keller /** 211203cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 211303cb4473SJacob Keller * @hw: pointer to HW struct 211403cb4473SJacob Keller * @cmd: Command to be sent to the port 211503cb4473SJacob Keller * 211603cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 211703cb4473SJacob Keller * command. 211803cb4473SJacob Keller */ 211903cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 212003cb4473SJacob Keller { 212103cb4473SJacob Keller u32 cmd_val, val; 212239b28106SJacob Keller int err; 212303cb4473SJacob Keller 212403cb4473SJacob Keller switch (cmd) { 212503cb4473SJacob Keller case INIT_TIME: 212603cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 212703cb4473SJacob Keller break; 212803cb4473SJacob Keller case INIT_INCVAL: 212903cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 213003cb4473SJacob Keller break; 213103cb4473SJacob Keller case ADJ_TIME: 213203cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 213303cb4473SJacob Keller break; 213403cb4473SJacob Keller case READ_TIME: 213503cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 213603cb4473SJacob Keller break; 213703cb4473SJacob Keller case ADJ_TIME_AT_TIME: 213803cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 213903cb4473SJacob Keller break; 214003cb4473SJacob Keller } 214103cb4473SJacob Keller 214203cb4473SJacob Keller /* Read, modify, write */ 214339b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 214439b28106SJacob Keller if (err) { 214539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 214639b28106SJacob Keller return err; 214703cb4473SJacob Keller } 214803cb4473SJacob Keller 214903cb4473SJacob Keller /* Modify necessary bits only and perform write */ 215003cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 215103cb4473SJacob Keller val |= cmd_val; 215203cb4473SJacob Keller 215339b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 215439b28106SJacob Keller if (err) { 215539b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 215639b28106SJacob Keller return err; 215703cb4473SJacob Keller } 215803cb4473SJacob Keller 215903cb4473SJacob Keller return 0; 216003cb4473SJacob Keller } 216103cb4473SJacob Keller 216203cb4473SJacob Keller /* Device agnostic functions 216303cb4473SJacob Keller * 2164*3a749623SJacob Keller * The following functions implement shared behavior common to both E822 and 2165*3a749623SJacob Keller * E810 devices, possibly calling a device specific implementation where 2166*3a749623SJacob Keller * necessary. 216703cb4473SJacob Keller */ 216803cb4473SJacob Keller 216903cb4473SJacob Keller /** 217003cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 217103cb4473SJacob Keller * @hw: pointer to the HW struct 217203cb4473SJacob Keller * 217303cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 217403cb4473SJacob Keller * was acquired, false otherwise. 217503cb4473SJacob Keller * 217603cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 217703cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 217803cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 217903cb4473SJacob Keller * bit set, it means that another function acquired the lock. 218003cb4473SJacob Keller * 218103cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 218203cb4473SJacob Keller * functions when done. 218303cb4473SJacob Keller */ 218403cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 218503cb4473SJacob Keller { 218603cb4473SJacob Keller u32 hw_lock; 218703cb4473SJacob Keller int i; 218803cb4473SJacob Keller 218903cb4473SJacob Keller #define MAX_TRIES 5 219003cb4473SJacob Keller 219103cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 219203cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 219303cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 2194587b839dSColin Ian King if (!hw_lock) 2195587b839dSColin Ian King break; 2196587b839dSColin Ian King 219703cb4473SJacob Keller /* Somebody is holding the lock */ 219803cb4473SJacob Keller usleep_range(10000, 20000); 219903cb4473SJacob Keller } 220003cb4473SJacob Keller 220103cb4473SJacob Keller return !hw_lock; 220203cb4473SJacob Keller } 220303cb4473SJacob Keller 220403cb4473SJacob Keller /** 220503cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 220603cb4473SJacob Keller * @hw: pointer to the HW struct 220703cb4473SJacob Keller * 220803cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 220903cb4473SJacob Keller * the PFTSYN_SEM register. 221003cb4473SJacob Keller */ 221103cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 221203cb4473SJacob Keller { 221303cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 221403cb4473SJacob Keller } 221503cb4473SJacob Keller 221603cb4473SJacob Keller /** 221703cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 221803cb4473SJacob Keller * @hw: pointer to HW struct 221903cb4473SJacob Keller * @cmd: the command to issue 222003cb4473SJacob Keller * 222103cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 222203cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 222303cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 222403cb4473SJacob Keller * timers. 222503cb4473SJacob Keller */ 222603cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 222703cb4473SJacob Keller { 222839b28106SJacob Keller int err; 222903cb4473SJacob Keller 223003cb4473SJacob Keller /* First, prepare the source timer */ 223103cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 223203cb4473SJacob Keller 223303cb4473SJacob Keller /* Next, prepare the ports */ 2234*3a749623SJacob Keller if (ice_is_e810(hw)) 223539b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 2236*3a749623SJacob Keller else 2237*3a749623SJacob Keller err = ice_ptp_port_cmd_e822(hw, cmd); 223839b28106SJacob Keller if (err) { 223939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 224039b28106SJacob Keller cmd, err); 224139b28106SJacob Keller return err; 224203cb4473SJacob Keller } 224303cb4473SJacob Keller 2244*3a749623SJacob Keller /* Write the sync command register to drive both source and PHY timer 2245*3a749623SJacob Keller * commands synchronously 224603cb4473SJacob Keller */ 2247*3a749623SJacob Keller ice_ptp_exec_tmr_cmd(hw); 224803cb4473SJacob Keller 224903cb4473SJacob Keller return 0; 225003cb4473SJacob Keller } 225103cb4473SJacob Keller 225203cb4473SJacob Keller /** 225303cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 225403cb4473SJacob Keller * @hw: pointer to HW struct 225503cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 225603cb4473SJacob Keller * 225703cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 225803cb4473SJacob Keller * step process: 225903cb4473SJacob Keller * 226003cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 226103cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 226203cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 226303cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 226403cb4473SJacob Keller */ 226503cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 226603cb4473SJacob Keller { 226703cb4473SJacob Keller u8 tmr_idx; 226839b28106SJacob Keller int err; 226903cb4473SJacob Keller 227003cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 227103cb4473SJacob Keller 227203cb4473SJacob Keller /* Source timers */ 227303cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 227403cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 227503cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 227603cb4473SJacob Keller 227703cb4473SJacob Keller /* PHY timers */ 227803cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 2279*3a749623SJacob Keller if (ice_is_e810(hw)) 228039b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 2281*3a749623SJacob Keller else 2282*3a749623SJacob Keller err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF); 228339b28106SJacob Keller if (err) 228439b28106SJacob Keller return err; 228503cb4473SJacob Keller 228603cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 228703cb4473SJacob Keller } 228803cb4473SJacob Keller 228903cb4473SJacob Keller /** 229003cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 229103cb4473SJacob Keller * @hw: pointer to HW struct 229203cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 229303cb4473SJacob Keller * 229403cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 229503cb4473SJacob Keller * process: 229603cb4473SJacob Keller * 229703cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 229803cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 229903cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 230003cb4473SJacob Keller * source and port timers to the new increment value at the next clock 230103cb4473SJacob Keller * cycle. 230203cb4473SJacob Keller */ 230303cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 230403cb4473SJacob Keller { 230503cb4473SJacob Keller u8 tmr_idx; 230639b28106SJacob Keller int err; 230703cb4473SJacob Keller 230803cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 230903cb4473SJacob Keller 231003cb4473SJacob Keller /* Shadow Adjust */ 231103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 231203cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 231303cb4473SJacob Keller 2314*3a749623SJacob Keller if (ice_is_e810(hw)) 231539b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 2316*3a749623SJacob Keller else 2317*3a749623SJacob Keller err = ice_ptp_prep_phy_incval_e822(hw, incval); 231839b28106SJacob Keller if (err) 231939b28106SJacob Keller return err; 232003cb4473SJacob Keller 232103cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 232203cb4473SJacob Keller } 232303cb4473SJacob Keller 232403cb4473SJacob Keller /** 232503cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 232603cb4473SJacob Keller * @hw: pointer to HW struct 232703cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 232803cb4473SJacob Keller * 232903cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 233003cb4473SJacob Keller */ 233103cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 233203cb4473SJacob Keller { 233339b28106SJacob Keller int err; 233403cb4473SJacob Keller 233503cb4473SJacob Keller if (!ice_ptp_lock(hw)) 233603cb4473SJacob Keller return -EBUSY; 233703cb4473SJacob Keller 233839b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 233903cb4473SJacob Keller 234003cb4473SJacob Keller ice_ptp_unlock(hw); 234103cb4473SJacob Keller 234239b28106SJacob Keller return err; 234303cb4473SJacob Keller } 234403cb4473SJacob Keller 234503cb4473SJacob Keller /** 234603cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 234703cb4473SJacob Keller * @hw: pointer to HW struct 234803cb4473SJacob Keller * @adj: Adjustment in nanoseconds 234903cb4473SJacob Keller * 235003cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 235103cb4473SJacob Keller * nanoseconds. This requires a three-step process: 235203cb4473SJacob Keller * 235303cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 235403cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 235503cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 235603cb4473SJacob Keller * both the source and port timers at the next clock cycle. 235703cb4473SJacob Keller */ 235803cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 235903cb4473SJacob Keller { 236003cb4473SJacob Keller u8 tmr_idx; 236139b28106SJacob Keller int err; 236203cb4473SJacob Keller 236303cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 236403cb4473SJacob Keller 236503cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 236603cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 236703cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 236803cb4473SJacob Keller * the value as a 2's complement integer. 236903cb4473SJacob Keller */ 237003cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 237103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 237203cb4473SJacob Keller 2373*3a749623SJacob Keller if (ice_is_e810(hw)) 237439b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 2375*3a749623SJacob Keller else 2376*3a749623SJacob Keller err = ice_ptp_prep_phy_adj_e822(hw, adj); 237739b28106SJacob Keller if (err) 237839b28106SJacob Keller return err; 237903cb4473SJacob Keller 238003cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 238103cb4473SJacob Keller } 238203cb4473SJacob Keller 238303cb4473SJacob Keller /** 238403cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 238503cb4473SJacob Keller * @hw: pointer to the HW struct 238603cb4473SJacob Keller * @block: the block to read from 238703cb4473SJacob Keller * @idx: the timestamp index to read 238803cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 238903cb4473SJacob Keller * 2390*3a749623SJacob Keller * Read a 40bit timestamp value out of the timestamp block. For E822 devices, 2391*3a749623SJacob Keller * the block is the quad to read from. For E810 devices, the block is the 2392*3a749623SJacob Keller * logical port to read from. 239303cb4473SJacob Keller */ 239403cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 239503cb4473SJacob Keller { 2396*3a749623SJacob Keller if (ice_is_e810(hw)) 239703cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 2398*3a749623SJacob Keller else 2399*3a749623SJacob Keller return ice_read_phy_tstamp_e822(hw, block, idx, tstamp); 240003cb4473SJacob Keller } 240103cb4473SJacob Keller 240203cb4473SJacob Keller /** 240303cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 240403cb4473SJacob Keller * @hw: pointer to the HW struct 240503cb4473SJacob Keller * @block: the block to read from 240603cb4473SJacob Keller * @idx: the timestamp index to reset 240703cb4473SJacob Keller * 2408*3a749623SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. For 2409*3a749623SJacob Keller * E822 devices, the block is the quad to clear from. For E810 devices, the 2410*3a749623SJacob Keller * block is the logical port to clear from. 241103cb4473SJacob Keller */ 241203cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 241303cb4473SJacob Keller { 2414*3a749623SJacob Keller if (ice_is_e810(hw)) 241503cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 2416*3a749623SJacob Keller else 2417*3a749623SJacob Keller return ice_clear_phy_tstamp_e822(hw, block, idx); 241803cb4473SJacob Keller } 2419885fe693SMaciej Machnikowski 2420885fe693SMaciej Machnikowski /* E810T SMA functions 2421885fe693SMaciej Machnikowski * 2422885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 2423885fe693SMaciej Machnikowski * to access the extended GPIOs available. 2424885fe693SMaciej Machnikowski */ 2425885fe693SMaciej Machnikowski 2426885fe693SMaciej Machnikowski /** 2427885fe693SMaciej Machnikowski * ice_get_pca9575_handle 2428885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2429885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 2430885fe693SMaciej Machnikowski * 2431885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 2432885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 2433885fe693SMaciej Machnikowski * will return cached value 2434885fe693SMaciej Machnikowski */ 2435885fe693SMaciej Machnikowski static int 2436885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 2437885fe693SMaciej Machnikowski { 2438885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 2439885fe693SMaciej Machnikowski struct ice_aq_desc desc; 2440885fe693SMaciej Machnikowski int status; 2441885fe693SMaciej Machnikowski u8 idx; 2442885fe693SMaciej Machnikowski 2443885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 2444885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 2445885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 2446885fe693SMaciej Machnikowski return 0; 2447885fe693SMaciej Machnikowski } 2448885fe693SMaciej Machnikowski 2449885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 2450885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 2451885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 2452885fe693SMaciej Machnikowski 2453885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 2454885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 2455885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 2456885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 2457885fe693SMaciej Machnikowski 2458885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 2459885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 2460885fe693SMaciej Machnikowski 2461885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 2462885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 2463885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 2464885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 2465885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 2466885fe693SMaciej Machnikowski else 2467885fe693SMaciej Machnikowski return -EOPNOTSUPP; 2468885fe693SMaciej Machnikowski 2469885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 2470885fe693SMaciej Machnikowski 2471885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 2472885fe693SMaciej Machnikowski if (status) 2473885fe693SMaciej Machnikowski return -EOPNOTSUPP; 2474885fe693SMaciej Machnikowski 2475885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 2476885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 2477885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 2478885fe693SMaciej Machnikowski return -EOPNOTSUPP; 2479885fe693SMaciej Machnikowski 2480885fe693SMaciej Machnikowski /* If present save the handle and return it */ 2481885fe693SMaciej Machnikowski hw->io_expander_handle = 2482885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 2483885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 2484885fe693SMaciej Machnikowski 2485885fe693SMaciej Machnikowski return 0; 2486885fe693SMaciej Machnikowski } 2487885fe693SMaciej Machnikowski 2488885fe693SMaciej Machnikowski /** 2489885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 2490885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2491885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 2492885fe693SMaciej Machnikowski * 2493885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 2494885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 2495885fe693SMaciej Machnikowski */ 2496885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 2497885fe693SMaciej Machnikowski { 2498885fe693SMaciej Machnikowski int status; 2499885fe693SMaciej Machnikowski u16 handle; 2500885fe693SMaciej Machnikowski u8 i; 2501885fe693SMaciej Machnikowski 2502885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 2503885fe693SMaciej Machnikowski if (status) 2504885fe693SMaciej Machnikowski return status; 2505885fe693SMaciej Machnikowski 2506885fe693SMaciej Machnikowski *data = 0; 2507885fe693SMaciej Machnikowski 2508885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 2509885fe693SMaciej Machnikowski bool pin; 2510885fe693SMaciej Machnikowski 2511885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 2512885fe693SMaciej Machnikowski &pin, NULL); 2513885fe693SMaciej Machnikowski if (status) 2514885fe693SMaciej Machnikowski break; 2515885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 2516885fe693SMaciej Machnikowski } 2517885fe693SMaciej Machnikowski 2518885fe693SMaciej Machnikowski return status; 2519885fe693SMaciej Machnikowski } 2520885fe693SMaciej Machnikowski 2521885fe693SMaciej Machnikowski /** 2522885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 2523885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2524885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 2525885fe693SMaciej Machnikowski * 2526885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 2527885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 2528885fe693SMaciej Machnikowski */ 2529885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 2530885fe693SMaciej Machnikowski { 2531885fe693SMaciej Machnikowski int status; 2532885fe693SMaciej Machnikowski u16 handle; 2533885fe693SMaciej Machnikowski u8 i; 2534885fe693SMaciej Machnikowski 2535885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 2536885fe693SMaciej Machnikowski if (status) 2537885fe693SMaciej Machnikowski return status; 2538885fe693SMaciej Machnikowski 2539885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 2540885fe693SMaciej Machnikowski bool pin; 2541885fe693SMaciej Machnikowski 2542885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 2543885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 2544885fe693SMaciej Machnikowski pin, NULL); 2545885fe693SMaciej Machnikowski if (status) 2546885fe693SMaciej Machnikowski break; 2547885fe693SMaciej Machnikowski } 2548885fe693SMaciej Machnikowski 2549885fe693SMaciej Machnikowski return status; 2550885fe693SMaciej Machnikowski } 2551885fe693SMaciej Machnikowski 2552885fe693SMaciej Machnikowski /** 2553885fe693SMaciej Machnikowski * ice_is_pca9575_present 2554885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 2555885fe693SMaciej Machnikowski * 2556885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 2557885fe693SMaciej Machnikowski */ 2558885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 2559885fe693SMaciej Machnikowski { 2560885fe693SMaciej Machnikowski u16 handle = 0; 2561885fe693SMaciej Machnikowski int status; 2562885fe693SMaciej Machnikowski 2563885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 2564885fe693SMaciej Machnikowski return false; 2565885fe693SMaciej Machnikowski 2566885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 2567885fe693SMaciej Machnikowski 2568885fe693SMaciej Machnikowski return !status && handle; 2569885fe693SMaciej Machnikowski } 2570b2ee7256SJacob Keller 2571b2ee7256SJacob Keller /** 2572b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 2573b2ee7256SJacob Keller * @hw: pointer to the HW struct 2574b2ee7256SJacob Keller * 2575b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 2576b2ee7256SJacob Keller */ 2577b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 2578b2ee7256SJacob Keller { 2579b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 2580b2ee7256SJacob Keller 2581b2ee7256SJacob Keller /* Enable source clocks */ 2582b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 2583b2ee7256SJacob Keller 2584b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 2585b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 2586b2ee7256SJacob Keller 2587*3a749623SJacob Keller if (ice_is_e810(hw)) 2588b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 2589*3a749623SJacob Keller else 2590*3a749623SJacob Keller return ice_ptp_init_phc_e822(hw); 2591b2ee7256SJacob Keller } 2592