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

Commit d2725470 authored by Taniya Das's avatar Taniya Das
Browse files

clk: qcom: clk-rcg2: Support update of RCG src/prediv



In the cases where RCG sources would support a slewing
parent and during a frequency switch if the new desired pre-div is
greater than the current pre-div then the RCG pre-div should be updated
before the slewing PLL source is updated.

There also could be a condition where the slewing parent alternate
outputs are used between different frequencies and in those conditions
if the new desired PLL frequency is greater than the current PLL
frequency the RCG source requires to be updated before the PLL rate
change.

Change-Id: I44ebca6f87ed9c99e5a324326995d18d3bd183d1
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
parent e3e20132
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ struct clk_rcg2 {
	u8			flags;
#define FORCE_ENABLE_RCG	BIT(0)
#define HW_CLK_CTRL_MODE	BIT(1)
#define RCG_UPDATE_BEFORE_PLL	BIT(2)
};

#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
+87 −15
Original line number Diff line number Diff line
@@ -258,9 +258,16 @@ static unsigned long
clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	struct clk_hw *parent = clk_hw_get_parent(hw);
	const struct freq_tbl *f_curr;
	u32 cfg, src, hid_div, m = 0, n = 0, mode = 0, mask;
	unsigned long rrate = 0;
	unsigned long rrate = 0, prate;

	if (rcg->flags & RCG_UPDATE_BEFORE_PLL) {
		prate =  clk_hw_get_rate(parent);
		if (prate != parent_rate)
			parent_rate = prate;
	}

	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
	src = cfg;
@@ -310,12 +317,81 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
	return rrate;
}

static int _determine_parent_and_update_div(struct clk_hw *hw,
		const struct freq_tbl *f, struct clk_hw *parent)
{
	struct clk_hw *curr_parent, *next_parent;
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	const struct freq_tbl *f_curr;
	bool update_rcg = false;
	u32 old_cfg, cfg, mask, regval;
	int ret, curr_src_index, next_src_index;

	/* Get the current parent for the current frequency */
	f_curr = qcom_find_freq(rcg->freq_tbl, rcg->current_freq);
	if (!f_curr)
		return -EINVAL;

	curr_src_index = qcom_find_src_index(hw, rcg->parent_map, f_curr->src);
	if (curr_src_index < 0)
		return curr_src_index;

	curr_parent = clk_hw_get_parent_by_index(hw, curr_src_index);
	if (!curr_parent)
		return -EINVAL;

	next_parent = parent;
	next_src_index = qcom_find_src_index(hw, rcg->parent_map, f->src);
	if (next_src_index < 0)
		return next_src_index;

	/* Slew PLL and  no update in RCG is required. */
	if ((curr_parent == next_parent) && (f->pre_div == f_curr->pre_div))
		return 0;

	if (curr_parent == next_parent || curr_parent != next_parent) {
		/* Read back the old configuration */
		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
				&old_cfg);

		if (f->pre_div > f_curr->pre_div) {
			mask = BIT(rcg->hid_width) - 1;
			cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
			update_rcg = true;
		}

		if (f_curr->src_freq < f->src_freq) {
			mask = CFG_SRC_SEL_MASK;
			cfg = (rcg->parent_map[next_src_index].cfg <<
					CFG_SRC_SEL_SHIFT);
			update_rcg = true;
		}

		if (!update_rcg)
			return 0;

		ret = regmap_update_bits(rcg->clkr.regmap,
				rcg->cmd_rcgr + CFG_REG, mask, cfg);
		if (ret) {
			pr_err("Failed to regmap update cfg\n");
			return ret;
		}

		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &regval);

		ret = update_config(rcg, old_cfg);
		if (ret)
			pr_err("Failed to update pre_div in determine rate\n");
	}

	return ret;
}

static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
				    struct clk_rate_request *req,
				    enum freq_policy policy)
{
	unsigned long clk_flags, rate = req->rate;
	struct clk_rate_request parent_req = { };
	struct clk_hw *p;
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	int index, ret = 0;
@@ -365,22 +441,18 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
	req->best_parent_rate = rate;
	req->rate = f->freq;

	if (f->src_freq != FIXED_FREQ_SRC) {
		rate = parent_req.rate = f->src_freq;
		parent_req.best_parent_hw = p;
		ret = __clk_determine_rate(p, &parent_req);
		if (ret)
			return ret;
	if ((rcg->flags & RCG_UPDATE_BEFORE_PLL) &&
			(clk_flags & CLK_SET_RATE_PARENT)) {

		ret = clk_set_rate(p->clk, parent_req.rate);
		if (ret) {
			pr_err("Failed set rate(%lu) on parent for non-fixed source\n",
							parent_req.rate);
			return ret;
		}
		if (!f->src_freq)
			return 0;

		ret = _determine_parent_and_update_div(hw, f, p);
		if (ret)
			pr_err("Failed to update the div value\n");
	}

	return 0;
	return ret;
}

static int clk_rcg2_determine_rate(struct clk_hw *hw,