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

Commit eb448596 authored by David Collins's avatar David Collins
Browse files

clk: qcom: clk-rcg2: correct set rate handling for FORCE_ENABLE_RCG



Currently, if clk_set_rate() is called on a disabled clock that
has flags = FORCE_ENABLE_RCG, the rate is neither physically set
nor properly cached in software.  This means that when the clock
is later enabled, its rate will not be what was previously
requested.

Change the handling of FORCE_ENABLE_RCG so that all clk_set_rate()
calls are respected regardless of a clock's enable state.  In
doing so, ensure that FORCE_ENABLE_RCG and enable_safe_config are
supported both individually and together.

Implement the following behavior:

enable_safe_config == true:
enable   - configure the RCG according to the cached current_freq
disable  - configure the RCG for CXO (safe) source
set_rate - (if prepared) configure the RCG for the requested rate
           (if not prepared) cache the rate in current_freq

flags | FORCE_ENABLE_RCG:
enable   - set ROOT_EN=1 to force the RCG to be enabled
disable  - set ROOT_EN=0
set_rate - configure the RCG for the requested rate;
           if disabled, then set ROOT_EN=1 before the
           configuration is changed and ROOT_EN=0 after

enable_safe_config && (flags | FORCE_ENABLE_RCG):
enable   - set ROOT_EN=1 and configure the RCG according to the
           cached current_freq
disable  - configure the RCG for CXO source and set ROOT_EN=0
set_rate - (if prepared) configure the RCG for the requested rate
           (if not prepared) cache the rate in current_freq

Change-Id: Ib7442e4a4b572ae7c567929044410e09a9886c76
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent ecbdac2c
Loading
Loading
Loading
Loading
+46 −16
Original line number Diff line number Diff line
@@ -177,6 +177,16 @@ static int clk_rcg2_clear_force_enable(struct clk_hw *hw)
					CMD_ROOT_EN, 0);
}

static bool clk_rcg2_is_force_enabled(struct clk_hw *hw)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	u32 val = 0;

	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &val);

	return val & CMD_ROOT_EN;
}

static int prepare_enable_rcg_srcs(struct clk *curr, struct clk *new)
{
	int rc = 0;
@@ -249,6 +259,7 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	const struct freq_tbl *f_curr;
	u32 cfg, src, hid_div, m = 0, n = 0, mode = 0, mask;
	unsigned long rrate = 0;

	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
	src = cfg;
@@ -286,7 +297,16 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
		hid_div &= mask;
	}

	return calc_rate(parent_rate, m, n, mode, hid_div);
	rrate = calc_rate(parent_rate, m, n, mode, hid_div);

	/*
	 * Check to cover the case when the RCG has been initialized to a
	 * non-CXO frequency before the clock driver has taken control of it.
	 */
	if (rcg->enable_safe_config && !rcg->current_freq)
		rcg->current_freq = rrate;

	return rrate;
}

static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
@@ -494,6 +514,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
	const struct freq_tbl *f, *f_curr;
	int ret, curr_src_index, new_src_index;
	struct clk_hw *curr_src = NULL, *new_src = NULL;
	bool force_enabled = false;

	switch (policy) {
	case FLOOR:
@@ -545,6 +566,10 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,

		/* The RCG could currently be disabled. Enable its parents. */
		ret = prepare_enable_rcg_srcs(curr_src->clk, new_src->clk);
		if (ret)
			return ret;
		force_enabled = clk_rcg2_is_force_enabled(hw);
		if (!force_enabled)
			clk_rcg2_set_force_enable(hw);
	}

@@ -553,6 +578,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
		return ret;

	if (rcg->flags & FORCE_ENABLE_RCG) {
		if (!force_enabled)
			clk_rcg2_clear_force_enable(hw);
		disable_unprepare_rcg_srcs(curr_src->clk, new_src->clk);
	}
@@ -591,11 +617,10 @@ static int clk_rcg2_enable(struct clk_hw *hw)
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	unsigned long rate;
	const struct freq_tbl *f;
	int ret;

	if (rcg->flags & FORCE_ENABLE_RCG) {
	if (rcg->flags & FORCE_ENABLE_RCG)
		clk_rcg2_set_force_enable(hw);
		return 0;
	}

	if (!rcg->enable_safe_config)
		return 0;
@@ -622,24 +647,27 @@ static int clk_rcg2_enable(struct clk_hw *hw)
	if (rate == cxo_f.freq)
		f = &cxo_f;

	if (!(rcg->flags & FORCE_ENABLE_RCG))
		clk_rcg2_set_force_enable(hw);
	clk_rcg2_configure(rcg, f);

	ret = clk_rcg2_configure(rcg, f);

	if (!(rcg->flags & FORCE_ENABLE_RCG))
		clk_rcg2_clear_force_enable(hw);

	return 0;
	return ret;
}

static void clk_rcg2_disable(struct clk_hw *hw)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	int ret;

	if (rcg->flags & FORCE_ENABLE_RCG) {
	if (!rcg->enable_safe_config) {
		if (rcg->flags & FORCE_ENABLE_RCG)
			clk_rcg2_clear_force_enable(hw);
		return;
	}

	if (!rcg->enable_safe_config)
		return;
	/*
	 * Park the RCG at a safe configuration - sourced off the CXO. This is
	 * needed for 2 reasons: In the case of RCGs sourcing PSCBCs, due to a
@@ -657,7 +685,9 @@ static void clk_rcg2_disable(struct clk_hw *hw)
	 * online. Therefore, the RCG can safely be switched.
	 */
	clk_rcg2_set_force_enable(hw);
	clk_rcg2_configure(rcg, &cxo_f);
	ret = clk_rcg2_configure(rcg, &cxo_f);
	if (ret)
		pr_err("%s: CXO configuration failed\n", clk_hw_get_name(hw));
	clk_rcg2_clear_force_enable(hw);
}