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

Commit f4a5a62a authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes I3a3a03f8,Iabed22d4 into msm-next

* changes:
  clk: Check for failure at clk_change_rate
  clk: qcom: clk-branch: Add support for branch clocks rate aggregation
parents 27216f2f b04fed9f
Loading
Loading
Loading
Loading
+30 −9
Original line number Diff line number Diff line
@@ -1488,7 +1488,7 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *core,
 * walk down a subtree and set the new rates notifying the rate
 * change on the way
 */
static void clk_change_rate(struct clk_core *core)
static int clk_change_rate(struct clk_core *core)
{
	struct clk_core *child;
	struct hlist_node *tmp;
@@ -1497,6 +1497,7 @@ static void clk_change_rate(struct clk_core *core)
	bool skip_set_rate = false;
	struct clk_core *old_parent;
	struct clk_core *parent = NULL;
	int rc = 0;

	old_rate = core->rate;

@@ -1539,8 +1540,13 @@ static void clk_change_rate(struct clk_core *core)

	trace_clk_set_rate(core, core->new_rate);

	if (!skip_set_rate && core->ops->set_rate)
		core->ops->set_rate(core->hw, core->new_rate, best_parent_rate);
	if (!skip_set_rate && core->ops->set_rate) {
		rc = core->ops->set_rate(core->hw, core->new_rate,
						best_parent_rate);
		if (rc)
			goto out;

	}

	trace_clk_set_rate_complete(core, core->new_rate);

@@ -1572,12 +1578,20 @@ static void clk_change_rate(struct clk_core *core)
		/* Skip children who will be reparented to another clock */
		if (child->new_parent && child->new_parent != core)
			continue;
		clk_change_rate(child);
		rc = clk_change_rate(child);
		if (rc)
			return rc;
	}

	/* handle the new child who might not be in core->children yet */
	if (core->new_child)
		clk_change_rate(core->new_child);
		rc = clk_change_rate(core->new_child);

	return rc;
out:
	trace_clk_set_rate_complete(core, core->new_rate);

	return rc;
}

static int clk_core_set_rate_nolock(struct clk_core *core,
@@ -1585,6 +1599,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
{
	struct clk_core *top, *fail_clk;
	unsigned long rate = req_rate;
	int ret = 0;

	if (!core)
		return 0;
@@ -1604,18 +1619,24 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
	/* notify that we are about to change rates */
	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
	if (fail_clk) {
		pr_debug("%s: failed to set %s rate\n", __func__,
				fail_clk->name);
		pr_debug("%s: failed to set %s clock to run at %lu\n", __func__,
				fail_clk->name, req_rate);
		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
		return -EBUSY;
	}

	/* change the rates */
	clk_change_rate(top);
	ret = clk_change_rate(top);
	if (ret) {
		pr_err("%s: failed to set %s clock to run at %lu\n", __func__,
				top->name, req_rate);
		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
		return ret;
	}

	core->req_rate = req_rate;

	return 0;
	return ret;
}

/**
+117 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/clk/qcom.h>
@@ -182,20 +183,136 @@ 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) {
			pr_err("Failed to scale %s to %lu\n",
				clk_hw_get_name(parent), new_rate);
			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);
	unsigned long rrate = 0;

	if (!parent)
		return -EPERM;

	rrate = clk_hw_round_rate(parent, rate);
	/*
	 * If the rounded rate that's returned is valid, update the parent_rate
	 * field so that the set_rate() call can be propagated to the parent.
	 */
	if (rrate > 0)
		*parent_rate = rrate;
	else
		pr_warn("Failed to get the parent's (%s) rounded rate\n",
					clk_hw_get_name(parent));

	return rrate;
}

static unsigned long clk_branch2_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	return to_clk_branch(hw)->rate;
}

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;

	if (!parent)
		return -EPERM;

	/*
	 * 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) {
				pr_err("Failed to scale %s to %lu\n",
					clk_hw_get_name(parent), branch_rate);
				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 (!parent)
		return;

	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,
};
EXPORT_SYMBOL_GPL(clk_branch2_ops);
+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)