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" 603cb4473SJacob Keller 703cb4473SJacob Keller /* Low level functions for interacting with and managing the device clock used 803cb4473SJacob Keller * for the Precision Time Protocol. 903cb4473SJacob Keller * 1003cb4473SJacob Keller * The ice hardware represents the current time using three registers: 1103cb4473SJacob Keller * 1203cb4473SJacob Keller * GLTSYN_TIME_H GLTSYN_TIME_L GLTSYN_TIME_R 1303cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1403cb4473SJacob Keller * | 32 bits | | 32 bits | | 32 bits | 1503cb4473SJacob Keller * +---------------+ +---------------+ +---------------+ 1603cb4473SJacob Keller * 1703cb4473SJacob Keller * The registers are incremented every clock tick using a 40bit increment 1803cb4473SJacob Keller * value defined over two registers: 1903cb4473SJacob Keller * 2003cb4473SJacob Keller * GLTSYN_INCVAL_H GLTSYN_INCVAL_L 2103cb4473SJacob Keller * +---------------+ +---------------+ 2203cb4473SJacob Keller * | 8 bit s | | 32 bits | 2303cb4473SJacob Keller * +---------------+ +---------------+ 2403cb4473SJacob Keller * 2503cb4473SJacob Keller * The increment value is added to the GLSTYN_TIME_R and GLSTYN_TIME_L 2603cb4473SJacob Keller * registers every clock source tick. Depending on the specific device 2703cb4473SJacob Keller * configuration, the clock source frequency could be one of a number of 2803cb4473SJacob Keller * values. 2903cb4473SJacob Keller * 3003cb4473SJacob Keller * For E810 devices, the increment frequency is 812.5 MHz 3103cb4473SJacob Keller * 3203cb4473SJacob Keller * The hardware captures timestamps in the PHY for incoming packets, and for 3303cb4473SJacob Keller * outgoing packets on request. To support this, the PHY maintains a timer 3403cb4473SJacob Keller * that matches the lower 64 bits of the global source timer. 3503cb4473SJacob Keller * 3603cb4473SJacob Keller * In order to ensure that the PHY timers and the source timer are equivalent, 3703cb4473SJacob Keller * shadow registers are used to prepare the desired initial values. A special 3803cb4473SJacob Keller * sync command is issued to trigger copying from the shadow registers into 3903cb4473SJacob Keller * the appropriate source and PHY registers simultaneously. 4003cb4473SJacob Keller */ 4103cb4473SJacob Keller 4203cb4473SJacob Keller /** 4303cb4473SJacob Keller * ice_get_ptp_src_clock_index - determine source clock index 4403cb4473SJacob Keller * @hw: pointer to HW struct 4503cb4473SJacob Keller * 4603cb4473SJacob Keller * Determine the source clock index currently in use, based on device 4703cb4473SJacob Keller * capabilities reported during initialization. 4803cb4473SJacob Keller */ 4903cb4473SJacob Keller u8 ice_get_ptp_src_clock_index(struct ice_hw *hw) 5003cb4473SJacob Keller { 5103cb4473SJacob Keller return hw->func_caps.ts_func_info.tmr_index_assoc; 5203cb4473SJacob Keller } 5303cb4473SJacob Keller 5403cb4473SJacob Keller /* E810 functions 5503cb4473SJacob Keller * 5603cb4473SJacob Keller * The following functions operate on the E810 series devices which use 5703cb4473SJacob Keller * a separate external PHY. 5803cb4473SJacob Keller */ 5903cb4473SJacob Keller 6003cb4473SJacob Keller /** 6103cb4473SJacob Keller * ice_read_phy_reg_e810 - Read register from external PHY on E810 6203cb4473SJacob Keller * @hw: pointer to the HW struct 6303cb4473SJacob Keller * @addr: the address to read from 6403cb4473SJacob Keller * @val: On return, the value read from the PHY 6503cb4473SJacob Keller * 6603cb4473SJacob Keller * Read a register from the external PHY on the E810 device. 6703cb4473SJacob Keller */ 6803cb4473SJacob Keller static int ice_read_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 *val) 6903cb4473SJacob Keller { 7003cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 7139b28106SJacob Keller int err; 7203cb4473SJacob Keller 7303cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 7403cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 7503cb4473SJacob Keller msg.opcode = ice_sbq_msg_rd; 7603cb4473SJacob Keller msg.dest_dev = rmn_0; 7703cb4473SJacob Keller 7839b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 7939b28106SJacob Keller if (err) { 8039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 8139b28106SJacob Keller err); 8239b28106SJacob Keller return err; 8303cb4473SJacob Keller } 8403cb4473SJacob Keller 8503cb4473SJacob Keller *val = msg.data; 8603cb4473SJacob Keller 8703cb4473SJacob Keller return 0; 8803cb4473SJacob Keller } 8903cb4473SJacob Keller 9003cb4473SJacob Keller /** 9103cb4473SJacob Keller * ice_write_phy_reg_e810 - Write register on external PHY on E810 9203cb4473SJacob Keller * @hw: pointer to the HW struct 9303cb4473SJacob Keller * @addr: the address to writem to 9403cb4473SJacob Keller * @val: the value to write to the PHY 9503cb4473SJacob Keller * 9603cb4473SJacob Keller * Write a value to a register of the external PHY on the E810 device. 9703cb4473SJacob Keller */ 9803cb4473SJacob Keller static int ice_write_phy_reg_e810(struct ice_hw *hw, u32 addr, u32 val) 9903cb4473SJacob Keller { 10003cb4473SJacob Keller struct ice_sbq_msg_input msg = {0}; 10139b28106SJacob Keller int err; 10203cb4473SJacob Keller 10303cb4473SJacob Keller msg.msg_addr_low = lower_16_bits(addr); 10403cb4473SJacob Keller msg.msg_addr_high = upper_16_bits(addr); 10503cb4473SJacob Keller msg.opcode = ice_sbq_msg_wr; 10603cb4473SJacob Keller msg.dest_dev = rmn_0; 10703cb4473SJacob Keller msg.data = val; 10803cb4473SJacob Keller 10939b28106SJacob Keller err = ice_sbq_rw_reg(hw, &msg); 11039b28106SJacob Keller if (err) { 11139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to send message to PHY, err %d\n", 11239b28106SJacob Keller err); 11339b28106SJacob Keller return err; 11403cb4473SJacob Keller } 11503cb4473SJacob Keller 11603cb4473SJacob Keller return 0; 11703cb4473SJacob Keller } 11803cb4473SJacob Keller 11903cb4473SJacob Keller /** 12003cb4473SJacob Keller * ice_read_phy_tstamp_e810 - Read a PHY timestamp out of the external PHY 12103cb4473SJacob Keller * @hw: pointer to the HW struct 12203cb4473SJacob Keller * @lport: the lport to read from 12303cb4473SJacob Keller * @idx: the timestamp index to read 12403cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 12503cb4473SJacob Keller * 12603cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block of the external PHY 12703cb4473SJacob Keller * on the E810 device. 12803cb4473SJacob Keller */ 12903cb4473SJacob Keller static int 13003cb4473SJacob Keller ice_read_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx, u64 *tstamp) 13103cb4473SJacob Keller { 13203cb4473SJacob Keller u32 lo_addr, hi_addr, lo, hi; 13339b28106SJacob Keller int err; 13403cb4473SJacob Keller 13503cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 13603cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 13703cb4473SJacob Keller 13839b28106SJacob Keller err = ice_read_phy_reg_e810(hw, lo_addr, &lo); 13939b28106SJacob Keller if (err) { 14039b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n", 14139b28106SJacob Keller err); 14239b28106SJacob Keller return err; 14303cb4473SJacob Keller } 14403cb4473SJacob Keller 14539b28106SJacob Keller err = ice_read_phy_reg_e810(hw, hi_addr, &hi); 14639b28106SJacob Keller if (err) { 14739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n", 14839b28106SJacob Keller err); 14939b28106SJacob Keller return err; 15003cb4473SJacob Keller } 15103cb4473SJacob Keller 15203cb4473SJacob Keller /* For E810 devices, the timestamp is reported with the lower 32 bits 15303cb4473SJacob Keller * in the low register, and the upper 8 bits in the high register. 15403cb4473SJacob Keller */ 15503cb4473SJacob Keller *tstamp = ((u64)hi) << TS_HIGH_S | ((u64)lo & TS_LOW_M); 15603cb4473SJacob Keller 15703cb4473SJacob Keller return 0; 15803cb4473SJacob Keller } 15903cb4473SJacob Keller 16003cb4473SJacob Keller /** 16103cb4473SJacob Keller * ice_clear_phy_tstamp_e810 - Clear a timestamp from the external PHY 16203cb4473SJacob Keller * @hw: pointer to the HW struct 16303cb4473SJacob Keller * @lport: the lport to read from 16403cb4473SJacob Keller * @idx: the timestamp index to reset 16503cb4473SJacob Keller * 16603cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block of the 16703cb4473SJacob Keller * external PHY on the E810 device. 16803cb4473SJacob Keller */ 16903cb4473SJacob Keller static int ice_clear_phy_tstamp_e810(struct ice_hw *hw, u8 lport, u8 idx) 17003cb4473SJacob Keller { 17103cb4473SJacob Keller u32 lo_addr, hi_addr; 17239b28106SJacob Keller int err; 17303cb4473SJacob Keller 17403cb4473SJacob Keller lo_addr = TS_EXT(LOW_TX_MEMORY_BANK_START, lport, idx); 17503cb4473SJacob Keller hi_addr = TS_EXT(HIGH_TX_MEMORY_BANK_START, lport, idx); 17603cb4473SJacob Keller 17739b28106SJacob Keller err = ice_write_phy_reg_e810(hw, lo_addr, 0); 17839b28106SJacob Keller if (err) { 17939b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear low PTP timestamp register, err %d\n", 18039b28106SJacob Keller err); 18139b28106SJacob Keller return err; 18203cb4473SJacob Keller } 18303cb4473SJacob Keller 18439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, hi_addr, 0); 18539b28106SJacob Keller if (err) { 18639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to clear high PTP timestamp register, err %d\n", 18739b28106SJacob Keller err); 18839b28106SJacob Keller return err; 18903cb4473SJacob Keller } 19003cb4473SJacob Keller 19103cb4473SJacob Keller return 0; 19203cb4473SJacob Keller } 19303cb4473SJacob Keller 19403cb4473SJacob Keller /** 19503cb4473SJacob Keller * ice_ptp_init_phy_e810 - Enable PTP function on the external PHY 19603cb4473SJacob Keller * @hw: pointer to HW struct 19703cb4473SJacob Keller * 19803cb4473SJacob Keller * Enable the timesync PTP functionality for the external PHY connected to 19903cb4473SJacob Keller * this function. 20003cb4473SJacob Keller */ 20103cb4473SJacob Keller int ice_ptp_init_phy_e810(struct ice_hw *hw) 20203cb4473SJacob Keller { 20303cb4473SJacob Keller u8 tmr_idx; 20439b28106SJacob Keller int err; 20503cb4473SJacob Keller 20603cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 20739b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_ENA(tmr_idx), 20803cb4473SJacob Keller GLTSYN_ENA_TSYN_ENA_M); 20939b28106SJacob Keller if (err) 21003cb4473SJacob Keller ice_debug(hw, ICE_DBG_PTP, "PTP failed in ena_phy_time_syn %d\n", 21139b28106SJacob Keller err); 21203cb4473SJacob Keller 21339b28106SJacob Keller return err; 21403cb4473SJacob Keller } 21503cb4473SJacob Keller 21603cb4473SJacob Keller /** 217*b2ee7256SJacob Keller * ice_ptp_init_phc_e810 - Perform E810 specific PHC initialization 218*b2ee7256SJacob Keller * @hw: pointer to HW struct 219*b2ee7256SJacob Keller * 220*b2ee7256SJacob Keller * Perform E810-specific PTP hardware clock initialization steps. 221*b2ee7256SJacob Keller */ 222*b2ee7256SJacob Keller static int ice_ptp_init_phc_e810(struct ice_hw *hw) 223*b2ee7256SJacob Keller { 224*b2ee7256SJacob Keller /* Ensure synchronization delay is zero */ 225*b2ee7256SJacob Keller wr32(hw, GLTSYN_SYNC_DLAY, 0); 226*b2ee7256SJacob Keller 227*b2ee7256SJacob Keller /* Initialize the PHY */ 228*b2ee7256SJacob Keller return ice_ptp_init_phy_e810(hw); 229*b2ee7256SJacob Keller } 230*b2ee7256SJacob Keller 231*b2ee7256SJacob Keller /** 23203cb4473SJacob Keller * ice_ptp_prep_phy_time_e810 - Prepare PHY port with initial time 23303cb4473SJacob Keller * @hw: Board private structure 23403cb4473SJacob Keller * @time: Time to initialize the PHY port clock to 23503cb4473SJacob Keller * 23603cb4473SJacob Keller * Program the PHY port ETH_GLTSYN_SHTIME registers in preparation setting the 23703cb4473SJacob Keller * initial clock time. The time will not actually be programmed until the 23803cb4473SJacob Keller * driver issues an INIT_TIME command. 23903cb4473SJacob Keller * 24003cb4473SJacob Keller * The time value is the upper 32 bits of the PHY timer, usually in units of 24103cb4473SJacob Keller * nominal nanoseconds. 24203cb4473SJacob Keller */ 24303cb4473SJacob Keller static int ice_ptp_prep_phy_time_e810(struct ice_hw *hw, u32 time) 24403cb4473SJacob Keller { 24503cb4473SJacob Keller u8 tmr_idx; 24639b28106SJacob Keller int err; 24703cb4473SJacob Keller 24803cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 24939b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_0(tmr_idx), 0); 25039b28106SJacob Keller if (err) { 25139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_0, err %d\n", 25239b28106SJacob Keller err); 25339b28106SJacob Keller return err; 25403cb4473SJacob Keller } 25503cb4473SJacob Keller 25639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHTIME_L(tmr_idx), time); 25739b28106SJacob Keller if (err) { 25839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write SHTIME_L, err %d\n", 25939b28106SJacob Keller err); 26039b28106SJacob Keller return err; 26103cb4473SJacob Keller } 26203cb4473SJacob Keller 26303cb4473SJacob Keller return 0; 26403cb4473SJacob Keller } 26503cb4473SJacob Keller 26603cb4473SJacob Keller /** 26703cb4473SJacob Keller * ice_ptp_prep_phy_adj_e810 - Prep PHY port for a time adjustment 26803cb4473SJacob Keller * @hw: pointer to HW struct 26903cb4473SJacob Keller * @adj: adjustment value to program 27003cb4473SJacob Keller * 27103cb4473SJacob Keller * Prepare the PHY port for an atomic adjustment by programming the PHY 27203cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual adjustment 27303cb4473SJacob Keller * is completed by issuing an ADJ_TIME sync command. 27403cb4473SJacob Keller * 27503cb4473SJacob Keller * The adjustment value only contains the portion used for the upper 32bits of 27603cb4473SJacob Keller * the PHY timer, usually in units of nominal nanoseconds. Negative 27703cb4473SJacob Keller * adjustments are supported using 2s complement arithmetic. 27803cb4473SJacob Keller */ 27903cb4473SJacob Keller static int ice_ptp_prep_phy_adj_e810(struct ice_hw *hw, s32 adj) 28003cb4473SJacob Keller { 28103cb4473SJacob Keller u8 tmr_idx; 28239b28106SJacob Keller int err; 28303cb4473SJacob Keller 28403cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 28503cb4473SJacob Keller 28603cb4473SJacob Keller /* Adjustments are represented as signed 2's complement values in 28703cb4473SJacob Keller * nanoseconds. Sub-nanosecond adjustment is not supported. 28803cb4473SJacob Keller */ 28939b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), 0); 29039b28106SJacob Keller if (err) { 29139b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_L, err %d\n", 29239b28106SJacob Keller err); 29339b28106SJacob Keller return err; 29403cb4473SJacob Keller } 29503cb4473SJacob Keller 29639b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), adj); 29739b28106SJacob Keller if (err) { 29839b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write adj to PHY SHADJ_H, err %d\n", 29939b28106SJacob Keller err); 30039b28106SJacob Keller return err; 30103cb4473SJacob Keller } 30203cb4473SJacob Keller 30303cb4473SJacob Keller return 0; 30403cb4473SJacob Keller } 30503cb4473SJacob Keller 30603cb4473SJacob Keller /** 30703cb4473SJacob Keller * ice_ptp_prep_phy_incval_e810 - Prep PHY port increment value change 30803cb4473SJacob Keller * @hw: pointer to HW struct 30903cb4473SJacob Keller * @incval: The new 40bit increment value to prepare 31003cb4473SJacob Keller * 31103cb4473SJacob Keller * Prepare the PHY port for a new increment value by programming the PHY 31203cb4473SJacob Keller * ETH_GLTSYN_SHADJ_L and ETH_GLTSYN_SHADJ_H registers. The actual change is 31303cb4473SJacob Keller * completed by issuing an INIT_INCVAL command. 31403cb4473SJacob Keller */ 31503cb4473SJacob Keller static int ice_ptp_prep_phy_incval_e810(struct ice_hw *hw, u64 incval) 31603cb4473SJacob Keller { 31703cb4473SJacob Keller u32 high, low; 31803cb4473SJacob Keller u8 tmr_idx; 31939b28106SJacob Keller int err; 32003cb4473SJacob Keller 32103cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 32203cb4473SJacob Keller low = lower_32_bits(incval); 32303cb4473SJacob Keller high = upper_32_bits(incval); 32403cb4473SJacob Keller 32539b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_L(tmr_idx), low); 32639b28106SJacob Keller if (err) { 32739b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval to PHY SHADJ_L, err %d\n", 32839b28106SJacob Keller err); 32939b28106SJacob Keller return err; 33003cb4473SJacob Keller } 33103cb4473SJacob Keller 33239b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_SHADJ_H(tmr_idx), high); 33339b28106SJacob Keller if (err) { 33439b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write incval PHY SHADJ_H, err %d\n", 33539b28106SJacob Keller err); 33639b28106SJacob Keller return err; 33703cb4473SJacob Keller } 33803cb4473SJacob Keller 33903cb4473SJacob Keller return 0; 34003cb4473SJacob Keller } 34103cb4473SJacob Keller 34203cb4473SJacob Keller /** 34303cb4473SJacob Keller * ice_ptp_port_cmd_e810 - Prepare all external PHYs for a timer command 34403cb4473SJacob Keller * @hw: pointer to HW struct 34503cb4473SJacob Keller * @cmd: Command to be sent to the port 34603cb4473SJacob Keller * 34703cb4473SJacob Keller * Prepare the external PHYs connected to this device for a timer sync 34803cb4473SJacob Keller * command. 34903cb4473SJacob Keller */ 35003cb4473SJacob Keller static int ice_ptp_port_cmd_e810(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 35103cb4473SJacob Keller { 35203cb4473SJacob Keller u32 cmd_val, val; 35339b28106SJacob Keller int err; 35403cb4473SJacob Keller 35503cb4473SJacob Keller switch (cmd) { 35603cb4473SJacob Keller case INIT_TIME: 35703cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_TIME; 35803cb4473SJacob Keller break; 35903cb4473SJacob Keller case INIT_INCVAL: 36003cb4473SJacob Keller cmd_val = GLTSYN_CMD_INIT_INCVAL; 36103cb4473SJacob Keller break; 36203cb4473SJacob Keller case ADJ_TIME: 36303cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_TIME; 36403cb4473SJacob Keller break; 36503cb4473SJacob Keller case READ_TIME: 36603cb4473SJacob Keller cmd_val = GLTSYN_CMD_READ_TIME; 36703cb4473SJacob Keller break; 36803cb4473SJacob Keller case ADJ_TIME_AT_TIME: 36903cb4473SJacob Keller cmd_val = GLTSYN_CMD_ADJ_INIT_TIME; 37003cb4473SJacob Keller break; 37103cb4473SJacob Keller } 37203cb4473SJacob Keller 37303cb4473SJacob Keller /* Read, modify, write */ 37439b28106SJacob Keller err = ice_read_phy_reg_e810(hw, ETH_GLTSYN_CMD, &val); 37539b28106SJacob Keller if (err) { 37639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to read GLTSYN_CMD, err %d\n", err); 37739b28106SJacob Keller return err; 37803cb4473SJacob Keller } 37903cb4473SJacob Keller 38003cb4473SJacob Keller /* Modify necessary bits only and perform write */ 38103cb4473SJacob Keller val &= ~TS_CMD_MASK_E810; 38203cb4473SJacob Keller val |= cmd_val; 38303cb4473SJacob Keller 38439b28106SJacob Keller err = ice_write_phy_reg_e810(hw, ETH_GLTSYN_CMD, val); 38539b28106SJacob Keller if (err) { 38639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to write back GLTSYN_CMD, err %d\n", err); 38739b28106SJacob Keller return err; 38803cb4473SJacob Keller } 38903cb4473SJacob Keller 39003cb4473SJacob Keller return 0; 39103cb4473SJacob Keller } 39203cb4473SJacob Keller 39303cb4473SJacob Keller /* Device agnostic functions 39403cb4473SJacob Keller * 39503cb4473SJacob Keller * The following functions implement useful behavior to hide the differences 39603cb4473SJacob Keller * between E810 and other devices. They call the device-specific 39703cb4473SJacob Keller * implementations where necessary. 39803cb4473SJacob Keller * 39903cb4473SJacob Keller * Currently, the driver only supports E810, but future work will enable 40003cb4473SJacob Keller * support for E822-based devices. 40103cb4473SJacob Keller */ 40203cb4473SJacob Keller 40303cb4473SJacob Keller /** 40403cb4473SJacob Keller * ice_ptp_lock - Acquire PTP global semaphore register lock 40503cb4473SJacob Keller * @hw: pointer to the HW struct 40603cb4473SJacob Keller * 40703cb4473SJacob Keller * Acquire the global PTP hardware semaphore lock. Returns true if the lock 40803cb4473SJacob Keller * was acquired, false otherwise. 40903cb4473SJacob Keller * 41003cb4473SJacob Keller * The PFTSYN_SEM register sets the busy bit on read, returning the previous 41103cb4473SJacob Keller * value. If software sees the busy bit cleared, this means that this function 41203cb4473SJacob Keller * acquired the lock (and the busy bit is now set). If software sees the busy 41303cb4473SJacob Keller * bit set, it means that another function acquired the lock. 41403cb4473SJacob Keller * 41503cb4473SJacob Keller * Software must clear the busy bit with a write to release the lock for other 41603cb4473SJacob Keller * functions when done. 41703cb4473SJacob Keller */ 41803cb4473SJacob Keller bool ice_ptp_lock(struct ice_hw *hw) 41903cb4473SJacob Keller { 42003cb4473SJacob Keller u32 hw_lock; 42103cb4473SJacob Keller int i; 42203cb4473SJacob Keller 42303cb4473SJacob Keller #define MAX_TRIES 5 42403cb4473SJacob Keller 42503cb4473SJacob Keller for (i = 0; i < MAX_TRIES; i++) { 42603cb4473SJacob Keller hw_lock = rd32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id)); 42703cb4473SJacob Keller hw_lock = hw_lock & PFTSYN_SEM_BUSY_M; 428587b839dSColin Ian King if (!hw_lock) 429587b839dSColin Ian King break; 430587b839dSColin Ian King 43103cb4473SJacob Keller /* Somebody is holding the lock */ 43203cb4473SJacob Keller usleep_range(10000, 20000); 43303cb4473SJacob Keller } 43403cb4473SJacob Keller 43503cb4473SJacob Keller return !hw_lock; 43603cb4473SJacob Keller } 43703cb4473SJacob Keller 43803cb4473SJacob Keller /** 43903cb4473SJacob Keller * ice_ptp_unlock - Release PTP global semaphore register lock 44003cb4473SJacob Keller * @hw: pointer to the HW struct 44103cb4473SJacob Keller * 44203cb4473SJacob Keller * Release the global PTP hardware semaphore lock. This is done by writing to 44303cb4473SJacob Keller * the PFTSYN_SEM register. 44403cb4473SJacob Keller */ 44503cb4473SJacob Keller void ice_ptp_unlock(struct ice_hw *hw) 44603cb4473SJacob Keller { 44703cb4473SJacob Keller wr32(hw, PFTSYN_SEM + (PFTSYN_SEM_BYTES * hw->pf_id), 0); 44803cb4473SJacob Keller } 44903cb4473SJacob Keller 45003cb4473SJacob Keller /** 45103cb4473SJacob Keller * ice_ptp_src_cmd - Prepare source timer for a timer command 45203cb4473SJacob Keller * @hw: pointer to HW structure 45303cb4473SJacob Keller * @cmd: Timer command 45403cb4473SJacob Keller * 45503cb4473SJacob Keller * Prepare the source timer for an upcoming timer sync command. 45603cb4473SJacob Keller */ 45703cb4473SJacob Keller static void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 45803cb4473SJacob Keller { 45903cb4473SJacob Keller u32 cmd_val; 46003cb4473SJacob Keller u8 tmr_idx; 46103cb4473SJacob Keller 46203cb4473SJacob Keller tmr_idx = ice_get_ptp_src_clock_index(hw); 46303cb4473SJacob Keller cmd_val = tmr_idx << SEL_CPK_SRC; 46403cb4473SJacob Keller 46503cb4473SJacob Keller switch (cmd) { 46603cb4473SJacob Keller case INIT_TIME: 46703cb4473SJacob Keller cmd_val |= GLTSYN_CMD_INIT_TIME; 46803cb4473SJacob Keller break; 46903cb4473SJacob Keller case INIT_INCVAL: 47003cb4473SJacob Keller cmd_val |= GLTSYN_CMD_INIT_INCVAL; 47103cb4473SJacob Keller break; 47203cb4473SJacob Keller case ADJ_TIME: 47303cb4473SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_TIME; 47403cb4473SJacob Keller break; 47503cb4473SJacob Keller case ADJ_TIME_AT_TIME: 47603cb4473SJacob Keller cmd_val |= GLTSYN_CMD_ADJ_INIT_TIME; 47703cb4473SJacob Keller break; 47803cb4473SJacob Keller case READ_TIME: 47903cb4473SJacob Keller cmd_val |= GLTSYN_CMD_READ_TIME; 48003cb4473SJacob Keller break; 48103cb4473SJacob Keller } 48203cb4473SJacob Keller 48303cb4473SJacob Keller wr32(hw, GLTSYN_CMD, cmd_val); 48403cb4473SJacob Keller } 48503cb4473SJacob Keller 48603cb4473SJacob Keller /** 48703cb4473SJacob Keller * ice_ptp_tmr_cmd - Prepare and trigger a timer sync command 48803cb4473SJacob Keller * @hw: pointer to HW struct 48903cb4473SJacob Keller * @cmd: the command to issue 49003cb4473SJacob Keller * 49103cb4473SJacob Keller * Prepare the source timer and PHY timers and then trigger the requested 49203cb4473SJacob Keller * command. This causes the shadow registers previously written in preparation 49303cb4473SJacob Keller * for the command to be synchronously applied to both the source and PHY 49403cb4473SJacob Keller * timers. 49503cb4473SJacob Keller */ 49603cb4473SJacob Keller static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) 49703cb4473SJacob Keller { 49839b28106SJacob Keller int err; 49903cb4473SJacob Keller 50003cb4473SJacob Keller /* First, prepare the source timer */ 50103cb4473SJacob Keller ice_ptp_src_cmd(hw, cmd); 50203cb4473SJacob Keller 50303cb4473SJacob Keller /* Next, prepare the ports */ 50439b28106SJacob Keller err = ice_ptp_port_cmd_e810(hw, cmd); 50539b28106SJacob Keller if (err) { 50639b28106SJacob Keller ice_debug(hw, ICE_DBG_PTP, "Failed to prepare PHY ports for timer command %u, err %d\n", 50739b28106SJacob Keller cmd, err); 50839b28106SJacob Keller return err; 50903cb4473SJacob Keller } 51003cb4473SJacob Keller 51103cb4473SJacob Keller /* Write the sync command register to drive both source and PHY timer commands 51203cb4473SJacob Keller * synchronously 51303cb4473SJacob Keller */ 51403cb4473SJacob Keller wr32(hw, GLTSYN_CMD_SYNC, SYNC_EXEC_CMD); 51503cb4473SJacob Keller 51603cb4473SJacob Keller return 0; 51703cb4473SJacob Keller } 51803cb4473SJacob Keller 51903cb4473SJacob Keller /** 52003cb4473SJacob Keller * ice_ptp_init_time - Initialize device time to provided value 52103cb4473SJacob Keller * @hw: pointer to HW struct 52203cb4473SJacob Keller * @time: 64bits of time (GLTSYN_TIME_L and GLTSYN_TIME_H) 52303cb4473SJacob Keller * 52403cb4473SJacob Keller * Initialize the device to the specified time provided. This requires a three 52503cb4473SJacob Keller * step process: 52603cb4473SJacob Keller * 52703cb4473SJacob Keller * 1) write the new init time to the source timer shadow registers 52803cb4473SJacob Keller * 2) write the new init time to the PHY timer shadow registers 52903cb4473SJacob Keller * 3) issue an init_time timer command to synchronously switch both the source 53003cb4473SJacob Keller * and port timers to the new init time value at the next clock cycle. 53103cb4473SJacob Keller */ 53203cb4473SJacob Keller int ice_ptp_init_time(struct ice_hw *hw, u64 time) 53303cb4473SJacob Keller { 53403cb4473SJacob Keller u8 tmr_idx; 53539b28106SJacob Keller int err; 53603cb4473SJacob Keller 53703cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 53803cb4473SJacob Keller 53903cb4473SJacob Keller /* Source timers */ 54003cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_L(tmr_idx), lower_32_bits(time)); 54103cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_H(tmr_idx), upper_32_bits(time)); 54203cb4473SJacob Keller wr32(hw, GLTSYN_SHTIME_0(tmr_idx), 0); 54303cb4473SJacob Keller 54403cb4473SJacob Keller /* PHY timers */ 54503cb4473SJacob Keller /* Fill Rx and Tx ports and send msg to PHY */ 54639b28106SJacob Keller err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF); 54739b28106SJacob Keller if (err) 54839b28106SJacob Keller return err; 54903cb4473SJacob Keller 55003cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_TIME); 55103cb4473SJacob Keller } 55203cb4473SJacob Keller 55303cb4473SJacob Keller /** 55403cb4473SJacob Keller * ice_ptp_write_incval - Program PHC with new increment value 55503cb4473SJacob Keller * @hw: pointer to HW struct 55603cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 55703cb4473SJacob Keller * 55803cb4473SJacob Keller * Program the PHC with a new increment value. This requires a three-step 55903cb4473SJacob Keller * process: 56003cb4473SJacob Keller * 56103cb4473SJacob Keller * 1) Write the increment value to the source timer shadow registers 56203cb4473SJacob Keller * 2) Write the increment value to the PHY timer shadow registers 56303cb4473SJacob Keller * 3) Issue an INIT_INCVAL timer command to synchronously switch both the 56403cb4473SJacob Keller * source and port timers to the new increment value at the next clock 56503cb4473SJacob Keller * cycle. 56603cb4473SJacob Keller */ 56703cb4473SJacob Keller int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) 56803cb4473SJacob Keller { 56903cb4473SJacob Keller u8 tmr_idx; 57039b28106SJacob Keller int err; 57103cb4473SJacob Keller 57203cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 57303cb4473SJacob Keller 57403cb4473SJacob Keller /* Shadow Adjust */ 57503cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); 57603cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); 57703cb4473SJacob Keller 57839b28106SJacob Keller err = ice_ptp_prep_phy_incval_e810(hw, incval); 57939b28106SJacob Keller if (err) 58039b28106SJacob Keller return err; 58103cb4473SJacob Keller 58203cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, INIT_INCVAL); 58303cb4473SJacob Keller } 58403cb4473SJacob Keller 58503cb4473SJacob Keller /** 58603cb4473SJacob Keller * ice_ptp_write_incval_locked - Program new incval while holding semaphore 58703cb4473SJacob Keller * @hw: pointer to HW struct 58803cb4473SJacob Keller * @incval: Source timer increment value per clock cycle 58903cb4473SJacob Keller * 59003cb4473SJacob Keller * Program a new PHC incval while holding the PTP semaphore. 59103cb4473SJacob Keller */ 59203cb4473SJacob Keller int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) 59303cb4473SJacob Keller { 59439b28106SJacob Keller int err; 59503cb4473SJacob Keller 59603cb4473SJacob Keller if (!ice_ptp_lock(hw)) 59703cb4473SJacob Keller return -EBUSY; 59803cb4473SJacob Keller 59939b28106SJacob Keller err = ice_ptp_write_incval(hw, incval); 60003cb4473SJacob Keller 60103cb4473SJacob Keller ice_ptp_unlock(hw); 60203cb4473SJacob Keller 60339b28106SJacob Keller return err; 60403cb4473SJacob Keller } 60503cb4473SJacob Keller 60603cb4473SJacob Keller /** 60703cb4473SJacob Keller * ice_ptp_adj_clock - Adjust PHC clock time atomically 60803cb4473SJacob Keller * @hw: pointer to HW struct 60903cb4473SJacob Keller * @adj: Adjustment in nanoseconds 61003cb4473SJacob Keller * 61103cb4473SJacob Keller * Perform an atomic adjustment of the PHC time by the specified number of 61203cb4473SJacob Keller * nanoseconds. This requires a three-step process: 61303cb4473SJacob Keller * 61403cb4473SJacob Keller * 1) Write the adjustment to the source timer shadow registers 61503cb4473SJacob Keller * 2) Write the adjustment to the PHY timer shadow registers 61603cb4473SJacob Keller * 3) Issue an ADJ_TIME timer command to synchronously apply the adjustment to 61703cb4473SJacob Keller * both the source and port timers at the next clock cycle. 61803cb4473SJacob Keller */ 61903cb4473SJacob Keller int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) 62003cb4473SJacob Keller { 62103cb4473SJacob Keller u8 tmr_idx; 62239b28106SJacob Keller int err; 62303cb4473SJacob Keller 62403cb4473SJacob Keller tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; 62503cb4473SJacob Keller 62603cb4473SJacob Keller /* Write the desired clock adjustment into the GLTSYN_SHADJ register. 62703cb4473SJacob Keller * For an ADJ_TIME command, this set of registers represents the value 62803cb4473SJacob Keller * to add to the clock time. It supports subtraction by interpreting 62903cb4473SJacob Keller * the value as a 2's complement integer. 63003cb4473SJacob Keller */ 63103cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); 63203cb4473SJacob Keller wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); 63303cb4473SJacob Keller 63439b28106SJacob Keller err = ice_ptp_prep_phy_adj_e810(hw, adj); 63539b28106SJacob Keller if (err) 63639b28106SJacob Keller return err; 63703cb4473SJacob Keller 63803cb4473SJacob Keller return ice_ptp_tmr_cmd(hw, ADJ_TIME); 63903cb4473SJacob Keller } 64003cb4473SJacob Keller 64103cb4473SJacob Keller /** 64203cb4473SJacob Keller * ice_read_phy_tstamp - Read a PHY timestamp from the timestamo block 64303cb4473SJacob Keller * @hw: pointer to the HW struct 64403cb4473SJacob Keller * @block: the block to read from 64503cb4473SJacob Keller * @idx: the timestamp index to read 64603cb4473SJacob Keller * @tstamp: on return, the 40bit timestamp value 64703cb4473SJacob Keller * 64803cb4473SJacob Keller * Read a 40bit timestamp value out of the timestamp block. 64903cb4473SJacob Keller */ 65003cb4473SJacob Keller int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) 65103cb4473SJacob Keller { 65203cb4473SJacob Keller return ice_read_phy_tstamp_e810(hw, block, idx, tstamp); 65303cb4473SJacob Keller } 65403cb4473SJacob Keller 65503cb4473SJacob Keller /** 65603cb4473SJacob Keller * ice_clear_phy_tstamp - Clear a timestamp from the timestamp block 65703cb4473SJacob Keller * @hw: pointer to the HW struct 65803cb4473SJacob Keller * @block: the block to read from 65903cb4473SJacob Keller * @idx: the timestamp index to reset 66003cb4473SJacob Keller * 66103cb4473SJacob Keller * Clear a timestamp, resetting its valid bit, from the timestamp block. 66203cb4473SJacob Keller */ 66303cb4473SJacob Keller int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) 66403cb4473SJacob Keller { 66503cb4473SJacob Keller return ice_clear_phy_tstamp_e810(hw, block, idx); 66603cb4473SJacob Keller } 667885fe693SMaciej Machnikowski 668885fe693SMaciej Machnikowski /* E810T SMA functions 669885fe693SMaciej Machnikowski * 670885fe693SMaciej Machnikowski * The following functions operate specifically on E810T hardware and are used 671885fe693SMaciej Machnikowski * to access the extended GPIOs available. 672885fe693SMaciej Machnikowski */ 673885fe693SMaciej Machnikowski 674885fe693SMaciej Machnikowski /** 675885fe693SMaciej Machnikowski * ice_get_pca9575_handle 676885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 677885fe693SMaciej Machnikowski * @pca9575_handle: GPIO controller's handle 678885fe693SMaciej Machnikowski * 679885fe693SMaciej Machnikowski * Find and return the GPIO controller's handle in the netlist. 680885fe693SMaciej Machnikowski * When found - the value will be cached in the hw structure and following calls 681885fe693SMaciej Machnikowski * will return cached value 682885fe693SMaciej Machnikowski */ 683885fe693SMaciej Machnikowski static int 684885fe693SMaciej Machnikowski ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) 685885fe693SMaciej Machnikowski { 686885fe693SMaciej Machnikowski struct ice_aqc_get_link_topo *cmd; 687885fe693SMaciej Machnikowski struct ice_aq_desc desc; 688885fe693SMaciej Machnikowski int status; 689885fe693SMaciej Machnikowski u8 idx; 690885fe693SMaciej Machnikowski 691885fe693SMaciej Machnikowski /* If handle was read previously return cached value */ 692885fe693SMaciej Machnikowski if (hw->io_expander_handle) { 693885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 694885fe693SMaciej Machnikowski return 0; 695885fe693SMaciej Machnikowski } 696885fe693SMaciej Machnikowski 697885fe693SMaciej Machnikowski /* If handle was not detected read it from the netlist */ 698885fe693SMaciej Machnikowski cmd = &desc.params.get_link_topo; 699885fe693SMaciej Machnikowski ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_topo); 700885fe693SMaciej Machnikowski 701885fe693SMaciej Machnikowski /* Set node type to GPIO controller */ 702885fe693SMaciej Machnikowski cmd->addr.topo_params.node_type_ctx = 703885fe693SMaciej Machnikowski (ICE_AQC_LINK_TOPO_NODE_TYPE_M & 704885fe693SMaciej Machnikowski ICE_AQC_LINK_TOPO_NODE_TYPE_GPIO_CTRL); 705885fe693SMaciej Machnikowski 706885fe693SMaciej Machnikowski #define SW_PCA9575_SFP_TOPO_IDX 2 707885fe693SMaciej Machnikowski #define SW_PCA9575_QSFP_TOPO_IDX 1 708885fe693SMaciej Machnikowski 709885fe693SMaciej Machnikowski /* Check if the SW IO expander controlling SMA exists in the netlist. */ 710885fe693SMaciej Machnikowski if (hw->device_id == ICE_DEV_ID_E810C_SFP) 711885fe693SMaciej Machnikowski idx = SW_PCA9575_SFP_TOPO_IDX; 712885fe693SMaciej Machnikowski else if (hw->device_id == ICE_DEV_ID_E810C_QSFP) 713885fe693SMaciej Machnikowski idx = SW_PCA9575_QSFP_TOPO_IDX; 714885fe693SMaciej Machnikowski else 715885fe693SMaciej Machnikowski return -EOPNOTSUPP; 716885fe693SMaciej Machnikowski 717885fe693SMaciej Machnikowski cmd->addr.topo_params.index = idx; 718885fe693SMaciej Machnikowski 719885fe693SMaciej Machnikowski status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); 720885fe693SMaciej Machnikowski if (status) 721885fe693SMaciej Machnikowski return -EOPNOTSUPP; 722885fe693SMaciej Machnikowski 723885fe693SMaciej Machnikowski /* Verify if we found the right IO expander type */ 724885fe693SMaciej Machnikowski if (desc.params.get_link_topo.node_part_num != 725885fe693SMaciej Machnikowski ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575) 726885fe693SMaciej Machnikowski return -EOPNOTSUPP; 727885fe693SMaciej Machnikowski 728885fe693SMaciej Machnikowski /* If present save the handle and return it */ 729885fe693SMaciej Machnikowski hw->io_expander_handle = 730885fe693SMaciej Machnikowski le16_to_cpu(desc.params.get_link_topo.addr.handle); 731885fe693SMaciej Machnikowski *pca9575_handle = hw->io_expander_handle; 732885fe693SMaciej Machnikowski 733885fe693SMaciej Machnikowski return 0; 734885fe693SMaciej Machnikowski } 735885fe693SMaciej Machnikowski 736885fe693SMaciej Machnikowski /** 737885fe693SMaciej Machnikowski * ice_read_sma_ctrl_e810t 738885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 739885fe693SMaciej Machnikowski * @data: pointer to data to be read from the GPIO controller 740885fe693SMaciej Machnikowski * 741885fe693SMaciej Machnikowski * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the 742885fe693SMaciej Machnikowski * PCA9575 expander, so only bits 3-7 in data are valid. 743885fe693SMaciej Machnikowski */ 744885fe693SMaciej Machnikowski int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) 745885fe693SMaciej Machnikowski { 746885fe693SMaciej Machnikowski int status; 747885fe693SMaciej Machnikowski u16 handle; 748885fe693SMaciej Machnikowski u8 i; 749885fe693SMaciej Machnikowski 750885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 751885fe693SMaciej Machnikowski if (status) 752885fe693SMaciej Machnikowski return status; 753885fe693SMaciej Machnikowski 754885fe693SMaciej Machnikowski *data = 0; 755885fe693SMaciej Machnikowski 756885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 757885fe693SMaciej Machnikowski bool pin; 758885fe693SMaciej Machnikowski 759885fe693SMaciej Machnikowski status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 760885fe693SMaciej Machnikowski &pin, NULL); 761885fe693SMaciej Machnikowski if (status) 762885fe693SMaciej Machnikowski break; 763885fe693SMaciej Machnikowski *data |= (u8)(!pin) << i; 764885fe693SMaciej Machnikowski } 765885fe693SMaciej Machnikowski 766885fe693SMaciej Machnikowski return status; 767885fe693SMaciej Machnikowski } 768885fe693SMaciej Machnikowski 769885fe693SMaciej Machnikowski /** 770885fe693SMaciej Machnikowski * ice_write_sma_ctrl_e810t 771885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 772885fe693SMaciej Machnikowski * @data: data to be written to the GPIO controller 773885fe693SMaciej Machnikowski * 774885fe693SMaciej Machnikowski * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 775885fe693SMaciej Machnikowski * of the PCA9575 expander, so only bits 3-7 in data are valid. 776885fe693SMaciej Machnikowski */ 777885fe693SMaciej Machnikowski int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) 778885fe693SMaciej Machnikowski { 779885fe693SMaciej Machnikowski int status; 780885fe693SMaciej Machnikowski u16 handle; 781885fe693SMaciej Machnikowski u8 i; 782885fe693SMaciej Machnikowski 783885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 784885fe693SMaciej Machnikowski if (status) 785885fe693SMaciej Machnikowski return status; 786885fe693SMaciej Machnikowski 787885fe693SMaciej Machnikowski for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { 788885fe693SMaciej Machnikowski bool pin; 789885fe693SMaciej Machnikowski 790885fe693SMaciej Machnikowski pin = !(data & (1 << i)); 791885fe693SMaciej Machnikowski status = ice_aq_set_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, 792885fe693SMaciej Machnikowski pin, NULL); 793885fe693SMaciej Machnikowski if (status) 794885fe693SMaciej Machnikowski break; 795885fe693SMaciej Machnikowski } 796885fe693SMaciej Machnikowski 797885fe693SMaciej Machnikowski return status; 798885fe693SMaciej Machnikowski } 799885fe693SMaciej Machnikowski 800885fe693SMaciej Machnikowski /** 801885fe693SMaciej Machnikowski * ice_is_pca9575_present 802885fe693SMaciej Machnikowski * @hw: pointer to the hw struct 803885fe693SMaciej Machnikowski * 804885fe693SMaciej Machnikowski * Check if the SW IO expander is present in the netlist 805885fe693SMaciej Machnikowski */ 806885fe693SMaciej Machnikowski bool ice_is_pca9575_present(struct ice_hw *hw) 807885fe693SMaciej Machnikowski { 808885fe693SMaciej Machnikowski u16 handle = 0; 809885fe693SMaciej Machnikowski int status; 810885fe693SMaciej Machnikowski 811885fe693SMaciej Machnikowski if (!ice_is_e810t(hw)) 812885fe693SMaciej Machnikowski return false; 813885fe693SMaciej Machnikowski 814885fe693SMaciej Machnikowski status = ice_get_pca9575_handle(hw, &handle); 815885fe693SMaciej Machnikowski 816885fe693SMaciej Machnikowski return !status && handle; 817885fe693SMaciej Machnikowski } 818*b2ee7256SJacob Keller 819*b2ee7256SJacob Keller /** 820*b2ee7256SJacob Keller * ice_ptp_init_phc - Initialize PTP hardware clock 821*b2ee7256SJacob Keller * @hw: pointer to the HW struct 822*b2ee7256SJacob Keller * 823*b2ee7256SJacob Keller * Perform the steps required to initialize the PTP hardware clock. 824*b2ee7256SJacob Keller */ 825*b2ee7256SJacob Keller int ice_ptp_init_phc(struct ice_hw *hw) 826*b2ee7256SJacob Keller { 827*b2ee7256SJacob Keller u8 src_idx = hw->func_caps.ts_func_info.tmr_index_owned; 828*b2ee7256SJacob Keller 829*b2ee7256SJacob Keller /* Enable source clocks */ 830*b2ee7256SJacob Keller wr32(hw, GLTSYN_ENA(src_idx), GLTSYN_ENA_TSYN_ENA_M); 831*b2ee7256SJacob Keller 832*b2ee7256SJacob Keller /* Clear event err indications for auxiliary pins */ 833*b2ee7256SJacob Keller (void)rd32(hw, GLTSYN_STAT(src_idx)); 834*b2ee7256SJacob Keller 835*b2ee7256SJacob Keller return ice_ptp_init_phc_e810(hw); 836*b2ee7256SJacob Keller } 837