[PATCH v2 4/5] clk: allow assigning parent lazily
Yang Xiwen via B4 Relay
devnull+forbidden405.outlook.com at kernel.org
Wed Dec 31 20:52:50 CET 2025
From: Yang Xiwen <forbidden405 at outlook.com>
Don't mandate the parent device exists when registering a clock.
Instead, cache the parent name in the core clk struct and resolve the
parent in clk_get_parent(), which is called lazily upon real use.
Disable this feature for xPLs by default to save size.
Signed-off-by: Yang Xiwen <forbidden405 at outlook.com>
---
drivers/clk/Kconfig | 12 ++++++++++++
drivers/clk/clk-uclass.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
drivers/clk/clk.c | 14 ++++++++++++--
include/clk.h | 2 ++
4 files changed, 68 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 19aa2ffa5396..bb2a97a4a07a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -40,6 +40,18 @@ config VPL_CLK
setting up clocks within TPL, and allows the same drivers to be
used as U-Boot proper.
+config CLK_LAZY_REPARENT
+ bool "Enable clock lazy reparenting feature"
+ depends on CLK_CCF
+ default n if SPL_CLK || TPL_CLK || VPL_CLK
+ default y
+ help
+ This option allows registering clocks in a less strict order that
+ Parent clocks can be registered before their children. The clock subsystem
+ will cache the parent's name and resolve it to the real parent device "lazily".
+ This is the default behavior in Linux clock subsystem. Enabling this feature
+ should simplifies the porting of Linux clock drivers to U-Boot.
+
config CLK_BCM6345
bool "Clock controller driver for BCM6345"
depends on CLK && ARCH_BMIPS
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index bfad71e7af70..cea79e05ea09 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -490,6 +490,32 @@ ulong clk_get_rate(struct clk *clk)
return ops->get_rate(clk);
}
+static struct udevice *clk_reparent(struct clk *clk, const char *parent_name)
+{
+ struct udevice *pdev;
+ int ret;
+
+ if (!clk_valid(clk))
+ return NULL;
+
+ if (!parent_name)
+ return NULL;
+
+ debug("%s(clk=%p) reparenting to %s\n", __func__, clk, parent_name);
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &pdev);
+ if (ret) {
+ log_err("%s(clk=%p) failed to find parent \"%s\"\n", __func__, clk, parent_name);
+ return NULL;
+ }
+
+ ret = device_reparent(clk->dev, pdev);
+ if (ret)
+ return NULL;
+
+ return pdev;
+}
+
struct clk *clk_get_parent(struct clk *clk)
{
struct udevice *pdev;
@@ -500,8 +526,18 @@ struct clk *clk_get_parent(struct clk *clk)
return NULL;
pdev = dev_get_parent(clk->dev);
- if (!pdev)
- return ERR_PTR(-ENODEV);
+ if (!pdev) {
+ if (CONFIG_IS_ENABLED(CLK_LAZY_REPARENT)) {
+ pdev = clk_reparent(clk, clk->parent_name);
+ free(clk->parent_name);
+ clk->parent_name = NULL;
+
+ if (!pdev)
+ return ERR_PTR(-ENODEV);
+ } else {
+ return ERR_PTR(-ENODEV);
+ }
+ }
if (device_get_uclass_id(pdev) != UCLASS_CLK)
return ERR_PTR(-ENODEV);
@@ -625,6 +661,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
if (!clk_valid(clk))
return 0;
+
+ free(clk->parent_name);
+ clk->parent_name = NULL;
+
ops = clk_dev_ops(clk->dev);
if (!ops->set_parent)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index b8c2e8d531b9..32b3c03ab09a 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -24,8 +24,18 @@ int clk_register(struct clk *clk, const char *drv_name,
if (parent_name) {
ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent);
if (ret) {
- log_err("%s: failed to get %s device (parent of %s)\n",
- __func__, parent_name, name);
+ log_debug("%s: failed to get %s device (parent of %s)\n",
+ __func__, parent_name, name);
+
+ if (CONFIG_IS_ENABLED(CLK_LAZY_REPARENT)) {
+ /*
+ * The parent is not yet registered.
+ * Cache the parent name and resolve it later.
+ */
+ clk->parent_name = strdup(parent_name);
+ if (!clk->parent_name)
+ return -ENOMEM;
+ }
} else {
log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name,
parent->name, parent);
diff --git a/include/clk.h b/include/clk.h
index a6ef4e026922..5f684dcbf9d2 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -37,6 +37,7 @@ struct udevice;
/**
* struct clk - A handle to (allowing control of) a single clock.
* @dev: The device which implements the clock signal.
+ * @parent_name: The name of the parent.
* @rate: The clock rate (in HZ).
* @flags: Flags used across common clock structure (e.g. %CLK_)
* Clock IP blocks specific flags (i.e. mux, div, gate, etc) are defined
@@ -62,6 +63,7 @@ struct udevice;
*/
struct clk {
struct udevice *dev;
+ char *parent_name;
long long rate; /* in HZ */
u32 flags;
int enable_count;
--
2.43.0
More information about the U-Boot
mailing list