diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0581-clk-bcm-Support-rate-change-propagation-on-bcm2835-c.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.4/0581-clk-bcm-Support-rate-change-propagation-on-bcm2835-c.patch | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0581-clk-bcm-Support-rate-change-propagation-on-bcm2835-c.patch b/target/linux/brcm2708/patches-4.4/0581-clk-bcm-Support-rate-change-propagation-on-bcm2835-c.patch new file mode 100644 index 0000000..bd7405e --- /dev/null +++ b/target/linux/brcm2708/patches-4.4/0581-clk-bcm-Support-rate-change-propagation-on-bcm2835-c.patch @@ -0,0 +1,129 @@ +From e75f021850a698fec611538e8ff293c22a4604f5 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon <boris.brezillon@free-electrons.com> +Date: Thu, 1 Dec 2016 22:00:19 +0100 +Subject: [PATCH] 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> +(cherry picked from commit 155e8b3b0ee320ae866b97dd31eba8a1f080a772) +--- + drivers/clk/bcm/clk-bcm2835.c | 67 ++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 63 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c +index 3fbd2e8..5f0e2f3 100644 +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -457,6 +457,9 @@ struct bcm2835_clock_data { + const char *const *parents; + int num_mux_parents; + ++ /* Bitmap encoding which parents accept rate change propagation. */ ++ unsigned int set_rate_parent; ++ + u32 ctl_reg; + u32 div_reg; + +@@ -1055,10 +1058,60 @@ bcm2835_clk_is_pllc(struct clk_hw *hw) + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; + } + ++static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, ++ int parent_idx, ++ unsigned long rate, ++ u32 *div, ++ unsigned long *prate) ++{ ++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); ++ struct bcm2835_cprman *cprman = clock->cprman; ++ const struct bcm2835_clock_data *data = clock->data; ++ unsigned long best_rate; ++ u32 curdiv, mindiv, maxdiv; ++ struct clk_hw *parent; ++ ++ parent = clk_hw_get_parent_by_index(hw, parent_idx); ++ ++ if (!(BIT(parent_idx) & data->set_rate_parent)) { ++ *prate = clk_hw_get_rate(parent); ++ *div = bcm2835_clock_choose_div(hw, rate, *prate, true); ++ ++ return bcm2835_clock_rate_from_divisor(clock, *prate, ++ *div); ++ } ++ ++ if (data->frac_bits) ++ dev_warn(cprman->dev, ++ "frac bits are not used when propagating rate change"); ++ ++ /* clamp to min divider of 2 if we're dealing with a mash clock */ ++ mindiv = data->is_mash_clock ? 2 : 1; ++ maxdiv = BIT(data->int_bits) - 1; ++ ++ /* TODO: Be smart, and only test a subset of the available divisors. */ ++ for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) { ++ unsigned long tmp_rate; ++ ++ tmp_rate = clk_hw_round_rate(parent, rate * curdiv); ++ tmp_rate /= curdiv; ++ if (curdiv == mindiv || ++ (tmp_rate > best_rate && tmp_rate <= rate)) ++ best_rate = tmp_rate; ++ ++ if (best_rate == rate) ++ break; ++ } ++ ++ *div = curdiv << CM_DIV_FRAC_BITS; ++ *prate = curdiv * best_rate; ++ ++ return best_rate; ++} ++ + 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; +@@ -1086,9 +1139,8 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, + 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); ++ rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate, ++ &div, &prate); + if (rate > best_rate && rate <= req->rate) { + best_parent = parent; + best_prate = prate; +@@ -1308,6 +1360,13 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, + if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0) + init.flags &= ~CLK_IS_CRITICAL; + ++ /* ++ * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate ++ * rate changes on at least of the parents. ++ */ ++ if (data->set_rate_parent) ++ init.flags |= CLK_SET_RATE_PARENT; ++ + if (data->is_vpu_clock) { + init.ops = &bcm2835_vpu_clock_clk_ops; + } else { +-- +2.1.4 + |