From ca18a9ebf0d6e8be8bebb93957de1d86917910a0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 24 Feb 2020 11:29:59 +0100 Subject: clk: initially enable critical clocks Critical clocks have to be enabled initially. We have to do this not only to enable the clock itself, but also to make sure its parents stay enabled and also to correctly enable the new parents during reparenting of the clock. Signed-off-by: Sascha Hauer --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ea3304bc7c..05bc21a6d4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -282,6 +282,9 @@ int clk_register(struct clk *clk) list_add_tail(&clk->list, &clks); + if (clk->flags & CLK_IS_CRITICAL) + clk_enable(clk); + return 0; } -- cgit v1.2.3 From f0b531594f0e7c133fc80ff050171d8ce5f8192a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 24 Feb 2020 11:37:13 +0100 Subject: clk: Do not let the enable count of critical clocks go below 1 The enable count of critical clocks may not drop below 1. Otherwise the new parent during a reparenting of a critical clock will not be enabled. Signed-off-by: Sascha Hauer --- drivers/clk/clk.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 05bc21a6d4..5777c9c58e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -84,12 +84,14 @@ void clk_disable(struct clk *clk) if (!clk->enable_count) return; + if (clk->enable_count == 1 && clk->flags & CLK_IS_CRITICAL) { + pr_warn("Disabling critical clock %s\n", clk->name); + return; + } + clk->enable_count--; if (!clk->enable_count) { - if (clk->flags & CLK_IS_CRITICAL) - return; - if (clk->ops->disable) clk->ops->disable(clk); -- cgit v1.2.3 From 5bf3e793ccef72e11a03ab3066a4893883249c5b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 24 Feb 2020 12:09:35 +0100 Subject: clk: print more consistent clock states In clk_dump we only print the state of clk_is_enabled(). Depending on the clock this can mean different things. When the clock provides an is_enabled() callback it will print its result, so the enabled state matches the hardware state of that clock, but doesn't necessarily mean its parents are enabled. If a clock does not provide an is_enabled() callback then we rely on our internal enable_count tracker. Change this to always print the hardware state of the current clock. It can be: - disabled: The clock is disabled (as provided by is_enabled()) - enabled: The clock is enabled (as provided by is_enabled()) - always enabled: The clock can't be disabled (no is_enabled callback and can't be enabled/disabled) - unknown: no is_enabled callback but can be enabled/disabled Additionally we print the enable_count variable, so from enable_count != 0 we can know that barebox has enabled the clock. Signed-off-by: Sascha Hauer --- drivers/clk/clk.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 5777c9c58e..b27ad6d249 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -632,12 +632,40 @@ int of_clk_init(struct device_node *root, const struct of_device_id *matches) } #endif +static const char *clk_hw_stat(struct clk *clk) +{ + if (clk->ops->is_enabled) { + if (clk->ops->is_enabled(clk)) + return "enabled"; + else + return "disabled"; + } + + if (!clk->ops->enable) + return "always enabled"; + + return "unknown"; +} + static void dump_one(struct clk *clk, int verbose, int indent) { struct clk *c; + int enabled = clk_is_enabled(clk); + const char *hwstat, *stat; + + hwstat = clk_hw_stat(clk); + + if (enabled == 0) + stat = "disabled"; + else + stat = "enabled"; + + printf("%*s%s (rate %lu, enable_count: %d, %s)\n", indent * 4, "", + clk->name, + clk_get_rate(clk), + clk->enable_count, + hwstat); - printf("%*s%s (rate %lu, %sabled)\n", indent * 4, "", clk->name, clk_get_rate(clk), - clk_is_enabled(clk) ? "en" : "dis"); if (verbose) { if (clk->num_parents > 1) { -- cgit v1.2.3