2016-12-02 10:50:26 +00:00
|
|
|
From ca56b6fab9cfc0beca2a706193f1c158e124c1f9 Mon Sep 17 00:00:00 2001
|
2016-06-08 09:59:37 +00:00
|
|
|
From: Eric Anholt <eric@anholt.net>
|
|
|
|
Date: Tue, 26 Apr 2016 12:39:45 -0700
|
2016-09-10 12:54:26 +00:00
|
|
|
Subject: [PATCH] clk: bcm2835: Skip PLLC clocks when deciding on a new clock
|
|
|
|
parent
|
2016-06-08 09:59:37 +00:00
|
|
|
|
|
|
|
If the firmware had set up a clock to source from PLLC, go along with
|
|
|
|
it. But if we're looking for a new parent, we don't want to switch it
|
|
|
|
to PLLC because the firmware will force PLLC (and thus the AXI bus
|
|
|
|
clock) to different frequencies during over-temp/under-voltage,
|
|
|
|
without notification to Linux.
|
|
|
|
|
|
|
|
On my system, this moves the Linux-enabled HDMI state machine and DSI1
|
|
|
|
escape clock over to plld_per from pllc_per. EMMC still ends up on
|
|
|
|
pllc_per, because the firmware had set it up to use that.
|
|
|
|
|
|
|
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
|
|
|
Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
|
|
|
|
---
|
|
|
|
drivers/clk/bcm/clk-bcm2835.c | 23 +++++++++++++++++++++++
|
|
|
|
1 file changed, 23 insertions(+)
|
|
|
|
|
|
|
|
--- a/drivers/clk/bcm/clk-bcm2835.c
|
|
|
|
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
2016-07-07 07:22:07 +00:00
|
|
|
@@ -1020,16 +1020,28 @@ static int bcm2835_clock_set_rate(struct
|
2016-06-08 09:59:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static bool
|
|
|
|
+bcm2835_clk_is_pllc(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ if (!hw)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static int bcm2835_clock_determine_rate(struct clk_hw *hw,
|
|
|
|
struct clk_rate_request *req)
|
|
|
|
{
|
|
|
|
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
|
|
|
struct clk_hw *parent, *best_parent = NULL;
|
|
|
|
+ bool current_parent_is_pllc;
|
|
|
|
unsigned long rate, best_rate = 0;
|
|
|
|
unsigned long prate, best_prate = 0;
|
|
|
|
size_t i;
|
|
|
|
u32 div;
|
|
|
|
|
|
|
|
+ current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));
|
|
|
|
+
|
|
|
|
/*
|
|
|
|
* Select parent clock that results in the closest but lower rate
|
|
|
|
*/
|
2016-07-07 07:22:07 +00:00
|
|
|
@@ -1037,6 +1049,17 @@ static int bcm2835_clock_determine_rate(
|
2016-06-08 09:59:37 +00:00
|
|
|
parent = clk_hw_get_parent_by_index(hw, i);
|
|
|
|
if (!parent)
|
|
|
|
continue;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Don't choose a PLLC-derived clock as our parent
|
|
|
|
+ * unless it had been manually set that way. PLLC's
|
|
|
|
+ * frequency gets adjusted by the firmware due to
|
|
|
|
+ * over-temp or under-voltage conditions, without
|
|
|
|
+ * prior notification to our clock consumer.
|
|
|
|
+ */
|
|
|
|
+ if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
prate = clk_hw_get_rate(parent);
|
|
|
|
div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
|
|
|
|
rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
|