[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20250818115801.2518912-1-Raju.Rangoju@amd.com>
Date: Mon, 18 Aug 2025 17:28:01 +0530
From: Raju Rangoju <Raju.Rangoju@....com>
To: <netdev@...r.kernel.org>
CC: <andrew+netdev@...n.ch>, <davem@...emloft.net>, <edumazet@...gle.com>,
<kuba@...nel.org>, <pabeni@...hat.com>, <richardcochran@...il.com>,
<linux-kernel@...r.kernel.org>, <Shyam-sundar.S-k@....com>, Raju Rangoju
<Raju.Rangoju@....com>
Subject: [PATCH net-next] amd-xgbe: Add PPS periodic output support
Add support for hardware PPS (Pulse Per Second) output to the
AMD XGBE driver. The implementation enables flexible periodic
output mode, exposing it via the PTP per_out interface.
The driver supports configuring PPS output using the standard
PTP subsystem, allowing precise periodic signal generation for
time synchronization applications.
The feature has been verified using the testptp tool and
oscilloscope.
Signed-off-by: Raju Rangoju <Raju.Rangoju@....com>
---
drivers/net/ethernet/amd/xgbe/Makefile | 2 +-
drivers/net/ethernet/amd/xgbe/xgbe-common.h | 60 +++++++++++++++++++--
drivers/net/ethernet/amd/xgbe/xgbe-pps.c | 58 ++++++++++++++++++++
drivers/net/ethernet/amd/xgbe/xgbe-ptp.c | 30 ++++++++++-
drivers/net/ethernet/amd/xgbe/xgbe.h | 12 +++++
5 files changed, 157 insertions(+), 5 deletions(-)
create mode 100644 drivers/net/ethernet/amd/xgbe/xgbe-pps.c
diff --git a/drivers/net/ethernet/amd/xgbe/Makefile b/drivers/net/ethernet/amd/xgbe/Makefile
index 5b0ab6240cf2..d546a212806a 100644
--- a/drivers/net/ethernet/amd/xgbe/Makefile
+++ b/drivers/net/ethernet/amd/xgbe/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_AMD_XGBE) += amd-xgbe.o
amd-xgbe-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \
xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \
- xgbe-hwtstamp.o xgbe-ptp.o \
+ xgbe-hwtstamp.o xgbe-ptp.o xgbe-pps.o\
xgbe-i2c.o xgbe-phy-v1.o xgbe-phy-v2.o \
xgbe-platform.o
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index 009fbc9b11ce..ef4a5c7a9454 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -223,11 +223,18 @@
#define MAC_TSSR 0x0d20
#define MAC_TXSNR 0x0d30
#define MAC_TXSSR 0x0d34
+#define MAC_AUXCR 0x0d40
+#define MAC_ATSNR 0x0d48
+#define MAC_ATSSR 0x0d4C
#define MAC_TICNR 0x0d58
#define MAC_TICSNR 0x0d5C
#define MAC_TECNR 0x0d60
#define MAC_TECSNR 0x0d64
-
+#define MAC_PPSCR 0x0d70
+#define MAC_PPS0_TTSR 0x0d80
+#define MAC_PPS0_TTNSR 0x0d84
+#define MAC_PPS0_INTERVAL 0x0d88
+#define MAC_PPS0_WIDTH 0x0d8C
#define MAC_QTFCR_INC 4
#define MAC_MACA_INC 4
#define MAC_HTR_INC 4
@@ -235,6 +242,29 @@
#define MAC_RQC2_INC 4
#define MAC_RQC2_Q_PER_REG 4
+/* PPS helpers */
+#define PPSEN0 BIT(4)
+#define MAC_PPSx_TTSR(x) ((MAC_PPS0_TTSR) + ((x) * 0x10))
+#define MAC_PPSx_TTNSR(x) ((MAC_PPS0_TTNSR) + ((x) * 0x10))
+#define MAC_PPSx_INTERVAL(x) ((MAC_PPS0_INTERVAL) + ((x) * 0x10))
+#define MAC_PPSx_WIDTH(x) ((MAC_PPS0_WIDTH) + ((x) * 0x10))
+#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
+#define PPS_MINIDX(x) ((x) * 8)
+#define PPSx_MASK(x) ({ \
+ unsigned int __x = (x); \
+ GENMASK(PPS_MAXIDX(__x), PPS_MINIDX(__x)); \
+})
+#define PPSCMDx(x, val) ({ \
+ unsigned int __x = (x); \
+ GENMASK(PPS_MINIDX(__x) + 3, PPS_MINIDX(__x)) & \
+ ((val) << PPS_MINIDX(__x)); \
+})
+#define TRGTMODSELx(x, val) ({ \
+ unsigned int __x = (x); \
+ GENMASK(PPS_MAXIDX(__x) - 1, PPS_MAXIDX(__x) - 2) & \
+ ((val) << (PPS_MAXIDX(__x) - 2)); \
+})
+
/* MAC register entry bit positions and sizes */
#define MAC_HWF0R_ADDMACADRSEL_INDEX 18
#define MAC_HWF0R_ADDMACADRSEL_WIDTH 5
@@ -460,8 +490,26 @@
#define MAC_TSCR_TXTSSTSM_WIDTH 1
#define MAC_TSSR_TXTSC_INDEX 15
#define MAC_TSSR_TXTSC_WIDTH 1
+#define MAC_TSSR_ATSSTN_INDEX 16
+#define MAC_TSSR_ATSSTN_WIDTH 4
+#define MAC_TSSR_ATSNS_INDEX 25
+#define MAC_TSSR_ATSNS_WIDTH 5
+#define MAC_TSSR_ATSSTM_INDEX 24
+#define MAC_TSSR_ATSSTM_WIDTH 1
+#define MAC_TSSR_ATSSTN_INDEX 16
+#define MAC_TSSR_ATSSTN_WIDTH 4
+#define MAC_TSSR_AUXTSTRIG_INDEX 2
+#define MAC_TSSR_AUXTSTRIG_WIDTH 1
#define MAC_TXSNR_TXTSSTSMIS_INDEX 31
#define MAC_TXSNR_TXTSSTSMIS_WIDTH 1
+#define MAC_AUXCR_ATSEN3_INDEX 7
+#define MAC_AUXCR_ATSEN3_WIDTH 1
+#define MAC_AUXCR_ATSEN2_INDEX 6
+#define MAC_AUXCR_ATSEN2_WIDTH 1
+#define MAC_AUXCR_ATSEN1_INDEX 5
+#define MAC_AUXCR_ATSEN1_WIDTH 1
+#define MAC_AUXCR_ATSEN0_INDEX 4
+#define MAC_AUXCR_ATSEN0_WIDTH 1
#define MAC_TICSNR_TSICSNS_INDEX 8
#define MAC_TICSNR_TSICSNS_WIDTH 8
#define MAC_TECSNR_TSECSNS_INDEX 8
@@ -496,8 +544,14 @@
#define MAC_VR_SNPSVER_WIDTH 8
#define MAC_VR_USERVER_INDEX 16
#define MAC_VR_USERVER_WIDTH 8
-
-/* MMC register offsets */
+#define MAC_PPSCR_PPSEN0_INDEX 4
+#define MAC_PPSCR_PPSEN0_WIDTH 1
+#define MAC_PPSCR_PPSCTRL0_INDEX 0
+#define MAC_PPSCR_PPSCTRL0_WIDTH 4
+#define MAC_PPSx_TTNSR_TRGTBUSY0_INDEX 31
+#define MAC_PPSx_TTNSR_TRGTBUSY0_WIDTH 1
+
+ /* MMC register offsets */
#define MMC_CR 0x0800
#define MMC_RISR 0x0804
#define MMC_TISR 0x0808
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pps.c b/drivers/net/ethernet/amd/xgbe/xgbe-pps.c
new file mode 100644
index 000000000000..449720a60df5
--- /dev/null
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-pps.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
+/*
+ * Copyright (c) 2014-2025, Advanced Micro Devices, Inc.
+ * Copyright (c) 2014, Synopsys, Inc.
+ * All rights reserved
+ *
+ * Author: Raju Rangoju <Raju.Rangoju@....com>
+ */
+
+#include "xgbe.h"
+#include "xgbe-common.h"
+
+int xgbe_pps_config(struct xgbe_prv_data *pdata,
+ struct xgbe_pps_config *cfg, int index, int on)
+{
+ unsigned int value = 0;
+ unsigned int tnsec;
+ u64 period;
+
+ tnsec = XGMAC_IOREAD(pdata, MAC_PPSx_TTNSR(index));
+ if (XGMAC_GET_BITS(tnsec, MAC_PPSx_TTNSR, TRGTBUSY0))
+ return -EBUSY;
+
+ value = XGMAC_IOREAD(pdata, MAC_PPSCR);
+
+ value &= ~PPSx_MASK(index);
+
+ if (!on) {
+ value |= PPSCMDx(index, 0x5);
+ value |= PPSEN0;
+ XGMAC_IOWRITE(pdata, MAC_PPSCR, value);
+ return 0;
+ }
+
+ XGMAC_IOWRITE(pdata, MAC_PPSx_TTSR(index), cfg->start.tv_sec);
+ XGMAC_IOWRITE(pdata, MAC_PPSx_TTNSR(index), cfg->start.tv_nsec);
+
+ period = cfg->period.tv_sec * NSEC_PER_SEC;
+ period += cfg->period.tv_nsec;
+ do_div(period, XGBE_V2_TSTAMP_SSINC);
+
+ if (period <= 1)
+ return -EINVAL;
+
+ XGMAC_IOWRITE(pdata, MAC_PPSx_INTERVAL(index), period - 1);
+ period >>= 1;
+ if (period <= 1)
+ return -EINVAL;
+
+ XGMAC_IOWRITE(pdata, MAC_PPSx_WIDTH(index), period - 1);
+
+ value |= PPSCMDx(index, 0x2);
+ value |= TRGTMODSELx(index, 0x2);
+ value |= PPSEN0;
+
+ XGMAC_IOWRITE(pdata, MAC_PPSCR, value);
+ return 0;
+}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
index 3658afc7801d..c4b7dcf886ec 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
@@ -106,7 +106,33 @@ static int xgbe_settime(struct ptp_clock_info *info,
static int xgbe_enable(struct ptp_clock_info *info,
struct ptp_clock_request *request, int on)
{
- return -EOPNOTSUPP;
+ struct xgbe_prv_data *pdata = container_of(info, struct xgbe_prv_data,
+ ptp_clock_info);
+ struct xgbe_pps_config *pps_cfg;
+ unsigned long flags;
+ int ret;
+
+ dev_dbg(pdata->dev, "rq->type %d on %d\n", request->type, on);
+
+ if (request->type != PTP_CLK_REQ_PEROUT)
+ return -EOPNOTSUPP;
+
+ /* Reject requests with unsupported flags */
+ if (request->perout.flags)
+ return -EOPNOTSUPP;
+
+ pps_cfg = &pdata->pps[request->perout.index];
+
+ pps_cfg->start.tv_sec = request->perout.start.sec;
+ pps_cfg->start.tv_nsec = request->perout.start.nsec;
+ pps_cfg->period.tv_sec = request->perout.period.sec;
+ pps_cfg->period.tv_nsec = request->perout.period.nsec;
+
+ spin_lock_irqsave(&pdata->tstamp_lock, flags);
+ ret = xgbe_pps_config(pdata, pps_cfg, request->perout.index, on);
+ spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
+
+ return ret;
}
void xgbe_ptp_register(struct xgbe_prv_data *pdata)
@@ -122,6 +148,8 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata)
info->adjtime = xgbe_adjtime;
info->gettimex64 = xgbe_gettimex;
info->settime64 = xgbe_settime;
+ info->n_per_out = pdata->hw_feat.pps_out_num;
+ info->n_ext_ts = pdata->hw_feat.aux_snap_num;
info->enable = xgbe_enable;
clock = ptp_clock_register(info, pdata->dev);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index d7e03e292ec4..adc2b5f69095 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -672,6 +672,11 @@ struct xgbe_ext_stats {
u64 rx_vxlan_csum_errors;
};
+struct xgbe_pps_config {
+ struct timespec64 start;
+ struct timespec64 period;
+};
+
struct xgbe_hw_if {
int (*tx_complete)(struct xgbe_ring_desc *);
@@ -1142,6 +1147,9 @@ struct xgbe_prv_data {
struct sk_buff *tx_tstamp_skb;
u64 tx_tstamp;
+ /* Pulse Per Second output */
+ struct xgbe_pps_config pps[4];
+
/* DCB support */
struct ieee_ets *ets;
struct ieee_pfc *pfc;
@@ -1304,6 +1312,10 @@ void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata,
int xgbe_init_ptp(struct xgbe_prv_data *pdata);
void xgbe_update_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec,
unsigned int nsec);
+
+int xgbe_pps_config(struct xgbe_prv_data *pdata, struct xgbe_pps_config *cfg,
+ int index, int on);
+
#ifdef CONFIG_DEBUG_FS
void xgbe_debugfs_init(struct xgbe_prv_data *);
void xgbe_debugfs_exit(struct xgbe_prv_data *);
--
2.34.1
Powered by blists - more mailing lists