Skip to content

Commit 7cbb78a

Browse files
kholkbebarino
authored andcommitted
clk: qcom: rcg2: Stop hardcoding gfx3d pingpong parent numbers
The function clk_gfx3d_determine_rate is selecting different PLLs to manage the GFX3D clock source in a special way: this one needs to be ping-pong'ed on different PLLs to ensure stability during frequency switching (set a PLL rate, let it stabilize, switch the RCG to the new PLL) and fast frequency transitions. This technique is currently being used in the MSM8996 SoC and the function was assuming that the parents were always at a specific index in the parents list, which is TRUE, if we use this only on the MSM8996 MMCC. Unfortunately, MSM8996 is not the only SoC that needs to ping-pong the graphics RCG, so choices are: 1. Make new special ops just to hardcode *again* other indexes, creating code duplication for (imo) no reason; or 2. Generalize this function, so that it becomes usable for a range of SoCs with slightly different ping-pong configuration. In this commit, the second road was taken: define a new "special" struct clk_rcg2_gfx3d, containing the ordered list of parents to ping-pong the graphics clock on, and the "regular" rcg2 clock structure in order to generalize the clk_gfx3d_determine_rate function and make it working for other SoCs. As for the function itself it is left with the assumption that we need to ping-pong over three parents. The reasons for this are: 1. The initial model was MSM8996, which has 3 parents for the graphics clock pingpong; 2. The other example that was taken into consideration is the SDM630/636/660 SoC gpu clock controller, which is ping-ponging over two dynamic clocked and one fixed clock PLL. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org> Link: https://lore.kernel.org/r/20210113183817.447866-6-angelogioacchino.delregno@somainline.org [sboyd@kernel.org: Grow some local variables, drop do_div() usage in favor of plain division, we're not dealing with a u64 here] Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent 9502d48 commit 7cbb78a

2 files changed

Lines changed: 46 additions & 20 deletions

File tree

drivers/clk/qcom/clk-rcg.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ struct clk_rcg2 {
153153

154154
#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
155155

156+
struct clk_rcg2_gfx3d {
157+
u8 div;
158+
struct clk_rcg2 rcg;
159+
struct clk_hw **hws;
160+
};
161+
162+
#define to_clk_rcg2_gfx3d(_hw) \
163+
container_of(to_clk_rcg2(_hw), struct clk_rcg2_gfx3d, rcg)
164+
156165
extern const struct clk_ops clk_rcg2_ops;
157166
extern const struct clk_ops clk_rcg2_floor_ops;
158167
extern const struct clk_ops clk_edp_pixel_ops;

drivers/clk/qcom/clk-rcg2.c

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -728,60 +728,77 @@ static int clk_gfx3d_determine_rate(struct clk_hw *hw,
728728
struct clk_rate_request *req)
729729
{
730730
struct clk_rate_request parent_req = { };
731-
struct clk_hw *p2, *p8, *p9, *xo;
732-
unsigned long p9_rate;
731+
struct clk_rcg2_gfx3d *cgfx = to_clk_rcg2_gfx3d(hw);
732+
struct clk_hw *xo, *p0, *p1, *p2;
733+
unsigned long request, p0_rate;
733734
int ret;
734735

736+
p0 = cgfx->hws[0];
737+
p1 = cgfx->hws[1];
738+
p2 = cgfx->hws[2];
739+
/*
740+
* This function does ping-pong the RCG between PLLs: if we don't
741+
* have at least one fixed PLL and two variable ones,
742+
* then it's not going to work correctly.
743+
*/
744+
if (WARN_ON(!p0 || !p1 || !p2))
745+
return -EINVAL;
746+
735747
xo = clk_hw_get_parent_by_index(hw, 0);
736748
if (req->rate == clk_hw_get_rate(xo)) {
737749
req->best_parent_hw = xo;
738750
return 0;
739751
}
740752

741-
p9 = clk_hw_get_parent_by_index(hw, 2);
742-
p2 = clk_hw_get_parent_by_index(hw, 3);
743-
p8 = clk_hw_get_parent_by_index(hw, 4);
753+
request = req->rate;
754+
if (cgfx->div > 1)
755+
parent_req.rate = request = request * cgfx->div;
744756

745-
/* PLL9 is a fixed rate PLL */
746-
p9_rate = clk_hw_get_rate(p9);
757+
/* This has to be a fixed rate PLL */
758+
p0_rate = clk_hw_get_rate(p0);
747759

748-
parent_req.rate = req->rate = min(req->rate, p9_rate);
749-
if (req->rate == p9_rate) {
750-
req->rate = req->best_parent_rate = p9_rate;
751-
req->best_parent_hw = p9;
760+
if (request == p0_rate) {
761+
req->rate = req->best_parent_rate = p0_rate;
762+
req->best_parent_hw = p0;
752763
return 0;
753764
}
754765

755-
if (req->best_parent_hw == p9) {
766+
if (req->best_parent_hw == p0) {
756767
/* Are we going back to a previously used rate? */
757-
if (clk_hw_get_rate(p8) == req->rate)
758-
req->best_parent_hw = p8;
759-
else
768+
if (clk_hw_get_rate(p2) == request)
760769
req->best_parent_hw = p2;
761-
} else if (req->best_parent_hw == p8) {
762-
req->best_parent_hw = p2;
770+
else
771+
req->best_parent_hw = p1;
772+
} else if (req->best_parent_hw == p2) {
773+
req->best_parent_hw = p1;
763774
} else {
764-
req->best_parent_hw = p8;
775+
req->best_parent_hw = p2;
765776
}
766777

767778
ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
768779
if (ret)
769780
return ret;
770781

771782
req->rate = req->best_parent_rate = parent_req.rate;
783+
if (cgfx->div > 1)
784+
req->rate /= cgfx->div;
772785

773786
return 0;
774787
}
775788

776789
static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
777790
unsigned long parent_rate, u8 index)
778791
{
779-
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
792+
struct clk_rcg2_gfx3d *cgfx = to_clk_rcg2_gfx3d(hw);
793+
struct clk_rcg2 *rcg = &cgfx->rcg;
780794
u32 cfg;
781795
int ret;
782796

783-
/* Just mux it, we don't use the division or m/n hardware */
784797
cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
798+
/* On some targets, the GFX3D RCG may need to divide PLL frequency */
799+
if (cgfx->div > 1)
800+
cfg |= ((2 * cgfx->div) - 1) << CFG_SRC_DIV_SHIFT;
801+
785802
ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
786803
if (ret)
787804
return ret;

0 commit comments

Comments
 (0)