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

Commit 0e1c06b8 authored by Amit Nischal's avatar Amit Nischal Committed by Gerrit - the friendly Code Review server
Browse files

clk: qcom: Add clk_ops to support runtime frequencies for esc clock



Some of the display panels requires multiple clock frequencies
to be derived runtime from the sources for its operation.
Add support for the same by adding esc clk_ops to calculate
the desired divider at run time for accuracy.

Change-Id: Ie3ec84bb1927f5313c887344368dceffb06035be
Signed-off-by: default avatarAmit Nischal <anischal@codeaurora.org>
parent 202aa1fb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
@@ -185,6 +185,7 @@ extern const struct clk_ops clk_byte2_ops;
extern const struct clk_ops clk_pixel_ops;
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_dp_ops;
extern const struct clk_ops clk_esc_ops;

extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk,
				struct device *dev, u8 rcg_flags);
+70 −0
Original line number Diff line number Diff line
@@ -1191,6 +1191,76 @@ const struct clk_ops clk_gfx3d_ops = {
};
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);

static int clk_esc_determine_rate(struct clk_hw *hw,
				    struct clk_rate_request *req)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	unsigned long parent_rate, div;
	u32 mask = BIT(rcg->hid_width) - 1;
	struct clk_hw *p;
	unsigned long rate = req->rate;

	if (rate == 0)
		return -EINVAL;

	p = req->best_parent_hw;
	req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate);

	div = ((2 * parent_rate) / rate) - 1;
	div = min_t(u32, div, mask);

	req->rate = clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div);

	return 0;
}

static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate,
			 unsigned long parent_rate)
{
	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
	struct freq_tbl f = { 0 };
	unsigned long div;
	int i, num_parents = clk_hw_get_num_parents(hw);
	u32 mask = BIT(rcg->hid_width) - 1;
	u32 cfg;

	div = ((2 * parent_rate) / rate) - 1;
	div = min_t(u32, div, mask);

	f.pre_div = div;

	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
	cfg &= CFG_SRC_SEL_MASK;
	cfg >>= CFG_SRC_SEL_SHIFT;

	for (i = 0; i < num_parents; i++) {
		if (cfg == rcg->parent_map[i].cfg) {
			f.src = rcg->parent_map[i].src;
			return clk_rcg2_configure(rcg, &f);
		}
	}

	return -EINVAL;
}

static int clk_esc_set_rate_and_parent(struct clk_hw *hw,
		unsigned long rate, unsigned long parent_rate, u8 index)
{
	return clk_esc_set_rate(hw, rate, parent_rate);
}

const struct clk_ops clk_esc_ops = {
	.is_enabled = clk_rcg2_is_enabled,
	.get_parent = clk_rcg2_get_parent,
	.set_parent = clk_rcg2_set_parent,
	.recalc_rate = clk_rcg2_recalc_rate,
	.determine_rate = clk_esc_determine_rate,
	.set_rate = clk_esc_set_rate,
	.set_rate_and_parent = clk_esc_set_rate_and_parent,
	.list_registers = clk_rcg2_list_registers,
};
EXPORT_SYMBOL(clk_esc_ops);

/* Common APIs to be used for DFS based RCGR */
static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset,
		u32 *mode, u32 *pre_div)