1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- From ca56b6fab9cfc0beca2a706193f1c158e124c1f9 Mon Sep 17 00:00:00 2001
- From: Eric Anholt <eric@anholt.net>
- Date: Tue, 26 Apr 2016 12:39:45 -0700
- Subject: [PATCH] clk: bcm2835: Skip PLLC clocks when deciding on a new clock
- parent
- 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
- @@ -1028,16 +1028,28 @@ static int bcm2835_clock_set_rate(struct
- 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
- */
- @@ -1045,6 +1057,17 @@ static int bcm2835_clock_determine_rate(
- 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);
|