[PATCH RFC 26/40] clk/clk-uclass: adapt for CCF_FULL
Casey Connolly <[email protected]> Thu, 19 Mar 2026 21:56:48 +0100
| Newsgroups | io.groups.u-boot-amlogic,org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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