Netdev List
 help / color / mirror / Atom feed
From: Petr Oros <poros@redhat.com>
To: Ivan Vecera <ivecera@redhat.com>, netdev@vger.kernel.org
Cc: Chris du Quesnay <Chris.duQuesnay@microchip.com>,
	Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
	"David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Jiri Pirko <jiri@resnulli.us>,
	Michal Schmidt <mschmidt@redhat.com>,
	Paolo Abeni <pabeni@redhat.com>,
	Pasi Vaananen <pvaanane@redhat.com>,
	Prathosh Satish <Prathosh.Satish@microchip.com>,
	Richard Cochran <richardcochran@gmail.com>,
	Simon Horman <horms@kernel.org>,
	Vadim Fedorenko <vadim.fedorenko@linux.dev>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v2 1/2] dpll: zl3073x: add channel ToD, phase step and TIE operations
Date: Fri, 17 Jul 2026 10:41:47 +0200	[thread overview]
Message-ID: <6f547bbb-596b-4937-8a3d-3d59d9b5ca96@redhat.com> (raw)
In-Reply-To: <20260713103739.1553284-2-ivecera@redhat.com>


On 7/13/26 12:37, Ivan Vecera wrote:
> Add low-level DPLL channel operations for ToD read/write/adjust,
> output phase step, delta frequency offset write and TIE (Time
> Interval Error) write. These serve as building blocks for the PTP
> clock callbacks added in the next patch.
>
> ToD operations use a wait-before-write pattern to avoid blocking
> after each operation. tod_adjust additionally waits for completion
> since callers may follow with phase step operations.
>
> The tod_ready_wait helper selects the poll timeout based on the
> current ToD command - write operations use a longer timeout (1000 ms)
> than reads (30 ms).
>
> The ToD read captures system timestamps (ptp_system_timestamp) around
> the HW command and completion poll to support cross-timestamping.
>
> The TIE write operation provides sub-picosecond resolution phase
> adjustment for modes where the DPLL is tracking a reference
> (AUTO and REFLOCK).
>
> Add output step-time mask invariant to zl3073x_chan and
> zl3073x_chan_is_out_stepped() helper to check if an output
> participates in step-time operations.
>
> Tested-by: Chris du Quesnay <Chris.duQuesnay@microchip.com>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
> ---
>   drivers/dpll/zl3073x/chan.c | 307 ++++++++++++++++++++++++++++++++++++
>   drivers/dpll/zl3073x/chan.h |  48 ++++++
>   drivers/dpll/zl3073x/core.c |   8 +
>   drivers/dpll/zl3073x/core.h |   8 +
>   drivers/dpll/zl3073x/regs.h |  56 +++++++
>   5 files changed, 427 insertions(+)
>
> diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c
> index 4ec2cf53dad46..53032e782fd4a 100644
> --- a/drivers/dpll/zl3073x/chan.c
> +++ b/drivers/dpll/zl3073x/chan.c
> @@ -3,6 +3,7 @@
>   #include <linux/cleanup.h>
>   #include <linux/delay.h>
>   #include <linux/dev_printk.h>
> +#include <linux/ptp_clock_kernel.h>
>   #include <linux/string.h>
>   #include <linux/types.h>
>   
> @@ -202,6 +203,11 @@ int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index)
>   		zl3073x_chan_refsel_state_get(chan),
>   		zl3073x_chan_refsel_ref_get(chan));
>   
> +	rc = zl3073x_read_u16(zldev, ZL_REG_OUTPUT_STEP_TIME_MASK,
> +			      &chan->out_step_time_mask);
> +	if (rc)
> +		return rc;
> +
>   	guard(mutex)(&zldev->multiop_lock);
>   
>   	/* Read DPLL configuration from mailbox */
> @@ -234,6 +240,307 @@ const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
>   	return &zldev->chan[index];
>   }
>   
> +/**
> + * zl3073x_chan_tod_ready_wait - wait for ToD semaphore to clear
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + *
> + * Polls the ToD control register until the semaphore bit is cleared,
> + * indicating the device has completed the previous ToD operation.
> + *
> + * Return: 0 on success, -EBUSY if semaphore not cleared, <0 on error
> + */
> +static int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch)
> +{
> +	unsigned int timeout;
> +	u8 tod_ctrl;
> +	int rc;
> +
> +	rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch), &tod_ctrl);
> +	if (rc)
> +		return rc;
> +
> +	switch (FIELD_GET(ZL_DPLL_TOD_CTRL_CMD, tod_ctrl)) {
> +	case ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ:
> +		timeout = ZL_POLL_TOD_WR_TIMEOUT_US;
> +		break;
> +	default:
> +		timeout = ZL_POLL_TOD_RD_TIMEOUT_US;
> +		break;
> +	}
> +
> +	rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch),
> +				  ZL_DPLL_TOD_CTRL_SEM, timeout);
> +
> +	return rc == -ETIMEDOUT ? -EBUSY : rc;
> +}
> +
> +/**
> + * zl3073x_chan_tod_ctrl - issue ToD command
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @cmd: ToD command to execute
> + *
> + * Writes the semaphore and command to dpll_tod_ctrl. The caller must
> + * ensure the device is ready (semaphore clear) before calling and
> + * must wait for completion if needed.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +static int zl3073x_chan_tod_ctrl(struct zl3073x_dev *zldev, u8 ch, u8 cmd)
> +{
> +	return zl3073x_write_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch),
> +				ZL_DPLL_TOD_CTRL_SEM | cmd);
> +}
> +
> +/**
> + * zl3073x_chan_tod_read - read ToD registers after issuing a command
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @next_hz: if true, read predicted ToD at next 1 Hz; otherwise read current
> + * @ts: timespec to store the result
> + * @sts: optional system timestamp pair for cross-timestamping
> + *
> + * Context: Caller must serialize all zl3073x_chan_tod_* calls externally.
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch,
> +			  bool next_hz, struct timespec64 *ts,
> +			  struct ptp_system_timestamp *sts)
> +{
> +	u32 nsec;
> +	u64 sec;
> +	u8 cmd;
> +	int rc;
> +
> +	if (next_hz)
> +		cmd = ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ;
> +	else
> +		cmd = ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT;
> +
> +	/* Wait for any previous ToD operation to complete */
> +	rc = zl3073x_chan_tod_ready_wait(zldev, ch);
> +	if (rc)
> +		return rc;
> +
> +	ptp_read_system_prets(sts);
> +	rc = zl3073x_chan_tod_ctrl(zldev, ch, cmd);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_chan_tod_ready_wait(zldev, ch);
> +	if (rc)
> +		return rc;
> +	ptp_read_system_postts(sts);
> +
> +	rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_TOD_SEC(ch), &sec);
> +	if (rc)
> +		return rc;
> +
> +	/* HW nanoseconds are always in [0, NSEC_PER_SEC) range */
> +	rc = zl3073x_read_u32(zldev, ZL_REG_DPLL_TOD_NS(ch), &nsec);
> +	if (rc)
> +		return rc;
> +
> +	ts->tv_sec = sec;
> +	ts->tv_nsec = nsec;
> +
> +	return 0;
> +}
> +
> +/**
> + * zl3073x_chan_tod_write - write ToD registers and trigger 1 Hz update
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @ts: time to set
> + *
> + * Context: Caller must serialize all zl3073x_chan_tod_* calls externally.
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch,
> +			   struct timespec64 ts)
> +{
> +	int rc;
> +
> +	/* Wait for any previous ToD operation to complete */
> +	rc = zl3073x_chan_tod_ready_wait(zldev, ch);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_TOD_SEC(ch), ts.tv_sec);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_write_u32(zldev, ZL_REG_DPLL_TOD_NS(ch), ts.tv_nsec);
> +	if (rc)
> +		return rc;
> +
> +	return zl3073x_chan_tod_ctrl(zldev, ch,
> +				    ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ);
> +}
> +
> +/**
> + * zl3073x_chan_tod_adjust - atomic ToD read-modify-write with rollover guard
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @delta: time adjustment to apply
> + *
> + * Reads the next-Hz ToD and current ToD, then checks whether enough time
> + * remains before the next 1 Hz rollover to safely complete the write.
> + * If less than 20 ms remains, waits for the rollover and increments the
> + * next-Hz seconds by one. Applies @delta and writes the result back.
> + *
> + * Context: Caller must serialize all zl3073x_chan_tod_* calls externally.
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch,
> +			    struct timespec64 delta)
> +{
> +	static const long threshold_ns = 20 * NSEC_PER_MSEC;
> +	struct timespec64 ts_next, ts_cur, diff;
> +	int rc;
> +
> +	/* Read predicted ToD at next 1 Hz tick */
> +	rc = zl3073x_chan_tod_read(zldev, ch, true, &ts_next, NULL);
> +	if (rc)
> +		return rc;
> +
> +	/* Read current ToD to determine remaining margin */
> +	rc = zl3073x_chan_tod_read(zldev, ch, false, &ts_cur, NULL);
> +	if (rc)
> +		return rc;
> +
> +	/* If too close to (or past) the next rollover, wait it out */
> +	diff = timespec64_sub(ts_next, ts_cur);
> +	if (diff.tv_sec < 0 || (!diff.tv_sec && diff.tv_nsec < threshold_ns)) {
> +		if (!diff.tv_sec && diff.tv_nsec)
> +			fsleep((unsigned long)diff.tv_nsec / NSEC_PER_USEC + 1);
> +		ts_next.tv_sec++;
> +	}
> +
> +	/* Apply delta to the next-Hz ToD */
> +	ts_next = timespec64_add(ts_next, delta);
> +	if (!timespec64_valid(&ts_next))
> +		return -EINVAL;
> +
> +	/* Write adjusted ToD back and wait for completion */
> +	rc = zl3073x_chan_tod_write(zldev, ch, ts_next);
> +	if (rc)
> +		return rc;
> +
> +	return zl3073x_chan_tod_ready_wait(zldev, ch);
> +}
> +
> +/**
> + * zl3073x_chan_df_offset_set - write delta frequency offset to hardware
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @offset: frequency offset in 2^-48 steps
> + *
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset)
> +{
> +	int rc;
> +
> +	rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_DF_OFFSET(ch), offset);
> +	if (!rc)
> +		zldev->chan[ch].df_offset = offset;
> +
> +	return rc;
> +}
> +
> +/**
> + * zl3073x_chan_tie_write - adjust DPLL phase using TIE write
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @delta_ns: phase adjustment in nanoseconds (must be within +-1s)
> + *
> + * Converts nanoseconds to TIE units (0.01 ps) and writes TIE data
> + * to the specified channel.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns)
> +{
> +	s64 tie_data;
> +	int rc;
> +
> +	guard(mutex)(&zldev->tie_lock);
> +
> +	/* Wait for any previous TIE operation to complete */
> +	rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_TIE_CTRL,
> +				  ZL_DPLL_TIE_CTRL_OP,
> +				  ZL_POLL_TIE_WR_TIMEOUT_US);
> +	if (rc)
> +		return rc;
> +
> +	/* Convert ns to TIE units (0.01 ps = 10^-14 s) */
> +	tie_data = delta_ns * 100000LL;
> +
> +	rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_TIE_DATA(ch), tie_data);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_TIE_CTRL_MASK, BIT(ch));
> +	if (rc)
> +		return rc;
> +
> +	return zl3073x_write_u8(zldev, ZL_REG_DPLL_TIE_CTRL,
> +				ZL_DPLL_TIE_CTRL_OP_WR);
> +}
> +
> +/**
> + * zl3073x_chan_phase_step - execute one output phase step operation
> + * @zldev: pointer to zl3073x device
> + * @ch: DPLL channel index
> + * @out_mask: bitmask of outputs to step
> + * @step_cycles: phase step in synthesizer clock cycles
> + * @tod_step: also step the ToD counter
> + *
> + * All masked outputs must use synthesizers of the same frequency since
> + * the step value is in synthesizer clock cycles.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch,
> +			    u16 out_mask, s32 step_cycles,
> +			    bool tod_step)
> +{
> +	u8 ctrl;
> +	int rc;
> +
> +	guard(mutex)(&zldev->phase_step_lock);
> +
> +	/* Wait for any previous phase step operation to complete */
> +	rc = zl3073x_poll_zero_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_CTRL,
> +				  ZL_OUTPUT_PHASE_STEP_CTRL_OP,
> +				  ZL_POLL_PHASE_STEP_TIMEOUT_US);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_STEP_DATA,
> +			       step_cycles);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_write_u16(zldev, ZL_REG_OUTPUT_PHASE_STEP_MASK, out_mask);
> +	if (rc)
> +		return rc;
> +
> +	rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_NUMBER, 1);
> +	if (rc)
> +		return rc;
> +
> +	ctrl = FIELD_PREP(ZL_OUTPUT_PHASE_STEP_CTRL_DPLL, ch) |
> +	       FIELD_PREP(ZL_OUTPUT_PHASE_STEP_CTRL_OP,
> +			  ZL_OUTPUT_PHASE_STEP_CTRL_OP_WRITE);
> +	if (tod_step)
> +		ctrl |= ZL_OUTPUT_PHASE_STEP_CTRL_TOD_STEP;
> +
> +	return zl3073x_write_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_CTRL, ctrl);
> +}
> +
>   /**
>    * zl3073x_chan_state_set - commit DPLL channel state changes to hardware
>    * @zldev: pointer to zl3073x_dev structure
> diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h
> index dc9c6d95bdee7..9dc5a3f1991f1 100644
> --- a/drivers/dpll/zl3073x/chan.h
> +++ b/drivers/dpll/zl3073x/chan.h
> @@ -5,10 +5,12 @@
>   
>   #include <linux/bitfield.h>
>   #include <linux/stddef.h>
> +#include <linux/time64.h>
>   #include <linux/types.h>
>   
>   #include "regs.h"
>   
> +struct ptp_system_timestamp;
>   struct zl3073x_dev;
>   
>   /**
> @@ -16,6 +18,7 @@ struct zl3073x_dev;
>    * @ctrl: DPLL control register value
>    * @mode_refsel: mode and reference selection register value
>    * @ref_prio: reference priority registers (4 bits per ref, P/N packed)
> + * @out_step_time_mask: output step-time mask
>    * @mon_status: monitor status register value
>    * @refsel_status: reference selection status register value
>    * @df_offset: frequency offset vs tracked reference in 2^-48 steps
> @@ -26,6 +29,9 @@ struct zl3073x_chan {
>   		u8	mode_refsel;
>   		u8	ref_prio[ZL3073X_NUM_REFS / 2];
>   	);
> +	struct_group(inv, /* Invariants */
> +		u16	out_step_time_mask;
> +	);
>   	struct_group(stat,
>   		u8	mon_status;
>   		u8	refsel_status;
> @@ -42,6 +48,20 @@ int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
>   int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
>   int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index);
>   
> +int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch,
> +			  bool next_hz, struct timespec64 *ts,
> +			  struct ptp_system_timestamp *sts);
> +int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch,
> +			   struct timespec64 ts);
> +int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch,
> +			    struct timespec64 delta);
> +int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch,
> +			    u16 out_mask, s32 step_cycles, bool tod_step);
> +
> +int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset);
> +
> +int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns);
> +
>   /**
>    * zl3073x_chan_df_offset_get - get cached df_offset vs tracked reference
>    * @chan: pointer to channel state
> @@ -200,6 +220,21 @@ static inline bool zl3073x_chan_mode_is_reflock(const struct zl3073x_chan *chan)
>   	return zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_REFLOCK;
>   }
>   
> +/**
> + * zl3073x_chan_mode_supports_tie - check if channel mode supports TIE write
> + * @chan: pointer to channel state
> + *
> + * TIE write is supported in AUTO and REFLOCK modes regardless of lock state.
> + *
> + * Return: true if TIE write is supported, false otherwise
> + */
> +static inline bool
> +zl3073x_chan_mode_supports_tie(const struct zl3073x_chan *chan)
> +{
> +	return zl3073x_chan_mode_is_auto(chan) ||
> +		zl3073x_chan_mode_is_reflock(chan);
> +}
> +
>   /**
>    * zl3073x_chan_is_ho_ready - check if holdover is ready
>    * @chan: pointer to channel state
> @@ -233,4 +268,17 @@ static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan)
>   	return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status);
>   }
>   
> +/**
> + * zl3073x_chan_is_out_stepped - check if output is in step-time mask
> + * @chan: pointer to channel state
> + * @out: output index
> + *
> + * Return: true if output is affected by step-time operations
> + */
> +static inline bool
> +zl3073x_chan_is_out_stepped(const struct zl3073x_chan *chan, u8 out)
> +{
> +	return !!(chan->out_step_time_mask & BIT(out));
> +}
> +
>   #endif /* _ZL3073X_CHAN_H */
> diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
> index 7f5afaaae6342..b2f9fc97fd1b6 100644
> --- a/drivers/dpll/zl3073x/core.c
> +++ b/drivers/dpll/zl3073x/core.c
> @@ -1033,6 +1033,14 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev)
>   	 * and/or polls are required to be done atomically.
>   	 */
>   	rc = devm_mutex_init(zldev->dev, &zldev->multiop_lock);
> +	if (rc)
> +		return dev_err_probe(zldev->dev, rc,
> +				     "Failed to initialize mutex\n");
> +	rc = devm_mutex_init(zldev->dev, &zldev->phase_step_lock);
> +	if (rc)
> +		return dev_err_probe(zldev->dev, rc,
> +				     "Failed to initialize mutex\n");
> +	rc = devm_mutex_init(zldev->dev, &zldev->tie_lock);
>   	if (rc)
>   		return dev_err_probe(zldev->dev, rc,
>   				     "Failed to initialize mutex\n");
> diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
> index 78dc208f3eea2..2dc836d0c8f6b 100644
> --- a/drivers/dpll/zl3073x/core.h
> +++ b/drivers/dpll/zl3073x/core.h
> @@ -26,6 +26,10 @@ struct zl3073x_dpll;
>   #define ZL_POLL_HWREG_TIMEOUT_US	(50 * USEC_PER_MSEC)
>   #define ZL_POLL_MB_TIMEOUT_US		(30 * USEC_PER_MSEC)
>   #define ZL_POLL_PHASE_ERR_TIMEOUT_US	(50 * USEC_PER_MSEC)
> +#define ZL_POLL_PHASE_STEP_TIMEOUT_US	(3000 * USEC_PER_MSEC)
> +#define ZL_POLL_TIE_WR_TIMEOUT_US	(1000 * USEC_PER_MSEC)
> +#define ZL_POLL_TOD_RD_TIMEOUT_US	(30 * USEC_PER_MSEC)
> +#define ZL_POLL_TOD_WR_TIMEOUT_US	(1000 * USEC_PER_MSEC)
>   
>   enum zl3073x_flags {
>   	ZL3073X_FLAG_REF_PHASE_COMP_32_BIT,
> @@ -55,6 +59,8 @@ struct zl3073x_chip_info {
>    * @regmap: regmap to access device registers
>    * @info: detected chip info
>    * @multiop_lock: to serialize multiple register operations
> + * @tie_lock: to serialize TIE write operations
> + * @phase_step_lock: to serialize output phase step operations
>    * @ref: array of input references' invariants
>    * @out: array of outs' invariants
>    * @synth: array of synths' invariants
> @@ -71,6 +77,8 @@ struct zl3073x_dev {
>   	struct regmap			*regmap;
>   	const struct zl3073x_chip_info	*info;
>   	struct mutex			multiop_lock;
> +	struct mutex			tie_lock;
> +	struct mutex			phase_step_lock;
>   
>   	/* Invariants */
>   	struct zl3073x_ref	ref[ZL3073X_NUM_REFS];
> diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h
> index b70ead7d4495b..447757e99845d 100644
> --- a/drivers/dpll/zl3073x/regs.h
> +++ b/drivers/dpll/zl3073x/regs.h
> @@ -179,6 +179,20 @@
>   #define ZL_DPLL_DF_READ_CMD			GENMASK(2, 0)
>   #define ZL_DPLL_DF_READ_CMD_ACC_I		4
>   
> +#define ZL_REG_DPLL_TIE_CTRL			ZL_REG(5, 0x30, 1)
> +#define ZL_DPLL_TIE_CTRL_OP			GENMASK(2, 0)
> +#define ZL_DPLL_TIE_CTRL_OP_WR			4
> +
> +#define ZL_REG_DPLL_TIE_CTRL_MASK		ZL_REG(5, 0x31, 1)
> +
> +#define ZL_REG_DPLL_TOD_CTRL(_idx)					\
> +	ZL_REG_IDX(_idx, 5, 0x38, 1, 8, 1)
> +#define ZL_DPLL_TOD_CTRL_SEM			BIT(4)
> +#define ZL_DPLL_TOD_CTRL_CMD			GENMASK(3, 0)
> +#define ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ	1
> +#define ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT	8
> +#define ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ	9
> +
>   #define ZL_REG_DPLL_MEAS_CTRL			ZL_REG(5, 0x50, 1)
>   #define ZL_DPLL_MEAS_CTRL_EN			BIT(0)
>   #define ZL_DPLL_MEAS_CTRL_AVG_FACTOR		GENMASK(7, 4)
> @@ -193,6 +207,9 @@
>   
>   /*******************************
>    * Register Pages 6-7, DPLL Data
> + *
> + * Per-channel registers with stride 0x20. Channels 0-3 reside on page 6,
> + * channel 4 on page 7.
>    *******************************/
>   
>   #define ZL_REG_DPLL_DF_OFFSET_03(_idx)					\
> @@ -202,6 +219,24 @@
>   	((_idx) < 4 ? ZL_REG_DPLL_DF_OFFSET_03(_idx) : ZL_REG_DPLL_DF_OFFSET_4)
>   #define ZL_DPLL_DF_OFFSET_UNKNOWN	S64_MIN
>   
> +#define ZL_REG_DPLL_TIE_DATA_03(_idx)					\
> +	ZL_REG_IDX(_idx, 6, 0x0C, 6, 4, 0x20)
> +#define ZL_REG_DPLL_TIE_DATA_4			ZL_REG(7, 0x0C, 6)
> +#define ZL_REG_DPLL_TIE_DATA(_idx)					\
> +	((_idx) < 4 ? ZL_REG_DPLL_TIE_DATA_03(_idx) : ZL_REG_DPLL_TIE_DATA_4)
> +
> +#define ZL_REG_DPLL_TOD_SEC_03(_idx)					\
> +	ZL_REG_IDX(_idx, 6, 0x12, 6, 4, 0x20)
> +#define ZL_REG_DPLL_TOD_SEC_4			ZL_REG(7, 0x12, 6)
> +#define ZL_REG_DPLL_TOD_SEC(_idx)					\
> +	((_idx) < 4 ? ZL_REG_DPLL_TOD_SEC_03(_idx) : ZL_REG_DPLL_TOD_SEC_4)
> +
> +#define ZL_REG_DPLL_TOD_NS_03(_idx)					\
> +	ZL_REG_IDX(_idx, 6, 0x18, 4, 4, 0x20)
> +#define ZL_REG_DPLL_TOD_NS_4			ZL_REG(7, 0x18, 4)
> +#define ZL_REG_DPLL_TOD_NS(_idx)					\
> +	((_idx) < 4 ? ZL_REG_DPLL_TOD_NS_03(_idx) : ZL_REG_DPLL_TOD_NS_4)
> +
>   /***********************************
>    * Register Page 9, Synth and Output
>    ***********************************/
> @@ -221,6 +256,8 @@
>   #define ZL_OUTPUT_CTRL_EN			BIT(0)
>   #define ZL_OUTPUT_CTRL_SYNTH_SEL		GENMASK(6, 4)
>   
> +#define ZL_REG_OUTPUT_STEP_TIME_MASK		ZL_REG(9, 0x36, 2)
> +
>   /*******************************
>    * Register Page 10, Ref Mailbox
>    *******************************/
> @@ -316,6 +353,25 @@
>   #define ZL_REG_OUTPUT_ESYNC_WIDTH		ZL_REG(14, 0x18, 4)
>   #define ZL_REG_OUTPUT_PHASE_COMP		ZL_REG(14, 0x20, 4)
>   
> +/***********************************
> + * Register Page 9, Output Phase Step
> + ***********************************/
> +
> +#define ZL_REG_OUTPUT_PHASE_STEP_CTRL		ZL_REG(9, 0x38, 1)
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_DPLL		GENMASK(6, 4)
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_TOD_STEP	BIT(3)
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_OP		GENMASK(1, 0)
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_NONE	0
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_RESET	1
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_READ	2
> +#define ZL_OUTPUT_PHASE_STEP_CTRL_OP_WRITE	3
> +
> +#define ZL_REG_OUTPUT_PHASE_STEP_NUMBER		ZL_REG(9, 0x39, 1)
> +
> +#define ZL_REG_OUTPUT_PHASE_STEP_MASK		ZL_REG(9, 0x3a, 2)
> +
> +#define ZL_REG_OUTPUT_PHASE_STEP_DATA		ZL_REG(9, 0x3c, 4)
> +
>   /*
>    * Register Page 255 - HW registers access
>    */

lgtm,

Reviewed-by: Petr Oros <poros@redhat.com>



  reply	other threads:[~2026-07-17  8:41 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-13 10:37 [PATCH net-next v2 0/2] dpll: zl3073x: add PTP clock support Ivan Vecera
2026-07-13 10:37 ` [PATCH net-next v2 1/2] dpll: zl3073x: add channel ToD, phase step and TIE operations Ivan Vecera
2026-07-17  8:41   ` Petr Oros [this message]
2026-07-13 10:37 ` [PATCH net-next v2 2/2] dpll: zl3073x: add PTP clock support Ivan Vecera
2026-07-17  8:43   ` Petr Oros

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6f547bbb-596b-4937-8a3d-3d59d9b5ca96@redhat.com \
    --to=poros@redhat.com \
    --cc=Chris.duQuesnay@microchip.com \
    --cc=Prathosh.Satish@microchip.com \
    --cc=arkadiusz.kubalewski@intel.com \
    --cc=davem@davemloft.net \
    --cc=horms@kernel.org \
    --cc=ivecera@redhat.com \
    --cc=jiri@resnulli.us \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mschmidt@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pvaanane@redhat.com \
    --cc=richardcochran@gmail.com \
    --cc=vadim.fedorenko@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox