Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v14 0/4] Support spread spectrum clocking for i.MX8M PLLs
@ 2026-09-04 10:06 Dario Binacchi
  2026-09-04 10:06 ` [PATCH v14 4/4] clk: imx: pll14xx: support spread spectrum clock generation Dario Binacchi
  0 siblings, 1 reply; 3+ messages in thread
From: Dario Binacchi @ 2026-09-04 10:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: michael, linux-amarula, Dario Binacchi, Abel Vesa, Brian Masney,
	Cristian Marussi, Fabio Estevam, Frank Li, Jerome Brunet,
	Peng Fan, Pengutronix Kernel Team, Sascha Hauer, Sebin Francis,
	Stephen Boyd, imx, linux-arm-kernel, linux-clk

The series adds support for spread spectrum clocking for i.MX8M{M,N,P}
PLLs (audio, video and DRAM). It has been tested for the video PLL on
boards using i.MX8MN and i.MX8MP.

While at it, it validates the spread spectrum configuration in the clk
core before it reaches the providers, and fixes the i.MX SCMI OEM
extension, which converted the spread to the wrong unit.

Patches 1 and 2 are fixes for 7.3 with Peng's Reviewed-by and do not
depend on the rest of the series, so they can be picked up separately.
Patches 3 and 4 are new material for the next merge window.

Changes in v14:
 - Move the fixes first, so that they can be picked up separately from
   the new patches.

Changes in v13:
 - Add patch "clk: scmi: reject SSC configuration out of the OEM field
   range".
 - Rename patch "clk: scmi: fix SSC permyriad conversion" to "clk: scmi:
   fix SSC spread conversion".

Changes in v12:
 - Add patch "clk: scmi: fix SSC permyriad conversion" to fix the
   permyriad to percent conversion in clk-scmi-oem.c, reported by
   Sashiko AI review.
 - Fix issues claimed by Sashiko for patch "clk: imx: pll14xx: support
   spread spectrum clock". See the details in the patch changelog.

Changes in v11:
 - Add patch "clk: validate spread spectrum configuration" to reject
   invalid parameters in the clk core before they reach the providers.
 - Fix issues claimed by Sashiko for patch "clk: imx: pll14xx: support
   spread spectrum clock". See the details in the patch changelog.
 
Changes in v10:
 - Drop patches 1-22, superseded by the generic spread spectrum clocking
   support from Peng Fan, merged in 7.3, so the i.MX8M specific infrastructure
   is no longer needed. This patch is now based on the following commits:
    - ae794aa6e88d ("dt-bindings: clock: Add spread spectrum definition")
    - c86814e70390 ("clk: Introduce clk_hw_set_spread_spectrum")
    - a7f16660af39 ("clk: conf: Support assigned-clock-sscs")
    - 7d98de6ffdab ("clk: Add KUnit tests for assigned-clock-sscs")
    https://lore.kernel.org/all/20260826165611.236321-1-sboyd@kernel.org/

Changes in v9:
 - Add 'Reviewed-by' tag of Peng Fan for imx8mn platform patches
 - Fix building warning raised by the kernel test robot for patch
   v8, 11/18 clk: imx: add support for i.MX8MN anatop clock driver
 - Add patches for imx8m{m,p} platforms:
    - 23/23 clk: imx8mm: support spread spectrum clock generation
    - 22/23 clk: imx: add support for i.MX8MM anatop clock driver
    - 21/23 clk: imx8mp: support spread spectrum clock generation
    - 20/23 clk: imx8mp: rename ccm_base to base
    - 19/23 clk: imx: add support for i.MX8MP anatop clock driver

Changes in v8:
 - Drop the patches added in version 7:
    - 10/23 dt-bindings: clock: imx8m-clock: add phandle to the anatop
    - 11/23 arm64: dts: imx8mm: add phandle to anatop within CCM
    - 12/23 arm64: dts: imx8mn: add phandle to anatop within CCM
    - 13/23 arm64: dts: imx8mp: add phandle to anatop within CCM
    - 14/23 arm64: dts: imx8mq: add phandle to anatop within CCM

Changes in v7:
 - Add and manage fsl,anatop property as phandle to the anatop node with
   the new patches:
    - 10/23 dt-bindings: clock: imx8m-clock: add phandle to the anatop
    - 11/23 arm64: dts: imx8mm: add phandle to anatop within CCM
    - 12/23 arm64: dts: imx8mn: add phandle to anatop within CCM
    - 13/23 arm64: dts: imx8mp: add phandle to anatop within CCM
    - 14/23 arm64: dts: imx8mq: add phandle to anatop within CCM

Changes in v6:
 - Merge patches:
    10/20 dt-bindings: clock: imx8mm: add binding definitions for anatop
    11/20 dt-bindings: clock: imx8mn: add binding definitions for anatop
    12/20 dt-bindings: clock: imx8mp: add binding definitions for anatop
    to
    05/20 dt-bindings: clock: imx8m-anatop: define clocks/clock-names
    now renamed
    05/18 dt-bindings: clock: imx8m-anatop: add oscillators and PLLs
 - Split the patch
    15/20 dt-bindings-clock-imx8m-clock-support-spread-spectru.patch
    into
    12/18 dt-bindings: clock: imx8m-clock: add PLLs
    16/18 dt-bindings: clock: imx8m-clock: support spread spectrum clocking

Changes in v5:
 - Fix compilation errors.
 - Separate driver code from dt-bindings

Changes in v4:
 - Add dt-bindings for anatop
 - Add anatop driver
 - Drop fsl,ssc-clocks from spread spectrum dt-bindings

Changes in v3:
 - Patches 1/8 has been added in version 3. The dt-bindings have
   been moved from fsl,imx8m-anatop.yaml to imx8m-clock.yaml. The
   anatop device (fsl,imx8m-anatop.yaml) is indeed more or less a
   syscon, so it represents a memory area accessible by ccm
   (imx8m-clock.yaml) to setup the PLLs.
 - Patches {3,5}/8 have been added in version 3.
 - Patches {4,6,8}/8 use ccm device node instead of the anatop one.

Changes in v2:
 - Add "allOf:" and place it after "required:" block, like in the
   example schema.
 - Move the properties definition to the top-level.
 - Drop unit types as requested by the "make dt_binding_check" command.

Dario Binacchi (4):
  clk: scmi: fix SSC spread conversion
  clk: validate spread spectrum configuration
  clk: scmi: reject SSC configuration out of the OEM field range
  clk: imx: pll14xx: support spread spectrum clock generation

 drivers/clk/clk-scmi-oem.c             |  27 ++++++-
 drivers/clk/clk.c                      |  14 ++++
 drivers/clk/clk_test.c                 |  12 +--
 drivers/clk/imx/clk-pll14xx.c          | 103 +++++++++++++++++++++++++
 drivers/clk/kunit_clk_assigned_rates.h |   4 +-
 5 files changed, 148 insertions(+), 12 deletions(-)

---
base-commit: bc35965f6940a9bf834d54187b6088b8eb09206d
branch: imx-pll14xx-spread-spectrum

-- 
2.43.0



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v14 4/4] clk: imx: pll14xx: support spread spectrum clock generation
  2026-09-04 10:06 [PATCH v14 0/4] Support spread spectrum clocking for i.MX8M PLLs Dario Binacchi
@ 2026-09-04 10:06 ` Dario Binacchi
  2026-09-04 12:49   ` Abel Vesa
  0 siblings, 1 reply; 3+ messages in thread
From: Dario Binacchi @ 2026-09-04 10:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: michael, linux-amarula, Dario Binacchi, Peng Fan, Abel Vesa,
	Brian Masney, Fabio Estevam, Frank Li, Jerome Brunet,
	Pengutronix Kernel Team, Sascha Hauer, Stephen Boyd, imx,
	linux-arm-kernel, linux-clk

Add support for spread spectrum clock (SSC) generation to the pll14xx
driver.

Tested on the video PLL of i.MX8MN and i.MX8MP based boards.

Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>

---

Changes in v14:
 - Rate limit the warnings on out of range SSC parameters, as they are
   re-evaluated on every rate change.
 - Add a comment on why the mrr computation cannot overflow.
 - Add Reviewed-by of Peng Fan.

Changes in v12:
 - Apply the SSC settings also from the set_spread_spectrum() callback
   to handle the case the clock framework skips set_rate() if the
   requested rate is unchanged.

Changes in v11:
 - Drop the dt-bindings/clock/clock.h include and use the enum
   clk_ssc_method values from clk-provider.h, as clk-scmi-oem.c does.
 - Disable SSC and clear the modulation fields in SSCG_CTRL when no
   spread method is configured, so that a setup left enabled by the
   bootloader is not kept active.
 - Skip the SSC setup instead of dividing by zero when modfreq_hz is
   zero or mfr truncates to zero.
 - Reject mfr and mrr values that do not fit the MFREQ_CTL and MRAT_CTL
   register fields instead of letting FIELD_PREP silently truncate
   them. This also prevents the 10000 * mfr multiplication from
   overflowing.
 - Compute the mfr divisor in 64-bit arithmetic, as the 32-bit product
   could wrap with out of range modfreq_hz values.

Changes in v10:
- Drop 'Reviewed-by' tag of Peng Fan.
- Adapt the driver to the new infrastructure. Implement the
  set_spread_spectrum() and get the modulation parameters from
  struct clk_spread_spectrum.

Changes in v9:
- Add 'Reviewed-by' tag of Peng Fan.

 drivers/clk/imx/clk-pll14xx.c | 103 ++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index b6f1cc9f5700..84e081193f24 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -13,6 +13,7 @@
 #include <linux/export.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/math64.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/jiffies.h>
@@ -22,6 +23,8 @@
 #define GNRL_CTL	0x0
 #define DIV_CTL0	0x4
 #define DIV_CTL1	0x8
+#define SSCG_CTRL	0xc
+
 #define LOCK_STATUS	BIT(31)
 #define LOCK_SEL_MASK	BIT(29)
 #define CLKE_MASK	BIT(11)
@@ -33,6 +36,13 @@
 #define KDIV_MASK	GENMASK(15, 0)
 #define KDIV_MIN	SHRT_MIN
 #define KDIV_MAX	SHRT_MAX
+#define SSCG_ENABLE	BIT(31)
+#define MFREQ_CTL_MASK	GENMASK(19, 12)
+#define MRAT_CTL_MASK	GENMASK(9, 4)
+#define SEL_PF_DOWN_SPREAD	0
+#define SEL_PF_UP_SPREAD	1
+#define SEL_PF_CENTER_SPREAD	2
+#define SEL_PF_MASK	GENMASK(1, 0)
 
 #define LOCK_TIMEOUT_US		10000
 
@@ -44,6 +54,7 @@ struct clk_pll14xx {
 	int rate_count;
 	s16 delta_k;
 	spinlock_t lock;
+	struct clk_spread_spectrum ss_conf;
 };
 
 #define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
@@ -366,6 +377,62 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
 	return 0;
 }
 
+static void __clk_pll1443x_set_spread_spectrum(struct clk_hw *hw,
+					       unsigned long parent_rate,
+					       unsigned int pdiv,
+					       unsigned int mdiv)
+{
+	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+	struct clk_spread_spectrum *conf = &pll->ss_conf;
+	u32 sscg_ctrl, mfr, mrr, sel_pf;
+
+	sscg_ctrl = readl_relaxed(pll->base + SSCG_CTRL);
+	sscg_ctrl &= ~(SSCG_ENABLE | MFREQ_CTL_MASK | MRAT_CTL_MASK | SEL_PF_MASK);
+
+	switch (conf->method) {
+	case CLK_SPREAD_CENTER:
+		sel_pf = SEL_PF_CENTER_SPREAD;
+		break;
+	case CLK_SPREAD_UP:
+		sel_pf = SEL_PF_UP_SPREAD;
+		break;
+	case CLK_SPREAD_DOWN:
+		sel_pf = SEL_PF_DOWN_SPREAD;
+		break;
+	default:
+		/* No spread: disable modulation and clear any stale state */
+		goto out;
+	}
+
+	if (!conf->modfreq_hz || !parent_rate || !pdiv)
+		goto out;
+
+	mfr = div64_u64(parent_rate, (u64)conf->modfreq_hz * pdiv * BIT(5));
+	if (!mfr || mfr > FIELD_MAX(MFREQ_CTL_MASK)) {
+		pr_warn_ratelimited("%s: SSC disabled, modulation frequency (%u Hz) out of range\n",
+				    clk_hw_get_name(hw), conf->modfreq_hz);
+		goto out;
+	}
+
+	/*
+	 * No overflow: the core limits spread_bp to 10000 and mdiv is a 10-bit
+	 * field, so the product is at most 10000 * 1023 * 64 < 2^32.
+	 */
+	mrr = (conf->spread_bp * mdiv * BIT(6)) / (10000 * mfr);
+	if (!mrr || mrr > FIELD_MAX(MRAT_CTL_MASK)) {
+		pr_warn_ratelimited("%s: SSC disabled, spread (%u permyriad) out of range\n",
+				    clk_hw_get_name(hw), conf->spread_bp);
+		goto out;
+	}
+
+	sscg_ctrl |= SSCG_ENABLE | FIELD_PREP(MFREQ_CTL_MASK, mfr) |
+		FIELD_PREP(MRAT_CTL_MASK, mrr) |
+		FIELD_PREP(SEL_PF_MASK, sel_pf);
+
+out:
+	writel_relaxed(sscg_ctrl, pll->base + SSCG_CTRL);
+}
+
 static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 				 unsigned long prate)
 {
@@ -390,6 +457,9 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 		writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv),
 			       pll->base + DIV_CTL1);
 
+		__clk_pll1443x_set_spread_spectrum(hw, prate, rate.pdiv,
+						   rate.mdiv);
+
 		spin_unlock_irqrestore(&pll->lock, flags);
 
 		return 0;
@@ -411,6 +481,8 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 
 	writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1);
 
+	__clk_pll1443x_set_spread_spectrum(hw, prate, rate.pdiv, rate.mdiv);
+
 	spin_unlock_irqrestore(&pll->lock, flags);
 
 	/*
@@ -437,6 +509,36 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
 	return 0;
 }
 
+static int clk_pll1443x_set_spread_spectrum(struct clk_hw *hw,
+					    const struct clk_spread_spectrum *ss_conf)
+{
+	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+	struct clk_hw *parent = clk_hw_get_parent(hw);
+	unsigned long parent_rate = parent ? clk_hw_get_rate(parent) : 0;
+	unsigned long flags;
+	u32 div_ctl0;
+
+	spin_lock_irqsave(&pll->lock, flags);
+
+	pll->ss_conf = *ss_conf;
+
+	/*
+	 * Apply the configuration to the hardware right away, using the
+	 * current PLL dividers: the clock framework does not call set_rate()
+	 * if the requested rate is unchanged, so relying on it would leave
+	 * the SSC settings unapplied when the PLL is already at the target
+	 * rate (e.g. configured by the bootloader).
+	 */
+	div_ctl0 = readl_relaxed(pll->base + DIV_CTL0);
+	__clk_pll1443x_set_spread_spectrum(hw, parent_rate,
+					   FIELD_GET(PDIV_MASK, div_ctl0),
+					   FIELD_GET(MDIV_MASK, div_ctl0));
+
+	spin_unlock_irqrestore(&pll->lock, flags);
+
+	return 0;
+}
+
 static int clk_pll14xx_prepare(struct clk_hw *hw)
 {
 	struct clk_pll14xx *pll = to_clk_pll14xx(hw);
@@ -509,6 +611,7 @@ static const struct clk_ops clk_pll1443x_ops = {
 	.recalc_rate	= clk_pll14xx_recalc_rate,
 	.determine_rate = clk_pll1443x_determine_rate,
 	.set_rate	= clk_pll1443x_set_rate,
+	.set_spread_spectrum = clk_pll1443x_set_spread_spectrum,
 };
 
 struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v14 4/4] clk: imx: pll14xx: support spread spectrum clock generation
  2026-09-04 10:06 ` [PATCH v14 4/4] clk: imx: pll14xx: support spread spectrum clock generation Dario Binacchi
@ 2026-09-04 12:49   ` Abel Vesa
  0 siblings, 0 replies; 3+ messages in thread
From: Abel Vesa @ 2026-09-04 12:49 UTC (permalink / raw)
  To: Dario Binacchi
  Cc: linux-kernel, michael, linux-amarula, Peng Fan, Abel Vesa,
	Brian Masney, Fabio Estevam, Frank Li, Jerome Brunet,
	Pengutronix Kernel Team, Sascha Hauer, Stephen Boyd, imx,
	linux-arm-kernel, linux-clk

On 26-09-04 12:06:33, Dario Binacchi wrote:
> Add support for spread spectrum clock (SSC) generation to the pll14xx
> driver.
> 
> Tested on the video PLL of i.MX8MN and i.MX8MP based boards.
> 
> Reviewed-by: Peng Fan <peng.fan@nxp.com>
> Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>

LGTM, so:

Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-04 12:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-04 10:06 [PATCH v14 0/4] Support spread spectrum clocking for i.MX8M PLLs Dario Binacchi
2026-09-04 10:06 ` [PATCH v14 4/4] clk: imx: pll14xx: support spread spectrum clock generation Dario Binacchi
2026-09-04 12:49   ` Abel Vesa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox