@@ -17,6 +17,7 @@
#include "stmmac.h"
#include "stmmac_platform.h"
+#include "dwmac1000.h"
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
@@ -428,6 +429,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
dwmac->ops = ops;
plat_dat->bsp_priv = dwmac;
plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
+ plat_dat->ext_snapshot_num = GMAC_TC_ATSEN0;
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
if (ret)
@@ -41,8 +41,7 @@
#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \
GMAC_INT_DISABLE_PCSLINK | \
GMAC_INT_DISABLE_PCSAN)
-#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \
- GMAC_INT_DISABLE_PCS)
+#define GMAC_INT_DEFAULT_MASK GMAC_INT_DISABLE_PCS
/* PMT Control and Status */
#define GMAC_PMT 0x0000002c
@@ -329,5 +328,14 @@ enum rtc_control {
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
#define GMAC_EXTHASH_BASE 0x500
+/* Timestamping registers */
+#define GMAC_TIMESTAMP_C0NTROL 0x00000700
+#define GMAC_TC_ATSFC BIT(24)
+#define GMAC_TC_ATSEN0 BIT(25)
+#define GMAC_TIMESTAMP_STATUS 0x00000728
+#define GMAC_AT_NS 0x00000730
+#define GMAC_AT_NS_MASK 0x7FFFFFFF
+#define GMAC_AT_S 0x00000734
+
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
#endif /* __DWMAC1000_H__ */
@@ -19,6 +19,7 @@
#include "stmmac.h"
#include "stmmac_pcs.h"
#include "dwmac1000.h"
+#include "stmmac_ptp.h"
static void dwmac1000_core_init(struct mac_device_info *hw,
struct net_device *dev)
@@ -294,9 +295,58 @@ static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
}
}
+static void get_ptptime(void __iomem *ioaddr, u64 *ptp_time)
+{
+ u64 ns;
+
+ ns = (readl(ioaddr + GMAC_AT_NS) & GMAC_AT_NS_MASK);
+ *ptp_time = ns;
+ ns = readl(ioaddr + GMAC_AT_S);
+ *ptp_time += ns * NSEC_PER_SEC;
+}
+
+static void dwmac1000_ptp_isr(struct stmmac_priv *priv)
+{
+ struct ptp_clock_event event;
+ u32 status_reg, num_snapshot;
+ unsigned long flags;
+ u64 ptp_time;
+ int i = 0;
+
+ if (priv->plat->int_snapshot_en) {
+ wake_up(&priv->tstamp_busy_wait);
+ return;
+ }
+
+ /* Read timestamp status to clear interrupt from either external
+ * timestamp or start/end of PPS.
+ */
+ status_reg = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
+
+ if (!priv->plat->ext_snapshot_en)
+ return;
+
+ num_snapshot = (status_reg & GMAC_TIMESTAMP_ATSNS_MASK) >>
+ GMAC_TIMESTAMP_ATSNS_SHIFT;
+ if (!num_snapshot)
+ return;
+
+ for (i = 0; i < num_snapshot; i++) {
+ read_lock_irqsave(&priv->ptp_lock, flags);
+ get_ptptime(priv->ioaddr, &ptp_time);
+ read_unlock_irqrestore(&priv->ptp_lock, flags);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = ptp_time;
+ ptp_clock_event(priv->ptp_clock, &event);
+ }
+}
+
static int dwmac1000_irq_status(struct mac_device_info *hw,
struct stmmac_extra_stats *x)
{
+ struct stmmac_priv *priv =
+ container_of(x, struct stmmac_priv, xstats);
void __iomem *ioaddr = hw->pcsr;
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
@@ -318,6 +368,9 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
x->irq_receive_pmt_irq_n++;
}
+ if (intr_status & GMAC_INT_STATUS_TSTAMP)
+ dwmac1000_ptp_isr(priv);
+
/* MAC tx/rx EEE LPI entry/exit interrupts */
if (intr_status & GMAC_INT_STATUS_LPIIS) {
/* Clean LPI interrupt by reading the Reg 12 */
@@ -502,6 +555,34 @@ static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)
writel(value, ioaddr + GMAC_CONTROL);
}
+static void dwmac1000_extts_configure(void __iomem *ioaddr, int ext_snapshot_num,
+ bool on, struct net_device *dev)
+{
+ u32 acr_value;
+
+ /* Since DWMAC1000 has only one external trigger input,
+ * ext_snapshot_num is not used
+ */
+ acr_value = readl(ioaddr + GMAC_TIMESTAMP_C0NTROL);
+ acr_value &= ~GMAC_TC_ATSEN0;
+ if (on) {
+ acr_value |= GMAC_TC_ATSEN0;
+ acr_value |= GMAC_TC_ATSFC;
+ netdev_dbg(dev, "Auxiliary Snapshot 0 enabled.\n");
+ } else {
+ netdev_dbg(dev, "Auxiliary Snapshot 0 disabled.\n");
+ }
+ writel(acr_value, ioaddr + GMAC_TIMESTAMP_C0NTROL);
+}
+
+static int dwmac1000_clear_snapshot_fifo(void __iomem *ioaddr)
+{
+ u32 acr_value;
+
+ return readl_poll_timeout(ioaddr + GMAC_TIMESTAMP_C0NTROL, acr_value,
+ !(acr_value & GMAC_TC_ATSFC), 10, 10000);
+}
+
const struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init,
.set_mac = stmmac_set_mac,
@@ -522,6 +603,8 @@ const struct stmmac_ops dwmac1000_ops = {
.pcs_rane = dwmac1000_rane,
.pcs_get_adv_lp = dwmac1000_get_adv_lp,
.set_mac_loopback = dwmac1000_set_mac_loopback,
+ .extts_configure = dwmac1000_extts_configure,
+ .clear_snapshot_fifo = dwmac1000_clear_snapshot_fifo
};
int dwmac1000_setup(struct stmmac_priv *priv)