mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
clk: allow assigning parent lazily
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. Reviewed-by: Simon Glass <simon.glass@canonical.com> Signed-off-by: Yang Xiwen <forbidden405@outlook.com>
This commit is contained in:
@@ -51,6 +51,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
|
||||
|
||||
@@ -495,6 +495,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;
|
||||
@@ -505,8 +531,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);
|
||||
@@ -630,6 +666,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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -47,6 +47,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
|
||||
@@ -72,6 +73,7 @@ struct udevice;
|
||||
*/
|
||||
struct clk {
|
||||
struct udevice *dev;
|
||||
char *parent_name;
|
||||
long long rate; /* in HZ */
|
||||
u32 flags;
|
||||
int enable_count;
|
||||
|
||||
Reference in New Issue
Block a user