diff options
Diffstat (limited to 'drivers/clk/clk-uclass.c')
-rw-r--r-- | drivers/clk/clk-uclass.c | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 53e7be764d..14254212ca 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -160,7 +160,7 @@ int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk) int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk) { int i, ret, err, count; - + bulk->count = 0; count = dev_count_phandle_with_args(dev, "clocks", "#clock-cells", 0); @@ -207,7 +207,8 @@ static struct clk *clk_set_default_get_by_id(struct clk *clk) return c; } -static int clk_set_default_parents(struct udevice *dev, int stage) +static int clk_set_default_parents(struct udevice *dev, + enum clk_defaults_stage stage) { struct clk clk, parent_clk, *c, *p; int index; @@ -241,6 +242,15 @@ static int clk_set_default_parents(struct udevice *dev, int stage) ret = clk_get_by_indexed_prop(dev, "assigned-clocks", index, &clk); + /* + * If the clock provider is not ready yet, let it handle + * the re-programming later. + */ + if (ret == -EPROBE_DEFER) { + ret = 0; + continue; + } + if (ret) { debug("%s: could not get assigned clock %d for %s\n", __func__, index, dev_read_name(dev)); @@ -251,10 +261,10 @@ static int clk_set_default_parents(struct udevice *dev, int stage) * It cannot be done right now but need to wait after the * device is probed */ - if (stage == 0 && clk.dev == dev) + if (stage == CLK_DEFAULTS_PRE && clk.dev == dev) continue; - if (stage > 0 && clk.dev != dev) + if (stage != CLK_DEFAULTS_PRE && clk.dev != dev) /* do not setup twice the parent clocks */ continue; @@ -280,7 +290,8 @@ static int clk_set_default_parents(struct udevice *dev, int stage) return 0; } -static int clk_set_default_rates(struct udevice *dev, int stage) +static int clk_set_default_rates(struct udevice *dev, + enum clk_defaults_stage stage) { struct clk clk, *c; int index; @@ -309,6 +320,15 @@ static int clk_set_default_rates(struct udevice *dev, int stage) ret = clk_get_by_indexed_prop(dev, "assigned-clocks", index, &clk); + /* + * If the clock provider is not ready yet, let it handle + * the re-programming later. + */ + if (ret == -EPROBE_DEFER) { + ret = 0; + continue; + } + if (ret) { dev_dbg(dev, "could not get assigned clock %d (err = %d)\n", @@ -320,10 +340,10 @@ static int clk_set_default_rates(struct udevice *dev, int stage) * It cannot be done right now but need to wait after the * device is probed */ - if (stage == 0 && clk.dev == dev) + if (stage == CLK_DEFAULTS_PRE && clk.dev == dev) continue; - if (stage > 0 && clk.dev != dev) + if (stage != CLK_DEFAULTS_PRE && clk.dev != dev) /* do not setup twice the parent clocks */ continue; @@ -346,16 +366,21 @@ fail: return ret; } -int clk_set_defaults(struct udevice *dev, int stage) +int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage) { int ret; if (!dev_has_ofnode(dev)) return 0; - /* If this not in SPL and pre-reloc state, don't take any action. */ + /* + * 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_SPL_BUILD) || (gd->flags & GD_FLG_RELOC))) - return 0; + if (stage != CLK_DEFAULTS_POST_FORCE) + return 0; debug("%s(%s)\n", __func__, dev_read_name(dev)); @@ -502,6 +527,8 @@ struct clk *clk_get_parent(struct clk *clk) return NULL; pdev = dev_get_parent(clk->dev); + if (!pdev) + return ERR_PTR(-ENODEV); pclk = dev_get_clk_ptr(pdev); if (!pclk) return ERR_PTR(-ENODEV); @@ -548,6 +575,22 @@ ulong clk_round_rate(struct clk *clk, ulong rate) return ops->round_rate(clk, rate); } +static void clk_clean_rate_cache(struct clk *clk) +{ + struct udevice *child_dev; + struct clk *clkp; + + if (!clk) + return; + + clk->rate = 0; + + list_for_each_entry(child_dev, &clk->dev->child_head, sibling_node) { + clkp = dev_get_clk_ptr(child_dev); + clk_clean_rate_cache(clkp); + } +} + ulong clk_set_rate(struct clk *clk, ulong rate) { const struct clk_ops *ops; @@ -560,6 +603,9 @@ ulong clk_set_rate(struct clk *clk, ulong rate) if (!ops->set_rate) return -ENOSYS; + /* Clean up cached rates for us and all child clocks */ + clk_clean_rate_cache(clk); + return ops->set_rate(clk, rate); } @@ -805,7 +851,7 @@ int clk_uclass_post_probe(struct udevice *dev) * where the DT is used to setup default parents and rates * using assigned-clocks */ - clk_set_defaults(dev, 1); + clk_set_defaults(dev, CLK_DEFAULTS_POST); return 0; } |