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

Commit 2b7927ed authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "clk: qcom: gcc: update the RCG before PLL for ope clock"

parents 35326f11 bae70990
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,
+7 −4
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@
static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner);
static DEFINE_VDD_REGULATORS(vdd_mx, VDD_NUM, 1, vdd_corner);

#define F_SLEW(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) }

enum {
	P_BI_TCXO,
	P_CORE_BI_PLL_TEST_SE,
@@ -1018,10 +1020,10 @@ static struct clk_rcg2 gcc_camss_ope_ahb_clk_src = {

static const struct freq_tbl ftbl_gcc_camss_ope_clk_src[] = {
	F(19200000, P_BI_TCXO, 1, 0, 0),
	F(200000000, P_GPLL8_OUT_MAIN, 2, 0, 0),
	F(266600000, P_GPLL8_OUT_MAIN, 1, 0, 0),
	F(465000000, P_GPLL8_OUT_MAIN, 1, 0, 0),
	F(580000000, P_GPLL8_OUT_EARLY, 1, 0, 0),
	F_SLEW(200000000, P_GPLL8_OUT_MAIN, 2, 0, 0, 800000000),
	F_SLEW(266600000, P_GPLL8_OUT_MAIN, 1, 0, 0, 533200000),
	F_SLEW(465000000, P_GPLL8_OUT_MAIN, 1, 0, 0, 930000000),
	F_SLEW(580000000, P_GPLL8_OUT_EARLY, 1, 0, 0, 580000000),
	{ }
};

@@ -1032,6 +1034,7 @@ static struct clk_rcg2 gcc_camss_ope_clk_src = {
	.parent_map = gcc_parent_map_6,
	.freq_tbl = ftbl_gcc_camss_ope_clk_src,
	.enable_safe_config = true,
	.flags = RCG_UPDATE_BEFORE_PLL,
	.clkr.hw.init = &(struct clk_init_data){
		.name = "gcc_camss_ope_clk_src",
		.parent_names = gcc_parent_names_6,