Commit 341f67e4 authored by Tan Tee Min's avatar Tan Tee Min Committed by David S. Miller
Browse files

net: stmmac: Add hardware supported cross-timestamp



Cross timestamping is supported on Integrated Ethernet Controller in
Intel SoC such as EHL and TGL with Always Running Timer.

The hardware cross-timestamp result is made available to
applications through the PTP_SYS_OFFSET_PRECISE ioctl which calls
stmmac_getcrosststamp().

Device time is stored in the MAC Auxiliary register. The 64-bit System
time (ART timestamp) is stored in registers that are only addressable
by using MDIO space.

Signed-off-by: default avatarTan Tee Min <tee.min.tan@intel.com>
Co-developed-by: default avatarWong Vee Khee <vee.khee.wong@linux.intel.com>
Signed-off-by: default avatarWong Vee Khee <vee.khee.wong@linux.intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bef32aa8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -388,6 +388,8 @@ struct dma_features {
	unsigned int estsel;
	unsigned int fpesel;
	unsigned int tbssel;
	/* Numbers of Auxiliary Snapshot Inputs */
	unsigned int aux_snapshot_n;
};

/* RX Buffer size must be multiple of 4/8/16 bytes */
+108 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "dwmac-intel.h"
#include "dwmac4.h"
#include "stmmac.h"
#include "stmmac_ptp.h"

#define INTEL_MGBE_ADHOC_ADDR	0x15
#define INTEL_MGBE_XPCS_ADDR	0x16
@@ -240,6 +241,108 @@ static void intel_mgbe_ptp_clk_freq_config(void *npriv)
	writel(gpio_value, priv->ioaddr + GMAC_GPIO_STATUS);
}

static void get_arttime(struct mii_bus *mii, int intel_adhoc_addr,
			u64 *art_time)
{
	u64 ns;

	ns = mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE3);
	ns <<= GMAC4_ART_TIME_SHIFT;
	ns |= mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE2);
	ns <<= GMAC4_ART_TIME_SHIFT;
	ns |= mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE1);
	ns <<= GMAC4_ART_TIME_SHIFT;
	ns |= mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE0);

	*art_time = ns;
}

static int intel_crosststamp(ktime_t *device,
			     struct system_counterval_t *system,
			     void *ctx)
{
	struct intel_priv_data *intel_priv;

	struct stmmac_priv *priv = (struct stmmac_priv *)ctx;
	void __iomem *ptpaddr = priv->ptpaddr;
	void __iomem *ioaddr = priv->hw->pcsr;
	unsigned long flags;
	u64 art_time = 0;
	u64 ptp_time = 0;
	u32 num_snapshot;
	u32 gpio_value;
	u32 acr_value;
	int ret;
	u32 v;
	int i;

	if (!boot_cpu_has(X86_FEATURE_ART))
		return -EOPNOTSUPP;

	intel_priv = priv->plat->bsp_priv;

	/* Enable Internal snapshot trigger */
	acr_value = readl(ptpaddr + PTP_ACR);
	acr_value &= ~PTP_ACR_MASK;
	switch (priv->plat->int_snapshot_num) {
	case AUX_SNAPSHOT0:
		acr_value |= PTP_ACR_ATSEN0;
		break;
	case AUX_SNAPSHOT1:
		acr_value |= PTP_ACR_ATSEN1;
		break;
	case AUX_SNAPSHOT2:
		acr_value |= PTP_ACR_ATSEN2;
		break;
	case AUX_SNAPSHOT3:
		acr_value |= PTP_ACR_ATSEN3;
		break;
	default:
		return -EINVAL;
	}
	writel(acr_value, ptpaddr + PTP_ACR);

	/* Clear FIFO */
	acr_value = readl(ptpaddr + PTP_ACR);
	acr_value |= PTP_ACR_ATSFC;
	writel(acr_value, ptpaddr + PTP_ACR);

	/* Trigger Internal snapshot signal
	 * Create a rising edge by just toggle the GPO1 to low
	 * and back to high.
	 */
	gpio_value = readl(ioaddr + GMAC_GPIO_STATUS);
	gpio_value &= ~GMAC_GPO1;
	writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
	gpio_value |= GMAC_GPO1;
	writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);

	/* Poll for time sync operation done */
	ret = readl_poll_timeout(priv->ioaddr + GMAC_INT_STATUS, v,
				 (v & GMAC_INT_TSIE), 100, 10000);

	if (ret == -ETIMEDOUT) {
		pr_err("%s: Wait for time sync operation timeout\n", __func__);
		return ret;
	}

	num_snapshot = (readl(ioaddr + GMAC_TIMESTAMP_STATUS) &
			GMAC_TIMESTAMP_ATSNS_MASK) >>
			GMAC_TIMESTAMP_ATSNS_SHIFT;

	/* Repeat until the timestamps are from the FIFO last segment */
	for (i = 0; i < num_snapshot; i++) {
		spin_lock_irqsave(&priv->ptp_lock, flags);
		stmmac_get_ptptime(priv, ptpaddr, &ptp_time);
		*device = ns_to_ktime(ptp_time);
		spin_unlock_irqrestore(&priv->ptp_lock, flags);
		get_arttime(priv->mii, intel_priv->mdio_adhoc_addr, &art_time);
		*system = convert_art_to_tsc(art_time);
	}

	return 0;
}

static void common_default_data(struct plat_stmmacenet_data *plat)
{
	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
@@ -384,6 +487,11 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
	plat->mdio_bus_data->phy_mask = 1 << INTEL_MGBE_ADHOC_ADDR;
	plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_ADDR;

	plat->int_snapshot_num = AUX_SNAPSHOT1;

	plat->has_crossts = true;
	plat->crosststamp = intel_crosststamp;

	return 0;
}

+8 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@
#define GMAC_L4_ADDR(reg)		(0x904 + (reg) * 0x30)
#define GMAC_L3_ADDR0(reg)		(0x910 + (reg) * 0x30)
#define GMAC_L3_ADDR1(reg)		(0x914 + (reg) * 0x30)
#define GMAC_TIMESTAMP_STATUS		0x00000b20

/* RX Queues Routing */
#define GMAC_RXQCTRL_AVCPQ_MASK		GENMASK(2, 0)
@@ -144,6 +145,7 @@
#define GMAC_INT_PCS_PHYIS		BIT(3)
#define GMAC_INT_PMT_EN			BIT(4)
#define GMAC_INT_LPI_EN			BIT(5)
#define GMAC_INT_TSIE			BIT(12)

#define	GMAC_PCS_IRQ_DEFAULT	(GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK |	\
				 GMAC_INT_PCS_ANE)
@@ -260,6 +262,7 @@ enum power_event {
#define GMAC_HW_RXFIFOSIZE		GENMASK(4, 0)

/* MAC HW features2 bitmap */
#define GMAC_HW_FEAT_AUXSNAPNUM		GENMASK(30, 28)
#define GMAC_HW_FEAT_PPSOUTNUM		GENMASK(26, 24)
#define GMAC_HW_FEAT_TXCHCNT		GENMASK(21, 18)
#define GMAC_HW_FEAT_RXCHCNT		GENMASK(15, 12)
@@ -305,6 +308,11 @@ enum power_event {
#define GMAC_L4DP0_SHIFT		16
#define GMAC_L4SP0			GENMASK(15, 0)

/* MAC Timestamp Status */
#define GMAC_TIMESTAMP_AUXTSTRIG	BIT(2)
#define GMAC_TIMESTAMP_ATSNS_MASK	GENMASK(29, 25)
#define GMAC_TIMESTAMP_ATSNS_SHIFT	25

/*  MTL registers */
#define MTL_OPERATION_MODE		0x00000c00
#define MTL_FRPE			BIT(15)
+2 −0
Original line number Diff line number Diff line
@@ -412,6 +412,8 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,

	/* IEEE 1588-2002 */
	dma_cap->time_stamp = 0;
	/* Number of Auxiliary Snapshot Inputs */
	dma_cap->aux_snapshot_n = (hw_cap & GMAC_HW_FEAT_AUXSNAPNUM) >> 28;

	/* MAC HW feature3 */
	hw_cap = readl(ioaddr + GMAC_HW_FEATURE3);
+3 −0
Original line number Diff line number Diff line
@@ -508,6 +508,7 @@ struct stmmac_hwtimestamp {
	int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
			       int add_sub, int gmac4);
	void (*get_systime) (void __iomem *ioaddr, u64 *systime);
	void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
};

#define stmmac_config_hw_tstamping(__priv, __args...) \
@@ -522,6 +523,8 @@ struct stmmac_hwtimestamp {
	stmmac_do_callback(__priv, ptp, adjust_systime, __args)
#define stmmac_get_systime(__priv, __args...) \
	stmmac_do_void_callback(__priv, ptp, get_systime, __args)
#define stmmac_get_ptptime(__priv, __args...) \
	stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)

/* Helpers to manage the descriptors for chain and ring modes */
struct stmmac_mode_ops {
Loading