clk: qcom: Add support for gfx clock to ping pong PLLs
GFX3D clock source might require to ping pong between the available PLL sources, so add support to check the current source and switch the next PLL source for different frequency. Change-Id: Iaf98e4d18fc0c3deb75ccce53e1c09cfc9dde550 Signed-off-by: Taniya Das <tdas@codeaurora.org>
This commit is contained in:
parent
057bdafd97
commit
d3d0687504
2 changed files with 80 additions and 0 deletions
|
@ -23,6 +23,7 @@ struct freq_tbl {
|
|||
u8 pre_div;
|
||||
u16 m;
|
||||
u16 n;
|
||||
unsigned long src_freq;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -184,5 +185,6 @@ extern const struct clk_ops clk_byte_ops;
|
|||
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_gfx3d_src_ops;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
|
@ -865,3 +866,80 @@ const struct clk_ops clk_gfx3d_ops = {
|
|||
.determine_rate = clk_gfx3d_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
|
||||
|
||||
static int clk_gfx3d_src_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_rate_request parent_req = { };
|
||||
struct clk_hw *p1, *p3, *xo, *curr_p;
|
||||
const struct freq_tbl *f;
|
||||
int ret;
|
||||
|
||||
xo = clk_hw_get_parent_by_index(hw, 0);
|
||||
if (req->rate == clk_hw_get_rate(xo)) {
|
||||
req->best_parent_hw = xo;
|
||||
req->best_parent_rate = req->rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f = qcom_find_freq(rcg->freq_tbl, req->rate);
|
||||
if (!f || (req->rate != f->freq))
|
||||
return -EINVAL;
|
||||
|
||||
/* Indexes of source from the parent map */
|
||||
p1 = clk_hw_get_parent_by_index(hw, 1);
|
||||
p3 = clk_hw_get_parent_by_index(hw, 2);
|
||||
|
||||
curr_p = clk_hw_get_parent(hw);
|
||||
parent_req.rate = f->src_freq;
|
||||
|
||||
if (curr_p == xo || curr_p == p3)
|
||||
req->best_parent_hw = p1;
|
||||
else if (curr_p == p1)
|
||||
req->best_parent_hw = p3;
|
||||
|
||||
parent_req.best_parent_hw = req->best_parent_hw;
|
||||
|
||||
ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req->best_parent_rate = parent_req.rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_gfx3d_src_set_rate_and_parent(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate, u8 index)
|
||||
{
|
||||
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
|
||||
const struct freq_tbl *f;
|
||||
u32 cfg;
|
||||
int ret;
|
||||
|
||||
cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
|
||||
|
||||
f = qcom_find_freq(rcg->freq_tbl, rate);
|
||||
if (!f)
|
||||
return -EINVAL;
|
||||
|
||||
/* Update the RCG-DIV */
|
||||
cfg |= f->pre_div << CFG_SRC_DIV_SHIFT;
|
||||
|
||||
ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return update_config(rcg);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gfx3d_src_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,
|
||||
.set_rate = clk_gfx3d_set_rate,
|
||||
.set_rate_and_parent = clk_gfx3d_src_set_rate_and_parent,
|
||||
.determine_rate = clk_gfx3d_src_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gfx3d_src_ops);
|
||||
|
|
Loading…
Add table
Reference in a new issue