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