Loading drivers/clk/qcom/clk-branch.c +92 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,53 @@ const struct clk_ops clk_branch_ops = { }; EXPORT_SYMBOL_GPL(clk_branch_ops); static int clk_branch2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_branch *branch = to_clk_branch(hw); struct clk_hw *parent = clk_hw_get_parent(hw); unsigned long curr_rate, new_rate, other_rate = 0; int ret = 0; if (!parent) return -EPERM; if (!branch->aggr_sibling_rates || !clk_hw_is_prepared(hw)) { branch->rate = rate; return 0; } other_rate = clk_aggregate_rate(hw, parent->core); curr_rate = max(other_rate, branch->rate); new_rate = max(other_rate, rate); if (new_rate != curr_rate) { ret = clk_set_rate(parent->clk, new_rate); if (ret) goto err; } branch->rate = rate; err: return ret; } static long clk_branch2_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { struct clk_hw *parent = clk_hw_get_parent(hw); if (!parent) return -EPERM; return clk_hw_round_rate(parent, rate); } static unsigned long clk_branch2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { return to_clk_branch(hw)->rate; } static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw) { struct clk_branch *br = to_clk_branch(hw); Loading Loading @@ -226,15 +273,60 @@ static int clk_branch2_enable(struct clk_hw *hw) return clk_branch_toggle(hw, true, clk_branch2_check_halt); } static int clk_branch2_prepare(struct clk_hw *hw) { struct clk_branch *branch = to_clk_branch(hw); struct clk_hw *parent = clk_hw_get_parent(hw); unsigned long curr_rate, branch_rate = branch->rate; int ret = 0; /* * Do the rate aggregation and scaling of the RCG in the prepare/ * unprepare functions to avoid potential RPM(/h) communication due to * votes on the voltage rails. */ if (branch->aggr_sibling_rates) { curr_rate = clk_aggregate_rate(hw, parent->core); if (branch_rate > curr_rate) { ret = clk_set_rate(parent->clk, branch_rate); if (ret) goto exit; } } exit: return ret; } static void clk_branch2_disable(struct clk_hw *hw) { clk_branch_toggle(hw, false, clk_branch2_check_halt); } static void clk_branch2_unprepare(struct clk_hw *hw) { struct clk_branch *branch = to_clk_branch(hw); struct clk_hw *parent = clk_hw_get_parent(hw); unsigned long curr_rate, new_rate, branch_rate = branch->rate; if (branch->aggr_sibling_rates) { new_rate = clk_aggregate_rate(hw, parent->core); curr_rate = max(new_rate, branch_rate); if (new_rate < curr_rate) if (clk_set_rate(parent->clk, new_rate)) pr_err("Failed to scale %s to %lu\n", clk_hw_get_name(parent), new_rate); } } const struct clk_ops clk_branch2_ops = { .prepare = clk_branch2_prepare, .enable = clk_branch2_enable, .unprepare = clk_branch2_unprepare, .disable = clk_branch2_disable, .is_enabled = clk_is_enabled_regmap, .set_rate = clk_branch2_set_rate, .round_rate = clk_branch2_round_rate, .recalc_rate = clk_branch2_recalc_rate, .set_flags = clk_branch_set_flags, .list_registers = clk_branch2_list_registers, }; Loading drivers/clk/qcom/clk-branch.h +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ * @halt_reg: halt register * @halt_bit: ANDed with @halt_reg to test for clock halted * @halt_check: type of halt checking to perform * @aggr_sibling_rates: set if the branch clock's parent needs to be scaled * based on an aggregation of its siblings votes. * @clkr: handle between common and hardware-specific interfaces * * Clock which can gate its output. Loading @@ -36,6 +38,8 @@ struct clk_branch { u8 hwcg_bit; u8 halt_bit; u8 halt_check; bool aggr_sibling_rates; unsigned long rate; #define BRANCH_VOTED BIT(7) /* Delay on disable */ #define BRANCH_HALT 0 /* pol: 1 = halt */ #define BRANCH_HALT_VOTED (BRANCH_HALT | BRANCH_VOTED) Loading Loading
drivers/clk/qcom/clk-branch.c +92 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,53 @@ const struct clk_ops clk_branch_ops = { }; EXPORT_SYMBOL_GPL(clk_branch_ops); static int clk_branch2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_branch *branch = to_clk_branch(hw); struct clk_hw *parent = clk_hw_get_parent(hw); unsigned long curr_rate, new_rate, other_rate = 0; int ret = 0; if (!parent) return -EPERM; if (!branch->aggr_sibling_rates || !clk_hw_is_prepared(hw)) { branch->rate = rate; return 0; } other_rate = clk_aggregate_rate(hw, parent->core); curr_rate = max(other_rate, branch->rate); new_rate = max(other_rate, rate); if (new_rate != curr_rate) { ret = clk_set_rate(parent->clk, new_rate); if (ret) goto err; } branch->rate = rate; err: return ret; } static long clk_branch2_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { struct clk_hw *parent = clk_hw_get_parent(hw); if (!parent) return -EPERM; return clk_hw_round_rate(parent, rate); } static unsigned long clk_branch2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { return to_clk_branch(hw)->rate; } static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw) { struct clk_branch *br = to_clk_branch(hw); Loading Loading @@ -226,15 +273,60 @@ static int clk_branch2_enable(struct clk_hw *hw) return clk_branch_toggle(hw, true, clk_branch2_check_halt); } static int clk_branch2_prepare(struct clk_hw *hw) { struct clk_branch *branch = to_clk_branch(hw); struct clk_hw *parent = clk_hw_get_parent(hw); unsigned long curr_rate, branch_rate = branch->rate; int ret = 0; /* * Do the rate aggregation and scaling of the RCG in the prepare/ * unprepare functions to avoid potential RPM(/h) communication due to * votes on the voltage rails. */ if (branch->aggr_sibling_rates) { curr_rate = clk_aggregate_rate(hw, parent->core); if (branch_rate > curr_rate) { ret = clk_set_rate(parent->clk, branch_rate); if (ret) goto exit; } } exit: return ret; } static void clk_branch2_disable(struct clk_hw *hw) { clk_branch_toggle(hw, false, clk_branch2_check_halt); } static void clk_branch2_unprepare(struct clk_hw *hw) { struct clk_branch *branch = to_clk_branch(hw); struct clk_hw *parent = clk_hw_get_parent(hw); unsigned long curr_rate, new_rate, branch_rate = branch->rate; if (branch->aggr_sibling_rates) { new_rate = clk_aggregate_rate(hw, parent->core); curr_rate = max(new_rate, branch_rate); if (new_rate < curr_rate) if (clk_set_rate(parent->clk, new_rate)) pr_err("Failed to scale %s to %lu\n", clk_hw_get_name(parent), new_rate); } } const struct clk_ops clk_branch2_ops = { .prepare = clk_branch2_prepare, .enable = clk_branch2_enable, .unprepare = clk_branch2_unprepare, .disable = clk_branch2_disable, .is_enabled = clk_is_enabled_regmap, .set_rate = clk_branch2_set_rate, .round_rate = clk_branch2_round_rate, .recalc_rate = clk_branch2_recalc_rate, .set_flags = clk_branch_set_flags, .list_registers = clk_branch2_list_registers, }; Loading
drivers/clk/qcom/clk-branch.h +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ * @halt_reg: halt register * @halt_bit: ANDed with @halt_reg to test for clock halted * @halt_check: type of halt checking to perform * @aggr_sibling_rates: set if the branch clock's parent needs to be scaled * based on an aggregation of its siblings votes. * @clkr: handle between common and hardware-specific interfaces * * Clock which can gate its output. Loading @@ -36,6 +38,8 @@ struct clk_branch { u8 hwcg_bit; u8 halt_bit; u8 halt_check; bool aggr_sibling_rates; unsigned long rate; #define BRANCH_VOTED BIT(7) /* Delay on disable */ #define BRANCH_HALT 0 /* pol: 1 = halt */ #define BRANCH_HALT_VOTED (BRANCH_HALT | BRANCH_VOTED) Loading