ice: implement basic E822 PTP support

Implement support for the basic operations needed to enable the PTP
hardware clock on E822 devices.

This includes implementations for the various PHY access functions, as
well as the ability to start and stop the PHY timers. This is different
from the E810 device because the configuration depends on link speed, so
we cannot just start the PHYs immediately. We must wait until the link
is up to get proper values for the speed based initialization.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Gurucharan G <gurucharanx.g@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
Jacob Keller 2021-10-13 08:54:51 -07:00 committed by Tony Nguyen
parent 405efa49b5
commit 3a7496234d
7 changed files with 2742 additions and 70 deletions

View file

@ -100,6 +100,7 @@
#define PF_SB_ATQT 0x0022FE00
#define PF_SB_ATQT_ATQT_S 0
#define PF_SB_ATQT_ATQT_M ICE_M(0x3FF, 0)
#define PF_SB_REM_DEV_CTL 0x002300F0
#define PRTDCB_GENC 0x00083000
#define PRTDCB_GENC_PFCLDA_S 16
#define PRTDCB_GENC_PFCLDA_M ICE_M(0xFFFF, 16)

View file

@ -1063,6 +1063,9 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up,
if (link_up == old_link && link_speed == old_link_speed)
return 0;
if (!ice_is_e810(&pf->hw))
ice_ptp_link_change(pf, pf->hw.pf_id, link_up);
if (ice_is_dcb_active(pf)) {
if (test_bit(ICE_FLAG_DCB_ENA, pf->flags))
ice_dcb_rebuild(pf);
@ -5839,6 +5842,8 @@ static int ice_up_complete(struct ice_vsi *vsi)
ice_print_link_msg(vsi, true);
netif_tx_start_all_queues(vsi->netdev);
netif_carrier_on(vsi->netdev);
if (!ice_is_e810(&pf->hw))
ice_ptp_link_change(pf, pf->hw.pf_id, true);
}
/* clear this now, and the first stats read will be used as baseline */
@ -6239,6 +6244,8 @@ int ice_down(struct ice_vsi *vsi)
WARN_ON(!test_bit(ICE_VSI_DOWN, vsi->state));
if (vsi->netdev && vsi->type == ICE_VSI_PF) {
if (!ice_is_e810(&vsi->back->hw))
ice_ptp_link_change(vsi->back, vsi->back->hw.pf_id, false);
netif_carrier_off(vsi->netdev);
netif_tx_disable(vsi->netdev);
} else if (vsi->type == ICE_VSI_SWITCHDEV_CTRL) {

View file

@ -6,6 +6,8 @@
#define E810_OUT_PROP_DELAY_NS 1
#define UNKNOWN_INCVAL_E822 0x100000000ULL
static const struct ptp_pin_desc ice_pin_desc_e810t[] = {
/* name idx func chan */
{ "GNSS", GNSS, PTP_PF_EXTTS, 0, { 0, } },
@ -689,7 +691,200 @@ static int ice_ptp_write_adj(struct ice_pf *pf, s32 adj)
*/
static u64 ice_base_incval(struct ice_pf *pf)
{
return ICE_PTP_NOMINAL_INCVAL_E810;
struct ice_hw *hw = &pf->hw;
u64 incval;
if (ice_is_e810(hw))
incval = ICE_PTP_NOMINAL_INCVAL_E810;
else if (ice_e822_time_ref(hw) < NUM_ICE_TIME_REF_FREQ)
incval = ice_e822_nominal_incval(ice_e822_time_ref(hw));
else
incval = UNKNOWN_INCVAL_E822;
dev_dbg(ice_pf_to_dev(pf), "PTP: using base increment value of 0x%016llx\n",
incval);
return incval;
}
/**
* ice_ptp_reset_ts_memory_quad - Reset timestamp memory for one quad
* @pf: The PF private data structure
* @quad: The quad (0-4)
*/
static void ice_ptp_reset_ts_memory_quad(struct ice_pf *pf, int quad)
{
struct ice_hw *hw = &pf->hw;
ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M);
ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M);
}
/**
* ice_ptp_port_phy_stop - Stop timestamping for a PHY port
* @ptp_port: PTP port to stop
*/
static int
ice_ptp_port_phy_stop(struct ice_ptp_port *ptp_port)
{
struct ice_pf *pf = ptp_port_to_pf(ptp_port);
u8 port = ptp_port->port_num;
struct ice_hw *hw = &pf->hw;
int err;
if (ice_is_e810(hw))
return 0;
mutex_lock(&ptp_port->ps_lock);
err = ice_stop_phy_timer_e822(hw, port, true);
if (err)
dev_err(ice_pf_to_dev(pf), "PTP failed to set PHY port %d down, err %d\n",
port, err);
mutex_unlock(&ptp_port->ps_lock);
return err;
}
/**
* ice_ptp_port_phy_restart - (Re)start and calibrate PHY timestamping
* @ptp_port: PTP port for which the PHY start is set
*
* Start the PHY timestamping block, and initiate Vernier timestamping
* calibration. If timestamping cannot be calibrated (such as if link is down)
* then disable the timestamping block instead.
*/
static int
ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
{
struct ice_pf *pf = ptp_port_to_pf(ptp_port);
u8 port = ptp_port->port_num;
struct ice_hw *hw = &pf->hw;
int err;
if (ice_is_e810(hw))
return 0;
if (!ptp_port->link_up)
return ice_ptp_port_phy_stop(ptp_port);
mutex_lock(&ptp_port->ps_lock);
/* temporarily disable Tx timestamps while calibrating PHY offset */
ptp_port->tx.calibrating = true;
/* Start the PHY timer in bypass mode */
err = ice_start_phy_timer_e822(hw, port, true);
if (err)
goto out_unlock;
/* Enable Tx timestamps right away */
ptp_port->tx.calibrating = false;
out_unlock:
if (err)
dev_err(ice_pf_to_dev(pf), "PTP failed to set PHY port %d up, err %d\n",
port, err);
mutex_unlock(&ptp_port->ps_lock);
return err;
}
/**
* ice_ptp_link_change - Set or clear port registers for timestamping
* @pf: Board private structure
* @port: Port for which the PHY start is set
* @linkup: Link is up or down
*/
int ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup)
{
struct ice_ptp_port *ptp_port;
if (!test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
return 0;
if (port >= ICE_NUM_EXTERNAL_PORTS)
return -EINVAL;
ptp_port = &pf->ptp.port;
if (ptp_port->port_num != port)
return -EINVAL;
/* Update cached link err for this port immediately */
ptp_port->link_up = linkup;
if (!test_bit(ICE_FLAG_PTP, pf->flags))
/* PTP is not setup */
return -EAGAIN;
return ice_ptp_port_phy_restart(ptp_port);
}
/**
* ice_ptp_reset_ts_memory - Reset timestamp memory for all quads
* @pf: The PF private data structure
*/
static void ice_ptp_reset_ts_memory(struct ice_pf *pf)
{
int quad;
quad = pf->hw.port_info->lport / ICE_PORTS_PER_QUAD;
ice_ptp_reset_ts_memory_quad(pf, quad);
}
/**
* ice_ptp_tx_ena_intr - Enable or disable the Tx timestamp interrupt
* @pf: PF private structure
* @ena: bool value to enable or disable interrupt
* @threshold: Minimum number of packets at which intr is triggered
*
* Utility function to enable or disable Tx timestamp interrupt and threshold
*/
static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold)
{
struct ice_hw *hw = &pf->hw;
int err = 0;
int quad;
u32 val;
ice_ptp_reset_ts_memory(pf);
for (quad = 0; quad < ICE_MAX_QUAD; quad++) {
err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG,
&val);
if (err)
break;
if (ena) {
val |= Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M;
val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_THR_M;
val |= ((threshold << Q_REG_TX_MEM_GBL_CFG_INTR_THR_S) &
Q_REG_TX_MEM_GBL_CFG_INTR_THR_M);
} else {
val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M;
}
err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG,
val);
if (err)
break;
}
if (err)
dev_err(ice_pf_to_dev(pf), "PTP failed in intr ena, err %d\n",
err);
return err;
}
/**
* ice_ptp_reset_phy_timestamping - Reset PHY timestamping block
* @pf: Board private structure
*/
static void ice_ptp_reset_phy_timestamping(struct ice_pf *pf)
{
ice_ptp_port_phy_restart(&pf->ptp.port);
}
/**
@ -916,7 +1111,10 @@ static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan,
start_time = div64_u64(current_time + NSEC_PER_SEC - 1,
NSEC_PER_SEC) * NSEC_PER_SEC + phase;
start_time -= E810_OUT_PROP_DELAY_NS;
if (ice_is_e810(hw))
start_time -= E810_OUT_PROP_DELAY_NS;
else
start_time -= ice_e822_pps_delay(ice_e822_time_ref(hw));
/* 2. Write TARGET time */
wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start_time));
@ -1099,6 +1297,12 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts)
struct ice_hw *hw = &pf->hw;
int err;
/* For Vernier mode, we need to recalibrate after new settime
* Start with disabling timestamp block
*/
if (pf->ptp.port.link_up)
ice_ptp_port_phy_stop(&pf->ptp.port);
if (!ice_ptp_lock(hw)) {
err = -EBUSY;
goto exit;
@ -1115,6 +1319,10 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts)
/* Reenable periodic outputs */
ice_ptp_enable_all_clkout(pf);
/* Recalibrate and re-enable timestamp block */
if (pf->ptp.port.link_up)
ice_ptp_port_phy_restart(&pf->ptp.port);
exit:
if (err) {
dev_err(ice_pf_to_dev(pf), "PTP failed to set time %d\n", err);
@ -1447,7 +1655,8 @@ static void ice_ptp_set_caps(struct ice_pf *pf)
info->gettimex64 = ice_ptp_gettimex64;
info->settime64 = ice_ptp_settime64;
ice_ptp_set_funcs_e810(pf, info);
if (ice_is_e810(&pf->hw))
ice_ptp_set_funcs_e810(pf, info);
}
/**
@ -1594,7 +1803,7 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
u8 idx;
/* Check if this tracker is initialized */
if (!tx->init)
if (!tx->init || tx->calibrating)
return -1;
spin_lock(&tx->lock);
@ -1716,6 +1925,27 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
tx->len = 0;
}
/**
* ice_ptp_init_tx_e822 - Initialize tracking for Tx timestamps
* @pf: Board private structure
* @tx: the Tx tracking structure to initialize
* @port: the port this structure tracks
*
* Initialize the Tx timestamp tracker for this port. For generic MAC devices,
* the timestamp block is shared for all ports in the same quad. To avoid
* ports using the same timestamp index, logically break the block of
* registers into chunks based on the port number.
*/
static int
ice_ptp_init_tx_e822(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port)
{
tx->quad = port / ICE_PORTS_PER_QUAD;
tx->quad_offset = tx->quad * INDEX_PER_PORT;
tx->len = INDEX_PER_PORT;
return ice_ptp_alloc_tx_tracker(tx);
}
/**
* ice_ptp_init_tx_e810 - Initialize tracking for Tx timestamps
* @pf: Board private structure
@ -1795,14 +2025,14 @@ void ice_ptp_reset(struct ice_pf *pf)
struct ice_ptp *ptp = &pf->ptp;
struct ice_hw *hw = &pf->hw;
struct timespec64 ts;
int err, itr = 1;
u64 time_diff;
int err = 1;
if (test_bit(ICE_PFR_REQ, pf->state))
goto pfr;
if (!hw->func_caps.ts_func_info.src_tmr_owned)
goto pfr;
goto reset_ts;
err = ice_ptp_init_phc(hw);
if (err)
@ -1840,10 +2070,24 @@ void ice_ptp_reset(struct ice_pf *pf)
/* Release the global hardware lock */
ice_ptp_unlock(hw);
if (!ice_is_e810(hw)) {
/* Enable quad interrupts */
err = ice_ptp_tx_ena_intr(pf, true, itr);
if (err)
goto err;
}
reset_ts:
/* Restart the PHY timestamping block */
ice_ptp_reset_phy_timestamping(pf);
pfr:
/* Init Tx structures */
if (ice_is_e810(&pf->hw))
err = ice_ptp_init_tx_e810(pf, &ptp->port.tx);
else
err = ice_ptp_init_tx_e822(pf, &ptp->port.tx,
ptp->port.port_num);
if (err)
goto err;
@ -1905,7 +2149,7 @@ static int ice_ptp_init_owner(struct ice_pf *pf)
{
struct ice_hw *hw = &pf->hw;
struct timespec64 ts;
int err;
int err, itr = 1;
err = ice_ptp_init_phc(hw);
if (err) {
@ -1938,6 +2182,13 @@ static int ice_ptp_init_owner(struct ice_pf *pf)
/* Release the global hardware lock */
ice_ptp_unlock(hw);
if (!ice_is_e810(hw)) {
/* Enable quad interrupts */
err = ice_ptp_tx_ena_intr(pf, true, itr);
if (err)
goto err_exit;
}
/* Ensure we have a clock device */
err = ice_ptp_create_clock(pf);
if (err)
@ -1983,6 +2234,21 @@ static int ice_ptp_init_work(struct ice_pf *pf, struct ice_ptp *ptp)
return 0;
}
/**
* ice_ptp_init_port - Initialize PTP port structure
* @pf: Board private structure
* @ptp_port: PTP port structure
*/
static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port)
{
mutex_init(&ptp_port->ps_lock);
if (ice_is_e810(&pf->hw))
return ice_ptp_init_tx_e810(pf, &ptp_port->tx);
return ice_ptp_init_tx_e822(pf, &ptp_port->tx, ptp_port->port_num);
}
/**
* ice_ptp_init - Initialize PTP hardware clock support
* @pf: Board private structure
@ -2001,10 +2267,6 @@ void ice_ptp_init(struct ice_pf *pf)
struct ice_hw *hw = &pf->hw;
int err;
/* PTP is currently only supported on E810 devices */
if (!ice_is_e810(hw))
return;
/* If this function owns the clock hardware, it must allocate and
* configure the PTP clock device to represent it.
*/
@ -2014,10 +2276,14 @@ void ice_ptp_init(struct ice_pf *pf)
goto err;
}
err = ice_ptp_init_tx_e810(pf, &pf->ptp.port.tx);
ptp->port.port_num = hw->pf_id;
err = ice_ptp_init_port(pf, &ptp->port);
if (err)
goto err;
/* Start the PHY timestamping block */
ice_ptp_reset_phy_timestamping(pf);
set_bit(ICE_FLAG_PTP, pf->flags);
err = ice_ptp_init_work(pf, ptp);
if (err)
@ -2057,6 +2323,8 @@ void ice_ptp_release(struct ice_pf *pf)
kthread_cancel_delayed_work_sync(&pf->ptp.work);
ice_ptp_port_phy_stop(&pf->ptp.port);
mutex_destroy(&pf->ptp.port.ps_lock);
if (pf->ptp.kworker) {
kthread_destroy_worker(pf->ptp.kworker);
pf->ptp.kworker = NULL;

View file

@ -82,6 +82,8 @@ struct ice_tx_tstamp {
* @quad_offset: offset into timestamp block of the quad to get the real index
* @len: length of the tstamps and in_use fields.
* @init: if true, the tracker is initialized;
* @calibrating: if true, the PHY is calibrating the Tx offset. During this
* window, timestamps are temporarily disabled.
*/
struct ice_ptp_tx {
struct kthread_work work;
@ -92,6 +94,7 @@ struct ice_ptp_tx {
u8 quad_offset;
u8 len;
u8 init;
u8 calibrating;
};
/* Quad and port information for initializing timestamp blocks */
@ -101,15 +104,20 @@ struct ice_ptp_tx {
/**
* struct ice_ptp_port - data used to initialize an external port for PTP
*
* This structure contains PTP data related to the external ports. Currently
* it is used for tracking the Tx timestamps of a port. In the future this
* structure will also hold information for the E822 port initialization
* logic.
* This structure contains data indicating whether a single external port is
* ready for PTP functionality. It is used to track the port initialization
* and determine when the port's PHY offset is valid.
*
* @tx: Tx timestamp tracking for this port
* @ps_lock: mutex used to protect the overall PTP PHY start procedure
* @link_up: indicates whether the link is up
* @port_num: the port number this structure represents
*/
struct ice_ptp_port {
struct ice_ptp_tx tx;
struct mutex ps_lock; /* protects overall PTP PHY start procedure */
bool link_up;
u8 port_num;
};
#define GLTSYN_TGT_H_IDX_MAX 4
@ -154,9 +162,15 @@ struct ice_ptp {
#define ptp_info_to_pf(i) \
container_of(__ptp_info_to_ptp((i)), struct ice_pf, ptp)
#define PFTSYN_SEM_BYTES 4
#define PTP_SHARED_CLK_IDX_VALID BIT(31)
#define TS_CMD_MASK 0xF
#define SYNC_EXEC_CMD 0x3
#define ICE_PTP_TS_VALID BIT(0)
#define FIFO_EMPTY BIT(2)
#define FIFO_OK 0xFF
#define ICE_PTP_FIFO_NUM_CHECKS 5
/* Per-channel register definitions */
#define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8))
#define GLTSYN_AUX_IN(_chan, _idx) (GLTSYN_AUX_IN_0(_idx) + ((_chan) * 8))
@ -177,6 +191,7 @@ struct ice_ptp {
#define N_PER_OUT_E810T 3
#define N_PER_OUT_E810T_NO_SMA 2
#define N_EXT_TS_E810_NO_SMA 2
#define ETH_GLTSYN_ENA(_i) (0x03000348 + ((_i) * 4))
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
struct ice_pf;
@ -195,6 +210,7 @@ void ice_ptp_reset(struct ice_pf *pf);
void ice_ptp_prepare_for_reset(struct ice_pf *pf);
void ice_ptp_init(struct ice_pf *pf);
void ice_ptp_release(struct ice_pf *pf);
int ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup);
#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
static inline int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr)
{
@ -226,5 +242,7 @@ static inline void ice_ptp_reset(struct ice_pf *pf) { }
static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf) { }
static inline void ice_ptp_init(struct ice_pf *pf) { }
static inline void ice_ptp_release(struct ice_pf *pf) { }
static inline int ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup)
{ return 0; }
#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
#endif /* _ICE_PTP_H_ */

View file

@ -0,0 +1,300 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2018-2021, Intel Corporation. */
#ifndef _ICE_PTP_CONSTS_H_
#define _ICE_PTP_CONSTS_H_
/* Constant definitions related to the hardware clock used for PTP 1588
* features and functionality.
*/
/* Constants defined for the PTP 1588 clock hardware. */
/* struct ice_time_ref_info_e822
*
* E822 hardware can use different sources as the reference for the PTP
* hardware clock. Each clock has different characteristics such as a slightly
* different frequency, etc.
*
* This lookup table defines several constants that depend on the current time
* reference. See the struct ice_time_ref_info_e822 for information about the
* meaning of each constant.
*/
const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ] = {
/* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */
{
/* pll_freq */
823437500, /* 823.4375 MHz PLL */
/* nominal_incval */
0x136e44fabULL,
/* pps_delay */
11,
},
/* ICE_TIME_REF_FREQ_122_880 -> 122.88 MHz */
{
/* pll_freq */
783360000, /* 783.36 MHz */
/* nominal_incval */
0x146cc2177ULL,
/* pps_delay */
12,
},
/* ICE_TIME_REF_FREQ_125_000 -> 125 MHz */
{
/* pll_freq */
796875000, /* 796.875 MHz */
/* nominal_incval */
0x141414141ULL,
/* pps_delay */
12,
},
/* ICE_TIME_REF_FREQ_153_600 -> 153.6 MHz */
{
/* pll_freq */
816000000, /* 816 MHz */
/* nominal_incval */
0x139b9b9baULL,
/* pps_delay */
12,
},
/* ICE_TIME_REF_FREQ_156_250 -> 156.25 MHz */
{
/* pll_freq */
830078125, /* 830.78125 MHz */
/* nominal_incval */
0x134679aceULL,
/* pps_delay */
11,
},
/* ICE_TIME_REF_FREQ_245_760 -> 245.76 MHz */
{
/* pll_freq */
783360000, /* 783.36 MHz */
/* nominal_incval */
0x146cc2177ULL,
/* pps_delay */
12,
},
};
/* struct ice_vernier_info_e822
*
* E822 hardware calibrates the delay of the timestamp indication from the
* actual packet transmission or reception during the initialization of the
* PHY. To do this, the hardware mechanism uses some conversions between the
* various clocks within the PHY block. This table defines constants used to
* calculate the correct conversion ratios in the PHY registers.
*
* Many of the values relate to the PAR/PCS clock conversion registers. For
* these registers, a value of 0 means that the associated register is not
* used by this link speed, and that the register should be cleared by writing
* 0. Other values specify the clock frequency in Hz.
*/
const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD] = {
/* ICE_PTP_LNK_SPD_1G */
{
/* tx_par_clk */
31250000, /* 31.25 MHz */
/* rx_par_clk */
31250000, /* 31.25 MHz */
/* tx_pcs_clk */
125000000, /* 125 MHz */
/* rx_pcs_clk */
125000000, /* 125 MHz */
/* tx_desk_rsgb_par */
0, /* unused */
/* rx_desk_rsgb_par */
0, /* unused */
/* tx_desk_rsgb_pcs */
0, /* unused */
/* rx_desk_rsgb_pcs */
0, /* unused */
/* tx_fixed_delay */
25140,
/* pmd_adj_divisor */
10000000,
/* rx_fixed_delay */
17372,
},
/* ICE_PTP_LNK_SPD_10G */
{
/* tx_par_clk */
257812500, /* 257.8125 MHz */
/* rx_par_clk */
257812500, /* 257.8125 MHz */
/* tx_pcs_clk */
156250000, /* 156.25 MHz */
/* rx_pcs_clk */
156250000, /* 156.25 MHz */
/* tx_desk_rsgb_par */
0, /* unused */
/* rx_desk_rsgb_par */
0, /* unused */
/* tx_desk_rsgb_pcs */
0, /* unused */
/* rx_desk_rsgb_pcs */
0, /* unused */
/* tx_fixed_delay */
6938,
/* pmd_adj_divisor */
82500000,
/* rx_fixed_delay */
6212,
},
/* ICE_PTP_LNK_SPD_25G */
{
/* tx_par_clk */
644531250, /* 644.53125 MHZ */
/* rx_par_clk */
644531250, /* 644.53125 MHz */
/* tx_pcs_clk */
390625000, /* 390.625 MHz */
/* rx_pcs_clk */
390625000, /* 390.625 MHz */
/* tx_desk_rsgb_par */
0, /* unused */
/* rx_desk_rsgb_par */
0, /* unused */
/* tx_desk_rsgb_pcs */
0, /* unused */
/* rx_desk_rsgb_pcs */
0, /* unused */
/* tx_fixed_delay */
2778,
/* pmd_adj_divisor */
206250000,
/* rx_fixed_delay */
2491,
},
/* ICE_PTP_LNK_SPD_25G_RS */
{
/* tx_par_clk */
0, /* unused */
/* rx_par_clk */
0, /* unused */
/* tx_pcs_clk */
0, /* unused */
/* rx_pcs_clk */
0, /* unused */
/* tx_desk_rsgb_par */
161132812, /* 162.1328125 MHz Reed Solomon gearbox */
/* rx_desk_rsgb_par */
161132812, /* 162.1328125 MHz Reed Solomon gearbox */
/* tx_desk_rsgb_pcs */
97656250, /* 97.62625 MHz Reed Solomon gearbox */
/* rx_desk_rsgb_pcs */
97656250, /* 97.62625 MHz Reed Solomon gearbox */
/* tx_fixed_delay */
3928,
/* pmd_adj_divisor */
206250000,
/* rx_fixed_delay */
29535,
},
/* ICE_PTP_LNK_SPD_40G */
{
/* tx_par_clk */
257812500,
/* rx_par_clk */
257812500,
/* tx_pcs_clk */
156250000, /* 156.25 MHz */
/* rx_pcs_clk */
156250000, /* 156.25 MHz */
/* tx_desk_rsgb_par */
0, /* unused */
/* rx_desk_rsgb_par */
156250000, /* 156.25 MHz deskew clock */
/* tx_desk_rsgb_pcs */
0, /* unused */
/* rx_desk_rsgb_pcs */
156250000, /* 156.25 MHz deskew clock */
/* tx_fixed_delay */
5666,
/* pmd_adj_divisor */
82500000,
/* rx_fixed_delay */
4244,
},
/* ICE_PTP_LNK_SPD_50G */
{
/* tx_par_clk */
644531250, /* 644.53125 MHZ */
/* rx_par_clk */
644531250, /* 644.53125 MHZ */
/* tx_pcs_clk */
390625000, /* 390.625 MHz */
/* rx_pcs_clk */
390625000, /* 390.625 MHz */
/* tx_desk_rsgb_par */
0, /* unused */
/* rx_desk_rsgb_par */
195312500, /* 193.3125 MHz deskew clock */
/* tx_desk_rsgb_pcs */
0, /* unused */
/* rx_desk_rsgb_pcs */
195312500, /* 193.3125 MHz deskew clock */
/* tx_fixed_delay */
2778,
/* pmd_adj_divisor */
206250000,
/* rx_fixed_delay */
2868,
},
/* ICE_PTP_LNK_SPD_50G_RS */
{
/* tx_par_clk */
0, /* unused */
/* rx_par_clk */
644531250, /* 644.53125 MHz */
/* tx_pcs_clk */
0, /* unused */
/* rx_pcs_clk */
644531250, /* 644.53125 MHz */
/* tx_desk_rsgb_par */
322265625, /* 322.265625 MHz Reed Solomon gearbox */
/* rx_desk_rsgb_par */
322265625, /* 322.265625 MHz Reed Solomon gearbox */
/* tx_desk_rsgb_pcs */
644531250, /* 644.53125 MHz Reed Solomon gearbox */
/* rx_desk_rsgb_pcs */
644531250, /* 644.53125 MHz Reed Solomon gearbox */
/* tx_fixed_delay */
2095,
/* pmd_adj_divisor */
206250000,
/* rx_fixed_delay */
14524,
},
/* ICE_PTP_LNK_SPD_100G_RS */
{
/* tx_par_clk */
0, /* unused */
/* rx_par_clk */
644531250, /* 644.53125 MHz */
/* tx_pcs_clk */
0, /* unused */
/* rx_pcs_clk */
644531250, /* 644.53125 MHz */
/* tx_desk_rsgb_par */
644531250, /* 644.53125 MHz Reed Solomon gearbox */
/* rx_desk_rsgb_par */
644531250, /* 644.53125 MHz Reed Solomon gearbox */
/* tx_desk_rsgb_pcs */
644531250, /* 644.53125 MHz Reed Solomon gearbox */
/* rx_desk_rsgb_pcs */
644531250, /* 644.53125 MHz Reed Solomon gearbox */
/* tx_fixed_delay */
1620,
/* pmd_adj_divisor */
206250000,
/* rx_fixed_delay */
7775,
},
};
#endif /* _ICE_PTP_CONSTS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,92 @@ enum ice_ptp_tmr_cmd {
READ_TIME
};
enum ice_ptp_serdes {
ICE_PTP_SERDES_1G,
ICE_PTP_SERDES_10G,
ICE_PTP_SERDES_25G,
ICE_PTP_SERDES_40G,
ICE_PTP_SERDES_50G,
ICE_PTP_SERDES_100G
};
enum ice_ptp_link_spd {
ICE_PTP_LNK_SPD_1G,
ICE_PTP_LNK_SPD_10G,
ICE_PTP_LNK_SPD_25G,
ICE_PTP_LNK_SPD_25G_RS,
ICE_PTP_LNK_SPD_40G,
ICE_PTP_LNK_SPD_50G,
ICE_PTP_LNK_SPD_50G_RS,
ICE_PTP_LNK_SPD_100G_RS,
NUM_ICE_PTP_LNK_SPD /* Must be last */
};
enum ice_ptp_fec_mode {
ICE_PTP_FEC_MODE_NONE,
ICE_PTP_FEC_MODE_CLAUSE74,
ICE_PTP_FEC_MODE_RS_FEC
};
/**
* struct ice_time_ref_info_e822
* @pll_freq: Frequency of PLL that drives timer ticks in Hz
* @nominal_incval: increment to generate nanoseconds in GLTSYN_TIME_L
* @pps_delay: propagation delay of the PPS output signal
*
* Characteristic information for the various TIME_REF sources possible in the
* E822 devices
*/
struct ice_time_ref_info_e822 {
u64 pll_freq;
u64 nominal_incval;
u8 pps_delay;
};
/**
* struct ice_vernier_info_e822
* @tx_par_clk: Frequency used to calculate P_REG_PAR_TX_TUS
* @rx_par_clk: Frequency used to calculate P_REG_PAR_RX_TUS
* @tx_pcs_clk: Frequency used to calculate P_REG_PCS_TX_TUS
* @rx_pcs_clk: Frequency used to calculate P_REG_PCS_RX_TUS
* @tx_desk_rsgb_par: Frequency used to calculate P_REG_DESK_PAR_TX_TUS
* @rx_desk_rsgb_par: Frequency used to calculate P_REG_DESK_PAR_RX_TUS
* @tx_desk_rsgb_pcs: Frequency used to calculate P_REG_DESK_PCS_TX_TUS
* @rx_desk_rsgb_pcs: Frequency used to calculate P_REG_DESK_PCS_RX_TUS
* @tx_fixed_delay: Fixed Tx latency measured in 1/100th nanoseconds
* @pmd_adj_divisor: Divisor used to calculate PDM alignment adjustment
* @rx_fixed_delay: Fixed Rx latency measured in 1/100th nanoseconds
*
* Table of constants used during as part of the Vernier calibration of the Tx
* and Rx timestamps. This includes frequency values used to compute TUs per
* PAR/PCS clock cycle, and static delay values measured during hardware
* design.
*
* Note that some values are not used for all link speeds, and the
* P_REG_DESK_PAR* registers may represent different clock markers at
* different link speeds, either the deskew marker for multi-lane link speeds
* or the Reed Solomon gearbox marker for RS-FEC.
*/
struct ice_vernier_info_e822 {
u32 tx_par_clk;
u32 rx_par_clk;
u32 tx_pcs_clk;
u32 rx_pcs_clk;
u32 tx_desk_rsgb_par;
u32 rx_desk_rsgb_par;
u32 tx_desk_rsgb_pcs;
u32 rx_desk_rsgb_pcs;
u32 tx_fixed_delay;
u32 pmd_adj_divisor;
u32 rx_fixed_delay;
};
/* Table of constants related to possible TIME_REF sources */
extern const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ];
/* Table of constants for Vernier calibration on E822 */
extern const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD];
/* Increment value to generate nanoseconds in the GLTSYN_TIME_L register for
* the E810 devices. Based off of a PLL with an 812.5 MHz frequency.
*/
@ -29,6 +115,57 @@ int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp);
int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx);
int ice_ptp_init_phc(struct ice_hw *hw);
/* E822 family functions */
int ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val);
int ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val);
int ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val);
int ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val);
int ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time);
/**
* ice_e822_time_ref - Get the current TIME_REF from capabilities
* @hw: pointer to the HW structure
*
* Returns the current TIME_REF from the capabilities structure.
*/
static inline enum ice_time_ref_freq ice_e822_time_ref(struct ice_hw *hw)
{
return hw->func_caps.ts_func_info.time_ref;
}
/**
* ice_set_e822_time_ref - Set new TIME_REF
* @hw: pointer to the HW structure
* @time_ref: new TIME_REF to set
*
* Update the TIME_REF in the capabilities structure in response to some
* change, such as an update to the CGU registers.
*/
static inline void
ice_set_e822_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref)
{
hw->func_caps.ts_func_info.time_ref = time_ref;
}
static inline u64 ice_e822_pll_freq(enum ice_time_ref_freq time_ref)
{
return e822_time_ref[time_ref].pll_freq;
}
static inline u64 ice_e822_nominal_incval(enum ice_time_ref_freq time_ref)
{
return e822_time_ref[time_ref].nominal_incval;
}
static inline u64 ice_e822_pps_delay(enum ice_time_ref_freq time_ref)
{
return e822_time_ref[time_ref].pps_delay;
}
/* E822 Vernier calibration functions */
int ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset);
int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port, bool bypass);
/* E810 family functions */
int ice_ptp_init_phy_e810(struct ice_hw *hw);
int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data);
@ -37,19 +174,194 @@ bool ice_is_pca9575_present(struct ice_hw *hw);
#define PFTSYN_SEM_BYTES 4
#define ICE_PTP_CLOCK_INDEX_0 0x00
#define ICE_PTP_CLOCK_INDEX_1 0x01
/* PHY timer commands */
#define SEL_CPK_SRC 8
#define SEL_PHY_SRC 3
/* Time Sync command Definitions */
#define GLTSYN_CMD_INIT_TIME BIT(0)
#define GLTSYN_CMD_INIT_INCVAL BIT(1)
#define GLTSYN_CMD_INIT_TIME_INCVAL (BIT(0) | BIT(1))
#define GLTSYN_CMD_ADJ_TIME BIT(2)
#define GLTSYN_CMD_ADJ_INIT_TIME (BIT(2) | BIT(3))
#define GLTSYN_CMD_READ_TIME BIT(7)
/* PHY port Time Sync command definitions */
#define PHY_CMD_INIT_TIME BIT(0)
#define PHY_CMD_INIT_INCVAL BIT(1)
#define PHY_CMD_ADJ_TIME (BIT(0) | BIT(1))
#define PHY_CMD_ADJ_TIME_AT_TIME (BIT(0) | BIT(2))
#define PHY_CMD_READ_TIME (BIT(0) | BIT(1) | BIT(2))
#define TS_CMD_MASK_E810 0xFF
#define TS_CMD_MASK 0xF
#define SYNC_EXEC_CMD 0x3
/* Macros to derive port low and high addresses on both quads */
#define P_Q0_L(a, p) ((((a) + (0x2000 * (p)))) & 0xFFFF)
#define P_Q0_H(a, p) ((((a) + (0x2000 * (p)))) >> 16)
#define P_Q1_L(a, p) ((((a) - (0x2000 * ((p) - ICE_PORTS_PER_QUAD)))) & 0xFFFF)
#define P_Q1_H(a, p) ((((a) - (0x2000 * ((p) - ICE_PORTS_PER_QUAD)))) >> 16)
/* PHY QUAD register base addresses */
#define Q_0_BASE 0x94000
#define Q_1_BASE 0x114000
/* Timestamp memory reset registers */
#define Q_REG_TS_CTRL 0x618
#define Q_REG_TS_CTRL_S 0
#define Q_REG_TS_CTRL_M BIT(0)
/* Timestamp availability status registers */
#define Q_REG_TX_MEMORY_STATUS_L 0xCF0
#define Q_REG_TX_MEMORY_STATUS_U 0xCF4
/* Tx FIFO status registers */
#define Q_REG_FIFO23_STATUS 0xCF8
#define Q_REG_FIFO01_STATUS 0xCFC
#define Q_REG_FIFO02_S 0
#define Q_REG_FIFO02_M ICE_M(0x3FF, 0)
#define Q_REG_FIFO13_S 10
#define Q_REG_FIFO13_M ICE_M(0x3FF, 10)
/* Interrupt control Config registers */
#define Q_REG_TX_MEM_GBL_CFG 0xC08
#define Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_S 0
#define Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M BIT(0)
#define Q_REG_TX_MEM_GBL_CFG_TX_TYPE_S 1
#define Q_REG_TX_MEM_GBL_CFG_TX_TYPE_M ICE_M(0xFF, 1)
#define Q_REG_TX_MEM_GBL_CFG_INTR_THR_S 9
#define Q_REG_TX_MEM_GBL_CFG_INTR_THR_M ICE_M(0x3F, 9)
#define Q_REG_TX_MEM_GBL_CFG_INTR_ENA_S 15
#define Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M BIT(15)
/* Tx Timestamp data registers */
#define Q_REG_TX_MEMORY_BANK_START 0xA00
/* PHY port register base addresses */
#define P_0_BASE 0x80000
#define P_4_BASE 0x106000
/* Timestamp init registers */
#define P_REG_RX_TIMER_INC_PRE_L 0x46C
#define P_REG_RX_TIMER_INC_PRE_U 0x470
#define P_REG_TX_TIMER_INC_PRE_L 0x44C
#define P_REG_TX_TIMER_INC_PRE_U 0x450
/* Timestamp match and adjust target registers */
#define P_REG_RX_TIMER_CNT_ADJ_L 0x474
#define P_REG_RX_TIMER_CNT_ADJ_U 0x478
#define P_REG_TX_TIMER_CNT_ADJ_L 0x454
#define P_REG_TX_TIMER_CNT_ADJ_U 0x458
/* Timestamp capture registers */
#define P_REG_RX_CAPTURE_L 0x4D8
#define P_REG_RX_CAPTURE_U 0x4DC
#define P_REG_TX_CAPTURE_L 0x4B4
#define P_REG_TX_CAPTURE_U 0x4B8
/* Timestamp PHY incval registers */
#define P_REG_TIMETUS_L 0x410
#define P_REG_TIMETUS_U 0x414
#define P_REG_40B_LOW_M 0xFF
#define P_REG_40B_HIGH_S 8
/* PHY window length registers */
#define P_REG_WL 0x40C
#define PTP_VERNIER_WL 0x111ed
/* PHY start registers */
#define P_REG_PS 0x408
#define P_REG_PS_START_S 0
#define P_REG_PS_START_M BIT(0)
#define P_REG_PS_BYPASS_MODE_S 1
#define P_REG_PS_BYPASS_MODE_M BIT(1)
#define P_REG_PS_ENA_CLK_S 2
#define P_REG_PS_ENA_CLK_M BIT(2)
#define P_REG_PS_LOAD_OFFSET_S 3
#define P_REG_PS_LOAD_OFFSET_M BIT(3)
#define P_REG_PS_SFT_RESET_S 11
#define P_REG_PS_SFT_RESET_M BIT(11)
/* PHY offset valid registers */
#define P_REG_TX_OV_STATUS 0x4D4
#define P_REG_TX_OV_STATUS_OV_S 0
#define P_REG_TX_OV_STATUS_OV_M BIT(0)
#define P_REG_RX_OV_STATUS 0x4F8
#define P_REG_RX_OV_STATUS_OV_S 0
#define P_REG_RX_OV_STATUS_OV_M BIT(0)
/* PHY offset ready registers */
#define P_REG_TX_OR 0x45C
#define P_REG_RX_OR 0x47C
/* PHY total offset registers */
#define P_REG_TOTAL_RX_OFFSET_L 0x460
#define P_REG_TOTAL_RX_OFFSET_U 0x464
#define P_REG_TOTAL_TX_OFFSET_L 0x440
#define P_REG_TOTAL_TX_OFFSET_U 0x444
/* Timestamp PAR/PCS registers */
#define P_REG_UIX66_10G_40G_L 0x480
#define P_REG_UIX66_10G_40G_U 0x484
#define P_REG_UIX66_25G_100G_L 0x488
#define P_REG_UIX66_25G_100G_U 0x48C
#define P_REG_DESK_PAR_RX_TUS_L 0x490
#define P_REG_DESK_PAR_RX_TUS_U 0x494
#define P_REG_DESK_PAR_TX_TUS_L 0x498
#define P_REG_DESK_PAR_TX_TUS_U 0x49C
#define P_REG_DESK_PCS_RX_TUS_L 0x4A0
#define P_REG_DESK_PCS_RX_TUS_U 0x4A4
#define P_REG_DESK_PCS_TX_TUS_L 0x4A8
#define P_REG_DESK_PCS_TX_TUS_U 0x4AC
#define P_REG_PAR_RX_TUS_L 0x420
#define P_REG_PAR_RX_TUS_U 0x424
#define P_REG_PAR_TX_TUS_L 0x428
#define P_REG_PAR_TX_TUS_U 0x42C
#define P_REG_PCS_RX_TUS_L 0x430
#define P_REG_PCS_RX_TUS_U 0x434
#define P_REG_PCS_TX_TUS_L 0x438
#define P_REG_PCS_TX_TUS_U 0x43C
#define P_REG_PAR_RX_TIME_L 0x4F0
#define P_REG_PAR_RX_TIME_U 0x4F4
#define P_REG_PAR_TX_TIME_L 0x4CC
#define P_REG_PAR_TX_TIME_U 0x4D0
#define P_REG_PAR_PCS_RX_OFFSET_L 0x4E8
#define P_REG_PAR_PCS_RX_OFFSET_U 0x4EC
#define P_REG_PAR_PCS_TX_OFFSET_L 0x4C4
#define P_REG_PAR_PCS_TX_OFFSET_U 0x4C8
#define P_REG_LINK_SPEED 0x4FC
#define P_REG_LINK_SPEED_SERDES_S 0
#define P_REG_LINK_SPEED_SERDES_M ICE_M(0x7, 0)
#define P_REG_LINK_SPEED_FEC_MODE_S 3
#define P_REG_LINK_SPEED_FEC_MODE_M ICE_M(0x3, 3)
#define P_REG_LINK_SPEED_FEC_MODE(reg) \
(((reg) & P_REG_LINK_SPEED_FEC_MODE_M) >> \
P_REG_LINK_SPEED_FEC_MODE_S)
/* PHY timestamp related registers */
#define P_REG_PMD_ALIGNMENT 0x0FC
#define P_REG_RX_80_TO_160_CNT 0x6FC
#define P_REG_RX_80_TO_160_CNT_RXCYC_S 0
#define P_REG_RX_80_TO_160_CNT_RXCYC_M BIT(0)
#define P_REG_RX_40_TO_160_CNT 0x8FC
#define P_REG_RX_40_TO_160_CNT_RXCYC_S 0
#define P_REG_RX_40_TO_160_CNT_RXCYC_M ICE_M(0x3, 0)
/* Rx FIFO status registers */
#define P_REG_RX_OV_FS 0x4F8
#define P_REG_RX_OV_FS_FIFO_STATUS_S 2
#define P_REG_RX_OV_FS_FIFO_STATUS_M ICE_M(0x3FF, 2)
/* Timestamp command registers */
#define P_REG_TX_TMR_CMD 0x448
#define P_REG_RX_TMR_CMD 0x468
/* E810 timesync enable register */
#define ETH_GLTSYN_ENA(_i) (0x03000348 + ((_i) * 4))
@ -69,9 +381,20 @@ bool ice_is_pca9575_present(struct ice_hw *hw);
/* Timestamp block macros */
#define TS_LOW_M 0xFFFFFFFF
#define TS_HIGH_M 0xFF
#define TS_HIGH_S 32
#define TS_PHY_LOW_M 0xFF
#define TS_PHY_HIGH_M 0xFFFFFFFF
#define TS_PHY_HIGH_S 8
#define BYTES_PER_IDX_ADDR_L_U 8
#define BYTES_PER_IDX_ADDR_L 4
/* Internal PHY timestamp address */
#define TS_L(a, idx) ((a) + ((idx) * BYTES_PER_IDX_ADDR_L_U))
#define TS_H(a, idx) ((a) + ((idx) * BYTES_PER_IDX_ADDR_L_U + \
BYTES_PER_IDX_ADDR_L))
/* External PHY timestamp address */
#define TS_EXT(a, port, idx) ((a) + (0x1000 * (port)) + \