printf: Remove unused 'bprintf'
[drm/drm-misc.git] / drivers / clk / sophgo / clk-cv18xx-pll.c
blob29e24098bf5f91cf70341ea9f3a2101081939efd
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
4 */
6 #include <linux/clk-provider.h>
7 #include <linux/io.h>
8 #include <linux/limits.h>
9 #include <linux/spinlock.h>
11 #include "clk-cv18xx-pll.h"
13 static inline struct cv1800_clk_pll *hw_to_cv1800_clk_pll(struct clk_hw *hw)
15 struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw);
17 return container_of(common, struct cv1800_clk_pll, common);
20 static unsigned long ipll_calc_rate(unsigned long parent_rate,
21 unsigned long pre_div_sel,
22 unsigned long div_sel,
23 unsigned long post_div_sel)
25 uint64_t rate = parent_rate;
27 rate *= div_sel;
28 do_div(rate, pre_div_sel * post_div_sel);
30 return rate;
33 static unsigned long ipll_recalc_rate(struct clk_hw *hw,
34 unsigned long parent_rate)
36 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
37 u32 value;
39 value = readl(pll->common.base + pll->pll_reg);
41 return ipll_calc_rate(parent_rate,
42 PLL_GET_PRE_DIV_SEL(value),
43 PLL_GET_DIV_SEL(value),
44 PLL_GET_POST_DIV_SEL(value));
47 static int ipll_find_rate(const struct cv1800_clk_pll_limit *limit,
48 unsigned long prate, unsigned long *rate,
49 u32 *value)
51 unsigned long best_rate = 0;
52 unsigned long trate = *rate;
53 unsigned long pre_div_sel = 0, div_sel = 0, post_div_sel = 0;
54 unsigned long pre, div, post;
55 u32 detected = *value;
56 unsigned long tmp;
58 for_each_pll_limit_range(pre, &limit->pre_div) {
59 for_each_pll_limit_range(div, &limit->div) {
60 for_each_pll_limit_range(post, &limit->post_div) {
61 tmp = ipll_calc_rate(prate, pre, div, post);
63 if (tmp > trate)
64 continue;
66 if ((trate - tmp) < (trate - best_rate)) {
67 best_rate = tmp;
68 pre_div_sel = pre;
69 div_sel = div;
70 post_div_sel = post;
76 if (best_rate) {
77 detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel);
78 detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel);
79 detected = PLL_SET_DIV_SEL(detected, div_sel);
80 *value = detected;
81 *rate = best_rate;
82 return 0;
85 return -EINVAL;
88 static int ipll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
90 u32 val;
91 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
93 return ipll_find_rate(pll->pll_limit, req->best_parent_rate,
94 &req->rate, &val);
97 static void pll_get_mode_ctrl(unsigned long div_sel,
98 bool (*mode_ctrl_check)(unsigned long,
99 unsigned long,
100 unsigned long),
101 const struct cv1800_clk_pll_limit *limit,
102 u32 *value)
104 unsigned long ictrl = 0, mode = 0;
105 u32 detected = *value;
107 for_each_pll_limit_range(mode, &limit->mode) {
108 for_each_pll_limit_range(ictrl, &limit->ictrl) {
109 if (mode_ctrl_check(div_sel, ictrl, mode)) {
110 detected = PLL_SET_SEL_MODE(detected, mode);
111 detected = PLL_SET_ICTRL(detected, ictrl);
112 *value = detected;
113 return;
119 static bool ipll_check_mode_ctrl_restrict(unsigned long div_sel,
120 unsigned long ictrl,
121 unsigned long mode)
123 unsigned long left_rest = 20 * div_sel;
124 unsigned long right_rest = 35 * div_sel;
125 unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2;
127 return test > left_rest && test <= right_rest;
130 static int ipll_set_rate(struct clk_hw *hw, unsigned long rate,
131 unsigned long parent_rate)
133 u32 regval, detected = 0;
134 unsigned long flags;
135 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
137 ipll_find_rate(pll->pll_limit, parent_rate, &rate, &detected);
138 pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected),
139 ipll_check_mode_ctrl_restrict,
140 pll->pll_limit, &detected);
142 spin_lock_irqsave(pll->common.lock, flags);
144 regval = readl(pll->common.base + pll->pll_reg);
145 regval = PLL_COPY_REG(regval, detected);
147 writel(regval, pll->common.base + pll->pll_reg);
149 spin_unlock_irqrestore(pll->common.lock, flags);
151 cv1800_clk_wait_for_lock(&pll->common, pll->pll_status.reg,
152 BIT(pll->pll_status.shift));
154 return 0;
157 static int pll_enable(struct clk_hw *hw)
159 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
161 return cv1800_clk_clearbit(&pll->common, &pll->pll_pwd);
164 static void pll_disable(struct clk_hw *hw)
166 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
168 cv1800_clk_setbit(&pll->common, &pll->pll_pwd);
171 static int pll_is_enable(struct clk_hw *hw)
173 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
175 return cv1800_clk_checkbit(&pll->common, &pll->pll_pwd) == 0;
178 const struct clk_ops cv1800_clk_ipll_ops = {
179 .disable = pll_disable,
180 .enable = pll_enable,
181 .is_enabled = pll_is_enable,
183 .recalc_rate = ipll_recalc_rate,
184 .determine_rate = ipll_determine_rate,
185 .set_rate = ipll_set_rate,
188 #define PLL_SYN_FACTOR_DOT_POS 26
189 #define PLL_SYN_FACTOR_MINIMUM ((4 << PLL_SYN_FACTOR_DOT_POS) + 1)
191 static bool fpll_is_factional_mode(struct cv1800_clk_pll *pll)
193 return cv1800_clk_checkbit(&pll->common, &pll->pll_syn->en);
196 static unsigned long fpll_calc_rate(unsigned long parent_rate,
197 unsigned long pre_div_sel,
198 unsigned long div_sel,
199 unsigned long post_div_sel,
200 unsigned long ssc_syn_set,
201 bool is_full_parent)
203 u64 dividend = parent_rate * div_sel;
204 u64 factor = ssc_syn_set * pre_div_sel * post_div_sel;
205 unsigned long rate;
207 dividend <<= PLL_SYN_FACTOR_DOT_POS - 1;
208 rate = div64_u64_rem(dividend, factor, &dividend);
210 if (is_full_parent) {
211 dividend <<= 1;
212 rate <<= 1;
215 rate += DIV64_U64_ROUND_CLOSEST(dividend, factor);
217 return rate;
220 static unsigned long fpll_recalc_rate(struct clk_hw *hw,
221 unsigned long parent_rate)
223 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
224 u32 value;
225 bool clk_full;
226 u32 syn_set;
228 if (!fpll_is_factional_mode(pll))
229 return ipll_recalc_rate(hw, parent_rate);
231 syn_set = readl(pll->common.base + pll->pll_syn->set);
233 if (syn_set == 0)
234 return 0;
236 clk_full = cv1800_clk_checkbit(&pll->common,
237 &pll->pll_syn->clk_half);
239 value = readl(pll->common.base + pll->pll_reg);
241 return fpll_calc_rate(parent_rate,
242 PLL_GET_PRE_DIV_SEL(value),
243 PLL_GET_DIV_SEL(value),
244 PLL_GET_POST_DIV_SEL(value),
245 syn_set, clk_full);
248 static unsigned long fpll_find_synthesizer(unsigned long parent,
249 unsigned long rate,
250 unsigned long pre_div,
251 unsigned long div,
252 unsigned long post_div,
253 bool is_full_parent,
254 u32 *ssc_syn_set)
256 u32 test_max = U32_MAX, test_min = PLL_SYN_FACTOR_MINIMUM;
257 unsigned long trate;
259 while (test_min < test_max) {
260 u32 tssc = (test_max + test_min) / 2;
262 trate = fpll_calc_rate(parent, pre_div, div, post_div,
263 tssc, is_full_parent);
265 if (trate == rate) {
266 test_min = tssc;
267 break;
270 if (trate > rate)
271 test_min = tssc + 1;
272 else
273 test_max = tssc - 1;
276 if (trate != 0)
277 *ssc_syn_set = test_min;
279 return trate;
282 static int fpll_find_rate(struct cv1800_clk_pll *pll,
283 const struct cv1800_clk_pll_limit *limit,
284 unsigned long prate,
285 unsigned long *rate,
286 u32 *value, u32 *ssc_syn_set)
288 unsigned long best_rate = 0;
289 unsigned long pre_div_sel = 0, div_sel = 0, post_div_sel = 0;
290 unsigned long pre, div, post;
291 unsigned long trate = *rate;
292 u32 detected = *value;
293 unsigned long tmp;
294 bool clk_full = cv1800_clk_checkbit(&pll->common,
295 &pll->pll_syn->clk_half);
297 for_each_pll_limit_range(pre, &limit->pre_div) {
298 for_each_pll_limit_range(post, &limit->post_div) {
299 for_each_pll_limit_range(div, &limit->div) {
300 tmp = fpll_find_synthesizer(prate, trate,
301 pre, div, post,
302 clk_full,
303 ssc_syn_set);
305 if ((trate - tmp) < (trate - best_rate)) {
306 best_rate = tmp;
307 pre_div_sel = pre;
308 div_sel = div;
309 post_div_sel = post;
315 if (best_rate) {
316 detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel);
317 detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel);
318 detected = PLL_SET_DIV_SEL(detected, div_sel);
319 *value = detected;
320 *rate = best_rate;
321 return 0;
324 return -EINVAL;
327 static int fpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
329 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
330 u32 val, ssc_syn_set;
332 if (!fpll_is_factional_mode(pll))
333 return ipll_determine_rate(hw, req);
335 fpll_find_rate(pll, &pll->pll_limit[2], req->best_parent_rate,
336 &req->rate, &val, &ssc_syn_set);
338 return 0;
341 static bool fpll_check_mode_ctrl_restrict(unsigned long div_sel,
342 unsigned long ictrl,
343 unsigned long mode)
345 unsigned long left_rest = 10 * div_sel;
346 unsigned long right_rest = 24 * div_sel;
347 unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2;
349 return test > left_rest && test <= right_rest;
352 static int fpll_set_rate(struct clk_hw *hw, unsigned long rate,
353 unsigned long parent_rate)
355 u32 regval;
356 u32 detected = 0, detected_ssc = 0;
357 unsigned long flags;
358 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
360 if (!fpll_is_factional_mode(pll))
361 return ipll_set_rate(hw, rate, parent_rate);
363 fpll_find_rate(pll, &pll->pll_limit[2], parent_rate,
364 &rate, &detected, &detected_ssc);
365 pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected),
366 fpll_check_mode_ctrl_restrict,
367 pll->pll_limit, &detected);
369 spin_lock_irqsave(pll->common.lock, flags);
371 writel(detected_ssc, pll->common.base + pll->pll_syn->set);
373 regval = readl(pll->common.base + pll->pll_reg);
374 regval = PLL_COPY_REG(regval, detected);
376 writel(regval, pll->common.base + pll->pll_reg);
378 spin_unlock_irqrestore(pll->common.lock, flags);
380 cv1800_clk_wait_for_lock(&pll->common, pll->pll_status.reg,
381 BIT(pll->pll_status.shift));
383 return 0;
386 static u8 fpll_get_parent(struct clk_hw *hw)
388 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
390 if (fpll_is_factional_mode(pll))
391 return 1;
393 return 0;
396 static int fpll_set_parent(struct clk_hw *hw, u8 index)
398 struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);
400 if (index)
401 cv1800_clk_setbit(&pll->common, &pll->pll_syn->en);
402 else
403 cv1800_clk_clearbit(&pll->common, &pll->pll_syn->en);
405 return 0;
408 const struct clk_ops cv1800_clk_fpll_ops = {
409 .disable = pll_disable,
410 .enable = pll_enable,
411 .is_enabled = pll_is_enable,
413 .recalc_rate = fpll_recalc_rate,
414 .determine_rate = fpll_determine_rate,
415 .set_rate = fpll_set_rate,
417 .set_parent = fpll_set_parent,
418 .get_parent = fpll_get_parent,