From: Dario Binacchi <dario.binacchi@amarulasolutions.com>
To: linux-kernel@vger.kernel.org
Cc: linux-amarula@amarulasolutions.com,
Dario Binacchi <dario.binacchi@amarulasolutions.com>,
Abel Vesa <abelvesa@kernel.org>,
Fabio Estevam <festevam@gmail.com>,
Michael Turquette <mturquette@baylibre.com>,
Peng Fan <peng.fan@nxp.com>,
Pengutronix Kernel Team <kernel@pengutronix.de>,
Sascha Hauer <s.hauer@pengutronix.de>,
Shawn Guo <shawnguo@kernel.org>, Stephen Boyd <sboyd@kernel.org>,
imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-clk@vger.kernel.org
Subject: [PATCH 2/6] clk: imx: pll14xx: support spread spectrum clock generation
Date: Sat, 28 Sep 2024 10:37:50 +0200 [thread overview]
Message-ID: <20240928083804.1073942-3-dario.binacchi@amarulasolutions.com> (raw)
In-Reply-To: <20240928083804.1073942-1-dario.binacchi@amarulasolutions.com>
This patch adds support for spread spectrum clock (SSC) generation for
the pll14xxx. The addition of the "imx_clk_hw_pll14xx_ssc" macro has
minimized the number of changes required to avoid compilation errors
following the addition of the SSC setup parameter to the
"imx_dev_clk_hw_pll14xx" macro used in the files clk-imx8m{m,n,p}.c.
The change to the clk-imx8mp-audiomix.c file prevents the patch from
causing a compilation error.
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---
drivers/clk/imx/clk-imx8mp-audiomix.c | 2 +-
drivers/clk/imx/clk-pll14xx.c | 102 +++++++++++++++++++++++++-
drivers/clk/imx/clk.h | 24 +++++-
3 files changed, 124 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/imx/clk-imx8mp-audiomix.c b/drivers/clk/imx/clk-imx8mp-audiomix.c
index b2cb157703c5..bfcf2975c217 100644
--- a/drivers/clk/imx/clk-imx8mp-audiomix.c
+++ b/drivers/clk/imx/clk-imx8mp-audiomix.c
@@ -365,7 +365,7 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev)
clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_REF_SEL] = hw;
hw = imx_dev_clk_hw_pll14xx(dev, "sai_pll", "sai_pll_ref_sel",
- base + 0x400, &imx_1443x_pll);
+ base + 0x400, &imx_1443x_pll, NULL);
if (IS_ERR(hw)) {
ret = PTR_ERR(hw);
goto err_clk_register;
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index d63564dbb12c..76014e243a57 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -20,6 +20,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)
@@ -31,6 +33,10 @@
#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_MASK GENMASK(1, 0)
#define LOCK_TIMEOUT_US 10000
@@ -40,6 +46,7 @@ struct clk_pll14xx {
enum imx_pll14xx_type type;
const struct imx_pll14xx_rate_table *rate_table;
int rate_count;
+ struct imx_pll14xx_ssc ssc;
};
#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
@@ -347,6 +354,27 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
return 0;
}
+static void clk_pll1443x_set_sscg(struct clk_hw *hw, unsigned long parent_rate,
+ unsigned int pdiv, unsigned int mdiv)
+{
+ struct clk_pll14xx *pll = to_clk_pll14xx(hw);
+ struct imx_pll14xx_ssc *ssc = &pll->ssc;
+ u32 sscg_ctrl = readl_relaxed(pll->base + SSCG_CTRL);
+
+ sscg_ctrl &=
+ ~(SSCG_ENABLE | MFREQ_CTL_MASK | MRAT_CTL_MASK | SEL_PF_MASK);
+ if (ssc->enable) {
+ u32 mfr = parent_rate / (ssc->mod_freq * pdiv * (1 << 5));
+ u32 mrr = (ssc->mod_rate * mdiv * (1 << 6)) / (100 * mfr);
+
+ sscg_ctrl |= SSCG_ENABLE | FIELD_PREP(MFREQ_CTL_MASK, mfr) |
+ FIELD_PREP(MRAT_CTL_MASK, mrr) |
+ FIELD_PREP(SEL_PF_MASK, ssc->mod_type);
+ }
+
+ writel_relaxed(sscg_ctrl, pll->base + SSCG_CTRL);
+}
+
static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
@@ -368,6 +396,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);
+ if (pll->ssc.enable)
+ clk_pll1443x_set_sscg(hw, prate, rate.pdiv, rate.mdiv);
+
return 0;
}
@@ -408,6 +439,9 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
gnrl_ctl &= ~BYPASS_MASK;
writel_relaxed(gnrl_ctl, pll->base + GNRL_CTL);
+ if (pll->ssc.enable)
+ clk_pll1443x_set_sscg(hw, prate, rate.pdiv, rate.mdiv);
+
return 0;
}
@@ -487,7 +521,8 @@ static const struct clk_ops clk_pll1443x_ops = {
struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
const char *parent_name, void __iomem *base,
- const struct imx_pll14xx_clk *pll_clk)
+ const struct imx_pll14xx_clk *pll_clk,
+ const struct imx_pll14xx_ssc *ssc)
{
struct clk_pll14xx *pll;
struct clk_hw *hw;
@@ -525,6 +560,8 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
pll->type = pll_clk->type;
pll->rate_table = pll_clk->rate_table;
pll->rate_count = pll_clk->rate_count;
+ if (ssc)
+ memcpy(&pll->ssc, ssc, sizeof(pll->ssc));
val = readl_relaxed(pll->base + GNRL_CTL);
val &= ~BYPASS_MASK;
@@ -542,3 +579,66 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
return hw;
}
EXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx);
+
+static enum imx_pll14xx_ssc_mod_type clk_pll14xx_ssc_mode(const char *name,
+ enum imx_pll14xx_ssc_mod_type def)
+{
+ int i;
+ struct {
+ const char *name;
+ enum imx_pll14xx_ssc_mod_type id;
+ } mod_methods[] = {
+ { .name = "down-spread", .id = IMX_PLL14XX_SSC_DOWN_SPREAD },
+ { .name = "up-spread", .id = IMX_PLL14XX_SSC_UP_SPREAD },
+ { .name = "center-spread", .id = IMX_PLL14XX_SSC_CENTER_SPREAD }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(mod_methods); i++) {
+ if (!strcmp(name, mod_methods[i].name))
+ return mod_methods[i].id;
+ }
+
+ return def;
+}
+
+void imx_clk_pll14xx_get_ssc_conf(struct device_node *np, int pll_id,
+ struct imx_pll14xx_ssc *ssc)
+{
+ int i, ret, offset, num_clks;
+ u32 clk_id, clk_cell_size;
+ const char *s;
+
+ if (!ssc)
+ return;
+
+ memset(ssc, 0, sizeof(*ssc));
+
+ num_clks = of_count_phandle_with_args(np, "fsl,ssc-clocks",
+ "#clock-cells");
+ if (num_clks <= 0)
+ return;
+
+ ret = of_property_read_u32(np, "#clock-cells", &clk_cell_size);
+ if (ret)
+ return;
+
+ for (i = 0; i < num_clks; i++) {
+ offset = i * clk_cell_size + 1;
+ of_property_read_u32_index(np, "fsl,ssc-clocks", offset,
+ &clk_id);
+ if (clk_id != pll_id)
+ continue;
+
+ of_property_read_u32_index(np, "fsl,ssc-modfreq-hz", i,
+ &ssc->mod_freq);
+ of_property_read_u32_index(np, "fsl,ssc-modrate-percent", i,
+ &ssc->mod_rate);
+ if (!of_property_read_string(np, "fsl,ssc-modmethod", &s))
+ ssc->mod_type = clk_pll14xx_ssc_mode(
+ s, IMX_PLL14XX_SSC_DOWN_SPREAD);
+
+ ssc->enable = true;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(imx_clk_pll14xx_get_ssc_conf);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index aa5202f284f3..8cbc75480569 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -62,6 +62,19 @@ struct imx_pll14xx_rate_table {
unsigned int kdiv;
};
+enum imx_pll14xx_ssc_mod_type {
+ IMX_PLL14XX_SSC_DOWN_SPREAD,
+ IMX_PLL14XX_SSC_UP_SPREAD,
+ IMX_PLL14XX_SSC_CENTER_SPREAD,
+};
+
+struct imx_pll14xx_ssc {
+ bool enable;
+ unsigned int mod_freq;
+ unsigned int mod_rate;
+ enum imx_pll14xx_ssc_mod_type mod_type;
+};
+
struct imx_pll14xx_clk {
enum imx_pll14xx_type type;
const struct imx_pll14xx_rate_table *rate_table;
@@ -222,11 +235,18 @@ extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer;
__imx_clk_hw_divider(name, parent, reg, shift, width, flags)
#define imx_clk_hw_pll14xx(name, parent_name, base, pll_clk) \
- imx_dev_clk_hw_pll14xx(NULL, name, parent_name, base, pll_clk)
+ imx_dev_clk_hw_pll14xx(NULL, name, parent_name, base, pll_clk, NULL)
+
+#define imx_clk_hw_pll14xx_ssc(name, parent_name, base, pll_clk, ssc) \
+ imx_dev_clk_hw_pll14xx(NULL, name, parent_name, base, pll_clk, ssc)
struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
const char *parent_name, void __iomem *base,
- const struct imx_pll14xx_clk *pll_clk);
+ const struct imx_pll14xx_clk *pll_clk,
+ const struct imx_pll14xx_ssc *ssc);
+
+void imx_clk_pll14xx_get_ssc_conf(struct device_node *np, int pll_id,
+ struct imx_pll14xx_ssc *ssc);
struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base);
--
2.43.0
next prev parent reply other threads:[~2024-09-28 8:38 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-28 8:37 [PATCH 0/6] Support spread spectrum clocking for i.MX8{M,N,P} PLLs Dario Binacchi
2024-09-28 8:37 ` [PATCH 1/6] dt-bindings: clock: imx8m-anatop: support spread spectrum clocking Dario Binacchi
2024-09-28 12:09 ` Krzysztof Kozlowski
2024-09-29 20:00 ` Dario Binacchi
2024-09-30 6:45 ` Krzysztof Kozlowski
2024-10-01 6:29 ` Dario Binacchi
2024-10-03 10:46 ` Krzysztof Kozlowski
2024-10-05 8:57 ` Dario Binacchi
2024-10-06 13:13 ` Krzysztof Kozlowski
2024-10-07 15:02 ` Dario Binacchi
2024-10-08 8:20 ` Krzysztof Kozlowski
2024-10-08 9:16 ` Dario Binacchi
2024-10-23 14:58 ` Dario Binacchi
2024-10-23 17:49 ` Krzysztof Kozlowski
2024-10-28 10:32 ` Dario Binacchi
2024-09-28 8:37 ` Dario Binacchi [this message]
2024-09-28 8:37 ` [PATCH 3/6] clk: imx8mm: support spread spectrum clock generation Dario Binacchi
2024-09-28 8:37 ` [PATCH 4/6] clk: imx8mn: " Dario Binacchi
2024-09-28 8:37 ` [PATCH 5/6] clk: imx8mp: don't lose the anatop device node Dario Binacchi
2024-09-28 8:37 ` [PATCH 6/6] clk: imx8mp: support spread spectrum clock generation Dario Binacchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240928083804.1073942-3-dario.binacchi@amarulasolutions.com \
--to=dario.binacchi@amarulasolutions.com \
--cc=abelvesa@kernel.org \
--cc=festevam@gmail.com \
--cc=imx@lists.linux.dev \
--cc=kernel@pengutronix.de \
--cc=linux-amarula@amarulasolutions.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mturquette@baylibre.com \
--cc=peng.fan@nxp.com \
--cc=s.hauer@pengutronix.de \
--cc=sboyd@kernel.org \
--cc=shawnguo@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.