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

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
...@@ -388,6 +388,8 @@ struct dma_features { ...@@ -388,6 +388,8 @@ struct dma_features {
unsigned int estsel; unsigned int estsel;
unsigned int fpesel; unsigned int fpesel;
unsigned int tbssel; unsigned int tbssel;
/* Numbers of Auxiliary Snapshot Inputs */
unsigned int aux_snapshot_n;
}; };
/* RX Buffer size must be multiple of 4/8/16 bytes */ /* RX Buffer size must be multiple of 4/8/16 bytes */
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "dwmac-intel.h" #include "dwmac-intel.h"
#include "dwmac4.h" #include "dwmac4.h"
#include "stmmac.h" #include "stmmac.h"
#include "stmmac_ptp.h"
#define INTEL_MGBE_ADHOC_ADDR 0x15 #define INTEL_MGBE_ADHOC_ADDR 0x15
#define INTEL_MGBE_XPCS_ADDR 0x16 #define INTEL_MGBE_XPCS_ADDR 0x16
...@@ -240,6 +241,108 @@ static void intel_mgbe_ptp_clk_freq_config(void *npriv) ...@@ -240,6 +241,108 @@ static void intel_mgbe_ptp_clk_freq_config(void *npriv)
writel(gpio_value, priv->ioaddr + GMAC_GPIO_STATUS); 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) static void common_default_data(struct plat_stmmacenet_data *plat)
{ {
plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ 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, ...@@ -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_ADHOC_ADDR;
plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_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; return 0;
} }
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30) #define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30)
#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30) #define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30)
#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30) #define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30)
#define GMAC_TIMESTAMP_STATUS 0x00000b20
/* RX Queues Routing */ /* RX Queues Routing */
#define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0) #define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0)
...@@ -144,6 +145,7 @@ ...@@ -144,6 +145,7 @@
#define GMAC_INT_PCS_PHYIS BIT(3) #define GMAC_INT_PCS_PHYIS BIT(3)
#define GMAC_INT_PMT_EN BIT(4) #define GMAC_INT_PMT_EN BIT(4)
#define GMAC_INT_LPI_EN BIT(5) #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 | \ #define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
GMAC_INT_PCS_ANE) GMAC_INT_PCS_ANE)
...@@ -260,6 +262,7 @@ enum power_event { ...@@ -260,6 +262,7 @@ enum power_event {
#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0) #define GMAC_HW_RXFIFOSIZE GENMASK(4, 0)
/* MAC HW features2 bitmap */ /* MAC HW features2 bitmap */
#define GMAC_HW_FEAT_AUXSNAPNUM GENMASK(30, 28)
#define GMAC_HW_FEAT_PPSOUTNUM GENMASK(26, 24) #define GMAC_HW_FEAT_PPSOUTNUM GENMASK(26, 24)
#define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18) #define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18)
#define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12) #define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12)
...@@ -305,6 +308,11 @@ enum power_event { ...@@ -305,6 +308,11 @@ enum power_event {
#define GMAC_L4DP0_SHIFT 16 #define GMAC_L4DP0_SHIFT 16
#define GMAC_L4SP0 GENMASK(15, 0) #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 */ /* MTL registers */
#define MTL_OPERATION_MODE 0x00000c00 #define MTL_OPERATION_MODE 0x00000c00
#define MTL_FRPE BIT(15) #define MTL_FRPE BIT(15)
......
...@@ -412,6 +412,8 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr, ...@@ -412,6 +412,8 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
/* IEEE 1588-2002 */ /* IEEE 1588-2002 */
dma_cap->time_stamp = 0; 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 */ /* MAC HW feature3 */
hw_cap = readl(ioaddr + GMAC_HW_FEATURE3); hw_cap = readl(ioaddr + GMAC_HW_FEATURE3);
......
...@@ -508,6 +508,7 @@ struct stmmac_hwtimestamp { ...@@ -508,6 +508,7 @@ struct stmmac_hwtimestamp {
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec, int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
int add_sub, int gmac4); int add_sub, int gmac4);
void (*get_systime) (void __iomem *ioaddr, u64 *systime); void (*get_systime) (void __iomem *ioaddr, u64 *systime);
void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
}; };
#define stmmac_config_hw_tstamping(__priv, __args...) \ #define stmmac_config_hw_tstamping(__priv, __args...) \
...@@ -522,6 +523,8 @@ struct stmmac_hwtimestamp { ...@@ -522,6 +523,8 @@ struct stmmac_hwtimestamp {
stmmac_do_callback(__priv, ptp, adjust_systime, __args) stmmac_do_callback(__priv, ptp, adjust_systime, __args)
#define stmmac_get_systime(__priv, __args...) \ #define stmmac_get_systime(__priv, __args...) \
stmmac_do_void_callback(__priv, ptp, get_systime, __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 */ /* Helpers to manage the descriptors for chain and ring modes */
struct stmmac_mode_ops { struct stmmac_mode_ops {
......
...@@ -153,6 +153,16 @@ static void get_systime(void __iomem *ioaddr, u64 *systime) ...@@ -153,6 +153,16 @@ static void get_systime(void __iomem *ioaddr, u64 *systime)
*systime = ns; *systime = ns;
} }
static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
{
u64 ns;
ns = readl(ptpaddr + PTP_ATNR);
ns += readl(ptpaddr + PTP_ATSR) * NSEC_PER_SEC;
*ptp_time = ns;
}
const struct stmmac_hwtimestamp stmmac_ptp = { const struct stmmac_hwtimestamp stmmac_ptp = {
.config_hw_tstamping = config_hw_tstamping, .config_hw_tstamping = config_hw_tstamping,
.init_systime = init_systime, .init_systime = init_systime,
...@@ -160,4 +170,5 @@ const struct stmmac_hwtimestamp stmmac_ptp = { ...@@ -160,4 +170,5 @@ const struct stmmac_hwtimestamp stmmac_ptp = {
.config_addend = config_addend, .config_addend = config_addend,
.adjust_systime = adjust_systime, .adjust_systime = adjust_systime,
.get_systime = get_systime, .get_systime = get_systime,
.get_ptptime = get_ptptime,
}; };
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*******************************************************************************/ *******************************************************************************/
#include "stmmac.h" #include "stmmac.h"
#include "stmmac_ptp.h" #include "stmmac_ptp.h"
#include "dwmac4.h"
/** /**
* stmmac_adjust_freq * stmmac_adjust_freq
...@@ -165,6 +166,36 @@ static int stmmac_enable(struct ptp_clock_info *ptp, ...@@ -165,6 +166,36 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
return ret; return ret;
} }
/**
* stmmac_get_syncdevicetime
* @device: current device time
* @system: system counter value read synchronously with device time
* @ctx: context provided by timekeeping code
* Description: Read device and system clock simultaneously and return the
* corrected clock values in ns.
**/
static int stmmac_get_syncdevicetime(ktime_t *device,
struct system_counterval_t *system,
void *ctx)
{
struct stmmac_priv *priv = (struct stmmac_priv *)ctx;
if (priv->plat->crosststamp)
return priv->plat->crosststamp(device, system, ctx);
else
return -EOPNOTSUPP;
}
static int stmmac_getcrosststamp(struct ptp_clock_info *ptp,
struct system_device_crosststamp *xtstamp)
{
struct stmmac_priv *priv =
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
return get_device_system_crosststamp(stmmac_get_syncdevicetime,
priv, NULL, xtstamp);
}
/* structure describing a PTP hardware clock */ /* structure describing a PTP hardware clock */
static struct ptp_clock_info stmmac_ptp_clock_ops = { static struct ptp_clock_info stmmac_ptp_clock_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -180,6 +211,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = { ...@@ -180,6 +211,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
.gettime64 = stmmac_get_time, .gettime64 = stmmac_get_time,
.settime64 = stmmac_set_time, .settime64 = stmmac_set_time,
.enable = stmmac_enable, .enable = stmmac_enable,
.getcrosststamp = stmmac_getcrosststamp,
}; };
/** /**
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */ #define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */
#define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */ #define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */
#define PTP_TAR 0x18 /* Timestamp Addend Reg */ #define PTP_TAR 0x18 /* Timestamp Addend Reg */
#define PTP_ACR 0x40 /* Auxiliary Control Reg */
#define PTP_ATNR 0x48 /* Auxiliary Timestamp - Nanoseconds Reg */
#define PTP_ATSR 0x4c /* Auxiliary Timestamp - Seconds Reg */
#define PTP_STNSUR_ADDSUB_SHIFT 31 #define PTP_STNSUR_ADDSUB_SHIFT 31
#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */ #define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
...@@ -64,4 +67,24 @@ ...@@ -64,4 +67,24 @@
#define PTP_SSIR_SSINC_MASK 0xff #define PTP_SSIR_SSINC_MASK 0xff
#define GMAC4_PTP_SSIR_SSINC_SHIFT 16 #define GMAC4_PTP_SSIR_SSINC_SHIFT 16
/* Auxiliary Control defines */
#define PTP_ACR_ATSFC BIT(0) /* Auxiliary Snapshot FIFO Clear */
#define PTP_ACR_ATSEN0 BIT(4) /* Auxiliary Snapshot 0 Enable */
#define PTP_ACR_ATSEN1 BIT(5) /* Auxiliary Snapshot 1 Enable */
#define PTP_ACR_ATSEN2 BIT(6) /* Auxiliary Snapshot 2 Enable */
#define PTP_ACR_ATSEN3 BIT(7) /* Auxiliary Snapshot 3 Enable */
#define PTP_ACR_MASK GENMASK(7, 4) /* Aux Snapshot Mask */
#define PMC_ART_VALUE0 0x01 /* PMC_ART[15:0] timer value */
#define PMC_ART_VALUE1 0x02 /* PMC_ART[31:16] timer value */
#define PMC_ART_VALUE2 0x03 /* PMC_ART[47:32] timer value */
#define PMC_ART_VALUE3 0x04 /* PMC_ART[63:48] timer value */
#define GMAC4_ART_TIME_SHIFT 16 /* ART TIME 16-bits shift */
enum aux_snapshot {
AUX_SNAPSHOT0 = 0x10,
AUX_SNAPSHOT1 = 0x20,
AUX_SNAPSHOT2 = 0x40,
AUX_SNAPSHOT3 = 0x80,
};
#endif /* __STMMAC_PTP_H__ */ #endif /* __STMMAC_PTP_H__ */
...@@ -186,6 +186,8 @@ struct plat_stmmacenet_data { ...@@ -186,6 +186,8 @@ struct plat_stmmacenet_data {
void (*exit)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv);
struct mac_device_info *(*setup)(void *priv); struct mac_device_info *(*setup)(void *priv);
int (*clks_config)(void *priv, bool enabled); int (*clks_config)(void *priv, bool enabled);
int (*crosststamp)(ktime_t *device, struct system_counterval_t *system,
void *ctx);
void *bsp_priv; void *bsp_priv;
struct clk *stmmac_clk; struct clk *stmmac_clk;
struct clk *pclk; struct clk *pclk;
...@@ -206,5 +208,7 @@ struct plat_stmmacenet_data { ...@@ -206,5 +208,7 @@ struct plat_stmmacenet_data {
u8 vlan_fail_q; u8 vlan_fail_q;
unsigned int eee_usecs_rate; unsigned int eee_usecs_rate;
struct pci_dev *pdev; struct pci_dev *pdev;
bool has_crossts;
int int_snapshot_num;
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment