diff options
author | Eric Anholt <eric@anholt.net> | 2016-06-01 15:05:36 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2016-09-07 11:57:44 -0400 |
commit | 67615c588a059b731df9d019edc3c561d8006ec9 (patch) | |
tree | 8451bec87070b3d25d439bab286799242cca56de | |
parent | 9e400c5cc5c105e35216ac59a346f20cdd7613be (diff) |
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")
Acked-by: Martin Sperl <kernel@martin.sperl.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | drivers/clk/bcm/clk-bcm2835.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index c6420b36cbcb..e8a9646afd6d 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c | |||
@@ -1009,16 +1009,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, | |||
1009 | return 0; | 1009 | return 0; |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | static bool | ||
1013 | bcm2835_clk_is_pllc(struct clk_hw *hw) | ||
1014 | { | ||
1015 | if (!hw) | ||
1016 | return false; | ||
1017 | |||
1018 | return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; | ||
1019 | } | ||
1020 | |||
1012 | static int bcm2835_clock_determine_rate(struct clk_hw *hw, | 1021 | static int bcm2835_clock_determine_rate(struct clk_hw *hw, |
1013 | struct clk_rate_request *req) | 1022 | struct clk_rate_request *req) |
1014 | { | 1023 | { |
1015 | struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); | 1024 | struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); |
1016 | struct clk_hw *parent, *best_parent = NULL; | 1025 | struct clk_hw *parent, *best_parent = NULL; |
1026 | bool current_parent_is_pllc; | ||
1017 | unsigned long rate, best_rate = 0; | 1027 | unsigned long rate, best_rate = 0; |
1018 | unsigned long prate, best_prate = 0; | 1028 | unsigned long prate, best_prate = 0; |
1019 | size_t i; | 1029 | size_t i; |
1020 | u32 div; | 1030 | u32 div; |
1021 | 1031 | ||
1032 | current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw)); | ||
1033 | |||
1022 | /* | 1034 | /* |
1023 | * Select parent clock that results in the closest but lower rate | 1035 | * Select parent clock that results in the closest but lower rate |
1024 | */ | 1036 | */ |
@@ -1026,6 +1038,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, | |||
1026 | parent = clk_hw_get_parent_by_index(hw, i); | 1038 | parent = clk_hw_get_parent_by_index(hw, i); |
1027 | if (!parent) | 1039 | if (!parent) |
1028 | continue; | 1040 | continue; |
1041 | |||
1042 | /* | ||
1043 | * Don't choose a PLLC-derived clock as our parent | ||
1044 | * unless it had been manually set that way. PLLC's | ||
1045 | * frequency gets adjusted by the firmware due to | ||
1046 | * over-temp or under-voltage conditions, without | ||
1047 | * prior notification to our clock consumer. | ||
1048 | */ | ||
1049 | if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) | ||
1050 | continue; | ||
1051 | |||
1029 | prate = clk_hw_get_rate(parent); | 1052 | prate = clk_hw_get_rate(parent); |
1030 | div = bcm2835_clock_choose_div(hw, req->rate, prate, true); | 1053 | div = bcm2835_clock_choose_div(hw, req->rate, prate, true); |
1031 | rate = bcm2835_clock_rate_from_divisor(clock, prate, div); | 1054 | rate = bcm2835_clock_rate_from_divisor(clock, prate, div); |