Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: bcm: Support rate change propagation on bcm2835 clocks

Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set
to a precise rate (in our case 108MHz). With the current implementation,
where peripheral clocks are not allowed to forward rate change requests
to their parents, it is impossible to match this requirement unless the
bootloader has configured things correctly, or a specific rate has been
assigned through the DT (with the assigned-clk-rates property).

Add a new field to struct bcm2835_clock_data to specify which parent
clocks accept rate change propagation, and support set rate propagation
in bcm2835_clock_determine_rate().

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Boris Brezillon and committed by
Stephen Boyd
155e8b3b 68af4fa8

+63 -4
+63 -4
drivers/clk/bcm/clk-bcm2835.c
··· 436 436 const char *const *parents; 437 437 int num_mux_parents; 438 438 439 + /* Bitmap encoding which parents accept rate change propagation. */ 440 + unsigned int set_rate_parent; 441 + 439 442 u32 ctl_reg; 440 443 u32 div_reg; 441 444 ··· 1020 1017 return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; 1021 1018 } 1022 1019 1020 + static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, 1021 + int parent_idx, 1022 + unsigned long rate, 1023 + u32 *div, 1024 + unsigned long *prate) 1025 + { 1026 + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 1027 + struct bcm2835_cprman *cprman = clock->cprman; 1028 + const struct bcm2835_clock_data *data = clock->data; 1029 + unsigned long best_rate; 1030 + u32 curdiv, mindiv, maxdiv; 1031 + struct clk_hw *parent; 1032 + 1033 + parent = clk_hw_get_parent_by_index(hw, parent_idx); 1034 + 1035 + if (!(BIT(parent_idx) & data->set_rate_parent)) { 1036 + *prate = clk_hw_get_rate(parent); 1037 + *div = bcm2835_clock_choose_div(hw, rate, *prate, true); 1038 + 1039 + return bcm2835_clock_rate_from_divisor(clock, *prate, 1040 + *div); 1041 + } 1042 + 1043 + if (data->frac_bits) 1044 + dev_warn(cprman->dev, 1045 + "frac bits are not used when propagating rate change"); 1046 + 1047 + /* clamp to min divider of 2 if we're dealing with a mash clock */ 1048 + mindiv = data->is_mash_clock ? 2 : 1; 1049 + maxdiv = BIT(data->int_bits) - 1; 1050 + 1051 + /* TODO: Be smart, and only test a subset of the available divisors. */ 1052 + for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) { 1053 + unsigned long tmp_rate; 1054 + 1055 + tmp_rate = clk_hw_round_rate(parent, rate * curdiv); 1056 + tmp_rate /= curdiv; 1057 + if (curdiv == mindiv || 1058 + (tmp_rate > best_rate && tmp_rate <= rate)) 1059 + best_rate = tmp_rate; 1060 + 1061 + if (best_rate == rate) 1062 + break; 1063 + } 1064 + 1065 + *div = curdiv << CM_DIV_FRAC_BITS; 1066 + *prate = curdiv * best_rate; 1067 + 1068 + return best_rate; 1069 + } 1070 + 1023 1071 static int bcm2835_clock_determine_rate(struct clk_hw *hw, 1024 1072 struct clk_rate_request *req) 1025 1073 { 1026 - struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 1027 1074 struct clk_hw *parent, *best_parent = NULL; 1028 1075 bool current_parent_is_pllc; 1029 1076 unsigned long rate, best_rate = 0; ··· 1101 1048 if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) 1102 1049 continue; 1103 1050 1104 - prate = clk_hw_get_rate(parent); 1105 - div = bcm2835_clock_choose_div(hw, req->rate, prate, true); 1106 - rate = bcm2835_clock_rate_from_divisor(clock, prate, div); 1051 + rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate, 1052 + &div, &prate); 1107 1053 if (rate > best_rate && rate <= req->rate) { 1108 1054 best_parent = parent; 1109 1055 best_prate = prate; ··· 1313 1261 init.num_parents = data->num_mux_parents; 1314 1262 init.name = data->name; 1315 1263 init.flags = data->flags | CLK_IGNORE_UNUSED; 1264 + 1265 + /* 1266 + * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate 1267 + * rate changes on at least of the parents. 1268 + */ 1269 + if (data->set_rate_parent) 1270 + init.flags |= CLK_SET_RATE_PARENT; 1316 1271 1317 1272 if (data->is_vpu_clock) { 1318 1273 init.ops = &bcm2835_vpu_clock_clk_ops;