From: Benjamin Bara <bbara93@gmail.com>
To: Rob Herring <robh+dt@kernel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
Conor Dooley <conor+dt@kernel.org>,
Shawn Guo <shawnguo@kernel.org>,
Sascha Hauer <s.hauer@pengutronix.de>,
Pengutronix Kernel Team <kernel@pengutronix.de>,
Fabio Estevam <festevam@gmail.com>,
NXP Linux Team <linux-imx@nxp.com>,
Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@kernel.org>,
Russell King <linux@armlinux.org.uk>,
Abel Vesa <abelvesa@kernel.org>, Peng Fan <peng.fan@nxp.com>
Cc: Frank Oltmanns <frank@oltmanns.dev>,
Maxime Ripard <mripard@kernel.org>,
devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org,
Benjamin Bara <benjamin.bara@skidata.com>
Subject: [PATCH 11/13] clk: imx: composite-8m: implement CLK_SET_RATE_PARENT
Date: Mon, 18 Sep 2023 00:40:07 +0200 [thread overview]
Message-ID: <20230918-imx8mp-dtsi-v1-11-1d008b3237c0@skidata.com> (raw)
In-Reply-To: <20230918-imx8mp-dtsi-v1-0-1d008b3237c0@skidata.com>
From: Benjamin Bara <benjamin.bara@skidata.com>
One of the key parts to enable dynamic clock propagation on the imx8m,
are the consumer-facing composites. They currently only divide,
therefore the parent must be already quite good in shape to provide a
close enough rate. Therefore, the parents are usually hard-assigned in
the dt. To workaround that, this commit enables propagation to the
parent of the composite.
If a rate cannot be reached exactly by only dividing, the parent is
asked (for now simply for the exact required rate - no dividers taken
into account). If the parent already has a configured rate, it's the
parent's job to ensure that all children are satisfied.
By using a notifier, the propagation-enabled clocks listen to clock
changes coming from the parent. If one is happening, it's the composites
job to verify if the rate is satisfying and if it is an intended change.
Otherwise, countermeasures have to be taken into account (e.g. setting
the rate back or aborting the change).
Signed-off-by: Benjamin Bara <benjamin.bara@skidata.com>
---
drivers/clk/imx/clk-composite-8m.c | 71 ++++++++++++++++++++++++++++++++++++--
1 file changed, 68 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c
index a121f1285110..068f61df28b1 100644
--- a/drivers/clk/imx/clk-composite-8m.c
+++ b/drivers/clk/imx/clk-composite-8m.c
@@ -4,6 +4,7 @@
*/
#include <linux/clk-provider.h>
+#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/io.h>
@@ -119,8 +120,12 @@ static int imx8m_divider_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_divider *divider = to_clk_divider(hw);
+ struct clk_hw *parent = clk_hw_get_parent(hw);
int prediv_value;
int div_value;
+ unsigned long target_rate;
+ struct clk_rate_request req_parent;
+ int ret;
/* if read only, just return current value */
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
@@ -140,9 +145,29 @@ static int imx8m_divider_determine_rate(struct clk_hw *hw,
divider->flags, prediv_value * div_value);
}
- return divider_determine_rate(hw, req, divider->table,
- PCG_PREDIV_WIDTH + PCG_DIV_WIDTH,
- divider->flags);
+ target_rate = req->rate;
+ ret = divider_determine_rate(hw, req, divider->table,
+ PCG_PREDIV_WIDTH + PCG_DIV_WIDTH,
+ divider->flags);
+ if (ret || req->rate == target_rate)
+ return ret;
+
+ /*
+ * If re-configuring the parent gives a better rate, do this instead.
+ * Avoid re-parenting for now, which could be done first if a possible
+ * parent already has a satisfying rate. The implementation does not
+ * consider the dividers between the parent and the current clock.
+ */
+ clk_hw_forward_rate_request(hw, req, parent, &req_parent, target_rate);
+ if (__clk_determine_rate(parent, &req_parent))
+ return 0;
+
+ if (abs(req_parent.rate - target_rate) < abs(req->rate - target_rate)) {
+ req->rate = req_parent.rate;
+ req->best_parent_rate = req_parent.rate;
+ }
+
+ return 0;
}
static const struct clk_ops imx8m_clk_composite_divider_ops = {
@@ -198,6 +223,33 @@ static const struct clk_ops imx8m_clk_composite_mux_ops = {
.determine_rate = imx8m_clk_composite_mux_determine_rate,
};
+static int imx8m_clk_composite_notifier_fn(struct notifier_block *notifier,
+ unsigned long code, void *data)
+{
+ struct clk_notifier_data *cnd = data;
+ struct clk_hw *hw = __clk_get_hw(cnd->clk);
+
+ if (code != PRE_RATE_CHANGE)
+ return NOTIFY_OK;
+
+ if (!__clk_is_rate_set(cnd->clk))
+ return NOTIFY_OK;
+
+ /*
+ * Consumer of a composite-m8 clock usually use the root clk, a gate
+ * connected to the composite (e.g. media_ldb and media_ldb_root).
+ * Therefore, evaluate the trigger's parent too.
+ */
+ if (cnd->clk != cnd->trigger && cnd->clk != clk_get_parent(cnd->trigger))
+ return notifier_from_errno(clk_hw_set_rate(hw, cnd->old_rate));
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block imx8m_clk_composite_notifier = {
+ .notifier_call = imx8m_clk_composite_notifier_fn,
+};
+
struct clk_hw *__imx8m_clk_hw_composite(const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg,
@@ -211,6 +263,7 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name,
struct clk_mux *mux = NULL;
const struct clk_ops *divider_ops;
const struct clk_ops *mux_ops;
+ int ret;
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
@@ -268,6 +321,18 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name,
if (IS_ERR(hw))
goto fail;
+ /*
+ * register a notifier which should switch back to the configured rate
+ * if the rate is going to be changed unintentionally.
+ */
+ if (flags & CLK_SET_RATE_PARENT) {
+ ret = clk_notifier_register(hw->clk, &imx8m_clk_composite_notifier);
+ if (ret) {
+ hw = ERR_PTR(ret);
+ goto fail;
+ }
+ }
+
return hw;
fail:
--
2.34.1
next prev parent reply other threads:[~2023-09-17 22:40 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-17 22:39 [PATCH 00/13] imx8mp: first clock propagation attempt (for LVDS) Benjamin Bara
2023-09-17 22:39 ` [PATCH 01/13] arm64: dts: imx8mp: lvds_bridge: use root instead of composite Benjamin Bara
2023-09-19 6:47 ` Maxime Ripard
2023-09-20 7:27 ` Benjamin Bara
2023-09-17 22:39 ` [PATCH 02/13] arm64: dts: imx8mp: re-parent IMX8MP_CLK_MEDIA_MIPI_PHY1_REF Benjamin Bara
2023-10-03 13:01 ` Adam Ford
2023-10-04 8:36 ` Benjamin Bara
2023-09-17 22:39 ` [PATCH 03/13] clk: implement clk_hw_set_rate() Benjamin Bara
2023-09-19 6:50 ` Maxime Ripard
2023-09-17 22:40 ` [PATCH 04/13] clk: print debug message if parent change is ignored Benjamin Bara
2023-09-17 22:40 ` [PATCH 05/13] clk: keep track of the trigger of an ongoing clk_set_rate Benjamin Bara
2023-09-19 7:06 ` Maxime Ripard
2023-09-20 7:50 ` Benjamin Bara
2023-09-17 22:40 ` [PATCH 06/13] clk: keep track if a clock is explicitly configured Benjamin Bara
2023-09-19 7:07 ` Maxime Ripard
2023-09-20 7:22 ` Benjamin Bara
2023-09-25 15:07 ` Maxime Ripard
2023-09-17 22:40 ` [PATCH 07/13] clk: detect unintended rate changes Benjamin Bara
2023-09-19 7:22 ` Maxime Ripard
2023-09-17 22:40 ` [PATCH 08/13] clk: divider: stop early if an optimal divider is found Benjamin Bara
2023-09-17 22:40 ` [PATCH 09/13] clk: imx: pll14xx: consider active rate for re-config Benjamin Bara
2023-09-17 22:40 ` [PATCH 10/13] clk: imx: composite-8m: convert compute_dividers to void Benjamin Bara
2023-09-17 22:40 ` Benjamin Bara [this message]
2023-09-17 22:40 ` [PATCH 12/13] clk: imx: imx8mp: allow LVDS clocks to set parent rate Benjamin Bara
2023-09-17 22:40 ` [PATCH 13/13] arm64: dts: imx8mp: remove assigned-clock-rate of IMX8MP_VIDEO_PLL1 Benjamin Bara
2023-09-18 5:00 ` [PATCH 00/13] imx8mp: first clock propagation attempt (for LVDS) Adam Ford
2023-09-18 17:59 ` Benjamin Bara
2023-09-19 7:37 ` Maxime Ripard
2023-09-18 17:24 ` Frank Oltmanns
2023-09-18 18:05 ` Benjamin Bara
2023-09-19 7:39 ` Maxime Ripard
2023-09-19 7:31 ` Maxime Ripard
2023-10-03 13:28 ` Adam Ford
2023-10-04 8:04 ` Alexander Stein
2023-10-04 8:28 ` Benjamin Bara
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=20230918-imx8mp-dtsi-v1-11-1d008b3237c0@skidata.com \
--to=bbara93@gmail.com \
--cc=abelvesa@kernel.org \
--cc=benjamin.bara@skidata.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=festevam@gmail.com \
--cc=frank@oltmanns.dev \
--cc=kernel@pengutronix.de \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-imx@nxp.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=mripard@kernel.org \
--cc=mturquette@baylibre.com \
--cc=peng.fan@nxp.com \
--cc=robh+dt@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).