Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ced3220 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "clk: qcom: clk-branch: Add support for branch clocks rate aggregation" into msm-4.9

parents 72702a80 9caf899c
Loading
Loading
Loading
Loading
+92 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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,
};
+4 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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)