[PATCH RFC 26/40] clk/clk-uclass: adapt for CCF_FULL
Casey Connolly
casey.connolly at linaro.org
Thu Mar 19 21:56:48 CET 2026
When building U-Boot with CCF_FULL support, most clk operations
are implemented in clk/ccf/clk.c, so we can remove the conflicting
definitions in clk-uclass.c.
Additionally, registering clock consumers works quite differently, so we
adapt clk_get_by_name() and similar functions to call into CCF. Notably
while in Linux the struct clk handle is allocated inside CCF (since
it's an opaque cookie), in U-Boot struct clk is public and typically
allocated by the consumer driver, so we need a small adjustment to allow
CCF to populate an already-allocated struct clk.
Signed-off-by: Casey Connolly <casey.connolly at linaro.org>
---
drivers/clk/clk-uclass.c | 297 +++++++++++++++++++++++++++--------------------
1 file changed, 172 insertions(+), 125 deletions(-)
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 095329e25f15..d54d76745560 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -23,8 +23,11 @@
#include <linux/bug.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
+#include <linux/clk/clk-conf.h>
+#include "ccf/clk.h"
+
static inline const struct clk_ops_uboot *clk_dev_ops(struct udevice *dev)
{
return (const struct clk_ops_uboot *)dev->driver->ops;
}
@@ -74,9 +77,9 @@ static int clk_of_xlate_default(struct clk *clk,
return 0;
}
-static int clk_get_by_index_tail(int ret, ofnode node,
+static int __maybe_unused clk_get_by_index_tail(int ret, ofnode node,
struct ofnode_phandle_args *args,
const char *list_name, int index,
struct clk *clk)
{
@@ -115,47 +118,30 @@ err:
return log_msg_ret("prop", ret);
}
-static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
- int index, struct clk *clk)
-{
- int ret;
- struct ofnode_phandle_args args;
-
- debug("%s(dev=%s, index=%d, clk=%p)\n", __func__, dev_read_name(dev),
- index, clk);
-
- assert(clk);
- clk->dev = NULL;
-
- ret = dev_read_phandle_with_args(dev, prop_name, "#clock-cells", 0,
- index, &args);
- if (ret) {
- debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
- __func__, ret);
- return log_ret(ret);
- }
-
- return clk_get_by_index_tail(ret, dev_ofnode(dev), &args, "clocks",
- index, clk);
-}
-
int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
{
return clk_get_by_index_nodev(dev_ofnode(dev), index, clk);
}
int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk)
{
+#if CONFIG_IS_ENABLED(CLK_CCF_FULL)
+ struct clk_hw *hw;
+
+ hw = of_clk_get_hw(node, index, NULL);
+ return clk_hw_create_clk_uboot(clk, hw);
+#else
struct ofnode_phandle_args args;
int ret;
ret = ofnode_parse_phandle_with_args(node, "clocks", "#clock-cells", 0,
index, &args);
return clk_get_by_index_tail(ret, node, &args, "clocks",
index, clk);
+#endif
}
int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
{
@@ -189,8 +175,86 @@ bulk_get_err:
return ret;
}
+int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
+{
+#if CONFIG_IS_ENABLED(CLK_CCF_FULL)
+ struct clk_hw *hw;
+
+ hw = of_clk_get_hw(dev_ofnode(dev), 0, name);
+ return clk_hw_create_clk_uboot(clk, hw);
+#else
+ return clk_get_by_name_nodev(dev_ofnode(dev), name, clk);
+#endif
+}
+#endif /* OF_REAL */
+
+int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
+{
+ int index = 0;
+
+ debug("%s(node=%s, name=%s, clk=%p)\n", __func__,
+ ofnode_get_name(node), name, clk);
+ clk->dev = NULL;
+
+ if (name) {
+ index = ofnode_stringlist_search(node, "clock-names", name);
+ if (index < 0) {
+ debug("fdt_stringlist_search() failed: %d\n", index);
+ return index;
+ }
+ }
+
+ return clk_get_by_index_nodev(node, index, clk);
+}
+
+int clk_release_all(struct clk *clk, unsigned int count)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < count; i++) {
+ debug("%s(clk[%u]=%p)\n", __func__, i, &clk[i]);
+
+ /* check if clock has been previously requested */
+ if (!clk[i].dev)
+ continue;
+
+ ret = clk_disable(&clk[i]);
+ if (ret && ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Full CCF has its own versions of these functions */
+#if !CONFIG_IS_ENABLED(CLK_CCF_FULL)
+static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
+ int index, struct clk *clk)
+{
+ int ret;
+ struct ofnode_phandle_args args;
+
+ debug("%s(dev=%s, index=%d, clk=%p)\n", __func__, dev_read_name(dev),
+ index, clk);
+
+ assert(clk);
+ clk->dev = NULL;
+
+ ret = dev_read_phandle_with_args(dev, prop_name, "#clock-cells", 0,
+ index, &args);
+ if (ret) {
+ debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
+ __func__, ret);
+ return log_ret(ret);
+ }
+
+ return clk_get_by_index_tail(ret, dev_ofnode(dev), &args, "clocks",
+ index, clk);
+}
+
static struct clk *clk_set_default_get_by_id(struct clk *clk)
{
struct clk *c = clk;
@@ -371,62 +435,8 @@ fail:
free(rates);
return ret;
}
-int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage)
-{
- int ret;
-
- if (!dev_has_ofnode(dev))
- return 0;
-
- /*
- * To avoid setting defaults twice, don't set them before relocation.
- * However, still set them for SPL. And still set them if explicitly
- * asked.
- */
- if (!(IS_ENABLED(CONFIG_XPL_BUILD) || (gd->flags & GD_FLG_RELOC)))
- if (stage != CLK_DEFAULTS_POST_FORCE)
- return 0;
-
- debug("%s(%s)\n", __func__, dev_read_name(dev));
-
- ret = clk_set_default_parents(dev, stage);
- if (ret)
- return ret;
-
- ret = clk_set_default_rates(dev, stage);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
-{
- return clk_get_by_name_nodev(dev_ofnode(dev), name, clk);
-}
-#endif /* OF_REAL */
-
-int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
-{
- int index = 0;
-
- debug("%s(node=%s, name=%s, clk=%p)\n", __func__,
- ofnode_get_name(node), name, clk);
- clk->dev = NULL;
-
- if (name) {
- index = ofnode_stringlist_search(node, "clock-names", name);
- if (index < 0) {
- debug("fdt_stringlist_search() failed: %d\n", index);
- return index;
- }
- }
-
- return clk_get_by_index_nodev(node, index, clk);
-}
-
const char *
clk_resolve_parent_clk(struct udevice *dev, const char *name)
{
struct udevice *parent;
@@ -443,28 +453,8 @@ clk_resolve_parent_clk(struct udevice *dev, const char *name)
return clk.dev->name;
}
-int clk_release_all(struct clk *clk, unsigned int count)
-{
- unsigned int i;
- int ret;
-
- for (i = 0; i < count; i++) {
- debug("%s(clk[%u]=%p)\n", __func__, i, &clk[i]);
-
- /* check if clock has been previously requested */
- if (!clk[i].dev)
- continue;
-
- ret = clk_disable(&clk[i]);
- if (ret && ret != -ENOSYS)
- return ret;
- }
-
- return 0;
-}
-
int clk_request(struct udevice *dev, struct clk *clk)
{
const struct clk_ops_uboot *ops;
@@ -704,21 +694,8 @@ int clk_enable(struct clk *clk)
return 0;
}
-int clk_enable_bulk(struct clk_bulk *bulk)
-{
- int i, ret;
-
- for (i = 0; i < bulk->count; i++) {
- ret = clk_enable(&bulk->clks[i]);
- if (ret < 0 && ret != -ENOSYS)
- return ret;
- }
-
- return 0;
-}
-
int clk_disable(struct clk *clk)
{
const struct clk_ops_uboot *ops;
struct clk *clkp = NULL;
@@ -769,21 +746,8 @@ int clk_disable(struct clk *clk)
return 0;
}
-int clk_disable_bulk(struct clk_bulk *bulk)
-{
- int i, ret;
-
- for (i = 0; i < bulk->count; i++) {
- ret = clk_disable(&bulk->clks[i]);
- if (ret < 0 && ret != -ENOSYS)
- return ret;
- }
-
- return 0;
-}
-
int clk_get_by_id(ulong id, struct clk **clkp)
{
struct udevice *dev;
struct uclass *uc;
@@ -820,8 +784,65 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
return true;
return false;
}
+#else
+long clk_get_parent_rate(struct clk *clk)
+{
+ struct clk *pclk;
+
+ if (!clk)
+ return -EINVAL;
+
+ pclk = clk_get_parent(clk);
+ return clk_get_rate(pclk);
+}
+
+static int clk_set_default_parents(struct udevice *dev,
+ enum clk_defaults_stage stage)
+{
+ return -ENOSYS;
+}
+
+static int clk_set_default_rates(struct udevice *dev,
+ enum clk_defaults_stage stage)
+{
+ return -ENOSYS;
+}
+#endif
+
+int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage)
+{
+ int ret;
+
+ if (!dev_has_ofnode(dev))
+ return 0;
+
+ /*
+ * To avoid setting defaults twice, don't set them before relocation.
+ * However, still set them for SPL. And still set them if explicitly
+ * asked.
+ */
+ if (!(IS_ENABLED(CONFIG_XPL_BUILD) || (gd->flags & GD_FLG_RELOC)))
+ if (stage != CLK_DEFAULTS_POST_FORCE)
+ return 0;
+
+ debug("%s(%s)\n", __func__, dev_read_name(dev));
+
+ if (CONFIG_IS_ENABLED(CLK_CCF_FULL)) {
+ return of_clk_set_defaults(dev_ofnode(dev), false);
+ } else {
+ ret = clk_set_default_parents(dev, stage);
+ if (ret)
+ return ret;
+
+ ret = clk_set_default_rates(dev, stage);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
struct clk *devm_clk_get(struct udevice *dev, const char *id)
{
int rc;
@@ -837,8 +858,34 @@ struct clk *devm_clk_get(struct udevice *dev, const char *id)
return clk;
}
+int clk_enable_bulk(struct clk_bulk *bulk)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = clk_enable(&bulk->clks[i]);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
+int clk_disable_bulk(struct clk_bulk *bulk)
+{
+ int i, ret;
+
+ for (i = 0; i < bulk->count; i++) {
+ ret = clk_disable(&bulk->clks[i]);
+ if (ret < 0 && ret != -ENOSYS)
+ return ret;
+ }
+
+ return 0;
+}
+
int clk_uclass_post_probe(struct udevice *dev)
{
/*
* when a clock provider is probed. Call clk_set_defaults()
--
2.51.0
More information about the U-Boot
mailing list