* [PATCH net-next 0/6] dpll: zl3073x: Refactor state management
@ 2025-11-10 17:58 Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 1/6] dpll: zl3073x: Store raw register values instead of parsed state Ivan Vecera
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, Petr Oros, linux-kernel
This patch set is a refactoring of the zl3073x driver to clean up
state management, improve modularity, and significantly reduce
on-demand I/O.
The driver's dpll.c implementation previously performed on-demand
register reads and writes (wrapped in mailbox operations) to get
or set properties like frequency, phase, and embedded-sync settings.
This cluttered the DPLL logic with low-level I/O, duplicated locking,
and led to inefficient bus traffic.
This series addresses this by:
1. Splitting the monolithic 'core.c' into logical units ('ref.c',
'out.c', 'synth.c').
2. Implementing a full read/write-back cache for 'zl3073x_ref' and
'zl3073x_out' structures.
All state is now read once during '_state_fetch()' (and status updated
periodically). DPLL get callbacks read from this cache. Set callbacks
modify a copy of the state, which is then committed via a new
'..._state_set()' function. These '_state_set' functions compare
the new state to the cached state and write *only* the modified
register values back to the hardware, all within a single mailbox
sequence.
The result is a much cleaner 'dpll.c' that is almost entirely
free of direct register I/O, and all state logic is properly
encapsulated in its respective file.
The series is broken down as follows:
* Patch 1: Changes the state structs to store raw register values
(e.g., 'config', 'ctrl') instead of parsed booleans, centralizing
parsing logic into the helpers.
* Patch 2: Splits the logic from 'core.c' into new 'ref.c', 'out.c'
and 'synth.c' files, creating a 'zl3073x_dev_...' abstraction layer.
* Patch 3: Introduces the caching concept by reading and caching
the reference monitor status periodically, removing scattered
reads from 'dpll.c'.
* Patch 4: Expands the 'zl3073x_ref' struct to cache *all* reference
properties and adds 'zl3073x_ref_state_set()' to write back changes.
* Patch 5: Does the same for the 'zl3073x_out' struct, caching all
output properties and adding 'zl3073x_out_state_set()'.
* Patch 6: A final cleanup that removes the 'zl3073x_dev_...' wrapper
functions that became redundant after the refactoring.
Ivan Vecera (6):
dpll: zl3073x: Store raw register values instead of parsed state
dpll: zl3073x: Split ref, out, and synth logic from core
dpll: zl3073x: Cache reference monitor status
dpll: zl3073x: Cache all reference properties in zl3073x_ref
dpll: zl3073x: Cache all output properties in zl3073x_out
dpll: zl3073x: Remove unused dev wrappers
drivers/dpll/zl3073x/Makefile | 3 +-
drivers/dpll/zl3073x/core.c | 243 +----------
drivers/dpll/zl3073x/core.h | 184 +++-----
drivers/dpll/zl3073x/dpll.c | 776 ++++++++--------------------------
drivers/dpll/zl3073x/out.c | 163 +++++++
drivers/dpll/zl3073x/out.h | 88 ++++
drivers/dpll/zl3073x/prop.c | 12 +-
drivers/dpll/zl3073x/ref.c | 197 +++++++++
drivers/dpll/zl3073x/ref.h | 126 ++++++
drivers/dpll/zl3073x/synth.c | 87 ++++
drivers/dpll/zl3073x/synth.h | 73 ++++
11 files changed, 1008 insertions(+), 944 deletions(-)
create mode 100644 drivers/dpll/zl3073x/out.c
create mode 100644 drivers/dpll/zl3073x/out.h
create mode 100644 drivers/dpll/zl3073x/ref.c
create mode 100644 drivers/dpll/zl3073x/ref.h
create mode 100644 drivers/dpll/zl3073x/synth.c
create mode 100644 drivers/dpll/zl3073x/synth.h
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-next 1/6] dpll: zl3073x: Store raw register values instead of parsed state
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
@ 2025-11-10 17:58 ` Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 2/6] dpll: zl3073x: Split ref, out, and synth logic from core Ivan Vecera
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, linux-kernel
The zl3073x_ref, zl3073x_out and zl3073x_synth structures
previously stored state that was parsed from register reads. This
included values like boolean 'enabled' flags, synthesizer selections,
and pre-calculated frequencies.
This commit refactors the state management to store the raw register
values directly in these structures. The various inline helper functions
are updated to parse these raw values on-demand using FIELD_GET.
Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/core.c | 81 ++++++++++++-------------------------
drivers/dpll/zl3073x/core.h | 61 ++++++++++++++++------------
2 files changed, 60 insertions(+), 82 deletions(-)
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index e42e527813cf8..50c1fe59bc7f0 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -598,25 +598,22 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
* @zldev: pointer to zl3073x_dev structure
* @index: input reference index to fetch state for
*
- * Function fetches information for the given input reference that are
- * invariant and stores them for later use.
+ * Function fetches state for the given input reference and stores it for
+ * later user.
*
* Return: 0 on success, <0 on error
*/
static int
zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
{
- struct zl3073x_ref *input = &zldev->ref[index];
- u8 ref_config;
+ struct zl3073x_ref *ref = &zldev->ref[index];
int rc;
/* If the input is differential then the configuration for N-pin
* reference is ignored and P-pin config is used for both.
*/
- if (zl3073x_is_n_pin(index) &&
- zl3073x_ref_is_diff(zldev, index - 1)) {
- input->enabled = zl3073x_ref_is_enabled(zldev, index - 1);
- input->diff = true;
+ if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(zldev, index - 1)) {
+ memcpy(ref, &zldev->ref[index - 1], sizeof(*ref));
return 0;
}
@@ -630,16 +627,14 @@ zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
return rc;
/* Read ref_config register */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref_config);
+ rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config);
if (rc)
return rc;
- input->enabled = FIELD_GET(ZL_REF_CONFIG_ENABLE, ref_config);
- input->diff = FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref_config);
-
dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
- str_enabled_disabled(input->enabled),
- input->diff ? "differential" : "single-ended");
+ str_enabled_disabled(zl3073x_ref_is_enabled(zldev, index)),
+ zl3073x_ref_is_diff(zldev, index)
+ ? "differential" : "single-ended");
return rc;
}
@@ -649,8 +644,8 @@ zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
* @zldev: pointer to zl3073x_dev structure
* @index: output index to fetch state for
*
- * Function fetches information for the given output (not output pin)
- * that are invariant and stores them for later use.
+ * Function fetches state of the given output (not output pin) and stores it
+ * for later use.
*
* Return: 0 on success, <0 on error
*/
@@ -658,22 +653,16 @@ static int
zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_out *out = &zldev->out[index];
- u8 output_ctrl, output_mode;
int rc;
/* Read output configuration */
- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &output_ctrl);
+ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl);
if (rc)
return rc;
- /* Store info about output enablement and synthesizer the output
- * is connected to.
- */
- out->enabled = FIELD_GET(ZL_OUTPUT_CTRL_EN, output_ctrl);
- out->synth = FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, output_ctrl);
-
dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
- str_enabled_disabled(out->enabled), out->synth);
+ str_enabled_disabled(zl3073x_out_is_enabled(zldev, index)),
+ zl3073x_out_synth_get(zldev, index));
guard(mutex)(&zldev->multiop_lock);
@@ -683,17 +672,13 @@ zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
if (rc)
return rc;
- /* Read output_mode */
- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
+ /* Read output mode */
+ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode);
if (rc)
return rc;
- /* Extract and store output signal format */
- out->signal_format = FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT,
- output_mode);
-
dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
- out->signal_format);
+ zl3073x_out_signal_format_get(zldev, index));
return rc;
}
@@ -703,8 +688,7 @@ zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
* @zldev: pointer to zl3073x_dev structure
* @index: synth index to fetch state for
*
- * Function fetches information for the given synthesizer that are
- * invariant and stores them for later use.
+ * Function fetches state of the given synthesizer and stores it for later use.
*
* Return: 0 on success, <0 on error
*/
@@ -712,25 +696,13 @@ static int
zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
{
struct zl3073x_synth *synth = &zldev->synth[index];
- u16 base, m, n;
- u8 synth_ctrl;
- u32 mult;
int rc;
/* Read synth control register */
- rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth_ctrl);
+ rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth->ctrl);
if (rc)
return rc;
- /* Store info about synth enablement and DPLL channel the synth is
- * driven by.
- */
- synth->enabled = FIELD_GET(ZL_SYNTH_CTRL_EN, synth_ctrl);
- synth->dpll = FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth_ctrl);
-
- dev_dbg(zldev->dev, "SYNTH%u is %s and driven by DPLL%u\n", index,
- str_enabled_disabled(synth->enabled), synth->dpll);
-
guard(mutex)(&zldev->multiop_lock);
/* Read synth configuration */
@@ -744,35 +716,32 @@ zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
*
* Read registers with these values
*/
- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &base);
+ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &synth->freq_base);
if (rc)
return rc;
- rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &mult);
+ rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &synth->freq_mult);
if (rc)
return rc;
- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &m);
+ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &synth->freq_m);
if (rc)
return rc;
- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &n);
+ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &synth->freq_n);
if (rc)
return rc;
/* Check denominator for zero to avoid div by 0 */
- if (!n) {
+ if (!synth->freq_n) {
dev_err(zldev->dev,
"Zero divisor for SYNTH%u retrieved from device\n",
index);
return -EINVAL;
}
- /* Compute and store synth frequency */
- zldev->synth[index].freq = div_u64(mul_u32_u32(base * m, mult), n);
-
dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index,
- zldev->synth[index].freq);
+ zl3073x_synth_freq_get(zldev, index));
return rc;
}
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index 1dca4ddcf2350..51d0fd6cfabfc 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -29,38 +29,38 @@ struct zl3073x_dpll;
/**
* struct zl3073x_ref - input reference invariant info
- * @enabled: input reference is enabled or disabled
- * @diff: true if input reference is differential
* @ffo: current fractional frequency offset
+ * @config: reference config
*/
struct zl3073x_ref {
- bool enabled;
- bool diff;
s64 ffo;
+ u8 config;
};
/**
* struct zl3073x_out - output invariant info
- * @enabled: out is enabled or disabled
- * @synth: synthesizer the out is connected to
- * @signal_format: out signal format
+ * @ctrl: output control
+ * @mode: output mode
*/
struct zl3073x_out {
- bool enabled;
- u8 synth;
- u8 signal_format;
+ u8 ctrl;
+ u8 mode;
};
/**
* struct zl3073x_synth - synthesizer invariant info
- * @freq: synthesizer frequency
- * @dpll: ID of DPLL the synthesizer is driven by
- * @enabled: synth is enabled or disabled
+ * @freq_mult: frequency multiplier
+ * @freq_base: frequency base
+ * @freq_m: frequency numerator
+ * @freq_n: frequency denominator
+ * @ctrl: synth control
*/
struct zl3073x_synth {
- u32 freq;
- u8 dpll;
- bool enabled;
+ u32 freq_mult;
+ u16 freq_base;
+ u16 freq_m;
+ u16 freq_n;
+ u8 ctrl;
};
/**
@@ -239,7 +239,10 @@ zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
static inline bool
zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->ref[index].diff;
+ if (FIELD_GET(ZL_REF_CONFIG_DIFF_EN, zldev->ref[index].config))
+ return true;
+
+ return false;
}
/**
@@ -252,7 +255,10 @@ zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
static inline bool
zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->ref[index].enabled;
+ if (FIELD_GET(ZL_REF_CONFIG_ENABLE, zldev->ref[index].config))
+ return true;
+
+ return false;
}
/**
@@ -265,7 +271,7 @@ zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
static inline u8
zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->synth[index].dpll;
+ return FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, zldev->synth[index].ctrl);
}
/**
@@ -278,7 +284,10 @@ zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
static inline u32
zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->synth[index].freq;
+ struct zl3073x_synth *synth = &zldev->synth[index];
+
+ return mul_u64_u32_div(synth->freq_base * synth->freq_m,
+ synth->freq_mult, synth->freq_n);
}
/**
@@ -291,7 +300,7 @@ zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
static inline bool
zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->synth[index].enabled;
+ return FIELD_GET(ZL_SYNTH_CTRL_EN, zldev->synth[index].ctrl);
}
/**
@@ -304,7 +313,7 @@ zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
static inline u8
zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->out[index].synth;
+ return FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, zldev->out[index].ctrl);
}
/**
@@ -321,10 +330,10 @@ zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
/* Output is enabled only if associated synth is enabled */
synth = zl3073x_out_synth_get(zldev, index);
- if (zl3073x_synth_is_enabled(zldev, synth))
- return zldev->out[index].enabled;
+ if (!zl3073x_synth_is_enabled(zldev, synth))
+ return false;
- return false;
+ return FIELD_GET(ZL_OUTPUT_CTRL_EN, zldev->out[index].ctrl);
}
/**
@@ -337,7 +346,7 @@ zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
static inline u8
zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->out[index].signal_format;
+ return FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, zldev->out[index].mode);
}
/**
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH net-next 2/6] dpll: zl3073x: Split ref, out, and synth logic from core
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 1/6] dpll: zl3073x: Store raw register values instead of parsed state Ivan Vecera
@ 2025-11-10 17:58 ` Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 3/6] dpll: zl3073x: Cache reference monitor status Ivan Vecera
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, linux-kernel
Refactor the zl3073x driver by splitting the logic for input
references, outputs and synthesizers out of the monolithic
core.[ch] files.
Move the logic for each functional block into its own dedicated files:
ref.[ch], out.[ch] and synth.[ch].
Specifically:
- Move state structures (zl3073x_ref, zl3073x_out, zl3073x_synth)
from core.h into their respective new headers
- Move state-fetching functions (..._state_fetch) from core.c to their
new .c files
- Move the zl3073x_ref_freq_factorize helper from core.c to ref.c
- Introduce a new helper layer to decouple the core device logic from
the state-parsing logic:
1. Move the original inline helpers (e.g., zl3073x_ref_is_enabled)
to the new headers (ref.h, etc.) and make them operate on a
const struct ... * pointer.
2. Create new zl3073x_dev_... prefixed functions in core.h
(e.g., zl3073x_dev_ref_is_enabled) and Implement these _dev_ functions
to fetch state using a new ..._state_get() helper and then call
the non-prefixed helper.
3. Update all driver-internal callers (in dpll.c, prop.c, etc.) to use
the new zl3073x_dev_... functions.
Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/Makefile | 3 +-
drivers/dpll/zl3073x/core.c | 194 ----------------------------------
drivers/dpll/zl3073x/core.h | 170 +++++++++++++----------------
drivers/dpll/zl3073x/dpll.c | 36 +++----
drivers/dpll/zl3073x/out.c | 67 ++++++++++++
drivers/dpll/zl3073x/out.h | 80 ++++++++++++++
drivers/dpll/zl3073x/prop.c | 12 +--
drivers/dpll/zl3073x/ref.c | 109 +++++++++++++++++++
drivers/dpll/zl3073x/ref.h | 66 ++++++++++++
drivers/dpll/zl3073x/synth.c | 87 +++++++++++++++
drivers/dpll/zl3073x/synth.h | 73 +++++++++++++
11 files changed, 582 insertions(+), 315 deletions(-)
create mode 100644 drivers/dpll/zl3073x/out.c
create mode 100644 drivers/dpll/zl3073x/out.h
create mode 100644 drivers/dpll/zl3073x/ref.c
create mode 100644 drivers/dpll/zl3073x/ref.h
create mode 100644 drivers/dpll/zl3073x/synth.c
create mode 100644 drivers/dpll/zl3073x/synth.h
diff --git a/drivers/dpll/zl3073x/Makefile b/drivers/dpll/zl3073x/Makefile
index 84e22aae57e5f..bd324c7fe7101 100644
--- a/drivers/dpll/zl3073x/Makefile
+++ b/drivers/dpll/zl3073x/Makefile
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_ZL3073X) += zl3073x.o
-zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o prop.o
+zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o \
+ out.o prop.o ref.o synth.o
obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o
zl3073x_i2c-objs := i2c.o
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index 50c1fe59bc7f0..2f340f7eb9ec3 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -129,47 +129,6 @@ const struct regmap_config zl3073x_regmap_config = {
};
EXPORT_SYMBOL_NS_GPL(zl3073x_regmap_config, "ZL3073X");
-/**
- * zl3073x_ref_freq_factorize - factorize given frequency
- * @freq: input frequency
- * @base: base frequency
- * @mult: multiplier
- *
- * Checks if the given frequency can be factorized using one of the
- * supported base frequencies. If so the base frequency and multiplier
- * are stored into appropriate parameters if they are not NULL.
- *
- * Return: 0 on success, -EINVAL if the frequency cannot be factorized
- */
-int
-zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
-{
- static const u16 base_freqs[] = {
- 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125,
- 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000,
- 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250,
- 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250,
- 32000, 40000, 50000, 62500,
- };
- u32 div;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(base_freqs); i++) {
- div = freq / base_freqs[i];
-
- if (div <= U16_MAX && (freq % base_freqs[i]) == 0) {
- if (base)
- *base = base_freqs[i];
- if (mult)
- *mult = div;
-
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
static bool
zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size)
{
@@ -593,159 +552,6 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
return rc;
}
-/**
- * zl3073x_ref_state_fetch - get input reference state
- * @zldev: pointer to zl3073x_dev structure
- * @index: input reference index to fetch state for
- *
- * Function fetches state for the given input reference and stores it for
- * later user.
- *
- * Return: 0 on success, <0 on error
- */
-static int
-zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
-{
- struct zl3073x_ref *ref = &zldev->ref[index];
- int rc;
-
- /* If the input is differential then the configuration for N-pin
- * reference is ignored and P-pin config is used for both.
- */
- if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(zldev, index - 1)) {
- memcpy(ref, &zldev->ref[index - 1], sizeof(*ref));
-
- return 0;
- }
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read reference configuration */
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(index));
- if (rc)
- return rc;
-
- /* Read ref_config register */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config);
- if (rc)
- return rc;
-
- dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
- str_enabled_disabled(zl3073x_ref_is_enabled(zldev, index)),
- zl3073x_ref_is_diff(zldev, index)
- ? "differential" : "single-ended");
-
- return rc;
-}
-
-/**
- * zl3073x_out_state_fetch - get output state
- * @zldev: pointer to zl3073x_dev structure
- * @index: output index to fetch state for
- *
- * Function fetches state of the given output (not output pin) and stores it
- * for later use.
- *
- * Return: 0 on success, <0 on error
- */
-static int
-zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
-{
- struct zl3073x_out *out = &zldev->out[index];
- int rc;
-
- /* Read output configuration */
- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl);
- if (rc)
- return rc;
-
- dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
- str_enabled_disabled(zl3073x_out_is_enabled(zldev, index)),
- zl3073x_out_synth_get(zldev, index));
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read output configuration */
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(index));
- if (rc)
- return rc;
-
- /* Read output mode */
- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode);
- if (rc)
- return rc;
-
- dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
- zl3073x_out_signal_format_get(zldev, index));
-
- return rc;
-}
-
-/**
- * zl3073x_synth_state_fetch - get synth state
- * @zldev: pointer to zl3073x_dev structure
- * @index: synth index to fetch state for
- *
- * Function fetches state of the given synthesizer and stores it for later use.
- *
- * Return: 0 on success, <0 on error
- */
-static int
-zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
-{
- struct zl3073x_synth *synth = &zldev->synth[index];
- int rc;
-
- /* Read synth control register */
- rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth->ctrl);
- if (rc)
- return rc;
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read synth configuration */
- rc = zl3073x_mb_op(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD,
- ZL_REG_SYNTH_MB_MASK, BIT(index));
- if (rc)
- return rc;
-
- /* The output frequency is determined by the following formula:
- * base * multiplier * numerator / denominator
- *
- * Read registers with these values
- */
- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &synth->freq_base);
- if (rc)
- return rc;
-
- rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &synth->freq_mult);
- if (rc)
- return rc;
-
- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &synth->freq_m);
- if (rc)
- return rc;
-
- rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &synth->freq_n);
- if (rc)
- return rc;
-
- /* Check denominator for zero to avoid div by 0 */
- if (!synth->freq_n) {
- dev_err(zldev->dev,
- "Zero divisor for SYNTH%u retrieved from device\n",
- index);
- return -EINVAL;
- }
-
- dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index,
- zl3073x_synth_freq_get(zldev, index));
-
- return rc;
-}
-
static int
zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
{
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index 51d0fd6cfabfc..fe779fc77dd09 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -9,7 +9,10 @@
#include <linux/mutex.h>
#include <linux/types.h>
+#include "out.h"
+#include "ref.h"
#include "regs.h"
+#include "synth.h"
struct device;
struct regmap;
@@ -27,42 +30,6 @@ struct zl3073x_dpll;
#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \
ZL3073X_NUM_OUTPUT_PINS)
-/**
- * struct zl3073x_ref - input reference invariant info
- * @ffo: current fractional frequency offset
- * @config: reference config
- */
-struct zl3073x_ref {
- s64 ffo;
- u8 config;
-};
-
-/**
- * struct zl3073x_out - output invariant info
- * @ctrl: output control
- * @mode: output mode
- */
-struct zl3073x_out {
- u8 ctrl;
- u8 mode;
-};
-
-/**
- * struct zl3073x_synth - synthesizer invariant info
- * @freq_mult: frequency multiplier
- * @freq_base: frequency base
- * @freq_m: frequency numerator
- * @freq_n: frequency denominator
- * @ctrl: synth control
- */
-struct zl3073x_synth {
- u32 freq_mult;
- u16 freq_base;
- u16 freq_m;
- u16 freq_n;
- u8 ctrl;
-};
-
/**
* struct zl3073x_dev - zl3073x device
* @dev: pointer to device
@@ -175,7 +142,6 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
* Misc operations
*****************/
-int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
static inline bool
@@ -217,181 +183,188 @@ zl3073x_output_pin_out_get(u8 id)
}
/**
- * zl3073x_ref_ffo_get - get current fractional frequency offset
+ * zl3073x_dev_ref_ffo_get - get current fractional frequency offset
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: the latest measured fractional frequency offset
*/
static inline s64
-zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
{
- return zldev->ref[index].ffo;
+ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
+
+ return zl3073x_ref_ffo_get(ref);
}
/**
- * zl3073x_ref_is_diff - check if the given input reference is differential
+ * zl3073x_dev_ref_is_diff - check if the given input reference is differential
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: true if reference is differential, false if reference is single-ended
*/
static inline bool
-zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
{
- if (FIELD_GET(ZL_REF_CONFIG_DIFF_EN, zldev->ref[index].config))
- return true;
+ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
- return false;
+ return zl3073x_ref_is_diff(ref);
}
/**
- * zl3073x_ref_is_enabled - check if the given input reference is enabled
+ * zl3073x_dev_ref_is_enabled - check if the given input reference is enabled
* @zldev: pointer to zl3073x device
* @index: input reference index
*
* Return: true if input refernce is enabled, false otherwise
*/
static inline bool
-zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
- if (FIELD_GET(ZL_REF_CONFIG_ENABLE, zldev->ref[index].config))
- return true;
+ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
- return false;
+ return zl3073x_ref_is_enabled(ref);
}
/**
- * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by
+ * zl3073x_dev_synth_dpll_get - get DPLL ID the synth is driven by
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: ID of DPLL the given synthetizer is driven by
*/
static inline u8
-zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
{
- return FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, zldev->synth[index].ctrl);
+ const struct zl3073x_synth *synth;
+
+ synth = zl3073x_synth_state_get(zldev, index);
+ return zl3073x_synth_dpll_get(synth);
}
/**
- * zl3073x_synth_freq_get - get synth current freq
+ * zl3073x_dev_synth_freq_get - get synth current freq
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: frequency of given synthetizer
*/
static inline u32
-zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
{
- struct zl3073x_synth *synth = &zldev->synth[index];
+ const struct zl3073x_synth *synth;
- return mul_u64_u32_div(synth->freq_base * synth->freq_m,
- synth->freq_mult, synth->freq_n);
+ synth = zl3073x_synth_state_get(zldev, index);
+ return zl3073x_synth_freq_get(synth);
}
/**
- * zl3073x_synth_is_enabled - check if the given synth is enabled
+ * zl3073x_dev_synth_is_enabled - check if the given synth is enabled
* @zldev: pointer to zl3073x device
* @index: synth index
*
* Return: true if synth is enabled, false otherwise
*/
static inline bool
-zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
- return FIELD_GET(ZL_SYNTH_CTRL_EN, zldev->synth[index].ctrl);
+ const struct zl3073x_synth *synth;
+
+ synth = zl3073x_synth_state_get(zldev, index);
+ return zl3073x_synth_is_enabled(synth);
}
/**
- * zl3073x_out_synth_get - get synth connected to given output
+ * zl3073x_dev_out_synth_get - get synth connected to given output
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: index of synth connected to given output.
*/
static inline u8
-zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_out_synth_get(struct zl3073x_dev *zldev, u8 index)
{
- return FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, zldev->out[index].ctrl);
+ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
+
+ return zl3073x_out_synth_get(out);
}
/**
- * zl3073x_out_is_enabled - check if the given output is enabled
+ * zl3073x_dev_out_is_enabled - check if the given output is enabled
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: true if the output is enabled, false otherwise
*/
static inline bool
-zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
{
- u8 synth;
+ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
+ const struct zl3073x_synth *synth;
+ u8 synth_id;
/* Output is enabled only if associated synth is enabled */
- synth = zl3073x_out_synth_get(zldev, index);
- if (!zl3073x_synth_is_enabled(zldev, synth))
- return false;
+ synth_id = zl3073x_out_synth_get(out);
+ synth = zl3073x_synth_state_get(zldev, synth_id);
- return FIELD_GET(ZL_OUTPUT_CTRL_EN, zldev->out[index].ctrl);
+ return zl3073x_synth_is_enabled(synth) && zl3073x_out_is_enabled(out);
}
/**
- * zl3073x_out_signal_format_get - get output signal format
+ * zl3073x_dev_out_signal_format_get - get output signal format
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: signal format of given output
*/
static inline u8
-zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)
{
- return FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, zldev->out[index].mode);
+ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
+
+ return zl3073x_out_signal_format_get(out);
}
/**
- * zl3073x_out_dpll_get - get DPLL ID the output is driven by
+ * zl3073x_dev_out_dpll_get - get DPLL ID the output is driven by
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: ID of DPLL the given output is driven by
*/
static inline
-u8 zl3073x_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
+u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
{
- u8 synth;
+ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
+ const struct zl3073x_synth *synth;
+ u8 synth_id;
/* Get synthesizer connected to given output */
- synth = zl3073x_out_synth_get(zldev, index);
+ synth_id = zl3073x_out_synth_get(out);
+ synth = zl3073x_synth_state_get(zldev, synth_id);
/* Return DPLL that drives the synth */
- return zl3073x_synth_dpll_get(zldev, synth);
+ return zl3073x_synth_dpll_get(synth);
}
/**
- * zl3073x_out_is_diff - check if the given output is differential
+ * zl3073x_dev_out_is_diff - check if the given output is differential
* @zldev: pointer to zl3073x device
* @index: output index
*
* Return: true if output is differential, false if output is single-ended
*/
static inline bool
-zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index)
+zl3073x_dev_out_is_diff(struct zl3073x_dev *zldev, u8 index)
{
- switch (zl3073x_out_signal_format_get(zldev, index)) {
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS:
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF:
- case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM:
- return true;
- default:
- break;
- }
+ const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
- return false;
+ return zl3073x_out_is_diff(out);
}
/**
- * zl3073x_output_pin_is_enabled - check if the given output pin is enabled
+ * zl3073x_dev_output_pin_is_enabled - check if the given output pin is enabled
* @zldev: pointer to zl3073x device
* @id: output pin id
*
@@ -401,16 +374,21 @@ zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index)
* Return: true if output pin is enabled, false if output pin is disabled
*/
static inline bool
-zl3073x_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id)
+zl3073x_dev_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id)
{
- u8 output = zl3073x_output_pin_out_get(id);
+ u8 out_id = zl3073x_output_pin_out_get(id);
+ const struct zl3073x_out *out;
+
+ out = zl3073x_out_state_get(zldev, out_id);
- /* Check if the whole output is enabled */
- if (!zl3073x_out_is_enabled(zldev, output))
+ /* Check if the output is enabled - call _dev_ helper that
+ * additionally checks for attached synth enablement.
+ */
+ if (!zl3073x_dev_out_is_enabled(zldev, out_id))
return false;
/* Check signal format */
- switch (zl3073x_out_signal_format_get(zldev, output)) {
+ switch (zl3073x_out_signal_format_get(out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED:
/* Both output pins are disabled by signal format */
return false;
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index d90150671d374..62996f26e065f 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -967,7 +967,7 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
* for N-division is also used for the esync divider so both cannot
* be used.
*/
- switch (zl3073x_out_signal_format_get(zldev, out)) {
+ switch (zl3073x_dev_out_signal_format_get(zldev, out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
return -EOPNOTSUPP;
@@ -1001,10 +1001,10 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
}
/* Get synth attached to output pin */
- synth = zl3073x_out_synth_get(zldev, out);
+ synth = zl3073x_dev_out_synth_get(zldev, out);
/* Get synth frequency */
- synth_freq = zl3073x_synth_freq_get(zldev, synth);
+ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode);
if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
@@ -1078,7 +1078,7 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
* for N-division is also used for the esync divider so both cannot
* be used.
*/
- switch (zl3073x_out_signal_format_get(zldev, out)) {
+ switch (zl3073x_dev_out_signal_format_get(zldev, out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
return -EOPNOTSUPP;
@@ -1117,10 +1117,10 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
goto write_mailbox;
/* Get synth attached to output pin */
- synth = zl3073x_out_synth_get(zldev, out);
+ synth = zl3073x_dev_out_synth_get(zldev, out);
/* Get synth frequency */
- synth_freq = zl3073x_synth_freq_get(zldev, synth);
+ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div);
if (rc)
@@ -1172,8 +1172,8 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin,
int rc;
out = zl3073x_output_pin_out_get(pin->id);
- synth = zl3073x_out_synth_get(zldev, out);
- synth_freq = zl3073x_synth_freq_get(zldev, synth);
+ synth = zl3073x_dev_out_synth_get(zldev, out);
+ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
guard(mutex)(&zldev->multiop_lock);
@@ -1195,7 +1195,7 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin,
}
/* Read used signal format for the given output */
- signal_format = zl3073x_out_signal_format_get(zldev, out);
+ signal_format = zl3073x_dev_out_signal_format_get(zldev, out);
switch (signal_format) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
@@ -1263,12 +1263,12 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
int rc;
out = zl3073x_output_pin_out_get(pin->id);
- synth = zl3073x_out_synth_get(zldev, out);
- synth_freq = zl3073x_synth_freq_get(zldev, synth);
+ synth = zl3073x_dev_out_synth_get(zldev, out);
+ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
new_div = synth_freq / (u32)frequency;
/* Get used signal format for the given output */
- signal_format = zl3073x_out_signal_format_get(zldev, out);
+ signal_format = zl3073x_dev_out_signal_format_get(zldev, out);
guard(mutex)(&zldev->multiop_lock);
@@ -1856,8 +1856,8 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO)
return false;
- is_diff = zl3073x_ref_is_diff(zldev, ref);
- is_enabled = zl3073x_ref_is_enabled(zldev, ref);
+ is_diff = zl3073x_dev_ref_is_diff(zldev, ref);
+ is_enabled = zl3073x_dev_ref_is_enabled(zldev, ref);
} else {
/* Output P&N pair shares single HW output */
u8 out = zl3073x_output_pin_out_get(index);
@@ -1865,7 +1865,7 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
name = "OUT";
/* Skip the pin if it is connected to different DPLL channel */
- if (zl3073x_out_dpll_get(zldev, out) != zldpll->id) {
+ if (zl3073x_dev_out_dpll_get(zldev, out) != zldpll->id) {
dev_dbg(zldev->dev,
"%s%u is driven by different DPLL\n", name,
out);
@@ -1873,8 +1873,8 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
return false;
}
- is_diff = zl3073x_out_is_diff(zldev, out);
- is_enabled = zl3073x_output_pin_is_enabled(zldev, index);
+ is_diff = zl3073x_dev_out_is_diff(zldev, out);
+ is_enabled = zl3073x_dev_output_pin_is_enabled(zldev, index);
}
/* Skip N-pin if the corresponding input/output is differential */
@@ -2124,7 +2124,7 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
return false;
/* Get the latest measured ref's ffo */
- ffo = zl3073x_ref_ffo_get(zldev, ref);
+ ffo = zl3073x_dev_ref_ffo_get(zldev, ref);
/* Compare with previous value */
if (pin->freq_offset != ffo) {
diff --git a/drivers/dpll/zl3073x/out.c b/drivers/dpll/zl3073x/out.c
new file mode 100644
index 0000000000000..a48f6917b39fb
--- /dev/null
+++ b/drivers/dpll/zl3073x/out.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/dev_printk.h>
+#include <linux/string.h>
+#include <linux/string_choices.h>
+#include <linux/types.h>
+
+#include "core.h"
+#include "out.h"
+
+/**
+ * zl3073x_out_state_fetch - fetch output state from hardware
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: output index to fetch state for
+ *
+ * Function fetches state of the given output from hardware and stores it
+ * for later use.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_out *out = &zldev->out[index];
+ int rc;
+
+ /* Read output configuration */
+ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl);
+ if (rc)
+ return rc;
+
+ dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
+ str_enabled_disabled(zl3073x_out_is_enabled(out)),
+ zl3073x_out_synth_get(out));
+
+ guard(mutex)(&zldev->multiop_lock);
+
+ /* Read output configuration */
+ rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
+ ZL_REG_OUTPUT_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* Read output mode */
+ rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode);
+ if (rc)
+ return rc;
+
+ dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
+ zl3073x_out_signal_format_get(out));
+
+ return rc;
+}
+
+/**
+ * zl3073x_out_state_get - get current output state
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: output index to get state for
+ *
+ * Return: pointer to given output state
+ */
+const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
+ u8 index)
+{
+ return &zldev->out[index];
+}
diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h
new file mode 100644
index 0000000000000..986aa046221da
--- /dev/null
+++ b/drivers/dpll/zl3073x/out.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ZL3073X_OUT_H
+#define _ZL3073X_OUT_H
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+
+#include "regs.h"
+
+struct zl3073x_dev;
+
+/**
+ * struct zl3073x_out - output state
+ * @ctrl: output control
+ * @mode: output mode
+ */
+struct zl3073x_out {
+ u8 ctrl;
+ u8 mode;
+};
+
+int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index);
+const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
+ u8 index);
+
+/**
+ * zl3073x_out_signal_format_get - get output signal format
+ * @out: pointer to out state
+ *
+ * Return: signal format of given output
+ */
+static inline u8 zl3073x_out_signal_format_get(const struct zl3073x_out *out)
+{
+ return FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT, out->mode);
+}
+
+/**
+ * zl3073x_out_is_diff - check if the given output is differential
+ * @out: pointer to out state
+ *
+ * Return: true if output is differential, false if output is single-ended
+ */
+static inline bool zl3073x_out_is_diff(const struct zl3073x_out *out)
+{
+ switch (zl3073x_out_signal_format_get(out)) {
+ case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS:
+ case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF:
+ case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/**
+ * zl3073x_out_is_enabled - check if the given output is enabled
+ * @out: pointer to out state
+ *
+ * Return: true if output is enabled, false if output is disabled
+ */
+static inline bool zl3073x_out_is_enabled(const struct zl3073x_out *out)
+{
+ return !!FIELD_GET(ZL_OUTPUT_CTRL_EN, out->ctrl);
+}
+
+/**
+ * zl3073x_out_synth_get - get synth connected to given output
+ * @out: pointer to out state
+ *
+ * Return: index of synth connected to given output.
+ */
+static inline u8 zl3073x_out_synth_get(const struct zl3073x_out *out)
+{
+ return FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, out->ctrl);
+}
+
+#endif /* _ZL3073X_OUT_H */
diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c
index 9e1fca5cdaf1e..4ed153087570b 100644
--- a/drivers/dpll/zl3073x/prop.c
+++ b/drivers/dpll/zl3073x/prop.c
@@ -46,10 +46,10 @@ zl3073x_pin_check_freq(struct zl3073x_dev *zldev, enum dpll_pin_direction dir,
/* Get output pin synthesizer */
out = zl3073x_output_pin_out_get(id);
- synth = zl3073x_out_synth_get(zldev, out);
+ synth = zl3073x_dev_out_synth_get(zldev, out);
/* Get synth frequency */
- synth_freq = zl3073x_synth_freq_get(zldev, synth);
+ synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
/* Check the frequency divides synth frequency */
if (synth_freq % (u32)freq)
@@ -93,13 +93,13 @@ zl3073x_prop_pin_package_label_set(struct zl3073x_dev *zldev,
prefix = "REF";
ref = zl3073x_input_pin_ref_get(id);
- is_diff = zl3073x_ref_is_diff(zldev, ref);
+ is_diff = zl3073x_dev_ref_is_diff(zldev, ref);
} else {
u8 out;
prefix = "OUT";
out = zl3073x_output_pin_out_get(id);
- is_diff = zl3073x_out_is_diff(zldev, out);
+ is_diff = zl3073x_dev_out_is_diff(zldev, out);
}
if (!is_diff)
@@ -217,8 +217,8 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
* the synth frequency count.
*/
out = zl3073x_output_pin_out_get(index);
- synth = zl3073x_out_synth_get(zldev, out);
- f = 2 * zl3073x_synth_freq_get(zldev, synth);
+ synth = zl3073x_dev_out_synth_get(zldev, out);
+ f = 2 * zl3073x_dev_synth_freq_get(zldev, synth);
props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1;
}
diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c
new file mode 100644
index 0000000000000..75652d9892af2
--- /dev/null
+++ b/drivers/dpll/zl3073x/ref.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/dev_printk.h>
+#include <linux/string.h>
+#include <linux/string_choices.h>
+#include <linux/types.h>
+
+#include "core.h"
+#include "ref.h"
+
+/**
+ * zl3073x_ref_freq_factorize - factorize given frequency
+ * @freq: input frequency
+ * @base: base frequency
+ * @mult: multiplier
+ *
+ * Checks if the given frequency can be factorized using one of the
+ * supported base frequencies. If so the base frequency and multiplier
+ * are stored into appropriate parameters if they are not NULL.
+ *
+ * Return: 0 on success, -EINVAL if the frequency cannot be factorized
+ */
+int
+zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult)
+{
+ static const u16 base_freqs[] = {
+ 1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125,
+ 128, 160, 200, 250, 256, 320, 400, 500, 625, 640, 800, 1000,
+ 1250, 1280, 1600, 2000, 2500, 3125, 3200, 4000, 5000, 6250,
+ 6400, 8000, 10000, 12500, 15625, 16000, 20000, 25000, 31250,
+ 32000, 40000, 50000, 62500,
+ };
+ u32 div;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(base_freqs); i++) {
+ div = freq / base_freqs[i];
+
+ if (div <= U16_MAX && (freq % base_freqs[i]) == 0) {
+ if (base)
+ *base = base_freqs[i];
+ if (mult)
+ *mult = div;
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * zl3073x_ref_state_fetch - fetch input reference state from hardware
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: input reference index to fetch state for
+ *
+ * Function fetches state for the given input reference from hardware and
+ * stores it for later use.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_ref *ref = &zldev->ref[index];
+ int rc;
+
+ /* If the input is differential then the configuration for N-pin
+ * reference is ignored and P-pin config is used for both.
+ */
+ if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) {
+ memcpy(ref, ref - 1, sizeof(*ref));
+
+ return 0;
+ }
+
+ guard(mutex)(&zldev->multiop_lock);
+
+ /* Read reference configuration */
+ rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
+ ZL_REG_REF_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* Read ref_config register */
+ rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config);
+ if (rc)
+ return rc;
+
+ dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
+ str_enabled_disabled(zl3073x_ref_is_enabled(ref)),
+ zl3073x_ref_is_diff(ref) ? "differential" : "single-ended");
+
+ return rc;
+}
+
+/**
+ * zl3073x_ref_state_get - get current input reference state
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: input reference index to get state for
+ *
+ * Return: pointer to given input reference state
+ */
+const struct zl3073x_ref *
+zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index)
+{
+ return &zldev->ref[index];
+}
diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h
new file mode 100644
index 0000000000000..e72f2c8750876
--- /dev/null
+++ b/drivers/dpll/zl3073x/ref.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ZL3073X_REF_H
+#define _ZL3073X_REF_H
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+
+#include "regs.h"
+
+struct zl3073x_dev;
+
+/**
+ * struct zl3073x_ref - input reference state
+ * @ffo: current fractional frequency offset
+ * @config: reference config
+ */
+struct zl3073x_ref {
+ s64 ffo;
+ u8 config;
+};
+
+int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index);
+
+const struct zl3073x_ref *zl3073x_ref_state_get(struct zl3073x_dev *zldev,
+ u8 index);
+
+int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
+
+/**
+ * zl3073x_ref_ffo_get - get current fractional frequency offset
+ * @ref: pointer to ref state
+ *
+ * Return: the latest measured fractional frequency offset
+ */
+static inline s64
+zl3073x_ref_ffo_get(const struct zl3073x_ref *ref)
+{
+ return ref->ffo;
+}
+
+/**
+ * zl3073x_ref_is_diff - check if the given input reference is differential
+ * @ref: pointer to ref state
+ *
+ * Return: true if reference is differential, false if reference is single-ended
+ */
+static inline bool
+zl3073x_ref_is_diff(const struct zl3073x_ref *ref)
+{
+ return !!FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref->config);
+}
+
+/**
+ * zl3073x_ref_is_enabled - check if the given input reference is enabled
+ * @ref: pointer to ref state
+ *
+ * Return: true if input refernce is enabled, false otherwise
+ */
+static inline bool
+zl3073x_ref_is_enabled(const struct zl3073x_ref *ref)
+{
+ return !!FIELD_GET(ZL_REF_CONFIG_ENABLE, ref->config);
+}
+
+#endif /* _ZL3073X_REF_H */
diff --git a/drivers/dpll/zl3073x/synth.c b/drivers/dpll/zl3073x/synth.c
new file mode 100644
index 0000000000000..da839572dab26
--- /dev/null
+++ b/drivers/dpll/zl3073x/synth.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/dev_printk.h>
+#include <linux/string.h>
+#include <linux/string_choices.h>
+#include <linux/types.h>
+
+#include "core.h"
+#include "synth.h"
+
+/**
+ * zl3073x_synth_state_fetch - fetch synth state from hardware
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: synth index to fetch state for
+ *
+ * Function fetches state of the given synthesizer from the hardware and
+ * stores it for later use.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_synth *synth = &zldev->synth[index];
+ int rc;
+
+ /* Read synth control register */
+ rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth->ctrl);
+ if (rc)
+ return rc;
+
+ guard(mutex)(&zldev->multiop_lock);
+
+ /* Read synth configuration */
+ rc = zl3073x_mb_op(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD,
+ ZL_REG_SYNTH_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* The output frequency is determined by the following formula:
+ * base * multiplier * numerator / denominator
+ *
+ * Read registers with these values
+ */
+ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &synth->freq_base);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &synth->freq_mult);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &synth->freq_m);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &synth->freq_n);
+ if (rc)
+ return rc;
+
+ /* Check denominator for zero to avoid div by 0 */
+ if (!synth->freq_n) {
+ dev_err(zldev->dev,
+ "Zero divisor for SYNTH%u retrieved from device\n",
+ index);
+ return -EINVAL;
+ }
+
+ dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index,
+ zl3073x_synth_freq_get(synth));
+
+ return rc;
+}
+
+/**
+ * zl3073x_synth_state_get - get current synth state
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: synth index to get state for
+ *
+ * Return: pointer to given synth state
+ */
+const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev,
+ u8 index)
+{
+ return &zldev->synth[index];
+}
diff --git a/drivers/dpll/zl3073x/synth.h b/drivers/dpll/zl3073x/synth.h
new file mode 100644
index 0000000000000..844d5cce8a8cc
--- /dev/null
+++ b/drivers/dpll/zl3073x/synth.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ZL3073X_SYNTH_H
+#define _ZL3073X_SYNTH_H
+
+#include <linux/bitfield.h>
+#include <linux/math64.h>
+#include <linux/types.h>
+
+#include "regs.h"
+
+struct zl3073x_dev;
+
+/**
+ * struct zl3073x_synth - synthesizer state
+ * @freq_mult: frequency multiplier
+ * @freq_base: frequency base
+ * @freq_m: frequency numerator
+ * @freq_n: frequency denominator
+ * @ctrl: synth control
+ */
+struct zl3073x_synth {
+ u32 freq_mult;
+ u16 freq_base;
+ u16 freq_m;
+ u16 freq_n;
+ u8 ctrl;
+};
+
+int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id);
+
+const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev,
+ u8 synth_id);
+
+int zl3073x_synth_state_set(struct zl3073x_dev *zldev, u8 synth_id,
+ const struct zl3073x_synth *synth);
+
+/**
+ * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by
+ * @synth: pointer to synth state
+ *
+ * Return: ID of DPLL the given synthetizer is driven by
+ */
+static inline u8 zl3073x_synth_dpll_get(const struct zl3073x_synth *synth)
+{
+ return FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth->ctrl);
+}
+
+/**
+ * zl3073x_synth_freq_get - get synth current freq
+ * @synth: pointer to synth state
+ *
+ * Return: frequency of given synthetizer
+ */
+static inline u32 zl3073x_synth_freq_get(const struct zl3073x_synth *synth)
+{
+ return mul_u64_u32_div(synth->freq_base * synth->freq_m,
+ synth->freq_mult, synth->freq_n);
+
+}
+
+/**
+ * zl3073x_synth_is_enabled - check if the given synth is enabled
+ * @synth: pointer to synth state
+ *
+ * Return: true if synth is enabled, false otherwise
+ */
+static inline bool zl3073x_synth_is_enabled(const struct zl3073x_synth *synth)
+{
+ return FIELD_GET(ZL_SYNTH_CTRL_EN, synth->ctrl);
+}
+
+#endif /* _ZL3073X_SYNTH_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH net-next 3/6] dpll: zl3073x: Cache reference monitor status
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 1/6] dpll: zl3073x: Store raw register values instead of parsed state Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 2/6] dpll: zl3073x: Split ref, out, and synth logic from core Ivan Vecera
@ 2025-11-10 17:58 ` Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref Ivan Vecera
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, linux-kernel
Instead of reading the ZL_REG_REF_MON_STATUS register every time
the reference status is needed, cache this value in the zl3073x_ref
struct.
This is achieved by:
* Adding a mon_status field to struct zl3073x_ref
* Introducing zl3073x_dev_ref_status_update() to read the status for
all references into this new cache field
* Calling this update function from the periodic work handler
* Adding zl3073x_ref_is_status_ok() and zl3073x_dev_ref_is_status_ok()
helpers to check the cached value
* Refactoring all callers in dpll.c to use the new
zl3073x_dev_ref_is_status_ok() helper, removing direct register reads
This change consolidates all status register reads into a single periodic
function and reduces I/O bus traffic in dpll callbacks.
Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/core.c | 18 +++++++
drivers/dpll/zl3073x/core.h | 15 ++++++
drivers/dpll/zl3073x/dpll.c | 96 ++++++++-----------------------------
drivers/dpll/zl3073x/ref.h | 13 +++++
4 files changed, 67 insertions(+), 75 deletions(-)
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index 2f340f7eb9ec3..383e2397dd033 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -591,6 +591,21 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
return rc;
}
+static void
+zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev)
+{
+ int i, rc;
+
+ for (i = 0; i < ZL3073X_NUM_REFS; i++) {
+ rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(i),
+ &zldev->ref[i].mon_status);
+ if (rc)
+ dev_warn(zldev->dev,
+ "Failed to get REF%u status: %pe\n", i,
+ ERR_PTR(rc));
+ }
+}
+
/**
* zl3073x_ref_phase_offsets_update - update reference phase offsets
* @zldev: pointer to zl3073x_dev structure
@@ -710,6 +725,9 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
struct zl3073x_dpll *zldpll;
int rc;
+ /* Update input references status */
+ zl3073x_dev_ref_status_update(zldev);
+
/* Update DPLL-to-connected-ref phase offsets registers */
rc = zl3073x_ref_phase_offsets_update(zldev, -1);
if (rc)
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index fe779fc77dd09..4148580d1f343 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -227,6 +227,21 @@ zl3073x_dev_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
return zl3073x_ref_is_enabled(ref);
}
+/*
+ * zl3073x_dev_ref_is_status_ok - check the given input reference status
+ * @zldev: pointer to zl3073x device
+ * @index: input reference index
+ *
+ * Return: true if the status is ok, false otherwise
+ */
+static inline bool
+zl3073x_dev_ref_is_status_ok(struct zl3073x_dev *zldev, u8 index)
+{
+ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
+
+ return zl3073x_ref_is_status_ok(ref);
+}
+
/**
* zl3073x_dev_synth_dpll_get - get DPLL ID the synth is driven by
* @zldev: pointer to zl3073x device
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 62996f26e065f..20c921d6f42cb 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -497,19 +497,10 @@ zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref)
if (rc)
return rc;
- if (ZL3073X_DPLL_REF_IS_VALID(*ref)) {
- u8 ref_status;
-
- /* Read the reference monitor status */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(*ref),
- &ref_status);
- if (rc)
- return rc;
-
- /* If the monitor indicates an error nothing is connected */
- if (ref_status != ZL_REF_MON_STATUS_OK)
- *ref = ZL3073X_DPLL_REF_NONE;
- }
+ /* If the monitor indicates an error nothing is connected */
+ if (ZL3073X_DPLL_REF_IS_VALID(*ref) &&
+ !zl3073x_dev_ref_is_status_ok(zldev, *ref))
+ *ref = ZL3073X_DPLL_REF_NONE;
return 0;
}
@@ -524,7 +515,7 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u8 conn_ref, ref, ref_status;
+ u8 conn_ref, ref;
s64 ref_phase;
int rc;
@@ -537,21 +528,9 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
* monitor feature is disabled.
*/
ref = zl3073x_input_pin_ref_get(pin->id);
- if (!zldpll->phase_monitor && ref != conn_ref) {
- *phase_offset = 0;
-
- return 0;
- }
-
- /* Get this pin monitor status */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref), &ref_status);
- if (rc)
- return rc;
-
- /* Report phase offset only if the input pin signal is present */
- if (ref_status != ZL_REF_MON_STATUS_OK) {
+ if ((!zldpll->phase_monitor && ref != conn_ref) ||
+ !zl3073x_dev_ref_is_status_ok(zldev, ref)) {
*phase_offset = 0;
-
return 0;
}
@@ -777,7 +756,7 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
- u8 ref, ref_conn, status;
+ u8 ref, ref_conn;
int rc;
ref = zl3073x_input_pin_ref_get(pin->id);
@@ -797,20 +776,9 @@ zl3073x_dpll_ref_state_get(struct zl3073x_dpll_pin *pin,
* pin as selectable.
*/
if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
- pin->selectable) {
- /* Read reference monitor status */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref),
- &status);
- if (rc)
- return rc;
-
- /* If the monitor indicates errors report the reference
- * as disconnected
- */
- if (status == ZL_REF_MON_STATUS_OK) {
- *state = DPLL_PIN_STATE_SELECTABLE;
- return 0;
- }
+ zl3073x_dev_ref_is_status_ok(zldev, ref) && pin->selectable) {
+ *state = DPLL_PIN_STATE_SELECTABLE;
+ return 0;
}
/* Otherwise report the pin as disconnected */
@@ -2036,37 +2004,23 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
ref = zl3073x_input_pin_ref_get(pin->id);
+ /* No phase offset if the ref monitor reports signal errors */
+ if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
+ return false;
+
/* Select register to read phase offset value depending on pin and
* phase monitor state:
* 1) For connected pin use dpll_phase_err_data register
* 2) For other pins use appropriate ref_phase register if the phase
- * monitor feature is enabled and reference monitor does not
- * report signal errors for given input pin
+ * monitor feature is enabled.
*/
- if (pin->pin_state == DPLL_PIN_STATE_CONNECTED) {
+ if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
- } else if (zldpll->phase_monitor) {
- u8 status;
-
- /* Get reference monitor status */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref),
- &status);
- if (rc) {
- dev_err(zldev->dev,
- "Failed to read %s refmon status: %pe\n",
- pin->label, ERR_PTR(rc));
-
- return false;
- }
-
- if (status != ZL_REF_MON_STATUS_OK)
- return false;
-
+ else if (zldpll->phase_monitor)
reg = ZL_REG_REF_PHASE(ref);
- } else {
+ else
/* The pin is not connected or phase monitor disabled */
return false;
- }
/* Read measured phase offset value */
rc = zl3073x_read_u48(zldev, reg, &phase_offset);
@@ -2105,22 +2059,14 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
- u8 ref, status;
s64 ffo;
- int rc;
+ u8 ref;
/* Get reference monitor status */
ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(ref), &status);
- if (rc) {
- dev_err(zldev->dev, "Failed to read %s refmon status: %pe\n",
- pin->label, ERR_PTR(rc));
-
- return false;
- }
/* Do not report ffo changes if the reference monitor report errors */
- if (status != ZL_REF_MON_STATUS_OK)
+ if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
return false;
/* Get the latest measured ref's ffo */
diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h
index e72f2c8750876..7cd44c377f51f 100644
--- a/drivers/dpll/zl3073x/ref.h
+++ b/drivers/dpll/zl3073x/ref.h
@@ -18,6 +18,7 @@ struct zl3073x_dev;
struct zl3073x_ref {
s64 ffo;
u8 config;
+ u8 mon_status;
};
int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index);
@@ -63,4 +64,16 @@ zl3073x_ref_is_enabled(const struct zl3073x_ref *ref)
return !!FIELD_GET(ZL_REF_CONFIG_ENABLE, ref->config);
}
+/**
+ * zl3073x_ref_is_status_ok - check the given input reference status
+ * @ref: pointer to ref state
+ *
+ * Return: true if the status is ok, false otherwise
+ */
+static inline bool
+zl3073x_ref_is_status_ok(const struct zl3073x_ref *ref)
+{
+ return ref->mon_status == ZL_REF_MON_STATUS_OK;
+}
+
#endif /* _ZL3073X_REF_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
` (2 preceding siblings ...)
2025-11-10 17:58 ` [PATCH net-next 3/6] dpll: zl3073x: Cache reference monitor status Ivan Vecera
@ 2025-11-10 17:58 ` Ivan Vecera
2025-11-11 6:52 ` kernel test robot
2025-11-10 17:58 ` [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 6/6] dpll: zl3073x: Remove unused dev wrappers Ivan Vecera
5 siblings, 1 reply; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, linux-kernel
Expand the zl3073x_ref structure to cache all reference-related
hardware registers, including frequency components, embedded-sync
settings and phase compensation. Previously, these registers were
read on-demand from various functions in dpll.c leading to frequent
mailbox operations.
Modify zl3073x_ref_state_fetch() to read and populate all these new
fields at once. Refactor all "getter" functions in dpll.c to read
from this new cached state instead of performing direct register
access.
Remove the standalone zl3073x_dpll_input_ref_frequency_get() helper,
as its functionality is now replaced by zl3073x_ref_freq_get() which
operates on the cached state and add a corresponding zl3073x_dev_...
wrapper.
Introduce a new function, zl3073x_ref_state_set(), to handle
writing changes back to the hardware. This function compares the
provided state with the current cached state and writes *only* the
modified register values to the device via a single mailbox sequence
before updating the local cache.
Refactor all dpll "setter" functions to modify a local copy of the
ref state and then call zl3073x_ref_state_set() to commit the changes.
As a cleanup, update callers in dpll.c that already have
a struct zl3073x_ref * to use the direct helpers instead of the
zl3073x_dev_... wrappers.
This change centralizes all reference-related register I/O into ref.c,
significantly reduces bus traffic, and simplifies the logic in dpll.c.
Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/core.h | 15 ++
drivers/dpll/zl3073x/dpll.c | 309 +++++++++---------------------------
drivers/dpll/zl3073x/ref.c | 88 ++++++++++
drivers/dpll/zl3073x/ref.h | 47 ++++++
4 files changed, 229 insertions(+), 230 deletions(-)
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index 4148580d1f343..fe8b70e25d3cc 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -197,6 +197,21 @@ zl3073x_dev_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
return zl3073x_ref_ffo_get(ref);
}
+/**
+ * zl3073x_dev_ref_freq_get - get input reference frequency
+ * @zldev: pointer to zl3073x device
+ * @index: input reference index
+ *
+ * Return: frequency of given input reference
+ */
+static inline u32
+zl3073x_dev_ref_freq_get(struct zl3073x_dev *zldev, u8 index)
+{
+ const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
+
+ return zl3073x_ref_freq_get(ref);
+}
+
/**
* zl3073x_dev_ref_is_diff - check if the given input reference is differential
* @zldev: pointer to zl3073x device
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 20c921d6f42cb..516092997aba0 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -100,60 +100,6 @@ zl3073x_dpll_pin_direction_get(const struct dpll_pin *dpll_pin, void *pin_priv,
return 0;
}
-/**
- * zl3073x_dpll_input_ref_frequency_get - get input reference frequency
- * @zldpll: pointer to zl3073x_dpll
- * @ref_id: reference id
- * @frequency: pointer to variable to store frequency
- *
- * Reads frequency of given input reference.
- *
- * Return: 0 on success, <0 on error
- */
-static int
-zl3073x_dpll_input_ref_frequency_get(struct zl3073x_dpll *zldpll, u8 ref_id,
- u32 *frequency)
-{
- struct zl3073x_dev *zldev = zldpll->dev;
- u16 base, mult, num, denom;
- int rc;
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read reference configuration */
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(ref_id));
- if (rc)
- return rc;
-
- /* Read registers to compute resulting frequency */
- rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &base);
- if (rc)
- return rc;
- rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &mult);
- if (rc)
- return rc;
- rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &num);
- if (rc)
- return rc;
- rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &denom);
- if (rc)
- return rc;
-
- /* Sanity check that HW has not returned zero denominator */
- if (!denom) {
- dev_err(zldev->dev,
- "Zero divisor for ref %u frequency got from device\n",
- ref_id);
- return -EINVAL;
- }
-
- /* Compute the frequency */
- *frequency = mul_u64_u32_div(base * mult, num, denom);
-
- return rc;
-}
-
static int
zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
void *pin_priv,
@@ -165,39 +111,15 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u8 ref, ref_sync_ctrl, sync_mode;
- u32 esync_div, ref_freq;
- int rc;
-
- /* Get reference frequency */
- ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_dpll_input_ref_frequency_get(zldpll, pin->id, &ref_freq);
- if (rc)
- return rc;
+ const struct zl3073x_ref *ref;
+ u8 ref_id;
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read reference configuration into mailbox */
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(ref));
- if (rc)
- return rc;
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
- /* Get ref sync mode */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref_sync_ctrl);
- if (rc)
- return rc;
-
- /* Get esync divisor */
- rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &esync_div);
- if (rc)
- return rc;
-
- sync_mode = FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref_sync_ctrl);
-
- switch (sync_mode) {
+ switch (FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl)) {
case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75:
- esync->freq = (esync_div == ZL_REF_ESYNC_DIV_1HZ) ? 1 : 0;
+ esync->freq = ref->esync_n_div == ZL_REF_ESYNC_DIV_1HZ ? 1 : 0;
esync->pulse = 25;
break;
default:
@@ -209,7 +131,7 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
/* If the pin supports esync control expose its range but only
* if the current reference frequency is > 1 Hz.
*/
- if (pin->esync_control && ref_freq > 1) {
+ if (pin->esync_control && zl3073x_ref_freq_get(ref) > 1) {
esync->range = esync_freq_ranges;
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
} else {
@@ -217,7 +139,7 @@ zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
esync->range_num = 0;
}
- return rc;
+ return 0;
}
static int
@@ -230,22 +152,11 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u8 ref, ref_sync_ctrl, sync_mode;
- int rc;
+ struct zl3073x_ref ref;
+ u8 ref_id, sync_mode;
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read reference configuration into mailbox */
- ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(ref));
- if (rc)
- return rc;
-
- /* Get ref sync mode */
- rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref_sync_ctrl);
- if (rc)
- return rc;
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = *zl3073x_ref_state_get(zldev, ref_id);
/* Use freq == 0 to disable esync */
if (!freq)
@@ -253,25 +164,16 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
else
sync_mode = ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75;
- ref_sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE;
- ref_sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode);
-
- /* Update ref sync control register */
- rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, ref_sync_ctrl);
- if (rc)
- return rc;
+ ref.sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE;
+ ref.sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode);
if (freq) {
- /* 1 Hz is only supported frequnecy currently */
- rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV,
- ZL_REF_ESYNC_DIV_1HZ);
- if (rc)
- return rc;
+ /* 1 Hz is only supported frequency now */
+ ref.esync_n_div = ZL_REF_ESYNC_DIV_1HZ;
}
- /* Commit reference configuration */
- return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
- ZL_REG_REF_MB_MASK, BIT(ref));
+ /* Update reference configuration */
+ return zl3073x_ref_state_set(zldev, ref_id, &ref);
}
static int
@@ -295,17 +197,12 @@ zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin,
{
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dpll_pin *pin = pin_priv;
- u32 ref_freq;
- u8 ref;
- int rc;
+ u8 ref_id;
- /* Read and return ref frequency */
- ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_dpll_input_ref_frequency_get(zldpll, ref, &ref_freq);
- if (!rc)
- *frequency = ref_freq;
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ *frequency = zl3073x_dev_ref_freq_get(zldpll->dev, ref_id);
- return rc;
+ return 0;
}
static int
@@ -318,39 +215,18 @@ zl3073x_dpll_input_pin_frequency_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u16 base, mult;
- u8 ref;
- int rc;
-
- /* Get base frequency and multiplier for the requested frequency */
- rc = zl3073x_ref_freq_factorize(frequency, &base, &mult);
- if (rc)
- return rc;
+ struct zl3073x_ref ref;
+ u8 ref_id;
- guard(mutex)(&zldev->multiop_lock);
+ /* Get reference state */
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = *zl3073x_ref_state_get(zldev, ref_id);
- /* Load reference configuration */
- ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(ref));
+ /* Update frequency */
+ zl3073x_ref_freq_set(&ref, frequency);
- /* Update base frequency, multiplier, numerator & denominator */
- rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE, base);
- if (rc)
- return rc;
- rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT, mult);
- if (rc)
- return rc;
- rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M, 1);
- if (rc)
- return rc;
- rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N, 1);
- if (rc)
- return rc;
-
- /* Commit reference configuration */
- return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
- ZL_REG_REF_MB_MASK, BIT(ref));
+ /* Commit reference state */
+ return zl3073x_ref_state_set(zldev, ref_id, &ref);
}
/**
@@ -515,21 +391,24 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u8 conn_ref, ref;
+ const struct zl3073x_ref *ref;
+ u8 conn_id, ref_id;
s64 ref_phase;
int rc;
/* Get currently connected reference */
- rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_ref);
+ rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_id);
if (rc)
return rc;
/* Report phase offset only for currently connected pin if the phase
- * monitor feature is disabled.
+ * monitor feature is disabled and only if the input pin signal is
+ * present.
*/
- ref = zl3073x_input_pin_ref_get(pin->id);
- if ((!zldpll->phase_monitor && ref != conn_ref) ||
- !zl3073x_dev_ref_is_status_ok(zldev, ref)) {
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
+ if ((!zldpll->phase_monitor && ref_id != conn_id) ||
+ !zl3073x_ref_is_status_ok(ref)) {
*phase_offset = 0;
return 0;
}
@@ -540,20 +419,12 @@ zl3073x_dpll_input_pin_phase_offset_get(const struct dpll_pin *dpll_pin,
* the phase offset is modded to the period of the signal
* the dpll is locked to.
*/
- if (ZL3073X_DPLL_REF_IS_VALID(conn_ref) && conn_ref != ref) {
+ if (ZL3073X_DPLL_REF_IS_VALID(conn_id) && conn_id != ref_id) {
u32 conn_freq, ref_freq;
- /* Get frequency of connected ref */
- rc = zl3073x_dpll_input_ref_frequency_get(zldpll, conn_ref,
- &conn_freq);
- if (rc)
- return rc;
-
- /* Get frequency of given ref */
- rc = zl3073x_dpll_input_ref_frequency_get(zldpll, ref,
- &ref_freq);
- if (rc)
- return rc;
+ /* Get frequency of connected and given ref */
+ conn_freq = zl3073x_dev_ref_freq_get(zldev, conn_id);
+ ref_freq = zl3073x_ref_freq_get(ref);
if (conn_freq > ref_freq) {
s64 conn_period, div_factor;
@@ -580,33 +451,23 @@ zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
+ const struct zl3073x_ref *ref;
s64 phase_comp;
- u8 ref;
- int rc;
-
- guard(mutex)(&zldev->multiop_lock);
+ u8 ref_id;
/* Read reference configuration */
- ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(ref));
- if (rc)
- return rc;
-
- /* Read current phase offset compensation */
- rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, &phase_comp);
- if (rc)
- return rc;
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
/* Perform sign extension for 48bit signed value */
- phase_comp = sign_extend64(phase_comp, 47);
+ phase_comp = sign_extend64(ref->phase_comp, 47);
/* Reverse two's complement negation applied during set and convert
* to 32bit signed int
*/
*phase_adjust = (s32)-phase_comp;
- return rc;
+ return 0;
}
static int
@@ -620,32 +481,20 @@ zl3073x_dpll_input_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- s64 phase_comp;
- u8 ref;
- int rc;
+ struct zl3073x_ref ref;
+ u8 ref_id;
+
+ /* Read reference configuration */
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = *zl3073x_ref_state_get(zldev, ref_id);
/* The value in the register is stored as two's complement negation
* of requested value.
*/
- phase_comp = -phase_adjust;
-
- guard(mutex)(&zldev->multiop_lock);
+ ref.phase_comp = -phase_adjust;
- /* Read reference configuration */
- ref = zl3073x_input_pin_ref_get(pin->id);
- rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
- ZL_REG_REF_MB_MASK, BIT(ref));
- if (rc)
- return rc;
-
- /* Write the requested value into the compensation register */
- rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, phase_comp);
- if (rc)
- return rc;
-
- /* Commit reference configuration */
- return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
- ZL_REG_REF_MB_MASK, BIT(ref));
+ /* Update reference configuration */
+ return zl3073x_ref_state_set(zldev, ref_id, &ref);
}
/**
@@ -1816,16 +1665,17 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
const char *name;
if (dir == DPLL_PIN_DIRECTION_INPUT) {
- u8 ref = zl3073x_input_pin_ref_get(index);
-
- name = "REF";
+ u8 ref_id = zl3073x_input_pin_ref_get(index);
+ const struct zl3073x_ref *ref;
/* Skip the pin if the DPLL is running in NCO mode */
if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO)
return false;
- is_diff = zl3073x_dev_ref_is_diff(zldev, ref);
- is_enabled = zl3073x_dev_ref_is_enabled(zldev, ref);
+ name = "REF";
+ ref = zl3073x_ref_state_get(zldev, ref_id);
+ is_diff = zl3073x_ref_is_diff(ref);
+ is_enabled = zl3073x_ref_is_enabled(ref);
} else {
/* Output P&N pair shares single HW output */
u8 out = zl3073x_output_pin_out_get(index);
@@ -1997,15 +1847,17 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
+ const struct zl3073x_ref *ref;
unsigned int reg;
s64 phase_offset;
- u8 ref;
+ u8 ref_id;
int rc;
- ref = zl3073x_input_pin_ref_get(pin->id);
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
/* No phase offset if the ref monitor reports signal errors */
- if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
+ if (!zl3073x_dev_ref_is_status_ok(zldev, ref_id))
return false;
/* Select register to read phase offset value depending on pin and
@@ -2017,9 +1869,8 @@ zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
else if (zldpll->phase_monitor)
- reg = ZL_REG_REF_PHASE(ref);
+ reg = ZL_REG_REF_PHASE(ref_id);
else
- /* The pin is not connected or phase monitor disabled */
return false;
/* Read measured phase offset value */
@@ -2059,24 +1910,22 @@ zl3073x_dpll_pin_ffo_check(struct zl3073x_dpll_pin *pin)
{
struct zl3073x_dpll *zldpll = pin->dpll;
struct zl3073x_dev *zldev = zldpll->dev;
- s64 ffo;
- u8 ref;
+ const struct zl3073x_ref *ref;
+ u8 ref_id;
/* Get reference monitor status */
- ref = zl3073x_input_pin_ref_get(pin->id);
+ ref_id = zl3073x_input_pin_ref_get(pin->id);
+ ref = zl3073x_ref_state_get(zldev, ref_id);
/* Do not report ffo changes if the reference monitor report errors */
- if (!zl3073x_dev_ref_is_status_ok(zldev, ref))
+ if (!zl3073x_ref_is_status_ok(ref))
return false;
- /* Get the latest measured ref's ffo */
- ffo = zl3073x_dev_ref_ffo_get(zldev, ref);
-
/* Compare with previous value */
- if (pin->freq_offset != ffo) {
+ if (pin->freq_offset != ref->ffo) {
dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n",
- pin->label, pin->freq_offset, ffo);
- pin->freq_offset = ffo;
+ pin->label, pin->freq_offset, ref->ffo);
+ pin->freq_offset = ref->ffo;
return true;
}
diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c
index 75652d9892af2..3a8ce44c199ca 100644
--- a/drivers/dpll/zl3073x/ref.c
+++ b/drivers/dpll/zl3073x/ref.c
@@ -88,6 +88,34 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
if (rc)
return rc;
+ /* Read frequency related registers */
+ rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &ref->freq_base);
+ if (rc)
+ return rc;
+ rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &ref->freq_mult);
+ if (rc)
+ return rc;
+ rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &ref->freq_ratio_m);
+ if (rc)
+ return rc;
+ rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &ref->freq_ratio_n);
+ if (rc)
+ return rc;
+
+ /* Read eSync and N-div rated registers */
+ rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &ref->esync_n_div);
+ if (rc)
+ return rc;
+ rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref->sync_ctrl);
+ if (rc)
+ return rc;
+
+ /* Read phase compensation register */
+ rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP,
+ &ref->phase_comp);
+ if (rc)
+ return rc;
+
dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
str_enabled_disabled(zl3073x_ref_is_enabled(ref)),
zl3073x_ref_is_diff(ref) ? "differential" : "single-ended");
@@ -107,3 +135,63 @@ zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index)
{
return &zldev->ref[index];
}
+
+#define ZL3073X_REF_SYNC_ONE(_zldev, _dref, _sref, _type, _field, _reg) \
+ ((_dref)->_field != (_sref)->_field ? \
+ zl3073x_write_##_type(_zldev, _reg, (_sref)->_field) : 0)
+
+int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
+ const struct zl3073x_ref *ref)
+{
+ struct zl3073x_ref *dref = &zldev->ref[index];
+ int rc;
+
+ guard(mutex)(&zldev->multiop_lock);
+
+ /* Read reference configuration into mailbox */
+ rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
+ ZL_REG_REF_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* Update mailbox with changed values */
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u16, freq_base,
+ ZL_REG_REF_FREQ_BASE);
+ if (!rc)
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u16, freq_mult,
+ ZL_REG_REF_FREQ_MULT);
+ if (!rc)
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u16, freq_ratio_m,
+ ZL_REG_REF_RATIO_M);
+ if (!rc)
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u16, freq_ratio_n,
+ ZL_REG_REF_RATIO_N);
+ if (!rc)
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u32, esync_n_div,
+ ZL_REG_REF_ESYNC_DIV);
+ if (!rc)
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u8, sync_ctrl,
+ ZL_REG_REF_SYNC_CTRL);
+ if (!rc)
+ rc = ZL3073X_REF_SYNC_ONE(zldev, dref, ref, u48, phase_comp,
+ ZL_REG_REF_PHASE_OFFSET_COMP);
+ if (rc)
+ return rc;
+
+ /* Commit reference configuration */
+ rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR,
+ ZL_REG_REF_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* After successful commit store new state */
+ dref->freq_base = ref->freq_base;
+ dref->freq_mult = ref->freq_mult;
+ dref->freq_ratio_m = ref->freq_ratio_m;
+ dref->freq_ratio_n = ref->freq_ratio_n;
+ dref->esync_n_div = ref->esync_n_div;
+ dref->sync_ctrl = ref->sync_ctrl;
+ dref->phase_comp = ref->phase_comp;
+
+ return 0;
+}
diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h
index 7cd44c377f51f..4e714b4ff638e 100644
--- a/drivers/dpll/zl3073x/ref.h
+++ b/drivers/dpll/zl3073x/ref.h
@@ -4,6 +4,7 @@
#define _ZL3073X_REF_H
#include <linux/bitfield.h>
+#include <linux/math64.h>
#include <linux/types.h>
#include "regs.h"
@@ -17,7 +18,14 @@ struct zl3073x_dev;
*/
struct zl3073x_ref {
s64 ffo;
+ u64 phase_comp;
+ u32 esync_n_div;
+ u16 freq_base;
+ u16 freq_mult;
+ u16 freq_ratio_m;
+ u16 freq_ratio_n;
u8 config;
+ u8 sync_ctrl;
u8 mon_status;
};
@@ -26,6 +34,9 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index);
const struct zl3073x_ref *zl3073x_ref_state_get(struct zl3073x_dev *zldev,
u8 index);
+int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index,
+ const struct zl3073x_ref *ref);
+
int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
/**
@@ -40,6 +51,42 @@ zl3073x_ref_ffo_get(const struct zl3073x_ref *ref)
return ref->ffo;
}
+/**
+ * zl3073x_ref_freq_get - get given input reference frequency
+ * @ref: pointer to ref state
+ *
+ * Return: frequency of the given input reference
+ */
+static inline u32
+zl3073x_ref_freq_get(const struct zl3073x_ref *ref)
+{
+ return mul_u64_u32_div(ref->freq_base * ref->freq_mult,
+ ref->freq_ratio_m, ref->freq_ratio_n);
+}
+
+/**
+ * zl3073x_ref_freq_set - set given input reference frequency
+ * @ref: pointer to ref state
+ * @freq: frequency to be set
+ *
+ * Return: 0 on success, <0 when frequency cannot be factorized
+ */
+static inline int
+zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq)
+{
+ u16 base, mult;
+ int rc;
+
+ rc = zl3073x_ref_freq_factorize(freq, &base, &mult);
+ if (rc)
+ return rc;
+
+ ref->freq_base = base;
+ ref->freq_mult = mult;
+
+ return 0;
+}
+
/**
* zl3073x_ref_is_diff - check if the given input reference is differential
* @ref: pointer to ref state
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
` (3 preceding siblings ...)
2025-11-10 17:58 ` [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref Ivan Vecera
@ 2025-11-10 17:58 ` Ivan Vecera
2025-11-11 10:42 ` kernel test robot
2025-11-10 17:58 ` [PATCH net-next 6/6] dpll: zl3073x: Remove unused dev wrappers Ivan Vecera
5 siblings, 1 reply; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, linux-kernel
Expand the zl3073x_out structure to cache all output-related
hardware registers, including divisors, widths, embedded-sync
parameters and phase compensation.
Modify zl3073x_out_state_fetch() to read and populate all these
new fields at once, including zero-divisor checks. Refactor all
dpll "getter" functions in dpll.c to read from this new
cached state instead of performing direct register access.
Introduce a new function, zl3073x_out_state_set(), to handle
writing changes back to the hardware. This function compares the
provided state with the current cached state and writes *only* the
modified register values via a single mailbox sequence before
updating the local cache.
Refactor all dpll "setter" functions to modify a local copy of
the output state and then call zl3073x_out_state_set() to
commit the changes.
This change centralizes all output-related register I/O into
out.c, significantly reduces bus traffic, and simplifies the logic
in dpll.c.
Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/dpll.c | 377 +++++++++---------------------------
drivers/dpll/zl3073x/out.c | 96 +++++++++
drivers/dpll/zl3073x/out.h | 8 +
3 files changed, 193 insertions(+), 288 deletions(-)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 516092997aba0..6e673ea4e789c 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -770,21 +770,19 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- struct device *dev = zldev->dev;
- u32 esync_period, esync_width;
- u8 clock_type, synth;
- u8 out, output_mode;
- u32 output_div;
+ const struct zl3073x_synth *synth;
+ const struct zl3073x_out *out;
+ u8 clock_type, out_id;
u32 synth_freq;
- int rc;
- out = zl3073x_output_pin_out_get(pin->id);
+ out_id = zl3073x_output_pin_out_get(pin->id);
+ out = zl3073x_out_state_get(zldev, out_id);
/* If N-division is enabled, esync is not supported. The register used
* for N-division is also used for the esync divider so both cannot
* be used.
*/
- switch (zl3073x_dev_out_signal_format_get(zldev, out)) {
+ switch (zl3073x_out_signal_format_get(out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
return -EOPNOTSUPP;
@@ -792,38 +790,11 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
break;
}
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read output configuration into mailbox */
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
- if (rc)
- return rc;
-
- /* Read output mode */
- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
- if (rc)
- return rc;
-
- /* Read output divisor */
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div);
- if (rc)
- return rc;
-
- /* Check output divisor for zero */
- if (!output_div) {
- dev_err(dev, "Zero divisor for OUTPUT%u got from device\n",
- out);
- return -EINVAL;
- }
-
- /* Get synth attached to output pin */
- synth = zl3073x_dev_out_synth_get(zldev, out);
-
- /* Get synth frequency */
- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
+ /* Get attached synth frequency */
+ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
+ synth_freq = zl3073x_synth_freq_get(synth);
- clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode);
+ clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode);
if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
/* No need to read esync data if it is not enabled */
esync->freq = 0;
@@ -832,38 +803,21 @@ zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
goto finish;
}
- /* Read esync period */
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &esync_period);
- if (rc)
- return rc;
-
- /* Check esync divisor for zero */
- if (!esync_period) {
- dev_err(dev, "Zero esync divisor for OUTPUT%u got from device\n",
- out);
- return -EINVAL;
- }
-
- /* Get esync pulse width in units of half synth cycles */
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, &esync_width);
- if (rc)
- return rc;
-
/* Compute esync frequency */
- esync->freq = synth_freq / output_div / esync_period;
+ esync->freq = synth_freq / out->div / out->esync_n_period;
/* By comparing the esync_pulse_width to the half of the pulse width
* the esync pulse percentage can be determined.
* Note that half pulse width is in units of half synth cycles, which
* is why it reduces down to be output_div.
*/
- esync->pulse = (50 * esync_width) / output_div;
+ esync->pulse = (50 * out->esync_n_width) / out->div;
finish:
/* Set supported esync ranges if the pin supports esync control and
* if the output frequency is > 1 Hz.
*/
- if (pin->esync_control && (synth_freq / output_div) > 1) {
+ if (pin->esync_control && (synth_freq / out->div) > 1) {
esync->range = esync_freq_ranges;
esync->range_num = ARRAY_SIZE(esync_freq_ranges);
} else {
@@ -881,21 +835,22 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
void *dpll_priv, u64 freq,
struct netlink_ext_ack *extack)
{
- u32 esync_period, esync_width, output_div;
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u8 clock_type, out, output_mode, synth;
+ const struct zl3073x_synth *synth;
+ struct zl3073x_out out;
+ u8 clock_type, out_id;
u32 synth_freq;
- int rc;
- out = zl3073x_output_pin_out_get(pin->id);
+ out_id = zl3073x_output_pin_out_get(pin->id);
+ out = *zl3073x_out_state_get(zldev, out_id);
/* If N-division is enabled, esync is not supported. The register used
* for N-division is also used for the esync divider so both cannot
* be used.
*/
- switch (zl3073x_dev_out_signal_format_get(zldev, out)) {
+ switch (zl3073x_out_signal_format_get(&out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
return -EOPNOTSUPP;
@@ -903,19 +858,6 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
break;
}
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read output configuration into mailbox */
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
- if (rc)
- return rc;
-
- /* Read output mode */
- rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
- if (rc)
- return rc;
-
/* Select clock type */
if (freq)
clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC;
@@ -923,38 +865,19 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL;
/* Update clock type in output mode */
- output_mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE;
- output_mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type);
- rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, output_mode);
- if (rc)
- return rc;
+ out.mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE;
+ out.mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type);
/* If esync is being disabled just write mailbox and finish */
if (!freq)
goto write_mailbox;
- /* Get synth attached to output pin */
- synth = zl3073x_dev_out_synth_get(zldev, out);
-
- /* Get synth frequency */
- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
-
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div);
- if (rc)
- return rc;
-
- /* Check output divisor for zero */
- if (!output_div) {
- dev_err(zldev->dev,
- "Zero divisor for OUTPUT%u got from device\n", out);
- return -EINVAL;
- }
+ /* Get attached synth frequency */
+ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out));
+ synth_freq = zl3073x_synth_freq_get(synth);
/* Compute and update esync period */
- esync_period = synth_freq / (u32)freq / output_div;
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, esync_period);
- if (rc)
- return rc;
+ out.esync_n_period = synth_freq / (u32)freq / out.div;
/* Half of the period in units of 1/2 synth cycle can be represented by
* the output_div. To get the supported esync pulse width of 25% of the
@@ -962,15 +885,11 @@ zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
* assumes that output_div is even, otherwise some resolution will be
* lost.
*/
- esync_width = output_div / 2;
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, esync_width);
- if (rc)
- return rc;
+ out.esync_n_width = out.div / 2;
write_mailbox:
/* Commit output configuration */
- return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
+ return zl3073x_out_state_set(zldev, out_id, &out);
}
static int
@@ -983,83 +902,46 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- struct device *dev = zldev->dev;
- u8 out, signal_format, synth;
- u32 output_div, synth_freq;
- int rc;
-
- out = zl3073x_output_pin_out_get(pin->id);
- synth = zl3073x_dev_out_synth_get(zldev, out);
- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read output configuration into mailbox */
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
- if (rc)
- return rc;
-
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div);
- if (rc)
- return rc;
+ const struct zl3073x_synth *synth;
+ const struct zl3073x_out *out;
+ u32 synth_freq;
+ u8 out_id;
- /* Check output divisor for zero */
- if (!output_div) {
- dev_err(dev, "Zero divisor for output %u got from device\n",
- out);
- return -EINVAL;
- }
+ out_id = zl3073x_output_pin_out_get(pin->id);
+ out = zl3073x_out_state_get(zldev, out_id);
- /* Read used signal format for the given output */
- signal_format = zl3073x_dev_out_signal_format_get(zldev, out);
+ /* Get attached synth frequency */
+ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
+ synth_freq = zl3073x_synth_freq_get(synth);
- switch (signal_format) {
+ switch (zl3073x_out_signal_format_get(out)) {
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV:
case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV:
/* In case of divided format we have to distiguish between
* given output pin type.
+ *
+ * For P-pin the resulting frequency is computed as simple
+ * division of synth frequency and output divisor.
+ *
+ * For N-pin we have to divide additionally by divisor stored
+ * in esync_n_period output mailbox register that is used as
+ * N-pin divisor for these modes.
*/
- if (zl3073x_dpll_is_p_pin(pin)) {
- /* For P-pin the resulting frequency is computed as
- * simple division of synth frequency and output
- * divisor.
- */
- *frequency = synth_freq / output_div;
- } else {
- /* For N-pin we have to divide additionally by
- * divisor stored in esync_period output mailbox
- * register that is used as N-pin divisor for these
- * modes.
- */
- u32 ndiv;
-
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
- &ndiv);
- if (rc)
- return rc;
+ *frequency = synth_freq / out->div;
- /* Check N-pin divisor for zero */
- if (!ndiv) {
- dev_err(dev,
- "Zero N-pin divisor for output %u got from device\n",
- out);
- return -EINVAL;
- }
+ if (!zl3073x_dpll_is_p_pin(pin))
+ *frequency = (u32)*frequency / out->esync_n_period;
- /* Compute final divisor for N-pin */
- *frequency = synth_freq / output_div / ndiv;
- }
break;
default:
/* In other modes the resulting frequency is computed as
* division of synth frequency and output divisor.
*/
- *frequency = synth_freq / output_div;
+ *frequency = synth_freq / out->div;
break;
}
- return rc;
+ return 0;
}
static int
@@ -1072,28 +954,21 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- struct device *dev = zldev->dev;
- u32 output_n_freq, output_p_freq;
- u8 out, signal_format, synth;
- u32 cur_div, new_div, ndiv;
- u32 synth_freq;
- int rc;
+ const struct zl3073x_synth *synth;
+ u8 out_id, signal_format;
+ u32 new_div, synth_freq;
+ struct zl3073x_out out;
- out = zl3073x_output_pin_out_get(pin->id);
- synth = zl3073x_dev_out_synth_get(zldev, out);
- synth_freq = zl3073x_dev_synth_freq_get(zldev, synth);
+ out_id = zl3073x_output_pin_out_get(pin->id);
+ out = *zl3073x_out_state_get(zldev, out_id);
+
+ /* Get attached synth frequency and compute new divisor */
+ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out));
+ synth_freq = zl3073x_synth_freq_get(synth);
new_div = synth_freq / (u32)frequency;
/* Get used signal format for the given output */
- signal_format = zl3073x_dev_out_signal_format_get(zldev, out);
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Load output configuration */
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
- if (rc)
- return rc;
+ signal_format = zl3073x_out_signal_format_get(&out);
/* Check signal format */
if (signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV &&
@@ -1101,99 +976,50 @@ zl3073x_dpll_output_pin_frequency_set(const struct dpll_pin *dpll_pin,
/* For non N-divided signal formats the frequency is computed
* as division of synth frequency and output divisor.
*/
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div);
- if (rc)
- return rc;
+ out.div = new_div;
/* For 50/50 duty cycle the divisor is equal to width */
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div);
- if (rc)
- return rc;
+ out.width = new_div;
/* Commit output configuration */
- return zl3073x_mb_op(zldev,
- ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
+ return zl3073x_out_state_set(zldev, out_id, &out);
}
- /* For N-divided signal format get current divisor */
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &cur_div);
- if (rc)
- return rc;
-
- /* Check output divisor for zero */
- if (!cur_div) {
- dev_err(dev, "Zero divisor for output %u got from device\n",
- out);
- return -EINVAL;
- }
-
- /* Get N-pin divisor (shares the same register with esync */
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &ndiv);
- if (rc)
- return rc;
-
- /* Check N-pin divisor for zero */
- if (!ndiv) {
- dev_err(dev,
- "Zero N-pin divisor for output %u got from device\n",
- out);
- return -EINVAL;
- }
-
- /* Compute current output frequency for P-pin */
- output_p_freq = synth_freq / cur_div;
-
- /* Compute current N-pin frequency */
- output_n_freq = output_p_freq / ndiv;
-
if (zl3073x_dpll_is_p_pin(pin)) {
/* We are going to change output frequency for P-pin but
* if the requested frequency is less than current N-pin
* frequency then indicate a failure as we are not able
* to compute N-pin divisor to keep its frequency unchanged.
+ *
+ * Update divisor for N-pin to keep N-pin frequency.
*/
- if (frequency <= output_n_freq)
+ out.esync_n_period = (out.esync_n_period * out.div) / new_div;
+ if (!out.esync_n_period)
return -EINVAL;
/* Update the output divisor */
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div);
- if (rc)
- return rc;
+ out.div = new_div;
/* For 50/50 duty cycle the divisor is equal to width */
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div);
- if (rc)
- return rc;
-
- /* Compute new divisor for N-pin */
- ndiv = (u32)frequency / output_n_freq;
+ out.width = out.div;
} else {
/* We are going to change frequency of N-pin but if
* the requested freq is greater or equal than freq of P-pin
* in the output pair we cannot compute divisor for the N-pin.
* In this case indicate a failure.
+ *
+ * Update divisor for N-pin
*/
- if (output_p_freq <= frequency)
+ out.esync_n_period = div64_u64(synth_freq, frequency * out.div);
+ if (!out.esync_n_period)
return -EINVAL;
-
- /* Compute new divisor for N-pin */
- ndiv = output_p_freq / (u32)frequency;
}
- /* Update divisor for the N-pin */
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, ndiv);
- if (rc)
- return rc;
-
/* For 50/50 duty cycle the divisor is equal to width */
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, ndiv);
- if (rc)
- return rc;
+ out.esync_n_width = out.esync_n_period;
/* Commit output configuration */
- return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
+ return zl3073x_out_state_set(zldev, out_id, &out);
}
static int
@@ -1207,30 +1033,18 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- s32 phase_comp;
- u8 out;
- int rc;
-
- guard(mutex)(&zldev->multiop_lock);
+ const struct zl3073x_out *out;
+ u8 out_id;
- /* Read output configuration */
- out = zl3073x_output_pin_out_get(pin->id);
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
- if (rc)
- return rc;
-
- /* Read current output phase compensation */
- rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, &phase_comp);
- if (rc)
- return rc;
+ out_id = zl3073x_output_pin_out_get(pin->id);
+ out = zl3073x_out_state_get(zldev, out_id);
/* Convert value to ps and reverse two's complement negation applied
* during 'set'
*/
- *phase_adjust = -phase_comp * pin->phase_gran;
+ *phase_adjust = -out->phase_comp * pin->phase_gran;
- return rc;
+ return 0;
}
static int
@@ -1244,31 +1058,19 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
struct zl3073x_dpll *zldpll = dpll_priv;
struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- u8 out;
- int rc;
+ struct zl3073x_out out;
+ u8 out_id;
+
+ out_id = zl3073x_output_pin_out_get(pin->id);
+ out = *zl3073x_out_state_get(zldev, out_id);
/* The value in the register is stored as two's complement negation
* of requested value and expressed in half synth clock cycles.
*/
- phase_adjust = -phase_adjust / pin->phase_gran;
-
- guard(mutex)(&zldev->multiop_lock);
-
- /* Read output configuration */
- out = zl3073x_output_pin_out_get(pin->id);
- rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
- if (rc)
- return rc;
-
- /* Write the requested value into the compensation register */
- rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, phase_adjust);
- if (rc)
- return rc;
+ out.phase_comp = -phase_adjust / pin->phase_gran;
/* Update output configuration from mailbox */
- return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
- ZL_REG_OUTPUT_MB_MASK, BIT(out));
+ return zl3073x_out_state_set(zldev, out_id, &out);
}
static int
@@ -1680,8 +1482,6 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
/* Output P&N pair shares single HW output */
u8 out = zl3073x_output_pin_out_get(index);
- name = "OUT";
-
/* Skip the pin if it is connected to different DPLL channel */
if (zl3073x_dev_out_dpll_get(zldev, out) != zldpll->id) {
dev_dbg(zldev->dev,
@@ -1691,6 +1491,7 @@ zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
return false;
}
+ name = "OUT";
is_diff = zl3073x_dev_out_is_diff(zldev, out);
is_enabled = zl3073x_dev_output_pin_is_enabled(zldev, index);
}
diff --git a/drivers/dpll/zl3073x/out.c b/drivers/dpll/zl3073x/out.c
index a48f6917b39fb..3bbe97fad3b34 100644
--- a/drivers/dpll/zl3073x/out.c
+++ b/drivers/dpll/zl3073x/out.c
@@ -50,6 +50,46 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
zl3073x_out_signal_format_get(out));
+ /* Read output divisor */
+ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div);
+ if (rc)
+ return rc;
+
+ if (!out->div) {
+ dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n",
+ index);
+ return -EINVAL;
+ }
+
+ dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div);
+
+ /* Read output width */
+ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
+ &out->esync_n_period);
+ if (rc)
+ return rc;
+
+ if (!out->esync_n_period) {
+ dev_err(zldev->dev,
+ "Zero esync divisor for OUT%u got from device\n",
+ index);
+ return -EINVAL;
+ }
+
+ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
+ &out->esync_n_width);
+ if (rc)
+ return rc;
+
+ rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
+ &out->phase_comp);
+ if (rc)
+ return rc;
+
return rc;
}
@@ -65,3 +105,59 @@ const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
{
return &zldev->out[index];
}
+
+#define ZL3073X_OUT_SYNC_ONE(_dev, _dst, _src, _type, _field, _reg) \
+ ((_dst)->_field != (_src)->_field ? \
+ zl3073x_write_##_type(_dev, _reg, (_src)->_field) : 0)
+
+int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
+ const struct zl3073x_out *out)
+{
+ struct zl3073x_out *dout = &zldev->out[index];
+ int rc;
+
+ guard(mutex)(&zldev->multiop_lock);
+
+ /* Read output configuration into mailbox */
+ rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
+ ZL_REG_OUTPUT_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* Update mailbox with changed values */
+ rc = ZL3073X_OUT_SYNC_ONE(zldev, dout, out, u32, div,
+ ZL_REG_OUTPUT_DIV);
+ if (!rc)
+ rc = ZL3073X_OUT_SYNC_ONE(zldev, dout, out, u32, width,
+ ZL_REG_OUTPUT_WIDTH);
+ if (!rc)
+ rc = ZL3073X_OUT_SYNC_ONE(zldev, dout, out, u32, esync_n_period,
+ ZL_REG_OUTPUT_ESYNC_PERIOD);
+ if (!rc)
+ rc = ZL3073X_OUT_SYNC_ONE(zldev, dout, out, u32, esync_n_width,
+ ZL_REG_OUTPUT_ESYNC_WIDTH);
+ if (!rc)
+ rc = ZL3073X_OUT_SYNC_ONE(zldev, dout, out, u8, mode,
+ ZL_REG_OUTPUT_MODE);
+ if (!rc)
+ rc = ZL3073X_OUT_SYNC_ONE(zldev, dout, out, u32, phase_comp,
+ ZL_REG_OUTPUT_PHASE_COMP);
+ if (rc)
+ return rc;
+
+ /* Commit output configuration */
+ rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
+ ZL_REG_OUTPUT_MB_MASK, BIT(index));
+ if (rc)
+ return rc;
+
+ /* After successful commit store new state */
+ dout->div = out->div;
+ dout->width = out->width;
+ dout->esync_n_period = out->esync_n_period;
+ dout->esync_n_width = out->esync_n_width;
+ dout->mode = out->mode;
+ dout->phase_comp = out->phase_comp;
+
+ return 0;
+}
diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h
index 986aa046221da..ff1fb7985d4de 100644
--- a/drivers/dpll/zl3073x/out.h
+++ b/drivers/dpll/zl3073x/out.h
@@ -16,6 +16,11 @@ struct zl3073x_dev;
* @mode: output mode
*/
struct zl3073x_out {
+ u32 div;
+ u32 width;
+ u32 esync_n_period;
+ u32 esync_n_width;
+ s32 phase_comp;
u8 ctrl;
u8 mode;
};
@@ -24,6 +29,9 @@ int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index);
const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
u8 index);
+int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
+ const struct zl3073x_out *out);
+
/**
* zl3073x_out_signal_format_get - get output signal format
* @out: pointer to out state
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH net-next 6/6] dpll: zl3073x: Remove unused dev wrappers
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
` (4 preceding siblings ...)
2025-11-10 17:58 ` [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out Ivan Vecera
@ 2025-11-10 17:58 ` Ivan Vecera
5 siblings, 0 replies; 9+ messages in thread
From: Ivan Vecera @ 2025-11-10 17:58 UTC (permalink / raw)
To: netdev
Cc: Petr Oros, Prathosh Satish, Vadim Fedorenko, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, linux-kernel
Remove several zl3073x_dev_... inline wrapper functions from core.h
as they are no longer used by any callers.
Removed functions:
* zl3073x_dev_ref_ffo_get
* zl3073x_dev_ref_is_enabled
* zl3073x_dev_synth_dpll_get
* zl3073x_dev_synth_is_enabled
* zl3073x_dev_out_signal_format_get
This is a cleanup after recent refactoring, as the remaining callers
now fetch the state object and use the base helpers directly.
Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/core.h | 77 -------------------------------------
1 file changed, 77 deletions(-)
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index fe8b70e25d3cc..09bca2d0926d5 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -182,21 +182,6 @@ zl3073x_output_pin_out_get(u8 id)
return id / 2;
}
-/**
- * zl3073x_dev_ref_ffo_get - get current fractional frequency offset
- * @zldev: pointer to zl3073x device
- * @index: input reference index
- *
- * Return: the latest measured fractional frequency offset
- */
-static inline s64
-zl3073x_dev_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
-{
- const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
-
- return zl3073x_ref_ffo_get(ref);
-}
-
/**
* zl3073x_dev_ref_freq_get - get input reference frequency
* @zldev: pointer to zl3073x device
@@ -227,21 +212,6 @@ zl3073x_dev_ref_is_diff(struct zl3073x_dev *zldev, u8 index)
return zl3073x_ref_is_diff(ref);
}
-/**
- * zl3073x_dev_ref_is_enabled - check if the given input reference is enabled
- * @zldev: pointer to zl3073x device
- * @index: input reference index
- *
- * Return: true if input refernce is enabled, false otherwise
- */
-static inline bool
-zl3073x_dev_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)
-{
- const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index);
-
- return zl3073x_ref_is_enabled(ref);
-}
-
/*
* zl3073x_dev_ref_is_status_ok - check the given input reference status
* @zldev: pointer to zl3073x device
@@ -257,22 +227,6 @@ zl3073x_dev_ref_is_status_ok(struct zl3073x_dev *zldev, u8 index)
return zl3073x_ref_is_status_ok(ref);
}
-/**
- * zl3073x_dev_synth_dpll_get - get DPLL ID the synth is driven by
- * @zldev: pointer to zl3073x device
- * @index: synth index
- *
- * Return: ID of DPLL the given synthetizer is driven by
- */
-static inline u8
-zl3073x_dev_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)
-{
- const struct zl3073x_synth *synth;
-
- synth = zl3073x_synth_state_get(zldev, index);
- return zl3073x_synth_dpll_get(synth);
-}
-
/**
* zl3073x_dev_synth_freq_get - get synth current freq
* @zldev: pointer to zl3073x device
@@ -289,22 +243,6 @@ zl3073x_dev_synth_freq_get(struct zl3073x_dev *zldev, u8 index)
return zl3073x_synth_freq_get(synth);
}
-/**
- * zl3073x_dev_synth_is_enabled - check if the given synth is enabled
- * @zldev: pointer to zl3073x device
- * @index: synth index
- *
- * Return: true if synth is enabled, false otherwise
- */
-static inline bool
-zl3073x_dev_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)
-{
- const struct zl3073x_synth *synth;
-
- synth = zl3073x_synth_state_get(zldev, index);
- return zl3073x_synth_is_enabled(synth);
-}
-
/**
* zl3073x_dev_out_synth_get - get synth connected to given output
* @zldev: pointer to zl3073x device
@@ -341,21 +279,6 @@ zl3073x_dev_out_is_enabled(struct zl3073x_dev *zldev, u8 index)
return zl3073x_synth_is_enabled(synth) && zl3073x_out_is_enabled(out);
}
-/**
- * zl3073x_dev_out_signal_format_get - get output signal format
- * @zldev: pointer to zl3073x device
- * @index: output index
- *
- * Return: signal format of given output
- */
-static inline u8
-zl3073x_dev_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)
-{
- const struct zl3073x_out *out = zl3073x_out_state_get(zldev, index);
-
- return zl3073x_out_signal_format_get(out);
-}
-
/**
* zl3073x_dev_out_dpll_get - get DPLL ID the output is driven by
* @zldev: pointer to zl3073x device
--
2.51.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref
2025-11-10 17:58 ` [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref Ivan Vecera
@ 2025-11-11 6:52 ` kernel test robot
0 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2025-11-11 6:52 UTC (permalink / raw)
To: Ivan Vecera, netdev
Cc: oe-kbuild-all, Petr Oros, Prathosh Satish, Vadim Fedorenko,
Arkadiusz Kubalewski, Jiri Pirko, Michal Schmidt, linux-kernel
Hi Ivan,
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/Ivan-Vecera/dpll-zl3073x-Store-raw-register-values-instead-of-parsed-state/20251111-020236
base: net-next/main
patch link: https://lore.kernel.org/r/20251110175818.1571610-5-ivecera%40redhat.com
patch subject: [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref
config: x86_64-randconfig-161-20251111 (https://download.01.org/0day-ci/archive/20251111/202511111402.yEyMEeLb-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251111/202511111402.yEyMEeLb-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/202511111402.yEyMEeLb-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/dpll/zl3073x/dpll.c: In function 'zl3073x_dpll_pin_phase_offset_check':
>> drivers/dpll/zl3073x/dpll.c:1850:35: warning: variable 'ref' set but not used [-Wunused-but-set-variable]
1850 | const struct zl3073x_ref *ref;
| ^~~
vim +/ref +1850 drivers/dpll/zl3073x/dpll.c
1836
1837 /**
1838 * zl3073x_dpll_pin_phase_offset_check - check for pin phase offset change
1839 * @pin: pin to check
1840 *
1841 * Check for the change of DPLL to connected pin phase offset change.
1842 *
1843 * Return: true on phase offset change, false otherwise
1844 */
1845 static bool
1846 zl3073x_dpll_pin_phase_offset_check(struct zl3073x_dpll_pin *pin)
1847 {
1848 struct zl3073x_dpll *zldpll = pin->dpll;
1849 struct zl3073x_dev *zldev = zldpll->dev;
> 1850 const struct zl3073x_ref *ref;
1851 unsigned int reg;
1852 s64 phase_offset;
1853 u8 ref_id;
1854 int rc;
1855
1856 ref_id = zl3073x_input_pin_ref_get(pin->id);
1857 ref = zl3073x_ref_state_get(zldev, ref_id);
1858
1859 /* No phase offset if the ref monitor reports signal errors */
1860 if (!zl3073x_dev_ref_is_status_ok(zldev, ref_id))
1861 return false;
1862
1863 /* Select register to read phase offset value depending on pin and
1864 * phase monitor state:
1865 * 1) For connected pin use dpll_phase_err_data register
1866 * 2) For other pins use appropriate ref_phase register if the phase
1867 * monitor feature is enabled.
1868 */
1869 if (pin->pin_state == DPLL_PIN_STATE_CONNECTED)
1870 reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id);
1871 else if (zldpll->phase_monitor)
1872 reg = ZL_REG_REF_PHASE(ref_id);
1873 else
1874 return false;
1875
1876 /* Read measured phase offset value */
1877 rc = zl3073x_read_u48(zldev, reg, &phase_offset);
1878 if (rc) {
1879 dev_err(zldev->dev, "Failed to read ref phase offset: %pe\n",
1880 ERR_PTR(rc));
1881
1882 return false;
1883 }
1884
1885 /* Convert to ps */
1886 phase_offset = div_s64(sign_extend64(phase_offset, 47), 100);
1887
1888 /* Compare with previous value */
1889 if (phase_offset != pin->phase_offset) {
1890 dev_dbg(zldev->dev, "%s phase offset changed: %lld -> %lld\n",
1891 pin->label, pin->phase_offset, phase_offset);
1892 pin->phase_offset = phase_offset;
1893
1894 return true;
1895 }
1896
1897 return false;
1898 }
1899
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out
2025-11-10 17:58 ` [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out Ivan Vecera
@ 2025-11-11 10:42 ` kernel test robot
0 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2025-11-11 10:42 UTC (permalink / raw)
To: Ivan Vecera, netdev
Cc: llvm, oe-kbuild-all, Petr Oros, Prathosh Satish, Vadim Fedorenko,
Arkadiusz Kubalewski, Jiri Pirko, Michal Schmidt, linux-kernel
Hi Ivan,
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/Ivan-Vecera/dpll-zl3073x-Store-raw-register-values-instead-of-parsed-state/20251111-020236
base: net-next/main
patch link: https://lore.kernel.org/r/20251110175818.1571610-6-ivecera%40redhat.com
patch subject: [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out
config: sparc64-allmodconfig (https://download.01.org/0day-ci/archive/20251111/202511111809.FLxbtr0Z-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 996639d6ebb86ff15a8c99b67f1c2e2117636ae7)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251111/202511111809.FLxbtr0Z-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/202511111809.FLxbtr0Z-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/dpll/zl3073x/dpll.c:1488:43: warning: variable 'name' is uninitialized when used here [-Wuninitialized]
1488 | "%s%u is driven by different DPLL\n", name,
| ^~~~
drivers/dpll/zl3073x/dpll.c:1467:18: note: initialize the variable 'name' to silence this warning
1467 | const char *name;
| ^
| = NULL
drivers/dpll/zl3073x/dpll.c:1651:28: warning: variable 'ref' set but not used [-Wunused-but-set-variable]
1651 | const struct zl3073x_ref *ref;
| ^
2 warnings generated.
vim +/name +1488 drivers/dpll/zl3073x/dpll.c
75a71ecc24125f9 Ivan Vecera 2025-07-04 1446
75a71ecc24125f9 Ivan Vecera 2025-07-04 1447 /**
75a71ecc24125f9 Ivan Vecera 2025-07-04 1448 * zl3073x_dpll_pin_is_registrable - check if the pin is registrable
75a71ecc24125f9 Ivan Vecera 2025-07-04 1449 * @zldpll: pointer to zl3073x_dpll structure
75a71ecc24125f9 Ivan Vecera 2025-07-04 1450 * @dir: pin direction
75a71ecc24125f9 Ivan Vecera 2025-07-04 1451 * @index: pin index
75a71ecc24125f9 Ivan Vecera 2025-07-04 1452 *
75a71ecc24125f9 Ivan Vecera 2025-07-04 1453 * Checks if the given pin can be registered to given DPLL. For both
75a71ecc24125f9 Ivan Vecera 2025-07-04 1454 * directions the pin can be registered if it is enabled. In case of
75a71ecc24125f9 Ivan Vecera 2025-07-04 1455 * differential signal type only P-pin is reported as registrable.
75a71ecc24125f9 Ivan Vecera 2025-07-04 1456 * And additionally for the output pin, the pin can be registered only
75a71ecc24125f9 Ivan Vecera 2025-07-04 1457 * if it is connected to synthesizer that is driven by given DPLL.
75a71ecc24125f9 Ivan Vecera 2025-07-04 1458 *
75a71ecc24125f9 Ivan Vecera 2025-07-04 1459 * Return: true if the pin is registrable, false if not
75a71ecc24125f9 Ivan Vecera 2025-07-04 1460 */
75a71ecc24125f9 Ivan Vecera 2025-07-04 1461 static bool
75a71ecc24125f9 Ivan Vecera 2025-07-04 1462 zl3073x_dpll_pin_is_registrable(struct zl3073x_dpll *zldpll,
75a71ecc24125f9 Ivan Vecera 2025-07-04 1463 enum dpll_pin_direction dir, u8 index)
75a71ecc24125f9 Ivan Vecera 2025-07-04 1464 {
75a71ecc24125f9 Ivan Vecera 2025-07-04 1465 struct zl3073x_dev *zldev = zldpll->dev;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1466 bool is_diff, is_enabled;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1467 const char *name;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1468
75a71ecc24125f9 Ivan Vecera 2025-07-04 1469 if (dir == DPLL_PIN_DIRECTION_INPUT) {
b35db42141ccf2a Ivan Vecera 2025-11-10 1470 u8 ref_id = zl3073x_input_pin_ref_get(index);
b35db42141ccf2a Ivan Vecera 2025-11-10 1471 const struct zl3073x_ref *ref;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1472
75a71ecc24125f9 Ivan Vecera 2025-07-04 1473 /* Skip the pin if the DPLL is running in NCO mode */
75a71ecc24125f9 Ivan Vecera 2025-07-04 1474 if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO)
75a71ecc24125f9 Ivan Vecera 2025-07-04 1475 return false;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1476
b35db42141ccf2a Ivan Vecera 2025-11-10 1477 name = "REF";
b35db42141ccf2a Ivan Vecera 2025-11-10 1478 ref = zl3073x_ref_state_get(zldev, ref_id);
b35db42141ccf2a Ivan Vecera 2025-11-10 1479 is_diff = zl3073x_ref_is_diff(ref);
b35db42141ccf2a Ivan Vecera 2025-11-10 1480 is_enabled = zl3073x_ref_is_enabled(ref);
75a71ecc24125f9 Ivan Vecera 2025-07-04 1481 } else {
75a71ecc24125f9 Ivan Vecera 2025-07-04 1482 /* Output P&N pair shares single HW output */
75a71ecc24125f9 Ivan Vecera 2025-07-04 1483 u8 out = zl3073x_output_pin_out_get(index);
75a71ecc24125f9 Ivan Vecera 2025-07-04 1484
75a71ecc24125f9 Ivan Vecera 2025-07-04 1485 /* Skip the pin if it is connected to different DPLL channel */
65b8e8e3bf41fda Ivan Vecera 2025-11-10 1486 if (zl3073x_dev_out_dpll_get(zldev, out) != zldpll->id) {
75a71ecc24125f9 Ivan Vecera 2025-07-04 1487 dev_dbg(zldev->dev,
75a71ecc24125f9 Ivan Vecera 2025-07-04 @1488 "%s%u is driven by different DPLL\n", name,
75a71ecc24125f9 Ivan Vecera 2025-07-04 1489 out);
75a71ecc24125f9 Ivan Vecera 2025-07-04 1490
75a71ecc24125f9 Ivan Vecera 2025-07-04 1491 return false;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1492 }
75a71ecc24125f9 Ivan Vecera 2025-07-04 1493
11e61915b41b996 Ivan Vecera 2025-11-10 1494 name = "OUT";
65b8e8e3bf41fda Ivan Vecera 2025-11-10 1495 is_diff = zl3073x_dev_out_is_diff(zldev, out);
65b8e8e3bf41fda Ivan Vecera 2025-11-10 1496 is_enabled = zl3073x_dev_output_pin_is_enabled(zldev, index);
75a71ecc24125f9 Ivan Vecera 2025-07-04 1497 }
75a71ecc24125f9 Ivan Vecera 2025-07-04 1498
75a71ecc24125f9 Ivan Vecera 2025-07-04 1499 /* Skip N-pin if the corresponding input/output is differential */
75a71ecc24125f9 Ivan Vecera 2025-07-04 1500 if (is_diff && zl3073x_is_n_pin(index)) {
75a71ecc24125f9 Ivan Vecera 2025-07-04 1501 dev_dbg(zldev->dev, "%s%u is differential, skipping N-pin\n",
75a71ecc24125f9 Ivan Vecera 2025-07-04 1502 name, index / 2);
75a71ecc24125f9 Ivan Vecera 2025-07-04 1503
75a71ecc24125f9 Ivan Vecera 2025-07-04 1504 return false;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1505 }
75a71ecc24125f9 Ivan Vecera 2025-07-04 1506
75a71ecc24125f9 Ivan Vecera 2025-07-04 1507 /* Skip the pin if it is disabled */
75a71ecc24125f9 Ivan Vecera 2025-07-04 1508 if (!is_enabled) {
75a71ecc24125f9 Ivan Vecera 2025-07-04 1509 dev_dbg(zldev->dev, "%s%u%c is disabled\n", name, index / 2,
75a71ecc24125f9 Ivan Vecera 2025-07-04 1510 zl3073x_is_p_pin(index) ? 'P' : 'N');
75a71ecc24125f9 Ivan Vecera 2025-07-04 1511
75a71ecc24125f9 Ivan Vecera 2025-07-04 1512 return false;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1513 }
75a71ecc24125f9 Ivan Vecera 2025-07-04 1514
75a71ecc24125f9 Ivan Vecera 2025-07-04 1515 return true;
75a71ecc24125f9 Ivan Vecera 2025-07-04 1516 }
75a71ecc24125f9 Ivan Vecera 2025-07-04 1517
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-11-11 10:42 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-10 17:58 [PATCH net-next 0/6] dpll: zl3073x: Refactor state management Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 1/6] dpll: zl3073x: Store raw register values instead of parsed state Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 2/6] dpll: zl3073x: Split ref, out, and synth logic from core Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 3/6] dpll: zl3073x: Cache reference monitor status Ivan Vecera
2025-11-10 17:58 ` [PATCH net-next 4/6] dpll: zl3073x: Cache all reference properties in zl3073x_ref Ivan Vecera
2025-11-11 6:52 ` kernel test robot
2025-11-10 17:58 ` [PATCH net-next 5/6] dpll: zl3073x: Cache all output properties in zl3073x_out Ivan Vecera
2025-11-11 10:42 ` kernel test robot
2025-11-10 17:58 ` [PATCH net-next 6/6] dpll: zl3073x: Remove unused dev wrappers Ivan Vecera
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).