Lines Matching +full:cpufreq +full:- +full:hw
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Based on clk-super.c
6 * Based on older tegra20-cpufreq driver by Colin Cross <ccross@google.com>
10 * Copyright (C) 2019 GRATE-DRIVER project
14 #include <linux/clk-provider.h>
33 static u8 cclk_super_get_parent(struct clk_hw *hw) in cclk_super_get_parent() argument
35 return tegra_clk_super_ops.get_parent(hw); in cclk_super_get_parent()
38 static int cclk_super_set_parent(struct clk_hw *hw, u8 index) in cclk_super_set_parent() argument
40 return tegra_clk_super_ops.set_parent(hw, index); in cclk_super_set_parent()
43 static int cclk_super_set_rate(struct clk_hw *hw, unsigned long rate, in cclk_super_set_rate() argument
46 return tegra_clk_super_ops.set_rate(hw, rate, parent_rate); in cclk_super_set_rate()
49 static unsigned long cclk_super_recalc_rate(struct clk_hw *hw, in cclk_super_recalc_rate() argument
52 struct tegra_clk_super_mux *super = to_clk_super_mux(hw); in cclk_super_recalc_rate()
53 u32 val = readl_relaxed(super->reg); in cclk_super_recalc_rate()
62 if (cclk_super_get_parent(hw) == PLLX_INDEX) in cclk_super_recalc_rate()
65 return tegra_clk_super_ops.recalc_rate(hw, parent_rate) >> div2; in cclk_super_recalc_rate()
68 static int cclk_super_determine_rate(struct clk_hw *hw, in cclk_super_determine_rate() argument
71 struct clk_hw *pllp_hw = clk_hw_get_parent_by_index(hw, PLLP_INDEX); in cclk_super_determine_rate()
72 struct clk_hw *pllx_hw = clk_hw_get_parent_by_index(hw, PLLX_INDEX); in cclk_super_determine_rate()
73 struct tegra_clk_super_mux *super = to_clk_super_mux(hw); in cclk_super_determine_rate()
75 long rate = req->rate; in cclk_super_determine_rate()
78 return -EINVAL; in cclk_super_determine_rate()
87 if (super->flags & TEGRA20_SUPER_CLK) in cclk_super_determine_rate()
91 .rate = req->rate, in cclk_super_determine_rate()
95 clk_hw_get_rate_range(hw, &parent.min_rate, in cclk_super_determine_rate()
97 tegra_clk_super_ops.determine_rate(hw, &parent); in cclk_super_determine_rate()
102 req->best_parent_rate = pllp_rate; in cclk_super_determine_rate()
103 req->best_parent_hw = pllp_hw; in cclk_super_determine_rate()
104 req->rate = rate; in cclk_super_determine_rate()
107 req->best_parent_rate = rate; in cclk_super_determine_rate()
108 req->best_parent_hw = pllx_hw; in cclk_super_determine_rate()
109 req->rate = rate; in cclk_super_determine_rate()
113 return -EINVAL; in cclk_super_determine_rate()
143 return ERR_PTR(-EBUSY); in tegra_clk_register_super_cclk()
147 return ERR_PTR(-ENOMEM); in tegra_clk_register_super_cclk()
154 super->reg = reg; in tegra_clk_register_super_cclk()
155 super->lock = lock; in tegra_clk_register_super_cclk()
156 super->width = 4; in tegra_clk_register_super_cclk()
157 super->flags = clk_super_flags; in tegra_clk_register_super_cclk()
158 super->hw.init = &init; in tegra_clk_register_super_cclk()
160 if (super->flags & TEGRA20_SUPER_CLK) { in tegra_clk_register_super_cclk()
165 super->frac_div.reg = reg + 4; in tegra_clk_register_super_cclk()
166 super->frac_div.shift = 16; in tegra_clk_register_super_cclk()
167 super->frac_div.width = 8; in tegra_clk_register_super_cclk()
168 super->frac_div.frac_width = 1; in tegra_clk_register_super_cclk()
169 super->frac_div.lock = lock; in tegra_clk_register_super_cclk()
170 super->div_ops = &tegra_clk_frac_div_ops; in tegra_clk_register_super_cclk()
176 * +---+ +-------+ +-+ +-+ +-+ in tegra_clk_register_super_cclk()
177 * PLLP+->+ +->+DIVIDER+->+0| +-------->+0| ------------->+0| in tegra_clk_register_super_cclk()
178 * | | +-------+ | | | +---+ | | | | | in tegra_clk_register_super_cclk()
179 * PLLC+->+MUX| | +->+ | S | | +->+ | +->+CPU in tegra_clk_register_super_cclk()
180 * ... | | | | | | K | | | | +-------+ | | in tegra_clk_register_super_cclk()
181 * PLLX+->+-->+------------>+1| +->+ I +->+1| +->+ DIV2 +->+1| in tegra_clk_register_super_cclk()
182 * +---+ +++ | P | +++ |SKIPPER| +++ in tegra_clk_register_super_cclk()
183 * ^ | P | ^ +-------+ ^ in tegra_clk_register_super_cclk()
185 * PLLX_SEL+--+ | R | | OVERHEAT+--+ in tegra_clk_register_super_cclk()
186 * +---+ | in tegra_clk_register_super_cclk()
188 * SUPER_CDIV_ENB+--+ in tegra_clk_register_super_cclk()
193 * At least for now we're not going to use clock-skipper, hence let's in tegra_clk_register_super_cclk()
200 clk = clk_register(NULL, &super->hw); in tegra_clk_register_super_cclk()
212 return -EINVAL; in tegra_cclk_pre_pllx_rate_change()
214 if (cclk_super_get_parent(&cclk_super->hw) == PLLX_INDEX) in tegra_cclk_pre_pllx_rate_change()
220 * CPU needs to be temporarily re-parented away from PLLX if PLLX in tegra_cclk_pre_pllx_rate_change()
224 cclk_super_set_parent(&cclk_super->hw, PLLP_INDEX); in tegra_cclk_pre_pllx_rate_change()
232 cclk_super_set_parent(&cclk_super->hw, PLLX_INDEX); in tegra_cclk_post_pllx_rate_change()