1 From 298433024e7f889e87a002f3888bcd5ab8a319cb Mon Sep 17 00:00:00 2001
2 From: Eric Anholt <eric@anholt.net>
3 Date: Tue, 26 Apr 2016 12:39:45 -0700
4 Subject: [PATCH] clk: bcm2835: Skip PLLC clocks when deciding on a new clock
7 If the firmware had set up a clock to source from PLLC, go along with
8 it. But if we're looking for a new parent, we don't want to switch it
9 to PLLC because the firmware will force PLLC (and thus the AXI bus
10 clock) to different frequencies during over-temp/under-voltage,
11 without notification to Linux.
13 On my system, this moves the Linux-enabled HDMI state machine and DSI1
14 escape clock over to plld_per from pllc_per. EMMC still ends up on
15 pllc_per, because the firmware had set it up to use that.
17 Signed-off-by: Eric Anholt <eric@anholt.net>
18 Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
20 drivers/clk/bcm/clk-bcm2835.c | 23 +++++++++++++++++++++++
21 1 file changed, 23 insertions(+)
23 --- a/drivers/clk/bcm/clk-bcm2835.c
24 +++ b/drivers/clk/bcm/clk-bcm2835.c
25 @@ -1022,16 +1022,28 @@ static int bcm2835_clock_set_rate(struct
30 +bcm2835_clk_is_pllc(struct clk_hw *hw)
35 + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
38 static int bcm2835_clock_determine_rate(struct clk_hw *hw,
39 struct clk_rate_request *req)
41 struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
42 struct clk_hw *parent, *best_parent = NULL;
43 + bool current_parent_is_pllc;
44 unsigned long rate, best_rate = 0;
45 unsigned long prate, best_prate = 0;
49 + current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));
52 * Select parent clock that results in the closest but lower rate
54 @@ -1039,6 +1051,17 @@ static int bcm2835_clock_determine_rate(
55 parent = clk_hw_get_parent_by_index(hw, i);
60 + * Don't choose a PLLC-derived clock as our parent
61 + * unless it had been manually set that way. PLLC's
62 + * frequency gets adjusted by the firmware due to
63 + * over-temp or under-voltage conditions, without
64 + * prior notification to our clock consumer.
66 + if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
69 prate = clk_hw_get_rate(parent);
70 div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
71 rate = bcm2835_clock_rate_from_divisor(clock, prate, div);