summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-02-06 20:44:24 -0800
committerJakub Kicinski <kuba@kernel.org>2026-02-06 20:44:24 -0800
commit5826eec8710c214f02f253c165d66a230f5a86c3 (patch)
treed693603aae6594071a4446309a6d62f0d1320f49
parenta14d9317904559a6948946de05bf9fb6f2a34fba (diff)
parent85a9aaac4a38a7ce68f30bd7678fca4e8c687fe2 (diff)
Merge branch 'dpll-zl3073x-include-current-frequency-in-supported-frequencies-list'
Ivan Vecera says: ==================== dpll: zl3073x: Include current frequency in supported frequencies list This series ensures that the current operating frequency of a DPLL pin is always reported in its supported frequencies list. Problem: When a ZL3073x DPLL pin is registered, its supported frequencies are read from the firmware node's "supported-frequencies-hz" property. However, if the firmware node is missing, or doesn't include the current operating frequency, the pin reports a frequency that isn't in its supported list. This inconsistency can confuse userspace tools that expect the current frequency to be among the supported values. Solution: Always include the current pin frequency as the first entry in the supported frequencies list, followed by any additional frequencies from the firmware node (with duplicates filtered out). Patch 1 refactors the output pin frequency calculation into a reusable helper function zl3073x_dev_output_pin_freq_get(), which mirrors the existing zl3073x_dev_ref_freq_get() for input pins. Patch 2 modifies zl3073x_pin_props_get() to obtain the current frequency early and place it at index 0 of the supported frequencies array, ensuring it is always present regardless of firmware node contents. ==================== Link: https://patch.msgid.link/20260205154350.3180465-1-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/dpll/zl3073x/core.h30
-rw-r--r--drivers/dpll/zl3073x/dpll.c39
-rw-r--r--drivers/dpll/zl3073x/out.h17
-rw-r--r--drivers/dpll/zl3073x/prop.c32
4 files changed, 69 insertions, 49 deletions
diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h
index 09bca2d0926d..dddfcacea5c0 100644
--- a/drivers/dpll/zl3073x/core.h
+++ b/drivers/dpll/zl3073x/core.h
@@ -302,6 +302,36 @@ u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index)
}
/**
+ * zl3073x_dev_output_pin_freq_get - get output pin frequency
+ * @zldev: pointer to zl3073x device
+ * @id: output pin id
+ *
+ * Computes the output pin frequency based on the synth frequency, output
+ * divisor, and signal format. For N-div formats, N-pin frequency is
+ * additionally divided by esync_n_period.
+ *
+ * Return: frequency of the given output pin in Hz
+ */
+static inline u32
+zl3073x_dev_output_pin_freq_get(struct zl3073x_dev *zldev, u8 id)
+{
+ const struct zl3073x_synth *synth;
+ const struct zl3073x_out *out;
+ u8 out_id;
+ u32 freq;
+
+ out_id = zl3073x_output_pin_out_get(id);
+ out = zl3073x_out_state_get(zldev, out_id);
+ synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
+ freq = zl3073x_synth_freq_get(synth) / out->div;
+
+ if (zl3073x_out_is_ndiv(out) && zl3073x_is_n_pin(id))
+ freq /= out->esync_n_period;
+
+ return freq;
+}
+
+/**
* zl3073x_dev_out_is_diff - check if the given output is differential
* @zldev: pointer to zl3073x device
* @index: output index
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index a99d143a7acd..eb94c29af2cf 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -916,46 +916,9 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin,
struct netlink_ext_ack *extack)
{
struct zl3073x_dpll *zldpll = dpll_priv;
- struct zl3073x_dev *zldev = zldpll->dev;
struct zl3073x_dpll_pin *pin = pin_priv;
- const struct zl3073x_synth *synth;
- const struct zl3073x_out *out;
- u32 synth_freq;
- u8 out_id;
- out_id = zl3073x_output_pin_out_get(pin->id);
- out = zl3073x_out_state_get(zldev, out_id);
-
- /* Get attached synth frequency */
- synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out));
- synth_freq = zl3073x_synth_freq_get(synth);
-
- 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.
- */
- *frequency = synth_freq / out->div;
-
- if (!zl3073x_dpll_is_p_pin(pin))
- *frequency = (u32)*frequency / out->esync_n_period;
-
- break;
- default:
- /* In other modes the resulting frequency is computed as
- * division of synth frequency and output divisor.
- */
- *frequency = synth_freq / out->div;
- break;
- }
+ *frequency = zl3073x_dev_output_pin_freq_get(zldpll->dev, pin->id);
return 0;
}
diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h
index e8ea7a0e0f07..318f9bb8da3a 100644
--- a/drivers/dpll/zl3073x/out.h
+++ b/drivers/dpll/zl3073x/out.h
@@ -80,6 +80,23 @@ static inline bool zl3073x_out_is_enabled(const struct zl3073x_out *out)
}
/**
+ * zl3073x_out_is_ndiv - check if the given output is in N-div mode
+ * @out: pointer to out state
+ *
+ * Return: true if output is in N-div mode, false otherwise
+ */
+static inline bool zl3073x_out_is_ndiv(const struct zl3073x_out *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 true;
+ default:
+ return false;
+ }
+}
+
+/**
* zl3073x_out_synth_get - get synth connected to given output
* @out: pointer to out state
*
diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c
index ad1f099cbe2b..8523dc8c226e 100644
--- a/drivers/dpll/zl3073x/prop.c
+++ b/drivers/dpll/zl3073x/prop.c
@@ -193,9 +193,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
{
struct dpll_pin_frequency *ranges;
struct zl3073x_pin_props *props;
- int i, j, num_freqs, rc;
+ int i, j, num_freqs = 0, rc;
+ u64 *freqs = NULL;
const char *type;
- u64 *freqs;
+ u32 curr_freq;
props = kzalloc(sizeof(*props), GFP_KERNEL);
if (!props)
@@ -207,6 +208,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
props->dpll_props.capabilities =
DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE |
DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE;
+ curr_freq = zl3073x_dev_ref_freq_get(zldev, index);
} else {
u8 out, synth;
u32 f;
@@ -220,6 +222,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
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;
+ curr_freq = zl3073x_dev_output_pin_freq_get(zldev, index);
}
props->dpll_props.phase_range.min = S32_MIN;
@@ -230,7 +233,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
/* Get firmware node for the given pin */
rc = zl3073x_prop_pin_fwnode_get(zldev, props, dir, index);
if (rc)
- return props; /* Return if it does not exist */
+ goto skip_fwnode_props;
/* Look for label property and store the value as board label */
fwnode_property_read_string(props->fwnode, "label",
@@ -264,9 +267,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
/* Read supported frequencies property if it is specified */
num_freqs = fwnode_property_count_u64(props->fwnode,
"supported-frequencies-hz");
- if (num_freqs <= 0)
- /* Return if the property does not exist or number is 0 */
- return props;
+ if (num_freqs <= 0) {
+ num_freqs = 0;
+ goto skip_fwnode_props;
+ }
/* The firmware node specifies list of supported frequencies while
* DPLL core pin properties requires list of frequency ranges.
@@ -283,19 +287,25 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev,
"supported-frequencies-hz", freqs,
num_freqs);
- /* Allocate frequency ranges list and fill it */
- ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL);
+skip_fwnode_props:
+ /* Allocate frequency ranges list - extra slot for current frequency */
+ ranges = kcalloc(num_freqs + 1, sizeof(*ranges), GFP_KERNEL);
if (!ranges) {
rc = -ENOMEM;
goto err_alloc_ranges;
}
- /* Convert list of frequencies to list of frequency ranges but
- * filter-out frequencies that are not representable by device
+ /* Start with current frequency at index 0 */
+ ranges[0] = (struct dpll_pin_frequency)DPLL_PIN_FREQUENCY(curr_freq);
+
+ /* Add frequencies from firmware node, skipping current frequency
+ * and filtering out frequencies not representable by device
*/
- for (i = 0, j = 0; i < num_freqs; i++) {
+ for (i = 0, j = 1; i < num_freqs; i++) {
struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]);
+ if (freqs[i] == curr_freq)
+ continue;
if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) {
ranges[j] = freq;
j++;