NETC Timer has three pulse channels, all of which support periodic pulse
output. Bind the channel to a ALARM register and then sets a future time
into the ALARM register. When the current time is greater than the ALARM
value, the FIPER register will be triggered to count down, and when the
count reaches 0, the pulse will be triggered. The PPS signal is also
implemented in this way.
For i.MX95, it only has ALARM1 can be used as an indication to the FIPER
start down counting, but i.MX943 has ALARM1 and ALARM2 can be used. That
is to say, only one channel can work for i.MX95, two channels for i.MX943
as most. Current implementation does not allow multiple channels to share
the same alarm register at the same time.
In addition, because of the introduction of PTP_CLK_REQ_PEROUT support,
the PPS channel is changed from being fixed to 0 to being dynamically
selected.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
v2: no changes
v3 changes:
1. Improve the commit message
2. Add revision to struct netc_timer
3. Use priv->tmr_emask to instead of reading TMR_EMASK register
4. Add pps_channel to struct netc_timer and NETC_TMR_INVALID_CHANNEL
5. Add some helper functions: netc_timer_enable/disable_periodic_pulse(),
and netc_timer_select_pps_channel()
6. Dynamically select PPS channel instead of fixed to channel 0.
---
drivers/ptp/ptp_netc.c | 356 +++++++++++++++++++++++++++++++++++------
1 file changed, 306 insertions(+), 50 deletions(-)
diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c
index 9026a967a5fe..aa88767f8355 100644
--- a/drivers/ptp/ptp_netc.c
+++ b/drivers/ptp/ptp_netc.c
@@ -53,12 +53,18 @@
#define NETC_TMR_CUR_TIME_H 0x00f4
#define NETC_TMR_REGS_BAR 0
+#define NETC_GLOBAL_OFFSET 0x10000
+#define NETC_GLOBAL_IPBRR0 0xbf8
+#define IPBRR0_IP_REV GENMASK(15, 0)
+#define NETC_REV_4_1 0x0401
#define NETC_TMR_FIPER_NUM 3
+#define NETC_TMR_INVALID_CHANNEL NETC_TMR_FIPER_NUM
#define NETC_TMR_DEFAULT_PRSC 2
#define NETC_TMR_DEFAULT_ALARM GENMASK_ULL(63, 0)
#define NETC_TMR_DEFAULT_FIPER GENMASK(31, 0)
#define NETC_TMR_FIPER_MAX_PW GENMASK(4, 0)
+#define NETC_TMR_ALARM_NUM 2
/* 1588 timer reference clock source select */
#define NETC_TMR_CCM_TIMER1 0 /* enet_timer1_clk_root, from CCM */
@@ -67,6 +73,19 @@
#define NETC_TMR_SYSCLK_333M 333333333U
+enum netc_pp_type {
+ NETC_PP_PPS = 1,
+ NETC_PP_PEROUT,
+};
+
+struct netc_pp {
+ enum netc_pp_type type;
+ bool enabled;
+ int alarm_id;
+ u32 period; /* pulse period, ns */
+ u64 stime; /* start time, ns */
+};
+
struct netc_timer {
void __iomem *base;
struct pci_dev *pdev;
@@ -82,8 +101,12 @@ struct netc_timer {
u64 period;
int irq;
+ int revision;
u32 tmr_emask;
- bool pps_enabled;
+ u8 pps_channel;
+ u8 fs_alarm_num;
+ u8 fs_alarm_bitmap;
+ struct netc_pp pp[NETC_TMR_FIPER_NUM]; /* periodic pulse */
};
#define netc_timer_rd(p, o) netc_read((p)->base + (o))
@@ -192,6 +215,7 @@ static u32 netc_timer_calculate_fiper_pw(struct netc_timer *priv,
static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel,
u32 integral_period)
{
+ struct netc_pp *pp = &priv->pp[channel];
u64 alarm;
/* Get the alarm value */
@@ -199,7 +223,116 @@ static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel,
alarm = roundup_u64(alarm, NSEC_PER_SEC);
alarm = roundup_u64(alarm, integral_period);
- netc_timer_alarm_write(priv, alarm, 0);
+ netc_timer_alarm_write(priv, alarm, pp->alarm_id);
+}
+
+static void netc_timer_set_perout_alarm(struct netc_timer *priv, int channel,
+ u32 integral_period)
+{
+ u64 cur_time = netc_timer_cur_time_read(priv);
+ struct netc_pp *pp = &priv->pp[channel];
+ u64 alarm, delta, min_time;
+ u32 period = pp->period;
+ u64 stime = pp->stime;
+
+ min_time = cur_time + NSEC_PER_MSEC + period;
+ if (stime < min_time) {
+ delta = min_time - stime;
+ stime += roundup_u64(delta, period);
+ }
+
+ alarm = roundup_u64(stime - period, integral_period);
+ netc_timer_alarm_write(priv, alarm, pp->alarm_id);
+}
+
+static int netc_timer_get_alarm_id(struct netc_timer *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->fs_alarm_num; i++) {
+ if (!(priv->fs_alarm_bitmap & BIT(i))) {
+ priv->fs_alarm_bitmap |= BIT(i);
+ break;
+ }
+ }
+
+ return i;
+}
+
+static u64 netc_timer_get_gclk_period(struct netc_timer *priv)
+{
+ /* TMR_GCLK_freq = (clk_freq / oclk_prsc) Hz.
+ * TMR_GCLK_period = NSEC_PER_SEC / TMR_GCLK_freq.
+ * TMR_GCLK_period = (NSEC_PER_SEC * oclk_prsc) / clk_freq
+ */
+
+ return div_u64(mul_u32_u32(NSEC_PER_SEC, priv->oclk_prsc),
+ priv->clk_freq);
+}
+
+static void netc_timer_enable_periodic_pulse(struct netc_timer *priv,
+ u8 channel)
+{
+ u32 fiper_pw, fiper, fiper_ctrl, integral_period;
+ struct netc_pp *pp = &priv->pp[channel];
+ int alarm_id = pp->alarm_id;
+
+ integral_period = netc_timer_get_integral_period(priv);
+ /* Set to desired FIPER interval in ns - TCLK_PERIOD */
+ fiper = pp->period - integral_period;
+ fiper_pw = netc_timer_calculate_fiper_pw(priv, fiper);
+
+ fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
+ fiper_ctrl &= ~(FIPER_CTRL_DIS(channel) | FIPER_CTRL_PW(channel) |
+ FIPER_CTRL_FS_ALARM(channel));
+ fiper_ctrl |= FIPER_CTRL_SET_PW(channel, fiper_pw);
+ fiper_ctrl |= alarm_id ? FIPER_CTRL_FS_ALARM(channel) : 0;
+
+ priv->tmr_emask |= TMR_TEVNET_PPEN(channel) |
+ TMR_TEVENT_ALMEN(alarm_id);
+
+ if (pp->type == NETC_PP_PPS)
+ netc_timer_set_pps_alarm(priv, channel, integral_period);
+ else
+ netc_timer_set_perout_alarm(priv, channel, integral_period);
+
+ netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask);
+ netc_timer_wr(priv, NETC_TMR_FIPER(channel), fiper);
+ netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
+}
+
+static void netc_timer_disable_periodic_pulse(struct netc_timer *priv,
+ u8 channel)
+{
+ struct netc_pp *pp = &priv->pp[channel];
+ int alarm_id = pp->alarm_id;
+ u32 fiper_ctrl;
+
+ if (!pp->enabled)
+ return;
+
+ priv->tmr_emask &= ~(TMR_TEVNET_PPEN(channel) |
+ TMR_TEVENT_ALMEN(alarm_id));
+
+ fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
+ fiper_ctrl |= FIPER_CTRL_DIS(channel);
+
+ netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, alarm_id);
+ netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask);
+ netc_timer_wr(priv, NETC_TMR_FIPER(channel), NETC_TMR_DEFAULT_FIPER);
+ netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
+}
+
+static u8 netc_timer_select_pps_channel(struct netc_timer *priv)
+{
+ int i;
+
+ for (i = 0; i < NETC_TMR_FIPER_NUM; i++) {
+ if (!priv->pp[i].enabled)
+ return i;
+ }
+
+ return NETC_TMR_INVALID_CHANNEL;
}
/* Note that users should not use this API to output PPS signal on
@@ -210,77 +343,178 @@ static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel,
static int netc_timer_enable_pps(struct netc_timer *priv,
struct ptp_clock_request *rq, int on)
{
- u32 fiper, fiper_ctrl;
+ struct device *dev = &priv->pdev->dev;
unsigned long flags;
+ struct netc_pp *pp;
+ int err = 0;
spin_lock_irqsave(&priv->lock, flags);
- fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
-
if (on) {
- u32 integral_period, fiper_pw;
+ int alarm_id;
+ u8 channel;
+
+ if (priv->pps_channel < NETC_TMR_FIPER_NUM) {
+ channel = priv->pps_channel;
+ } else {
+ channel = netc_timer_select_pps_channel(priv);
+ if (channel == NETC_TMR_INVALID_CHANNEL) {
+ dev_err(dev, "No available FIPERs\n");
+ err = -EBUSY;
+ goto unlock_spinlock;
+ }
+ }
- if (priv->pps_enabled)
+ pp = &priv->pp[channel];
+ if (pp->enabled)
goto unlock_spinlock;
- integral_period = netc_timer_get_integral_period(priv);
- fiper = NSEC_PER_SEC - integral_period;
- fiper_pw = netc_timer_calculate_fiper_pw(priv, fiper);
- fiper_ctrl &= ~(FIPER_CTRL_DIS(0) | FIPER_CTRL_PW(0) |
- FIPER_CTRL_FS_ALARM(0));
- fiper_ctrl |= FIPER_CTRL_SET_PW(0, fiper_pw);
- priv->tmr_emask |= TMR_TEVNET_PPEN(0) | TMR_TEVENT_ALMEN(0);
- priv->pps_enabled = true;
- netc_timer_set_pps_alarm(priv, 0, integral_period);
+ alarm_id = netc_timer_get_alarm_id(priv);
+ if (alarm_id == priv->fs_alarm_num) {
+ dev_err(dev, "No available ALARMs\n");
+ err = -EBUSY;
+ goto unlock_spinlock;
+ }
+
+ pp->enabled = true;
+ pp->type = NETC_PP_PPS;
+ pp->alarm_id = alarm_id;
+ pp->period = NSEC_PER_SEC;
+ priv->pps_channel = channel;
+
+ netc_timer_enable_periodic_pulse(priv, channel);
} else {
- if (!priv->pps_enabled)
+ /* pps_channel is invalid if PPS is not enabled, so no
+ * processing is needed.
+ */
+ if (priv->pps_channel >= NETC_TMR_FIPER_NUM)
goto unlock_spinlock;
- fiper = NETC_TMR_DEFAULT_FIPER;
- priv->tmr_emask &= ~(TMR_TEVNET_PPEN(0) |
- TMR_TEVENT_ALMEN(0));
- fiper_ctrl |= FIPER_CTRL_DIS(0);
- priv->pps_enabled = false;
- netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0);
+ netc_timer_disable_periodic_pulse(priv, priv->pps_channel);
+ priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id);
+ pp = &priv->pp[priv->pps_channel];
+ memset(pp, 0, sizeof(*pp));
+ priv->pps_channel = NETC_TMR_INVALID_CHANNEL;
}
- netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask);
- netc_timer_wr(priv, NETC_TMR_FIPER(0), fiper);
- netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
+unlock_spinlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return err;
+}
+
+static int net_timer_enable_perout(struct netc_timer *priv,
+ struct ptp_clock_request *rq, int on)
+{
+ struct device *dev = &priv->pdev->dev;
+ u32 channel = rq->perout.index;
+ unsigned long flags;
+ struct netc_pp *pp;
+ int err = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ pp = &priv->pp[channel];
+ if (pp->type == NETC_PP_PPS) {
+ dev_err(dev, "FIPER%u is being used for PPS\n", channel);
+ err = -EBUSY;
+ goto unlock_spinlock;
+ }
+
+ if (on) {
+ u64 period_ns, gclk_period, max_period, min_period;
+ struct timespec64 period, stime;
+ u32 integral_period;
+ int alarm_id;
+
+ period.tv_sec = rq->perout.period.sec;
+ period.tv_nsec = rq->perout.period.nsec;
+ period_ns = timespec64_to_ns(&period);
+
+ integral_period = netc_timer_get_integral_period(priv);
+ max_period = (u64)NETC_TMR_DEFAULT_FIPER + integral_period;
+ gclk_period = netc_timer_get_gclk_period(priv);
+ min_period = gclk_period * 4 + integral_period;
+ if (period_ns > max_period || period_ns < min_period) {
+ dev_err(dev, "The period range is %llu ~ %llu\n",
+ min_period, max_period);
+ err = -EINVAL;
+ goto unlock_spinlock;
+ }
+
+ if (pp->enabled) {
+ alarm_id = pp->alarm_id;
+ } else {
+ alarm_id = netc_timer_get_alarm_id(priv);
+ if (alarm_id == priv->fs_alarm_num) {
+ dev_err(dev, "No available ALARMs\n");
+ err = -EBUSY;
+ goto unlock_spinlock;
+ }
+
+ pp->type = NETC_PP_PEROUT;
+ pp->enabled = true;
+ pp->alarm_id = alarm_id;
+ }
+
+ stime.tv_sec = rq->perout.start.sec;
+ stime.tv_nsec = rq->perout.start.nsec;
+ pp->stime = timespec64_to_ns(&stime);
+ pp->period = period_ns;
+
+ netc_timer_enable_periodic_pulse(priv, channel);
+ } else {
+ netc_timer_disable_periodic_pulse(priv, channel);
+ priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id);
+ memset(pp, 0, sizeof(*pp));
+ }
unlock_spinlock:
spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ return err;
}
-static void netc_timer_disable_pps_fiper(struct netc_timer *priv)
+static void netc_timer_disable_fiper(struct netc_timer *priv)
{
- u32 fiper_ctrl;
+ u32 fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
+ int i;
- if (!priv->pps_enabled)
- return;
+ for (i = 0; i < NETC_TMR_FIPER_NUM; i++) {
+ if (!priv->pp[i].enabled)
+ continue;
+
+ fiper_ctrl |= FIPER_CTRL_DIS(i);
+ netc_timer_wr(priv, NETC_TMR_FIPER(i), NETC_TMR_DEFAULT_FIPER);
+ }
- fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
- fiper_ctrl |= FIPER_CTRL_DIS(0);
- netc_timer_wr(priv, NETC_TMR_FIPER(0), NETC_TMR_DEFAULT_FIPER);
netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
}
-static void netc_timer_enable_pps_fiper(struct netc_timer *priv)
+static void netc_timer_enable_fiper(struct netc_timer *priv)
{
- u32 fiper_ctrl, integral_period, fiper;
+ u32 integral_period = netc_timer_get_integral_period(priv);
+ u32 fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
+ int i;
- if (!priv->pps_enabled)
- return;
+ for (i = 0; i < NETC_TMR_FIPER_NUM; i++) {
+ struct netc_pp *pp = &priv->pp[i];
+ u32 fiper;
- integral_period = netc_timer_get_integral_period(priv);
- fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
- fiper_ctrl &= ~FIPER_CTRL_DIS(0);
- fiper = NSEC_PER_SEC - integral_period;
+ if (!pp->enabled)
+ continue;
+
+ fiper_ctrl &= ~FIPER_CTRL_DIS(i);
+
+ if (pp->type == NETC_PP_PPS)
+ netc_timer_set_pps_alarm(priv, i, integral_period);
+ else if (pp->type == NETC_PP_PEROUT)
+ netc_timer_set_perout_alarm(priv, i, integral_period);
+
+ fiper = pp->period - integral_period;
+ netc_timer_wr(priv, NETC_TMR_FIPER(i), fiper);
+ }
- netc_timer_set_pps_alarm(priv, 0, integral_period);
- netc_timer_wr(priv, NETC_TMR_FIPER(0), fiper);
netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl);
}
@@ -292,6 +526,8 @@ static int netc_timer_enable(struct ptp_clock_info *ptp,
switch (rq->type) {
case PTP_CLK_REQ_PPS:
return netc_timer_enable_pps(priv, rq, on);
+ case PTP_CLK_REQ_PEROUT:
+ return net_timer_enable_perout(priv, rq, on);
default:
return -EOPNOTSUPP;
}
@@ -310,9 +546,9 @@ static void netc_timer_adjust_period(struct netc_timer *priv, u64 period)
tmr_ctrl = u32_replace_bits(old_tmr_ctrl, integral_period,
TMR_CTRL_TCLK_PERIOD);
if (tmr_ctrl != old_tmr_ctrl) {
- netc_timer_disable_pps_fiper(priv);
+ netc_timer_disable_fiper(priv);
netc_timer_wr(priv, NETC_TMR_CTRL, tmr_ctrl);
- netc_timer_enable_pps_fiper(priv);
+ netc_timer_enable_fiper(priv);
}
netc_timer_wr(priv, NETC_TMR_ADD, fractional_period);
@@ -339,7 +575,7 @@ static int netc_timer_adjtime(struct ptp_clock_info *ptp, s64 delta)
spin_lock_irqsave(&priv->lock, flags);
- netc_timer_disable_pps_fiper(priv);
+ netc_timer_disable_fiper(priv);
/* Adjusting TMROFF instead of TMR_CNT is that the timer
* counter keeps increasing during reading and writing
@@ -349,7 +585,7 @@ static int netc_timer_adjtime(struct ptp_clock_info *ptp, s64 delta)
tmr_off += delta;
netc_timer_offset_write(priv, tmr_off);
- netc_timer_enable_pps_fiper(priv);
+ netc_timer_enable_fiper(priv);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -386,10 +622,10 @@ static int netc_timer_settime64(struct ptp_clock_info *ptp,
spin_lock_irqsave(&priv->lock, flags);
- netc_timer_disable_pps_fiper(priv);
+ netc_timer_disable_fiper(priv);
netc_timer_offset_write(priv, 0);
netc_timer_cnt_write(priv, ns);
- netc_timer_enable_pps_fiper(priv);
+ netc_timer_enable_fiper(priv);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -418,6 +654,7 @@ static const struct ptp_clock_info netc_timer_ptp_caps = {
.n_pins = 0,
.n_alarm = 2,
.pps = 1,
+ .n_per_out = 3,
.adjfine = netc_timer_adjfine,
.adjtime = netc_timer_adjtime,
.gettimex64 = netc_timer_gettimex64,
@@ -575,6 +812,9 @@ static irqreturn_t netc_timer_isr(int irq, void *data)
if (tmr_event & TMR_TEVENT_ALMEN(0))
netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0);
+ if (tmr_event & TMR_TEVENT_ALMEN(1))
+ netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 1);
+
if (tmr_event & TMR_TEVENT_PPEN_ALL) {
event.type = PTP_CLOCK_PPS;
ptp_clock_event(priv->clock, &event);
@@ -619,6 +859,15 @@ static void netc_timer_free_msix_irq(struct netc_timer *priv)
pci_free_irq_vectors(pdev);
}
+static int netc_timer_get_global_ip_rev(struct netc_timer *priv)
+{
+ u32 val;
+
+ val = netc_timer_rd(priv, NETC_GLOBAL_OFFSET + NETC_GLOBAL_IPBRR0);
+
+ return val & IPBRR0_IP_REV;
+}
+
static int netc_timer_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -631,6 +880,12 @@ static int netc_timer_probe(struct pci_dev *pdev,
return err;
priv = pci_get_drvdata(pdev);
+ priv->revision = netc_timer_get_global_ip_rev(priv);
+ if (priv->revision == NETC_REV_4_1)
+ priv->fs_alarm_num = 1;
+ else
+ priv->fs_alarm_num = NETC_TMR_ALARM_NUM;
+
err = netc_timer_parse_dt(priv);
if (err) {
if (err != -EPROBE_DEFER)
@@ -640,6 +895,7 @@ static int netc_timer_probe(struct pci_dev *pdev,
priv->caps = netc_timer_ptp_caps;
priv->oclk_prsc = NETC_TMR_DEFAULT_PRSC;
+ priv->pps_channel = NETC_TMR_INVALID_CHANNEL;
spin_lock_init(&priv->lock);
err = netc_timer_init_msix_irq(priv);
--
2.34.1
Hi Wei, kernel test robot noticed the following build warnings: [auto build test WARNING on net-next/main] url: https://github.com/intel-lab-lkp/linux/commits/Wei-Fang/dt-bindings-ptp-add-NETC-Timer-PTP-clock/20250812-181510 base: net-next/main patch link: https://lore.kernel.org/r/20250812094634.489901-7-wei.fang%40nxp.com patch subject: [PATCH v3 net-next 06/15] ptp: netc: add periodic pulse output support config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20250813/202508131027.y3pyBEJQ-lkp@intel.com/config) compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 3769ce013be2879bf0b329c14a16f5cb766f26ce) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250813/202508131027.y3pyBEJQ-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202508131027.y3pyBEJQ-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/ptp/ptp_netc.c:394:33: warning: variable 'pp' is uninitialized when used here [-Wuninitialized] 394 | priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id); | ^~ drivers/ptp/ptp_netc.c:348:20: note: initialize the variable 'pp' to silence this warning 348 | struct netc_pp *pp; | ^ | = NULL 1 warning generated. vim +/pp +394 drivers/ptp/ptp_netc.c 337 338 /* Note that users should not use this API to output PPS signal on 339 * external pins, because PTP_CLK_REQ_PPS trigger internal PPS event 340 * for input into kernel PPS subsystem. See: 341 * https://lore.kernel.org/r/20201117213826.18235-1-a.fatoum@pengutronix.de 342 */ 343 static int netc_timer_enable_pps(struct netc_timer *priv, 344 struct ptp_clock_request *rq, int on) 345 { 346 struct device *dev = &priv->pdev->dev; 347 unsigned long flags; 348 struct netc_pp *pp; 349 int err = 0; 350 351 spin_lock_irqsave(&priv->lock, flags); 352 353 if (on) { 354 int alarm_id; 355 u8 channel; 356 357 if (priv->pps_channel < NETC_TMR_FIPER_NUM) { 358 channel = priv->pps_channel; 359 } else { 360 channel = netc_timer_select_pps_channel(priv); 361 if (channel == NETC_TMR_INVALID_CHANNEL) { 362 dev_err(dev, "No available FIPERs\n"); 363 err = -EBUSY; 364 goto unlock_spinlock; 365 } 366 } 367 368 pp = &priv->pp[channel]; 369 if (pp->enabled) 370 goto unlock_spinlock; 371 372 alarm_id = netc_timer_get_alarm_id(priv); 373 if (alarm_id == priv->fs_alarm_num) { 374 dev_err(dev, "No available ALARMs\n"); 375 err = -EBUSY; 376 goto unlock_spinlock; 377 } 378 379 pp->enabled = true; 380 pp->type = NETC_PP_PPS; 381 pp->alarm_id = alarm_id; 382 pp->period = NSEC_PER_SEC; 383 priv->pps_channel = channel; 384 385 netc_timer_enable_periodic_pulse(priv, channel); 386 } else { 387 /* pps_channel is invalid if PPS is not enabled, so no 388 * processing is needed. 389 */ 390 if (priv->pps_channel >= NETC_TMR_FIPER_NUM) 391 goto unlock_spinlock; 392 393 netc_timer_disable_periodic_pulse(priv, priv->pps_channel); > 394 priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id); 395 pp = &priv->pp[priv->pps_channel]; 396 memset(pp, 0, sizeof(*pp)); 397 priv->pps_channel = NETC_TMR_INVALID_CHANNEL; 398 } 399 400 unlock_spinlock: 401 spin_unlock_irqrestore(&priv->lock, flags); 402 403 return err; 404 } 405 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
On Tue, Aug 12, 2025 at 05:46:25PM +0800, Wei Fang wrote: > NETC Timer has three pulse channels, all of which support periodic pulse > output. Bind the channel to a ALARM register and then sets a future time > into the ALARM register. When the current time is greater than the ALARM > value, the FIPER register will be triggered to count down, and when the > count reaches 0, the pulse will be triggered. The PPS signal is also > implemented in this way. > > For i.MX95, it only has ALARM1 can be used as an indication to the FIPER > start down counting, but i.MX943 has ALARM1 and ALARM2 can be used. That > is to say, only one channel can work for i.MX95, two channels for i.MX943 > as most. Current implementation does not allow multiple channels to share > the same alarm register at the same time. Keep short and simple. i.MX96 have only ALARM1. i.MX943 have ALARM1 and ALARM2. So only one channel for i.MX95, two channels for i.MX943 since channel sharing are not supported yet. > > In addition, because of the introduction of PTP_CLK_REQ_PEROUT support, > the PPS channel is changed from being fixed to 0 to being dynamically > selected. Nit: Change the PPS channel to be dynamically selected from fixed number (0) because add PTP_CLK_REQ_PEROUT support. Reviewed-by: Frank Li <Frank.Li@nxp.com> > > Signed-off-by: Wei Fang <wei.fang@nxp.com> > > --- > v2: no changes > v3 changes: > 1. Improve the commit message > 2. Add revision to struct netc_timer > 3. Use priv->tmr_emask to instead of reading TMR_EMASK register > 4. Add pps_channel to struct netc_timer and NETC_TMR_INVALID_CHANNEL > 5. Add some helper functions: netc_timer_enable/disable_periodic_pulse(), > and netc_timer_select_pps_channel() > 6. Dynamically select PPS channel instead of fixed to channel 0. > --- > drivers/ptp/ptp_netc.c | 356 +++++++++++++++++++++++++++++++++++------ > 1 file changed, 306 insertions(+), 50 deletions(-) > > diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c > index 9026a967a5fe..aa88767f8355 100644 > --- a/drivers/ptp/ptp_netc.c > +++ b/drivers/ptp/ptp_netc.c > @@ -53,12 +53,18 @@ > #define NETC_TMR_CUR_TIME_H 0x00f4 > > #define NETC_TMR_REGS_BAR 0 > +#define NETC_GLOBAL_OFFSET 0x10000 > +#define NETC_GLOBAL_IPBRR0 0xbf8 > +#define IPBRR0_IP_REV GENMASK(15, 0) > +#define NETC_REV_4_1 0x0401 > > #define NETC_TMR_FIPER_NUM 3 > +#define NETC_TMR_INVALID_CHANNEL NETC_TMR_FIPER_NUM > #define NETC_TMR_DEFAULT_PRSC 2 > #define NETC_TMR_DEFAULT_ALARM GENMASK_ULL(63, 0) > #define NETC_TMR_DEFAULT_FIPER GENMASK(31, 0) > #define NETC_TMR_FIPER_MAX_PW GENMASK(4, 0) > +#define NETC_TMR_ALARM_NUM 2 > > /* 1588 timer reference clock source select */ > #define NETC_TMR_CCM_TIMER1 0 /* enet_timer1_clk_root, from CCM */ > @@ -67,6 +73,19 @@ > > #define NETC_TMR_SYSCLK_333M 333333333U > > +enum netc_pp_type { > + NETC_PP_PPS = 1, > + NETC_PP_PEROUT, > +}; > + > +struct netc_pp { > + enum netc_pp_type type; > + bool enabled; > + int alarm_id; > + u32 period; /* pulse period, ns */ > + u64 stime; /* start time, ns */ > +}; > + > struct netc_timer { > void __iomem *base; > struct pci_dev *pdev; > @@ -82,8 +101,12 @@ struct netc_timer { > u64 period; > > int irq; > + int revision; > u32 tmr_emask; > - bool pps_enabled; > + u8 pps_channel; > + u8 fs_alarm_num; > + u8 fs_alarm_bitmap; > + struct netc_pp pp[NETC_TMR_FIPER_NUM]; /* periodic pulse */ > }; > > #define netc_timer_rd(p, o) netc_read((p)->base + (o)) > @@ -192,6 +215,7 @@ static u32 netc_timer_calculate_fiper_pw(struct netc_timer *priv, > static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel, > u32 integral_period) > { > + struct netc_pp *pp = &priv->pp[channel]; > u64 alarm; > > /* Get the alarm value */ > @@ -199,7 +223,116 @@ static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel, > alarm = roundup_u64(alarm, NSEC_PER_SEC); > alarm = roundup_u64(alarm, integral_period); > > - netc_timer_alarm_write(priv, alarm, 0); > + netc_timer_alarm_write(priv, alarm, pp->alarm_id); > +} > + > +static void netc_timer_set_perout_alarm(struct netc_timer *priv, int channel, > + u32 integral_period) > +{ > + u64 cur_time = netc_timer_cur_time_read(priv); > + struct netc_pp *pp = &priv->pp[channel]; > + u64 alarm, delta, min_time; > + u32 period = pp->period; > + u64 stime = pp->stime; > + > + min_time = cur_time + NSEC_PER_MSEC + period; > + if (stime < min_time) { > + delta = min_time - stime; > + stime += roundup_u64(delta, period); > + } > + > + alarm = roundup_u64(stime - period, integral_period); > + netc_timer_alarm_write(priv, alarm, pp->alarm_id); > +} > + > +static int netc_timer_get_alarm_id(struct netc_timer *priv) > +{ > + int i; > + > + for (i = 0; i < priv->fs_alarm_num; i++) { > + if (!(priv->fs_alarm_bitmap & BIT(i))) { > + priv->fs_alarm_bitmap |= BIT(i); > + break; > + } > + } > + > + return i; > +} > + > +static u64 netc_timer_get_gclk_period(struct netc_timer *priv) > +{ > + /* TMR_GCLK_freq = (clk_freq / oclk_prsc) Hz. > + * TMR_GCLK_period = NSEC_PER_SEC / TMR_GCLK_freq. > + * TMR_GCLK_period = (NSEC_PER_SEC * oclk_prsc) / clk_freq > + */ > + > + return div_u64(mul_u32_u32(NSEC_PER_SEC, priv->oclk_prsc), > + priv->clk_freq); > +} > + > +static void netc_timer_enable_periodic_pulse(struct netc_timer *priv, > + u8 channel) > +{ > + u32 fiper_pw, fiper, fiper_ctrl, integral_period; > + struct netc_pp *pp = &priv->pp[channel]; > + int alarm_id = pp->alarm_id; > + > + integral_period = netc_timer_get_integral_period(priv); > + /* Set to desired FIPER interval in ns - TCLK_PERIOD */ > + fiper = pp->period - integral_period; > + fiper_pw = netc_timer_calculate_fiper_pw(priv, fiper); > + > + fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > + fiper_ctrl &= ~(FIPER_CTRL_DIS(channel) | FIPER_CTRL_PW(channel) | > + FIPER_CTRL_FS_ALARM(channel)); > + fiper_ctrl |= FIPER_CTRL_SET_PW(channel, fiper_pw); > + fiper_ctrl |= alarm_id ? FIPER_CTRL_FS_ALARM(channel) : 0; > + > + priv->tmr_emask |= TMR_TEVNET_PPEN(channel) | > + TMR_TEVENT_ALMEN(alarm_id); > + > + if (pp->type == NETC_PP_PPS) > + netc_timer_set_pps_alarm(priv, channel, integral_period); > + else > + netc_timer_set_perout_alarm(priv, channel, integral_period); > + > + netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask); > + netc_timer_wr(priv, NETC_TMR_FIPER(channel), fiper); > + netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); > +} > + > +static void netc_timer_disable_periodic_pulse(struct netc_timer *priv, > + u8 channel) > +{ > + struct netc_pp *pp = &priv->pp[channel]; > + int alarm_id = pp->alarm_id; > + u32 fiper_ctrl; > + > + if (!pp->enabled) > + return; > + > + priv->tmr_emask &= ~(TMR_TEVNET_PPEN(channel) | > + TMR_TEVENT_ALMEN(alarm_id)); > + > + fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > + fiper_ctrl |= FIPER_CTRL_DIS(channel); > + > + netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, alarm_id); > + netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask); > + netc_timer_wr(priv, NETC_TMR_FIPER(channel), NETC_TMR_DEFAULT_FIPER); > + netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); > +} > + > +static u8 netc_timer_select_pps_channel(struct netc_timer *priv) > +{ > + int i; > + > + for (i = 0; i < NETC_TMR_FIPER_NUM; i++) { > + if (!priv->pp[i].enabled) > + return i; > + } > + > + return NETC_TMR_INVALID_CHANNEL; > } > > /* Note that users should not use this API to output PPS signal on > @@ -210,77 +343,178 @@ static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel, > static int netc_timer_enable_pps(struct netc_timer *priv, > struct ptp_clock_request *rq, int on) > { > - u32 fiper, fiper_ctrl; > + struct device *dev = &priv->pdev->dev; > unsigned long flags; > + struct netc_pp *pp; > + int err = 0; > > spin_lock_irqsave(&priv->lock, flags); > > - fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > - > if (on) { > - u32 integral_period, fiper_pw; > + int alarm_id; > + u8 channel; > + > + if (priv->pps_channel < NETC_TMR_FIPER_NUM) { > + channel = priv->pps_channel; > + } else { > + channel = netc_timer_select_pps_channel(priv); > + if (channel == NETC_TMR_INVALID_CHANNEL) { > + dev_err(dev, "No available FIPERs\n"); > + err = -EBUSY; > + goto unlock_spinlock; > + } > + } > > - if (priv->pps_enabled) > + pp = &priv->pp[channel]; > + if (pp->enabled) > goto unlock_spinlock; > > - integral_period = netc_timer_get_integral_period(priv); > - fiper = NSEC_PER_SEC - integral_period; > - fiper_pw = netc_timer_calculate_fiper_pw(priv, fiper); > - fiper_ctrl &= ~(FIPER_CTRL_DIS(0) | FIPER_CTRL_PW(0) | > - FIPER_CTRL_FS_ALARM(0)); > - fiper_ctrl |= FIPER_CTRL_SET_PW(0, fiper_pw); > - priv->tmr_emask |= TMR_TEVNET_PPEN(0) | TMR_TEVENT_ALMEN(0); > - priv->pps_enabled = true; > - netc_timer_set_pps_alarm(priv, 0, integral_period); > + alarm_id = netc_timer_get_alarm_id(priv); > + if (alarm_id == priv->fs_alarm_num) { > + dev_err(dev, "No available ALARMs\n"); > + err = -EBUSY; > + goto unlock_spinlock; > + } > + > + pp->enabled = true; > + pp->type = NETC_PP_PPS; > + pp->alarm_id = alarm_id; > + pp->period = NSEC_PER_SEC; > + priv->pps_channel = channel; > + > + netc_timer_enable_periodic_pulse(priv, channel); > } else { > - if (!priv->pps_enabled) > + /* pps_channel is invalid if PPS is not enabled, so no > + * processing is needed. > + */ > + if (priv->pps_channel >= NETC_TMR_FIPER_NUM) > goto unlock_spinlock; > > - fiper = NETC_TMR_DEFAULT_FIPER; > - priv->tmr_emask &= ~(TMR_TEVNET_PPEN(0) | > - TMR_TEVENT_ALMEN(0)); > - fiper_ctrl |= FIPER_CTRL_DIS(0); > - priv->pps_enabled = false; > - netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0); > + netc_timer_disable_periodic_pulse(priv, priv->pps_channel); > + priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id); > + pp = &priv->pp[priv->pps_channel]; > + memset(pp, 0, sizeof(*pp)); > + priv->pps_channel = NETC_TMR_INVALID_CHANNEL; > } > > - netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask); > - netc_timer_wr(priv, NETC_TMR_FIPER(0), fiper); > - netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); > +unlock_spinlock: > + spin_unlock_irqrestore(&priv->lock, flags); > + > + return err; > +} > + > +static int net_timer_enable_perout(struct netc_timer *priv, > + struct ptp_clock_request *rq, int on) > +{ > + struct device *dev = &priv->pdev->dev; > + u32 channel = rq->perout.index; > + unsigned long flags; > + struct netc_pp *pp; > + int err = 0; > + > + spin_lock_irqsave(&priv->lock, flags); > + > + pp = &priv->pp[channel]; > + if (pp->type == NETC_PP_PPS) { > + dev_err(dev, "FIPER%u is being used for PPS\n", channel); > + err = -EBUSY; > + goto unlock_spinlock; > + } > + > + if (on) { > + u64 period_ns, gclk_period, max_period, min_period; > + struct timespec64 period, stime; > + u32 integral_period; > + int alarm_id; > + > + period.tv_sec = rq->perout.period.sec; > + period.tv_nsec = rq->perout.period.nsec; > + period_ns = timespec64_to_ns(&period); > + > + integral_period = netc_timer_get_integral_period(priv); > + max_period = (u64)NETC_TMR_DEFAULT_FIPER + integral_period; > + gclk_period = netc_timer_get_gclk_period(priv); > + min_period = gclk_period * 4 + integral_period; > + if (period_ns > max_period || period_ns < min_period) { > + dev_err(dev, "The period range is %llu ~ %llu\n", > + min_period, max_period); > + err = -EINVAL; > + goto unlock_spinlock; > + } > + > + if (pp->enabled) { > + alarm_id = pp->alarm_id; > + } else { > + alarm_id = netc_timer_get_alarm_id(priv); > + if (alarm_id == priv->fs_alarm_num) { > + dev_err(dev, "No available ALARMs\n"); > + err = -EBUSY; > + goto unlock_spinlock; > + } > + > + pp->type = NETC_PP_PEROUT; > + pp->enabled = true; > + pp->alarm_id = alarm_id; > + } > + > + stime.tv_sec = rq->perout.start.sec; > + stime.tv_nsec = rq->perout.start.nsec; > + pp->stime = timespec64_to_ns(&stime); > + pp->period = period_ns; > + > + netc_timer_enable_periodic_pulse(priv, channel); > + } else { > + netc_timer_disable_periodic_pulse(priv, channel); > + priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id); > + memset(pp, 0, sizeof(*pp)); > + } > > unlock_spinlock: > spin_unlock_irqrestore(&priv->lock, flags); > > - return 0; > + return err; > } > > -static void netc_timer_disable_pps_fiper(struct netc_timer *priv) > +static void netc_timer_disable_fiper(struct netc_timer *priv) > { > - u32 fiper_ctrl; > + u32 fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > + int i; > > - if (!priv->pps_enabled) > - return; > + for (i = 0; i < NETC_TMR_FIPER_NUM; i++) { > + if (!priv->pp[i].enabled) > + continue; > + > + fiper_ctrl |= FIPER_CTRL_DIS(i); > + netc_timer_wr(priv, NETC_TMR_FIPER(i), NETC_TMR_DEFAULT_FIPER); > + } > > - fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > - fiper_ctrl |= FIPER_CTRL_DIS(0); > - netc_timer_wr(priv, NETC_TMR_FIPER(0), NETC_TMR_DEFAULT_FIPER); > netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); > } > > -static void netc_timer_enable_pps_fiper(struct netc_timer *priv) > +static void netc_timer_enable_fiper(struct netc_timer *priv) > { > - u32 fiper_ctrl, integral_period, fiper; > + u32 integral_period = netc_timer_get_integral_period(priv); > + u32 fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > + int i; > > - if (!priv->pps_enabled) > - return; > + for (i = 0; i < NETC_TMR_FIPER_NUM; i++) { > + struct netc_pp *pp = &priv->pp[i]; > + u32 fiper; > > - integral_period = netc_timer_get_integral_period(priv); > - fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > - fiper_ctrl &= ~FIPER_CTRL_DIS(0); > - fiper = NSEC_PER_SEC - integral_period; > + if (!pp->enabled) > + continue; > + > + fiper_ctrl &= ~FIPER_CTRL_DIS(i); > + > + if (pp->type == NETC_PP_PPS) > + netc_timer_set_pps_alarm(priv, i, integral_period); > + else if (pp->type == NETC_PP_PEROUT) > + netc_timer_set_perout_alarm(priv, i, integral_period); > + > + fiper = pp->period - integral_period; > + netc_timer_wr(priv, NETC_TMR_FIPER(i), fiper); > + } > > - netc_timer_set_pps_alarm(priv, 0, integral_period); > - netc_timer_wr(priv, NETC_TMR_FIPER(0), fiper); > netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); > } > > @@ -292,6 +526,8 @@ static int netc_timer_enable(struct ptp_clock_info *ptp, > switch (rq->type) { > case PTP_CLK_REQ_PPS: > return netc_timer_enable_pps(priv, rq, on); > + case PTP_CLK_REQ_PEROUT: > + return net_timer_enable_perout(priv, rq, on); > default: > return -EOPNOTSUPP; > } > @@ -310,9 +546,9 @@ static void netc_timer_adjust_period(struct netc_timer *priv, u64 period) > tmr_ctrl = u32_replace_bits(old_tmr_ctrl, integral_period, > TMR_CTRL_TCLK_PERIOD); > if (tmr_ctrl != old_tmr_ctrl) { > - netc_timer_disable_pps_fiper(priv); > + netc_timer_disable_fiper(priv); > netc_timer_wr(priv, NETC_TMR_CTRL, tmr_ctrl); > - netc_timer_enable_pps_fiper(priv); > + netc_timer_enable_fiper(priv); > } > > netc_timer_wr(priv, NETC_TMR_ADD, fractional_period); > @@ -339,7 +575,7 @@ static int netc_timer_adjtime(struct ptp_clock_info *ptp, s64 delta) > > spin_lock_irqsave(&priv->lock, flags); > > - netc_timer_disable_pps_fiper(priv); > + netc_timer_disable_fiper(priv); > > /* Adjusting TMROFF instead of TMR_CNT is that the timer > * counter keeps increasing during reading and writing > @@ -349,7 +585,7 @@ static int netc_timer_adjtime(struct ptp_clock_info *ptp, s64 delta) > tmr_off += delta; > netc_timer_offset_write(priv, tmr_off); > > - netc_timer_enable_pps_fiper(priv); > + netc_timer_enable_fiper(priv); > > spin_unlock_irqrestore(&priv->lock, flags); > > @@ -386,10 +622,10 @@ static int netc_timer_settime64(struct ptp_clock_info *ptp, > > spin_lock_irqsave(&priv->lock, flags); > > - netc_timer_disable_pps_fiper(priv); > + netc_timer_disable_fiper(priv); > netc_timer_offset_write(priv, 0); > netc_timer_cnt_write(priv, ns); > - netc_timer_enable_pps_fiper(priv); > + netc_timer_enable_fiper(priv); > > spin_unlock_irqrestore(&priv->lock, flags); > > @@ -418,6 +654,7 @@ static const struct ptp_clock_info netc_timer_ptp_caps = { > .n_pins = 0, > .n_alarm = 2, > .pps = 1, > + .n_per_out = 3, > .adjfine = netc_timer_adjfine, > .adjtime = netc_timer_adjtime, > .gettimex64 = netc_timer_gettimex64, > @@ -575,6 +812,9 @@ static irqreturn_t netc_timer_isr(int irq, void *data) > if (tmr_event & TMR_TEVENT_ALMEN(0)) > netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0); > > + if (tmr_event & TMR_TEVENT_ALMEN(1)) > + netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 1); > + > if (tmr_event & TMR_TEVENT_PPEN_ALL) { > event.type = PTP_CLOCK_PPS; > ptp_clock_event(priv->clock, &event); > @@ -619,6 +859,15 @@ static void netc_timer_free_msix_irq(struct netc_timer *priv) > pci_free_irq_vectors(pdev); > } > > +static int netc_timer_get_global_ip_rev(struct netc_timer *priv) > +{ > + u32 val; > + > + val = netc_timer_rd(priv, NETC_GLOBAL_OFFSET + NETC_GLOBAL_IPBRR0); > + > + return val & IPBRR0_IP_REV; > +} > + > static int netc_timer_probe(struct pci_dev *pdev, > const struct pci_device_id *id) > { > @@ -631,6 +880,12 @@ static int netc_timer_probe(struct pci_dev *pdev, > return err; > > priv = pci_get_drvdata(pdev); > + priv->revision = netc_timer_get_global_ip_rev(priv); > + if (priv->revision == NETC_REV_4_1) > + priv->fs_alarm_num = 1; > + else > + priv->fs_alarm_num = NETC_TMR_ALARM_NUM; > + > err = netc_timer_parse_dt(priv); > if (err) { > if (err != -EPROBE_DEFER) > @@ -640,6 +895,7 @@ static int netc_timer_probe(struct pci_dev *pdev, > > priv->caps = netc_timer_ptp_caps; > priv->oclk_prsc = NETC_TMR_DEFAULT_PRSC; > + priv->pps_channel = NETC_TMR_INVALID_CHANNEL; > spin_lock_init(&priv->lock); > > err = netc_timer_init_msix_irq(priv); > -- > 2.34.1 >
On Tue, Aug 12, 2025 at 05:46:25PM +0800, Wei Fang wrote: > @@ -210,77 +343,178 @@ static void netc_timer_set_pps_alarm(struct netc_timer *priv, int channel, > static int netc_timer_enable_pps(struct netc_timer *priv, > struct ptp_clock_request *rq, int on) > { > - u32 fiper, fiper_ctrl; > + struct device *dev = &priv->pdev->dev; > unsigned long flags; > + struct netc_pp *pp; > + int err = 0; > > spin_lock_irqsave(&priv->lock, flags); > > - fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL); > - > if (on) { ... > } else { > - if (!priv->pps_enabled) > + /* pps_channel is invalid if PPS is not enabled, so no > + * processing is needed. > + */ > + if (priv->pps_channel >= NETC_TMR_FIPER_NUM) > goto unlock_spinlock; > > - fiper = NETC_TMR_DEFAULT_FIPER; > - priv->tmr_emask &= ~(TMR_TEVNET_PPEN(0) | > - TMR_TEVENT_ALMEN(0)); > - fiper_ctrl |= FIPER_CTRL_DIS(0); > - priv->pps_enabled = false; > - netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0); > + netc_timer_disable_periodic_pulse(priv, priv->pps_channel); > + priv->fs_alarm_bitmap &= ~BIT(pp->alarm_id); You dereference "pp"->alarm_id before assigning "pp" one line below. > + pp = &priv->pp[priv->pps_channel]; > + memset(pp, 0, sizeof(*pp)); > + priv->pps_channel = NETC_TMR_INVALID_CHANNEL; > } > > - netc_timer_wr(priv, NETC_TMR_TEMASK, priv->tmr_emask); > - netc_timer_wr(priv, NETC_TMR_FIPER(0), fiper); > - netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); > +unlock_spinlock: > + spin_unlock_irqrestore(&priv->lock, flags); > + > + return err; > +}
© 2016 - 2025 Red Hat, Inc.