* [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi
@ 2026-03-12 6:58 Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 1/6] dt-bindings: clock: Add spread spectrum definition Peng Fan (OSS)
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
Since the assigned-clock-sscs property [1] has been accepted into the device
tree schema, we can now support it in the Linux clock driver. Therefore,
I've picked up the previously submitted work [2] titled "clk: Support
spread spectrum and use it in clk-pll144x and clk-scmi."
As more than six months have passed since [2] was posted, I’m treating this
patchset as a new submission rather than a v3.
- Introduce clk_set_spread_spectrum to set the parameters for enabling
spread spectrum of a clock.
- Parse 'assigned-clock-sscs' and configure it by default before using the
clock. This property is parsed before parsing clock rate.
- Enable this feature for clk-scmi on i.MX95.
Because SCMI spec will not include spread spectrum as a standard
extension, we still need to use NXP i.MX OEM extension.
[1] https://github.com/devicetree-org/dt-schema/pull/154
[2] https://lore.kernel.org/all/20250205-clk-ssc-v2-0-fa73083caa92@nxp.com/
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Changes in v9:
- Rebased to next-20260311
- Fix kunit test by setting return value to 0 when there is no
assigned-clocks in patch 3
- Link to v8: https://lore.kernel.org/r/20260302-clk-ssc-v7-1-v8-0-2356443a7e4c@nxp.com
Changes in v8:
- Add R-b from Cristian for patch 5 and patch 6
- Add comment for scmi_clk_oem_info in patch 6
- Rebased to next-20260227
- Link to v7: https://lore.kernel.org/r/20251231-clk-ssc-v7-1-v7-0-380e8b58f9e3@nxp.com
Changes in v7:
- Add R-b from Sebin
- Drop __free usage per comment from Krzysztof in patch 3
- Link to v6: https://lore.kernel.org/linux-clk/20251128-clk-ssc-v6-2-v6-0-cfafdb5d6811@nxp.com/
Changes in v6:
- Add kunit build warning
- Update OEM string comparation per Sebin
- Link to v5: https://lore.kernel.org/linux-clk/20251009-clk-ssc-v5-1-v5-0-d6447d76171e@nxp.com/
Changes in v5:
- Per Stephen, export clk_hw_set_spread_spectrum, use enum for method,
add const for set_spread_spectrum and rename clk_ss/conf to ss_conf.
- Per Sebin, Cristian, Sudeep, I added clk-scmi-oem.c to support vendor
extensions.
- Link to v4: https://lore.kernel.org/arm-scmi/aNQPWO6pfA_3mmxf@redhat.com/T/#me81231bf286e2a8e4e00a68707ed1e525a2b4a3d
Changes in v4:
- Add R-b for patch 1 from Brian
- Drop unecessary change in patch 4 Per Brian
- Link to v3: https://lore.kernel.org/r/20250912-clk-ssc-version1-v3-0-fd1e07476ba1@nxp.com
Changes in v3:
- New patch 1 for dt-bindings per comment from Brian
https://lore.kernel.org/all/aLeEFzXkPog_dt2B@x1/
This might not be good to add a new dt-binding file in v3. But this is
quite a simple file that just has four macros to encode modulation
method. So hope this is fine for DT maintainers.
- Add Brain's R-b for patch 2
- New patch 3 to add Kunit test per Brain. Since Brain helped
draft part of the code, I added Co-developed-by tag from Brain.
- Link to v2: https://lore.kernel.org/r/20250901-clk-ssc-version1-v2-0-1d0a486dffe6@nxp.com
Changes in v2:
- Simplify the code in patch 2 per Dan Carpenter and Brian Masney
- Rebased to next-20250829
- Link to v1: https://lore.kernel.org/r/20250812-clk-ssc-version1-v1-0-cef60f20d770@nxp.com
---
Peng Fan (6):
dt-bindings: clock: Add spread spectrum definition
clk: Introduce clk_hw_set_spread_spectrum
clk: conf: Support assigned-clock-sscs
clk: Add KUnit tests for assigned-clock-sscs
clk: scmi: Introduce common header for SCMI clock interface
clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver
drivers/clk/Makefile | 8 +-
drivers/clk/clk-conf.c | 76 +++++++++++++
drivers/clk/clk-scmi-oem.c | 108 ++++++++++++++++++
drivers/clk/clk-scmi.c | 44 +++-----
drivers/clk/clk-scmi.h | 51 +++++++++
drivers/clk/clk.c | 27 +++++
drivers/clk/clk_test.c | 121 ++++++++++++++++++++-
drivers/clk/kunit_clk_assigned_rates.h | 10 ++
drivers/clk/kunit_clk_assigned_rates_multiple.dtso | 6 +
...kunit_clk_assigned_rates_multiple_consumer.dtso | 6 +
drivers/clk/kunit_clk_assigned_rates_one.dtso | 3 +
.../clk/kunit_clk_assigned_rates_one_consumer.dtso | 3 +
.../clk/kunit_clk_assigned_rates_u64_multiple.dtso | 6 +
...t_clk_assigned_rates_u64_multiple_consumer.dtso | 6 +
drivers/clk/kunit_clk_assigned_rates_u64_one.dtso | 3 +
.../kunit_clk_assigned_rates_u64_one_consumer.dtso | 3 +
drivers/clk/kunit_clk_assigned_sscs_null.dtso | 16 +++
.../clk/kunit_clk_assigned_sscs_null_consumer.dtso | 20 ++++
drivers/clk/kunit_clk_assigned_sscs_without.dtso | 15 +++
.../kunit_clk_assigned_sscs_without_consumer.dtso | 19 ++++
drivers/clk/kunit_clk_assigned_sscs_zero.dtso | 12 ++
.../clk/kunit_clk_assigned_sscs_zero_consumer.dtso | 16 +++
include/dt-bindings/clock/clock.h | 14 +++
include/linux/clk-provider.h | 31 ++++++
24 files changed, 592 insertions(+), 32 deletions(-)
---
base-commit: 4095b5b3b22162df4bacade89b1814f774c5df42
change-id: 20251231-clk-ssc-v7-1-402dd4f9e629
Best regards,
--
Peng Fan <peng.fan@nxp.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v9 1/6] dt-bindings: clock: Add spread spectrum definition
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
@ 2026-03-12 6:58 ` Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 2/6] clk: Introduce clk_hw_set_spread_spectrum Peng Fan (OSS)
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Per dt-schema, the modulation methods are: down-spread(3), up-spread(2),
center-spread(1), no-spread(0). So define them in dt-bindings to avoid
write the magic number in device tree.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
include/dt-bindings/clock/clock.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/include/dt-bindings/clock/clock.h b/include/dt-bindings/clock/clock.h
new file mode 100644
index 0000000000000000000000000000000000000000..155e2653a120bf10747bd7f4d47f25e0493e0464
--- /dev/null
+++ b/include/dt-bindings/clock/clock.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_H
+#define __DT_BINDINGS_CLOCK_H
+
+#define CLK_SSC_NO_SPREAD 0
+#define CLK_SSC_CENTER_SPREAD 1
+#define CLK_SSC_UP_SPREAD 2
+#define CLK_SSC_DOWN_SPREAD 3
+
+#endif /* __DT_BINDINGS_CLOCK_H */
--
2.37.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 2/6] clk: Introduce clk_hw_set_spread_spectrum
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 1/6] dt-bindings: clock: Add spread spectrum definition Peng Fan (OSS)
@ 2026-03-12 6:58 ` Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 3/6] clk: conf: Support assigned-clock-sscs Peng Fan (OSS)
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Add clk_hw_set_spread_spectrum to configure a clock to enable spread
spectrum feature. set_spread_spectrum ops is added for clk drivers to
have their own hardware specific implementation.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/clk.c | 27 +++++++++++++++++++++++++++
include/linux/clk-provider.h | 31 +++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 47093cda9df32223c1120c3710261296027c4cd3..3d9b2e2f7a5b269e1f07bdcd4101799ff6839441 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2784,6 +2784,33 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL_GPL(clk_set_max_rate);
+int clk_hw_set_spread_spectrum(struct clk_hw *hw, const struct clk_spread_spectrum *ss_conf)
+{
+ struct clk_core *core;
+ int ret;
+
+ if (!hw)
+ return 0;
+
+ core = hw->core;
+
+ clk_prepare_lock();
+
+ ret = clk_pm_runtime_get(core);
+ if (ret)
+ goto fail;
+
+ if (core->ops->set_spread_spectrum)
+ ret = core->ops->set_spread_spectrum(hw, ss_conf);
+
+ clk_pm_runtime_put(core);
+
+fail:
+ clk_prepare_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_hw_set_spread_spectrum);
+
/**
* clk_get_parent - return the parent of a clk
* @clk: the clk whose parent gets returned
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 630705a47129453c241f1b1755f2c2f2a7ed8f77..9ec25bbccd613eafd77aca080dd7f51b1bfdadc1 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -6,6 +6,7 @@
#ifndef __LINUX_CLK_PROVIDER_H
#define __LINUX_CLK_PROVIDER_H
+#include <dt-bindings/clock/clock.h>
#include <linux/of.h>
#include <linux/of_clk.h>
@@ -84,6 +85,26 @@ struct clk_duty {
unsigned int den;
};
+enum clk_ssc_method {
+ CLK_SPREAD_NO = CLK_SSC_NO_SPREAD,
+ CLK_SPREAD_CENTER = CLK_SSC_CENTER_SPREAD,
+ CLK_SPREAD_UP = CLK_SSC_UP_SPREAD,
+ CLK_SPREAD_DOWN = CLK_SSC_DOWN_SPREAD,
+};
+
+/**
+ * struct clk_spread_spectrum - Structure encoding spread spectrum of a clock
+ *
+ * @modfreq_hz: Modulation frequency
+ * @spread_bp: Modulation percent in permyriad
+ * @method: Modulation method
+ */
+struct clk_spread_spectrum {
+ u32 modfreq_hz;
+ u32 spread_bp;
+ enum clk_ssc_method method;
+};
+
/**
* struct clk_ops - Callback operations for hardware clocks; these are to
* be provided by the clock implementation, and will be called by drivers
@@ -178,6 +199,12 @@ struct clk_duty {
* separately via calls to .set_parent and .set_rate.
* Returns 0 on success, -EERROR otherwise.
*
+ * @set_spread_spectrum: Optional callback used to configure the spread
+ * spectrum modulation frequency, percentage, and method
+ * to reduce EMI by spreading the clock frequency over a
+ * wider range.
+ * Returns 0 on success, -EERROR otherwise.
+ *
* @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
* is expressed in ppb (parts per billion). The parent accuracy is
* an input parameter.
@@ -255,6 +282,8 @@ struct clk_ops {
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate, u8 index);
+ int (*set_spread_spectrum)(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
unsigned long parent_accuracy);
int (*get_phase)(struct clk_hw *hw);
@@ -1430,6 +1459,8 @@ void clk_hw_get_rate_range(struct clk_hw *hw, unsigned long *min_rate,
unsigned long *max_rate);
void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
unsigned long max_rate);
+int clk_hw_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
{
--
2.37.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 3/6] clk: conf: Support assigned-clock-sscs
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 1/6] dt-bindings: clock: Add spread spectrum definition Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 2/6] clk: Introduce clk_hw_set_spread_spectrum Peng Fan (OSS)
@ 2026-03-12 6:58 ` Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 4/6] clk: Add KUnit tests for assigned-clock-sscs Peng Fan (OSS)
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Parse the Spread Spectrum Configuration(SSC) from device tree and configure
them before using the clock.
Each SSC is three u32 elements which means '<modfreq spreaddepth
modmethod>', so assigned-clock-sscs is an array of multiple three u32
elements.
Reviewed-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/clk-conf.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
index 303a0bb26e54a95655ce094a35b989c97ebc6fd8..550b8ae375a2cae8aa6ca22152753ce8d95332b5 100644
--- a/drivers/clk/clk-conf.c
+++ b/drivers/clk/clk-conf.c
@@ -155,6 +155,78 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
return 0;
}
+static int __set_clk_spread_spectrum(struct device_node *node, bool clk_supplier)
+{
+ u32 elem_size = sizeof(struct clk_spread_spectrum);
+ struct clk_spread_spectrum *sscs;
+ struct of_phandle_args clkspec;
+ int rc, count, index;
+ struct clk *clk;
+
+ /* modfreq, spreadPercent, modmethod */
+ count = of_property_count_elems_of_size(node, "assigned-clock-sscs", elem_size);
+ if (count <= 0)
+ return 0;
+
+ sscs = kcalloc(count, elem_size, GFP_KERNEL);
+ if (!sscs)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(node, "assigned-clock-sscs", (u32 *)sscs,
+ count * 3);
+ if (rc)
+ goto free_sscs;
+
+ for (index = 0; index < count; index++) {
+ struct clk_spread_spectrum *conf = &sscs[index];
+ struct clk_hw *hw;
+
+ if (!conf->modfreq_hz && !conf->spread_bp && !conf->method)
+ continue;
+
+ rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells",
+ index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT) {
+ rc = 0;
+ continue;
+ } else
+ goto free_sscs;
+ }
+
+ if (clkspec.np == node && !clk_supplier) {
+ of_node_put(clkspec.np);
+ goto free_sscs;
+ }
+
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) != -EPROBE_DEFER)
+ pr_warn("clk: couldn't get clock %d for %pOF\n",
+ index, node);
+ rc = PTR_ERR(clk);
+ goto free_sscs;
+ }
+
+ hw = __clk_get_hw(clk);
+ rc = clk_hw_set_spread_spectrum(hw, conf);
+ if (rc < 0) {
+ pr_err("clk: couldn't set %s clk spread spectrum %u %u %u: %d\n",
+ __clk_get_name(clk), conf->modfreq_hz, conf->spread_bp,
+ conf->method, rc);
+ /* Do not fail */
+ rc = 0;
+ }
+ clk_put(clk);
+ }
+
+free_sscs:
+ kfree(sscs);
+ return rc;
+}
+
/**
* of_clk_set_defaults() - parse and set assigned clocks configuration
* @node: device node to apply clock settings for
@@ -174,6 +246,10 @@ int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
if (!node)
return 0;
+ rc = __set_clk_spread_spectrum(node, clk_supplier);
+ if (rc < 0)
+ return rc;
+
rc = __set_clk_parents(node, clk_supplier);
if (rc < 0)
return rc;
--
2.37.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 4/6] clk: Add KUnit tests for assigned-clock-sscs
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
` (2 preceding siblings ...)
2026-03-12 6:58 ` [PATCH v9 3/6] clk: conf: Support assigned-clock-sscs Peng Fan (OSS)
@ 2026-03-12 6:58 ` Peng Fan (OSS)
2026-04-29 2:38 ` Stephen Boyd
2026-03-12 6:58 ` [PATCH v9 5/6] clk: scmi: Introduce common header for SCMI clock interface Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 6/6] clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver Peng Fan (OSS)
5 siblings, 1 reply; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Spread spectrum configuration is part of clock frequency settings,
and its behavior can be validated similarly to assigned clock rates.
Extend the existing KUnit tests for assigned-clock-rates to cover
assigned-clock-sscs by reusing the test framework. Add new test
device trees:
- kunit_clk_assigned_sscs_null.dtso
- kunit_clk_assigned_sscs_null_consumer.dtso
- kunit_clk_assigned_sscs_without.dtso
- kunit_clk_assigned_sscs_without_consumer.dtso
- kunit_clk_assigned_sscs_zero.dtso
- kunit_clk_assigned_sscs_zero_consumer.dtso
These tests cover various invalid configurations of assigned-clock-sscs,
ensuring robustness and consistent error handling, similar to the coverage
provided for assigned-clock-rates.
Co-developed-by: Brian Masney <bmasney@redhat.com>
Signed-off-by: Brian Masney <bmasney@redhat.com>
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/Makefile | 6 +
drivers/clk/clk_test.c | 121 ++++++++++++++++++++-
drivers/clk/kunit_clk_assigned_rates.h | 10 ++
drivers/clk/kunit_clk_assigned_rates_multiple.dtso | 6 +
...kunit_clk_assigned_rates_multiple_consumer.dtso | 6 +
drivers/clk/kunit_clk_assigned_rates_one.dtso | 3 +
.../clk/kunit_clk_assigned_rates_one_consumer.dtso | 3 +
.../clk/kunit_clk_assigned_rates_u64_multiple.dtso | 6 +
...t_clk_assigned_rates_u64_multiple_consumer.dtso | 6 +
drivers/clk/kunit_clk_assigned_rates_u64_one.dtso | 3 +
.../kunit_clk_assigned_rates_u64_one_consumer.dtso | 3 +
drivers/clk/kunit_clk_assigned_sscs_null.dtso | 16 +++
.../clk/kunit_clk_assigned_sscs_null_consumer.dtso | 20 ++++
drivers/clk/kunit_clk_assigned_sscs_without.dtso | 15 +++
.../kunit_clk_assigned_sscs_without_consumer.dtso | 19 ++++
drivers/clk/kunit_clk_assigned_sscs_zero.dtso | 12 ++
.../clk/kunit_clk_assigned_sscs_zero_consumer.dtso | 16 +++
17 files changed, 268 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f52cf3ac64fcce7e20f3fd91f837c5096375521a..d569d0ea3153efe593efbbd51e022b2415234d3a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,12 @@ clk-test-y := clk_test.o \
kunit_clk_assigned_rates_without_consumer.dtbo.o \
kunit_clk_assigned_rates_zero.dtbo.o \
kunit_clk_assigned_rates_zero_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_null.dtbo.o \
+ kunit_clk_assigned_sscs_null_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_without.dtbo.o \
+ kunit_clk_assigned_sscs_without_consumer.dtbo.o \
+ kunit_clk_assigned_sscs_zero.dtbo.o \
+ kunit_clk_assigned_sscs_zero_consumer.dtbo.o \
kunit_clk_hw_get_dev_of_node.dtbo.o \
kunit_clk_parent_data_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index a268d7b5d4cb28ec1f029f828c31107f8e130556..97113b61c2841701a44603ca9935638374000a2e 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -28,6 +28,7 @@ static const struct clk_ops empty_clk_ops = { };
struct clk_dummy_context {
struct clk_hw hw;
unsigned long rate;
+ struct clk_spread_spectrum sscs;
};
static unsigned long clk_dummy_recalc_rate(struct clk_hw *hw,
@@ -83,6 +84,17 @@ static int clk_dummy_set_rate(struct clk_hw *hw,
return 0;
}
+static int clk_dummy_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf)
+{
+ struct clk_dummy_context *ctx =
+ container_of(hw, struct clk_dummy_context, hw);
+
+ ctx->sscs = *ss_conf;
+
+ return 0;
+}
+
static int clk_dummy_single_set_parent(struct clk_hw *hw, u8 index)
{
if (index >= clk_hw_get_num_parents(hw))
@@ -100,18 +112,21 @@ static const struct clk_ops clk_dummy_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_determine_rate,
.set_rate = clk_dummy_set_rate,
+ .set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_maximize_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_maximize_rate,
.set_rate = clk_dummy_set_rate,
+ .set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_minimize_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_minimize_rate,
.set_rate = clk_dummy_set_rate,
+ .set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_single_parent_ops = {
@@ -3097,6 +3112,7 @@ struct clk_assigned_rates_context {
* @overlay_end: Pointer to end of DT overlay to apply for test
* @rate0: Initial rate of first clk
* @rate1: Initial rate of second clk
+ * @sscs: Initial spread spectrum settings
* @consumer_test: true if a consumer is being tested
*/
struct clk_assigned_rates_test_param {
@@ -3105,6 +3121,7 @@ struct clk_assigned_rates_test_param {
u8 *overlay_end;
unsigned long rate0;
unsigned long rate1;
+ struct clk_spread_spectrum sscs;
bool consumer_test;
};
@@ -3116,7 +3133,7 @@ static void
clk_assigned_rates_register_clk(struct kunit *test,
struct clk_dummy_context *ctx,
struct device_node *np, const char *name,
- unsigned long rate)
+ unsigned long rate, const struct clk_spread_spectrum *sscs)
{
struct clk_init_data init = { };
@@ -3124,6 +3141,7 @@ clk_assigned_rates_register_clk(struct kunit *test,
init.ops = &clk_dummy_rate_ops;
ctx->hw.init = &init;
ctx->rate = rate;
+ ctx->sscs = *sscs;
KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw));
KUNIT_ASSERT_EQ(test, ctx->rate, rate);
@@ -3167,14 +3185,16 @@ static int clk_assigned_rates_test_init(struct kunit *test)
KUNIT_ASSERT_LT(test, clk_cells, 2);
clk_assigned_rates_register_clk(test, &ctx->clk0, np,
- "test_assigned_rate0", test_param->rate0);
+ "test_assigned_rate0", test_param->rate0,
+ &test_param->sscs);
if (clk_cells == 0) {
KUNIT_ASSERT_EQ(test, 0,
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get,
&ctx->clk0.hw));
} else if (clk_cells == 1) {
clk_assigned_rates_register_clk(test, &ctx->clk1, np,
- "test_assigned_rate1", test_param->rate1);
+ "test_assigned_rate1", test_param->rate1,
+ &test_param->sscs);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL));
@@ -3203,6 +3223,9 @@ static void clk_assigned_rates_assigns_one(struct kunit *test)
struct clk_assigned_rates_context *ctx = test->priv;
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
}
static void clk_assigned_rates_assigns_multiple(struct kunit *test)
@@ -3210,7 +3233,13 @@ static void clk_assigned_rates_assigns_multiple(struct kunit *test)
struct clk_assigned_rates_context *ctx = test->priv;
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
KUNIT_EXPECT_EQ(test, ctx->clk1.rate, ASSIGNED_RATES_1_RATE);
+ KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.modfreq_hz, ASSIGNED_SSCS_1_MODFREQ);
+ KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.spread_bp, ASSIGNED_SSCS_1_SPREAD);
+ KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.method, ASSIGNED_SSCS_1_METHOD);
}
static void clk_assigned_rates_skips(struct kunit *test)
@@ -3222,6 +3251,19 @@ static void clk_assigned_rates_skips(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, test_param->rate0);
}
+static void clk_assigned_sscs_skips(struct kunit *test)
+{
+ struct clk_assigned_rates_context *ctx = test->priv;
+ const struct clk_assigned_rates_test_param *test_param = test->param_value;
+
+ KUNIT_EXPECT_NE(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
+ KUNIT_EXPECT_NE(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
+ KUNIT_EXPECT_NE(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, test_param->sscs.modfreq_hz);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, test_param->sscs.spread_bp);
+ KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, test_param->sscs.method);
+}
+
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one);
@@ -3384,6 +3426,77 @@ KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_skips,
clk_assigned_rates_skips_test_params,
desc)
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero_consumer);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null);
+OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null_consumer);
+
+/* Test cases that skip changing the sscs due to malformed DT */
+static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_params[] = {
+ {
+ /*
+ * Test that an assigned-clock-sscs property without an assigned-clocks
+ * property fails when the property is in the provider.
+ */
+ .desc = "provider missing assigned-clocks",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without),
+ .sscs = {50000, 60000, 3},
+ },
+ {
+ /*
+ * Test that an assigned-clock-rates property without an assigned-clocks
+ * property fails when the property is in the consumer.
+ */
+ .desc = "consumer missing assigned-clocks",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without_consumer),
+ .sscs = {50000, 60000, 3},
+ .consumer_test = true,
+ },
+ {
+ /*
+ * Test that an assigned-clock-rates property of zero doesn't
+ * set a rate when the property is in the provider.
+ */
+ .desc = "provider assigned-clock-sscs of zero",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero),
+ .sscs = {50000, 60000, 3},
+ },
+ {
+ /*
+ * Test that an assigned-clock-rates property of zero doesn't
+ * set a rate when the property is in the consumer.
+ */
+ .desc = "consumer assigned-clock-sscs of zero",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero_consumer),
+ .sscs = {50000, 60000, 3},
+ .consumer_test = true,
+ },
+ {
+ /*
+ * Test that an assigned-clocks property with a null phandle
+ * doesn't set a rate when the property is in the provider.
+ */
+ .desc = "provider assigned-clocks null phandle",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null),
+ .sscs = {50000, 60000, 3},
+ },
+ {
+ /*
+ * Test that an assigned-clocks property with a null phandle
+ * doesn't set a rate when the property is in the consumer.
+ */
+ .desc = "provider assigned-clocks null phandle",
+ TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null_consumer),
+ .sscs = {50000, 60000, 3},
+ .consumer_test = true,
+ },
+};
+KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_skips,
+ clk_assigned_sscs_skips_test_params,
+ desc)
+
static struct kunit_case clk_assigned_rates_test_cases[] = {
KUNIT_CASE_PARAM(clk_assigned_rates_assigns_one,
clk_assigned_rates_assigns_one_gen_params),
@@ -3391,6 +3504,8 @@ static struct kunit_case clk_assigned_rates_test_cases[] = {
clk_assigned_rates_assigns_multiple_gen_params),
KUNIT_CASE_PARAM(clk_assigned_rates_skips,
clk_assigned_rates_skips_gen_params),
+ KUNIT_CASE_PARAM(clk_assigned_sscs_skips,
+ clk_assigned_sscs_skips_gen_params),
{}
};
diff --git a/drivers/clk/kunit_clk_assigned_rates.h b/drivers/clk/kunit_clk_assigned_rates.h
index df2d84dcaa93511694b6da842debdc3cfd3a6c19..d7ae5ec2d25bed79b8438e8ce580872131ce4286 100644
--- a/drivers/clk/kunit_clk_assigned_rates.h
+++ b/drivers/clk/kunit_clk_assigned_rates.h
@@ -1,8 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <dt-bindings/clock/clock.h>
+
#ifndef _KUNIT_CLK_ASSIGNED_RATES_H
#define _KUNIT_CLK_ASSIGNED_RATES_H
#define ASSIGNED_RATES_0_RATE 1600000
#define ASSIGNED_RATES_1_RATE 9700000
+#define ASSIGNED_SSCS_0_MODFREQ 10000
+#define ASSIGNED_SSCS_0_SPREAD 30000
+#define ASSIGNED_SSCS_0_METHOD CLK_SSC_CENTER_SPREAD
+#define ASSIGNED_SSCS_1_MODFREQ 20000
+#define ASSIGNED_SSCS_1_SPREAD 40000
+#define ASSIGNED_SSCS_1_METHOD CLK_SSC_UP_SPREAD
+
#endif
diff --git a/drivers/clk/kunit_clk_assigned_rates_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_multiple.dtso
index e600736e70f5041ddeb1bfb0d6074746a064e08a..6c54d65444d5d779c9fa4bb2a79c4742dd88f6d0 100644
--- a/drivers/clk/kunit_clk_assigned_rates_multiple.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_multiple.dtso
@@ -12,5 +12,11 @@ clk: kunit-clock {
<&clk 1>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
<ASSIGNED_RATES_1_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
index 260aba458daf2bc57fde46b5442453e7de10faac..b1fee396c4b1e51341a411168569d8351bb23b12 100644
--- a/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
@@ -16,5 +16,11 @@ kunit-clock-consumer {
<&clk 1>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
<ASSIGNED_RATES_1_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_one.dtso b/drivers/clk/kunit_clk_assigned_rates_one.dtso
index dd95ec9b1cf977883f71564a94602ae518937132..da6e91b9e6bda0ef2c8f601a08aef1f10fda4baa 100644
--- a/drivers/clk/kunit_clk_assigned_rates_one.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_one.dtso
@@ -10,5 +10,8 @@ clk: kunit-clock {
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
index a41dca806318b031187c1b8739fcf71eb088a480..4b6e06048f863d014aed8222652d6d9d38e9238b 100644
--- a/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
@@ -14,5 +14,8 @@ kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
index 389b4e2eb7f74f1770ff5f5c4be5b45dd344dc9c..3a717dab2d00b7fdaff580e30ed2cc520683ef95 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
@@ -12,5 +12,11 @@ clk: kunit-clock {
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
index 3e117fd59b7da19cd8a603af77eff29175ce6900..cbee7cbad068f3336f0c8997a5b3e9af4db565c9 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso
@@ -16,5 +16,11 @@ kunit-clock-consumer {
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>,
+ <ASSIGNED_SSCS_1_MODFREQ
+ ASSIGNED_SSCS_1_SPREAD
+ ASSIGNED_SSCS_1_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
index 87041264e8f544dafddf2e905efc89dc1f917c54..9b04d6927f0830a5621af1cbea503a427b46bee0 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
@@ -10,5 +10,8 @@ clk: kunit-clock {
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
index 3259c003aec0be3269ab60a4a3a95df69f8de1f8..4784d40520f4193e4f08c8981386f0772a063452 100644
--- a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
+++ b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
@@ -14,5 +14,8 @@ kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
};
};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_null.dtso b/drivers/clk/kunit_clk_assigned_sscs_null.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..43b2068c845dea53ea1328bb63a2f58a4b8ef339
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_null.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clocks = <0>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..bda008f5aaa35e53af97863e4f2e6d8a168cc053
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_null_consumer.dtso
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clocks = <0>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_without.dtso b/drivers/clk/kunit_clk_assigned_sscs_without.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..08660846b55c12122bfb211c01c377a3a45223c9
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_without.dtso
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..e1c089c6f0c0223f16f7ac9a396e7ac7b821c967
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_without_consumer.dtso
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+#include "kunit_clk_assigned_rates.h"
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
+ ASSIGNED_SSCS_0_SPREAD
+ ASSIGNED_SSCS_0_METHOD>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_zero.dtso b/drivers/clk/kunit_clk_assigned_sscs_zero.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..f39f4e754e532c9c1b1fdf034700e5af1f3f0779
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_zero.dtso
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ assigned-clocks = <&clk>;
+ assigned-clock-sscs = <0 0 0>;
+ };
+};
diff --git a/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso b/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..d6bd7dfada7e2f455cb23e483b9bd6ce24839e3a
--- /dev/null
+++ b/drivers/clk/kunit_clk_assigned_sscs_zero_consumer.dtso
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+/plugin/;
+
+&{/} {
+ clk: kunit-clock {
+ compatible = "test,clk-assigned-rates";
+ #clock-cells = <0>;
+ };
+
+ kunit-clock-consumer {
+ compatible = "test,clk-consumer";
+ assigned-clocks = <&clk>;
+ assigned-clock-sscs = <0 0 0>;
+ };
+};
--
2.37.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 5/6] clk: scmi: Introduce common header for SCMI clock interface
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
` (3 preceding siblings ...)
2026-03-12 6:58 ` [PATCH v9 4/6] clk: Add KUnit tests for assigned-clock-sscs Peng Fan (OSS)
@ 2026-03-12 6:58 ` Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 6/6] clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver Peng Fan (OSS)
5 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
From: Peng Fan <peng.fan@nxp.com>
Added a new header file 'clk-scmi.h' to define common structures and
interfaces for the SCMI clock driver. This header will also be used by
OEM-specific extensions to ensure consistency and reusability.
Moved relevant structure definitions from the driver implementation to
'clk-scmi.h' to facilitate shared usage.
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/clk-scmi.c | 27 +--------------------------
drivers/clk/clk-scmi.h | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 26 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index 6b286ea6f1218c802d0ebb782c75a19057581c20..bf85924d61985eb9e596419349eb883e3817de73 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -14,32 +14,7 @@
#include <linux/scmi_protocol.h>
#include <asm/div64.h>
-#define NOT_ATOMIC false
-#define ATOMIC true
-
-enum scmi_clk_feats {
- SCMI_CLK_ATOMIC_SUPPORTED,
- SCMI_CLK_STATE_CTRL_SUPPORTED,
- SCMI_CLK_RATE_CTRL_SUPPORTED,
- SCMI_CLK_PARENT_CTRL_SUPPORTED,
- SCMI_CLK_DUTY_CYCLE_SUPPORTED,
- SCMI_CLK_FEATS_COUNT
-};
-
-#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
-
-static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
-
-struct scmi_clk {
- u32 id;
- struct device *dev;
- struct clk_hw hw;
- const struct scmi_clock_info *info;
- const struct scmi_protocol_handle *ph;
- struct clk_parent_data *parent_data;
-};
-
-#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
+const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
diff --git a/drivers/clk/clk-scmi.h b/drivers/clk/clk-scmi.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ef6adc77c836dc2d599ff852cdc941f217ee388
--- /dev/null
+++ b/drivers/clk/clk-scmi.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SCMI_CLK_H
+#define __SCMI_CLK_H
+
+#include <linux/bits.h>
+#include <linux/scmi_protocol.h>
+#include <linux/types.h>
+
+#define NOT_ATOMIC false
+#define ATOMIC true
+
+enum scmi_clk_feats {
+ SCMI_CLK_ATOMIC_SUPPORTED,
+ SCMI_CLK_STATE_CTRL_SUPPORTED,
+ SCMI_CLK_RATE_CTRL_SUPPORTED,
+ SCMI_CLK_PARENT_CTRL_SUPPORTED,
+ SCMI_CLK_DUTY_CYCLE_SUPPORTED,
+ SCMI_CLK_FEATS_COUNT
+};
+
+#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
+
+struct scmi_clk {
+ u32 id;
+ struct device *dev;
+ struct clk_hw hw;
+ const struct scmi_clock_info *info;
+ const struct scmi_protocol_handle *ph;
+ struct clk_parent_data *parent_data;
+};
+
+#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
+
+extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
+
+#endif
--
2.37.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v9 6/6] clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
` (4 preceding siblings ...)
2026-03-12 6:58 ` [PATCH v9 5/6] clk: scmi: Introduce common header for SCMI clock interface Peng Fan (OSS)
@ 2026-03-12 6:58 ` Peng Fan (OSS)
5 siblings, 0 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-03-12 6:58 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Cristian Marussi, Sebin Francis, Brian Masney,
Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
From: Peng Fan <peng.fan@nxp.com>
- Introduce 'clk-scmi-oem.c' to support vendor-specific OEM extensions
for the SCMI clock driver, allows clean integration of vendor-specific
features without impacting the core SCMI clock driver logic.
- Extend 'clk-scmi.h' with 'scmi_clk_oem' structure and related
declarations.
- Initialize OEM extensions via 'scmi_clk_oem_init()'.
- Support querying OEM-specific features and setting spread spectrum.
- Pass 'scmi_device' to 'scmi_clk_ops_select()' for OEM data access.
Reviewed-by: Sebin Francis <sebin.francis@ti.com>
Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/clk/Makefile | 2 +-
drivers/clk/clk-scmi-oem.c | 108 +++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/clk-scmi.c | 19 ++++++--
drivers/clk/clk-scmi.h | 11 +++++
4 files changed, 136 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d569d0ea3153efe593efbbd51e022b2415234d3a..0b74a458255b2d50030cb4a2102599228c3660bd 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -93,7 +93,7 @@ obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o
obj-$(CONFIG_COMMON_CLK_RPMI) += clk-rpmi.o
obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
-obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o
+obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o clk-scmi-oem.o
obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
obj-$(CONFIG_COMMON_CLK_SI5341) += clk-si5341.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
diff --git a/drivers/clk/clk-scmi-oem.c b/drivers/clk/clk-scmi-oem.c
new file mode 100644
index 0000000000000000000000000000000000000000..be11d359b4ec3633868f33bb429c7cfec9f1e48e
--- /dev/null
+++ b/drivers/clk/clk-scmi-oem.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Vendor OEM extension for System Control and Power Interface (SCMI)
+ * Protocol based clock driver
+ *
+ * Copyright 2025 NXP
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/scmi_imx_protocol.h>
+#include <linux/scmi_protocol.h>
+
+#include "clk-scmi.h"
+
+#define SCMI_CLOCK_CFG_IMX_SSC 0x80
+#define SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK GENMASK(7, 0)
+#define SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK GENMASK(23, 8)
+#define SCMI_CLOCK_IMX_SS_ENABLE_MASK BIT(24)
+
+/*
+ * Selection is based on SCMI vendor_id/sub_vendor_id and optional machine
+ * compatible string, without involving impl_ver. impl_ver‑specific behavior
+ * should be considered a bug and handled via SCMI Quirk framework.
+ */
+struct scmi_clk_oem_info {
+ char *vendor_id;
+ char *sub_vendor_id;
+ char *compatible;
+ const void *data;
+};
+
+static int
+scmi_clk_imx_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf)
+{
+ struct scmi_clk *clk = to_scmi_clk(hw);
+ int ret;
+ u32 val;
+
+ /*
+ * extConfigValue[7:0] - spread percentage (%)
+ * extConfigValue[23:8] - Modulation Frequency
+ * extConfigValue[24] - Enable/Disable
+ * extConfigValue[31:25] - Reserved
+ */
+ val = FIELD_PREP(SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK, ss_conf->spread_bp / 10000);
+ val |= FIELD_PREP(SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK, ss_conf->modfreq_hz);
+ if (ss_conf->method != CLK_SPREAD_NO)
+ val |= SCMI_CLOCK_IMX_SS_ENABLE_MASK;
+ ret = scmi_proto_clk_ops->config_oem_set(clk->ph, clk->id,
+ SCMI_CLOCK_CFG_IMX_SSC,
+ val, false);
+ if (ret)
+ dev_warn(clk->dev,
+ "Failed to set spread spectrum(%u,%u,%u) for clock ID %d\n",
+ ss_conf->modfreq_hz, ss_conf->spread_bp, ss_conf->method,
+ clk->id);
+
+ return ret;
+}
+
+static int
+scmi_clk_imx_query_oem_feats(const struct scmi_protocol_handle *ph, u32 id,
+ unsigned int *feats_key)
+{
+ int ret;
+ u32 val;
+
+ ret = scmi_proto_clk_ops->config_oem_get(ph, id,
+ SCMI_CLOCK_CFG_IMX_SSC,
+ &val, NULL, false);
+ if (!ret)
+ *feats_key |= BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED);
+
+ return 0;
+}
+
+static const struct scmi_clk_oem scmi_clk_oem_imx = {
+ .query_ext_oem_feats = scmi_clk_imx_query_oem_feats,
+ .set_spread_spectrum = scmi_clk_imx_set_spread_spectrum,
+};
+
+static const struct scmi_clk_oem_info info[] = {
+ { SCMI_IMX_VENDOR, SCMI_IMX_SUBVENDOR, NULL, &scmi_clk_oem_imx },
+};
+
+int scmi_clk_oem_init(struct scmi_device *sdev)
+{
+ const struct scmi_handle *handle = sdev->handle;
+ int i, size = ARRAY_SIZE(info);
+
+ for (i = 0; i < size; i++) {
+ if (strcmp(handle->version->vendor_id, info[i].vendor_id) ||
+ strcmp(handle->version->sub_vendor_id, info[i].sub_vendor_id))
+ continue;
+ if (info[i].compatible &&
+ !of_machine_is_compatible(info[i].compatible))
+ continue;
+
+ break;
+ }
+
+ if (i < size)
+ dev_set_drvdata(&sdev->dev, (void *)info[i].data);
+
+ return 0;
+}
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index bf85924d61985eb9e596419349eb883e3817de73..1ed2091e3d4a951c8662db4c94dee4b9c98b8326 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -14,6 +14,8 @@
#include <linux/scmi_protocol.h>
#include <asm/div64.h>
+#include "clk-scmi.h"
+
const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
@@ -242,6 +244,7 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
static const struct clk_ops *
scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
{
+ struct scmi_clk_oem *oem_data = dev_get_drvdata(dev);
struct clk_ops *ops;
ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
@@ -288,11 +291,15 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
ops->set_duty_cycle = scmi_clk_set_duty_cycle;
}
+ if (oem_data && (feats_key & BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED)))
+ ops->set_spread_spectrum = oem_data->set_spread_spectrum;
+
return ops;
}
/**
* scmi_clk_ops_select() - Select a proper set of clock operations
+ * @sdev: pointer to the SCMI device
* @sclk: A reference to an SCMI clock descriptor
* @atomic_capable: A flag to indicate if atomic mode is supported by the
* transport
@@ -317,8 +324,8 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
* NULL otherwise.
*/
static const struct clk_ops *
-scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
- unsigned int atomic_threshold_us,
+scmi_clk_ops_select(struct scmi_device *sdev, struct scmi_clk *sclk,
+ bool atomic_capable, unsigned int atomic_threshold_us,
const struct clk_ops **clk_ops_db, size_t db_size)
{
int ret;
@@ -326,6 +333,7 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
const struct scmi_clock_info *ci = sclk->info;
unsigned int feats_key = 0;
const struct clk_ops *ops;
+ struct scmi_clk_oem *oem_data = dev_get_drvdata(&sdev->dev);
/*
* Note that when transport is atomic but SCMI protocol did not
@@ -350,6 +358,9 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
&val, NULL, false);
if (!ret)
feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
+
+ if (oem_data && oem_data->query_ext_oem_feats)
+ oem_data->query_ext_oem_feats(sclk->ph, sclk->id, &feats_key);
}
if (WARN_ON(feats_key >= db_size))
@@ -407,6 +418,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
clk_data->num = count;
hws = clk_data->hws;
+ scmi_clk_oem_init(sdev);
+
transport_is_atomic = handle->is_transport_atomic(handle,
&atomic_threshold_us);
@@ -438,7 +451,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
* to avoid sharing the devm_ allocated clk_ops between multiple
* SCMI clk driver instances.
*/
- scmi_ops = scmi_clk_ops_select(sclk, transport_is_atomic,
+ scmi_ops = scmi_clk_ops_select(sdev, sclk, transport_is_atomic,
atomic_threshold_us,
scmi_clk_ops_db,
ARRAY_SIZE(scmi_clk_ops_db));
diff --git a/drivers/clk/clk-scmi.h b/drivers/clk/clk-scmi.h
index 6ef6adc77c836dc2d599ff852cdc941f217ee388..d7f63f36c56d155f728325efd6bcf7fe2585b170 100644
--- a/drivers/clk/clk-scmi.h
+++ b/drivers/clk/clk-scmi.h
@@ -7,6 +7,7 @@
#define __SCMI_CLK_H
#include <linux/bits.h>
+#include <linux/clk-provider.h>
#include <linux/scmi_protocol.h>
#include <linux/types.h>
@@ -19,6 +20,7 @@ enum scmi_clk_feats {
SCMI_CLK_RATE_CTRL_SUPPORTED,
SCMI_CLK_PARENT_CTRL_SUPPORTED,
SCMI_CLK_DUTY_CYCLE_SUPPORTED,
+ SCMI_CLK_EXT_OEM_SSC_SUPPORTED,
SCMI_CLK_FEATS_COUNT
};
@@ -37,4 +39,13 @@ struct scmi_clk {
extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
+struct scmi_clk_oem {
+ int (*query_ext_oem_feats)(const struct scmi_protocol_handle *ph,
+ u32 id, unsigned int *feats_key);
+ int (*set_spread_spectrum)(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
+};
+
+int scmi_clk_oem_init(struct scmi_device *dev);
+
#endif
--
2.37.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v9 4/6] clk: Add KUnit tests for assigned-clock-sscs
2026-03-12 6:58 ` [PATCH v9 4/6] clk: Add KUnit tests for assigned-clock-sscs Peng Fan (OSS)
@ 2026-04-29 2:38 ` Stephen Boyd
0 siblings, 0 replies; 8+ messages in thread
From: Stephen Boyd @ 2026-04-29 2:38 UTC (permalink / raw)
To: Peng Fan (OSS), Brian Masney, Conor Dooley, Cristian Marussi,
Krzysztof Kozlowski, Michael Turquette, Rob Herring,
Sebin Francis, Sudeep Holla
Cc: linux-kernel, linux-clk, devicetree, arm-scmi, linux-arm-kernel,
Peng Fan
Quoting Peng Fan (OSS) (2026-03-11 23:58:20)
> diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
> index a268d7b5d4cb28ec1f029f828c31107f8e130556..97113b61c2841701a44603ca9935638374000a2e 100644
> --- a/drivers/clk/clk_test.c
> +++ b/drivers/clk/clk_test.c
> @@ -3203,6 +3223,9 @@ static void clk_assigned_rates_assigns_one(struct kunit *test)
> struct clk_assigned_rates_context *ctx = test->priv;
>
> KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
> }
>
> static void clk_assigned_rates_assigns_multiple(struct kunit *test)
> @@ -3210,7 +3233,13 @@ static void clk_assigned_rates_assigns_multiple(struct kunit *test)
> struct clk_assigned_rates_context *ctx = test->priv;
>
> KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
> KUNIT_EXPECT_EQ(test, ctx->clk1.rate, ASSIGNED_RATES_1_RATE);
> + KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.modfreq_hz, ASSIGNED_SSCS_1_MODFREQ);
> + KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.spread_bp, ASSIGNED_SSCS_1_SPREAD);
> + KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.method, ASSIGNED_SSCS_1_METHOD);
> }
>
> static void clk_assigned_rates_skips(struct kunit *test)
> @@ -3222,6 +3251,19 @@ static void clk_assigned_rates_skips(struct kunit *test)
> KUNIT_EXPECT_EQ(test, ctx->clk0.rate, test_param->rate0);
> }
>
> +static void clk_assigned_sscs_skips(struct kunit *test)
> +{
> + struct clk_assigned_rates_context *ctx = test->priv;
> + const struct clk_assigned_rates_test_param *test_param = test->param_value;
> +
> + KUNIT_EXPECT_NE(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
> + KUNIT_EXPECT_NE(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
> + KUNIT_EXPECT_NE(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, test_param->sscs.modfreq_hz);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, test_param->sscs.spread_bp);
> + KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, test_param->sscs.method);
> +}
> +
> OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one);
> OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one_consumer);
> OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one);
> @@ -3384,6 +3426,77 @@ KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_skips,
> clk_assigned_rates_skips_test_params,
> desc)
>
> +OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without);
> +OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without_consumer);
> +OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero);
> +OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero_consumer);
> +OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null);
> +OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null_consumer);
> +
> +/* Test cases that skip changing the sscs due to malformed DT */
> +static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_params[] = {
> + {
> + /*
> + * Test that an assigned-clock-sscs property without an assigned-clocks
> + * property fails when the property is in the provider.
> + */
> + .desc = "provider missing assigned-clocks",
> + TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without),
> + .sscs = {50000, 60000, 3},
> + },
> + {
> + /*
> + * Test that an assigned-clock-rates property without an assigned-clocks
It is?
> + * property fails when the property is in the consumer.
> + */
> + .desc = "consumer missing assigned-clocks",
> + TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without_consumer),
> + .sscs = {50000, 60000, 3},
> + .consumer_test = true,
> + },
> + {
> + /*
> + * Test that an assigned-clock-rates property of zero doesn't
Typo?
> + * set a rate when the property is in the provider.
> + */
> + .desc = "provider assigned-clock-sscs of zero",
> + TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero),
> + .sscs = {50000, 60000, 3},
> + },
> + {
> + /*
> + * Test that an assigned-clock-rates property of zero doesn't
> + * set a rate when the property is in the consumer.
> + */
> + .desc = "consumer assigned-clock-sscs of zero",
> + TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero_consumer),
> + .sscs = {50000, 60000, 3},
> + .consumer_test = true,
> + },
> + {
> + /*
> + * Test that an assigned-clocks property with a null phandle
> + * doesn't set a rate when the property is in the provider.
> + */
> + .desc = "provider assigned-clocks null phandle",
> + TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null),
> + .sscs = {50000, 60000, 3},
> + },
> + {
> + /*
> + * Test that an assigned-clocks property with a null phandle
> + * doesn't set a rate when the property is in the consumer.
None of these comments are correct.
> + */
> + .desc = "provider assigned-clocks null phandle",
> + TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null_consumer),
> + .sscs = {50000, 60000, 3},
> + .consumer_test = true,
> + },
> +};
> +KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_skips,
> + clk_assigned_sscs_skips_test_params,
> + desc)
> +
> static struct kunit_case clk_assigned_rates_test_cases[] = {
> KUNIT_CASE_PARAM(clk_assigned_rates_assigns_one,
> clk_assigned_rates_assigns_one_gen_params),
> @@ -3391,6 +3504,8 @@ static struct kunit_case clk_assigned_rates_test_cases[] = {
> clk_assigned_rates_assigns_multiple_gen_params),
> KUNIT_CASE_PARAM(clk_assigned_rates_skips,
> clk_assigned_rates_skips_gen_params),
> + KUNIT_CASE_PARAM(clk_assigned_sscs_skips,
> + clk_assigned_sscs_skips_gen_params),
> {}
> };
Instead of adding on another case just copy the entire thing,
kunit_case, test_params, etc. and implement the tests you want. Test
code is the opposite of DRY (DAMP?) so don't be afraid to just copy a
bunch of stuff. The reason why that is encouraged is because existing
tests are unchanged, and we don't have to worry that this patch breaks
the existing tests. It also helps the reviewer see the whole picture
because all the test code is in the patch instead of in the context.
For example, clk_assigned_rates_assigns_multiple() is saying that a
clock-assigned-rates property with multiple rates assigns multiple
rates. It's not supposed to be testing ssc. Don't modify it.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-04-29 3:47 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-12 6:58 [PATCH v9 0/6] clk: Support spread spectrum and use it in clk-scmi Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 1/6] dt-bindings: clock: Add spread spectrum definition Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 2/6] clk: Introduce clk_hw_set_spread_spectrum Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 3/6] clk: conf: Support assigned-clock-sscs Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 4/6] clk: Add KUnit tests for assigned-clock-sscs Peng Fan (OSS)
2026-04-29 2:38 ` Stephen Boyd
2026-03-12 6:58 ` [PATCH v9 5/6] clk: scmi: Introduce common header for SCMI clock interface Peng Fan (OSS)
2026-03-12 6:58 ` [PATCH v9 6/6] clk: scmi: Add i.MX95 OEM extension support for SCMI clock driver Peng Fan (OSS)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox