Merge branch 'CR_3049_Hibernation_mason.huo' into 'jh7110-5.15.y-devel'
[platform/kernel/linux-starfive.git] / drivers / clk / starfive / clk-starfive-jh7110-gen.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * StarFive JH7110 Clock Generator Driver
4  *
5  * Copyright (C) 2022 Xingyu Wu <xingyu.wu@starfivetech.com>
6  */
7
8 #include <linux/bits.h>
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
11 #include <linux/device.h>
12 #include <linux/init.h>
13 #include <linux/io.h>
14 #include <linux/kernel.h>
15 #include <linux/mod_devicetable.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/of_device.h>
19 #include <linux/pm_runtime.h>
20
21 #include <dt-bindings/clock/starfive-jh7110-clkgen.h>
22 #include "clk-starfive-jh7110.h"
23 #include "clk-starfive-jh7110-pll.h"
24
25 static struct jh7110_clk * __init jh7110_clk_from(struct clk_hw *hw)
26 {
27         return container_of(hw, struct jh7110_clk, hw);
28 }
29
30 static struct jh7110_clk_priv *jh7110_priv_from(struct jh7110_clk *clk)
31 {
32         return container_of(clk, struct jh7110_clk_priv, reg[clk->idx]);
33 }
34
35 void __iomem *jh7110_clk_reg_addr_get(struct jh7110_clk *clk)
36 {
37         void __iomem *reg;
38         struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
39
40         if (clk->reg_flags == JH7110_CLK_SYS_FLAG)
41                 reg = priv->sys_base + 4 * clk->idx;
42         else if (clk->reg_flags == JH7110_CLK_STG_FLAG)
43                 reg = priv->stg_base + 4 * (clk->idx - JH7110_CLK_SYS_REG_END);
44         else if (clk->reg_flags == JH7110_CLK_AON_FLAG)
45                 reg = priv->aon_base + 4 * (clk->idx - JH7110_CLK_STG_REG_END);
46         else if (clk->reg_flags == JH7110_CLK_VOUT_FLAG)
47                 reg = priv->vout_base + 4 * clk->idx;
48         else if (clk->reg_flags == JH7110_CLK_ISP_FLAG)
49                 reg = priv->isp_base + 4 * clk->idx;
50
51         return reg;
52 }
53
54 static u32 jh7110_clk_reg_get(struct jh7110_clk *clk)
55 {
56         void __iomem *reg = jh7110_clk_reg_addr_get(clk);
57
58         if ((clk->reg_flags == JH7110_CLK_ISP_FLAG) || (clk->reg_flags == JH7110_CLK_VOUT_FLAG)) {
59                 int ret;
60                 struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
61
62                 if (pm_runtime_suspended(priv->dev)) {
63                         ret = pm_runtime_get_sync(priv->dev);
64                         if (ret < 0) {
65                                 dev_err(priv->dev, "cannot resume device :%d.\n", ret);
66                                 return 0;
67                         }
68                         pm_runtime_put(priv->dev);
69                 }
70         }
71
72         return readl_relaxed(reg);
73 }
74
75 static void jh7110_clk_reg_rmw(struct jh7110_clk *clk, u32 mask, u32 value)
76 {
77         struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
78         void __iomem *reg = jh7110_clk_reg_addr_get(clk);
79         unsigned long flags;
80
81         spin_lock_irqsave(&priv->rmw_lock, flags);
82         if ((clk->idx == JH7110_UART3_CLK_CORE
83                 || clk->idx == JH7110_UART4_CLK_CORE
84                 || clk->idx == JH7110_UART5_CLK_CORE)
85                 && (value != JH7110_CLK_ENABLE))
86                 value  <<= 8;
87         value |= jh7110_clk_reg_get(clk) & ~mask;
88         writel_relaxed(value, reg);
89         spin_unlock_irqrestore(&priv->rmw_lock, flags);
90 }
91
92 static int jh7110_clk_enable(struct clk_hw *hw)
93 {
94         struct jh7110_clk *clk = jh7110_clk_from(hw);
95
96         jh7110_clk_reg_rmw(clk, JH7110_CLK_ENABLE, JH7110_CLK_ENABLE);
97         return 0;
98 }
99
100 static void jh7110_clk_disable(struct clk_hw *hw)
101 {
102         struct jh7110_clk *clk = jh7110_clk_from(hw);
103
104         jh7110_clk_reg_rmw(clk, JH7110_CLK_ENABLE, 0);
105 }
106
107 static int jh7110_clk_is_enabled(struct clk_hw *hw)
108 {
109         struct jh7110_clk *clk = jh7110_clk_from(hw);
110
111         return !!(jh7110_clk_reg_get(clk) & JH7110_CLK_ENABLE);
112 }
113
114 static unsigned long jh7110_clk_recalc_rate(struct clk_hw *hw,
115                                                 unsigned long parent_rate)
116 {
117         struct jh7110_clk *clk = jh7110_clk_from(hw);
118         u32 div = jh7110_clk_reg_get(clk) & JH7110_CLK_DIV_MASK;
119
120         if (clk->idx == JH7110_UART3_CLK_CORE
121                 || clk->idx == JH7110_UART4_CLK_CORE
122                 || clk->idx == JH7110_UART5_CLK_CORE)
123                 div = div >> 8;
124
125         return div ? parent_rate / div : 0;
126 }
127
128 static int jh7110_clk_determine_rate(struct clk_hw *hw,
129                                         struct clk_rate_request *req)
130 {
131         struct jh7110_clk *clk = jh7110_clk_from(hw);
132         unsigned long parent = req->best_parent_rate;
133         unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate);
134         unsigned long div = min_t(unsigned long,
135                                 DIV_ROUND_UP(parent, rate), clk->max_div);
136         unsigned long result = parent / div;
137
138         /*
139          * we want the result clamped by min_rate and max_rate if possible:
140          * case 1: div hits the max divider value, which means it's less than
141          * parent / rate, so the result is greater than rate and min_rate in
142          * particular. we can't do anything about result > max_rate because the
143          * divider doesn't go any further.
144          * case 2: div = DIV_ROUND_UP(parent, rate) which means the result is
145          * always lower or equal to rate and max_rate. however the result may
146          * turn out lower than min_rate, but then the next higher rate is fine:
147          *      div - 1 = ceil(parent / rate) - 1 < parent / rate
148          * and thus
149          *      min_rate <= rate < parent / (div - 1)
150          */
151         if (result < req->min_rate && div > 1)
152                 result = parent / (div - 1);
153
154         req->rate = result;
155         return 0;
156 }
157
158 static int jh7110_clk_set_rate(struct clk_hw *hw,
159                                 unsigned long rate,
160                                 unsigned long parent_rate)
161 {
162         struct jh7110_clk *clk = jh7110_clk_from(hw);
163         unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate),
164                                         1UL, (unsigned long)clk->max_div);
165
166         jh7110_clk_reg_rmw(clk, JH7110_CLK_DIV_MASK, div);
167         return 0;
168 }
169
170 static u8 jh7110_clk_get_parent(struct clk_hw *hw)
171 {
172         struct jh7110_clk *clk = jh7110_clk_from(hw);
173         u32 value = jh7110_clk_reg_get(clk);
174
175         return (value & JH7110_CLK_MUX_MASK) >> JH7110_CLK_MUX_SHIFT;
176 }
177
178 static int jh7110_clk_set_parent(struct clk_hw *hw, u8 index)
179 {
180         struct jh7110_clk *clk = jh7110_clk_from(hw);
181         u32 value = (u32)index << JH7110_CLK_MUX_SHIFT;
182
183         jh7110_clk_reg_rmw(clk, JH7110_CLK_MUX_MASK, value);
184         return 0;
185 }
186
187 static int jh7110_clk_mux_determine_rate(struct clk_hw *hw,
188                                          struct clk_rate_request *req)
189 {
190         return clk_mux_determine_rate_flags(hw, req, 0);
191 }
192
193 static int jh7110_clk_get_phase(struct clk_hw *hw)
194 {
195         struct jh7110_clk *clk = jh7110_clk_from(hw);
196         u32 value = jh7110_clk_reg_get(clk);
197
198         return (value & JH7110_CLK_INVERT) ? 180 : 0;
199 }
200
201 static int jh7110_clk_set_phase(struct clk_hw *hw, int degrees)
202 {
203         struct jh7110_clk *clk = jh7110_clk_from(hw);
204         u32 value;
205
206         if (degrees == 0)
207                 value = 0;
208         else if (degrees == 180)
209                 value = JH7110_CLK_INVERT;
210         else
211                 return -EINVAL;
212
213         jh7110_clk_reg_rmw(clk, JH7110_CLK_INVERT, value);
214         return 0;
215 }
216
217 #ifdef CONFIG_DEBUG_FS
218 static void jh7110_clk_debug_init(struct clk_hw *hw, struct dentry *dentry)
219 {
220         static const struct debugfs_reg32 jh7110_clk_reg = {
221                 .name = "CTRL",
222                 .offset = 0,
223         };
224         struct jh7110_clk *clk = jh7110_clk_from(hw);
225         struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
226         struct debugfs_regset32 *regset;
227
228         regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
229         if (!regset)
230                 return;
231
232         regset->regs = &jh7110_clk_reg;
233         regset->nregs = 1;
234         regset->base = jh7110_clk_reg_addr_get(clk);
235
236         debugfs_create_regset32("registers", 0400, dentry, regset);
237 }
238 #else
239 #define jh7110_clk_debug_init NULL
240 #endif
241
242 static const struct clk_ops jh7110_clk_gate_ops = {
243         .enable = jh7110_clk_enable,
244         .disable = jh7110_clk_disable,
245         .is_enabled = jh7110_clk_is_enabled,
246         .debug_init = jh7110_clk_debug_init,
247 };
248
249 static const struct clk_ops jh7110_clk_div_ops = {
250         .recalc_rate = jh7110_clk_recalc_rate,
251         .determine_rate = jh7110_clk_determine_rate,
252         .set_rate = jh7110_clk_set_rate,
253         .debug_init = jh7110_clk_debug_init,
254 };
255
256 static const struct clk_ops jh7110_clk_gdiv_ops = {
257         .enable = jh7110_clk_enable,
258         .disable = jh7110_clk_disable,
259         .is_enabled = jh7110_clk_is_enabled,
260         .recalc_rate = jh7110_clk_recalc_rate,
261         .determine_rate = jh7110_clk_determine_rate,
262         .set_rate = jh7110_clk_set_rate,
263         .debug_init = jh7110_clk_debug_init,
264 };
265
266 static const struct clk_ops jh7110_clk_mux_ops = {
267         .determine_rate = jh7110_clk_mux_determine_rate,
268         .set_parent = jh7110_clk_set_parent,
269         .get_parent = jh7110_clk_get_parent,
270         .debug_init = jh7110_clk_debug_init,
271 };
272
273 static const struct clk_ops jh7110_clk_gmux_ops = {
274         .enable = jh7110_clk_enable,
275         .disable = jh7110_clk_disable,
276         .is_enabled = jh7110_clk_is_enabled,
277         .determine_rate = jh7110_clk_mux_determine_rate,
278         .set_parent = jh7110_clk_set_parent,
279         .get_parent = jh7110_clk_get_parent,
280         .debug_init = jh7110_clk_debug_init,
281 };
282
283 static const struct clk_ops jh7110_clk_mdiv_ops = {
284         .recalc_rate = jh7110_clk_recalc_rate,
285         .determine_rate = jh7110_clk_determine_rate,
286         .get_parent = jh7110_clk_get_parent,
287         .set_parent = jh7110_clk_set_parent,
288         .set_rate = jh7110_clk_set_rate,
289         .debug_init = jh7110_clk_debug_init,
290 };
291
292 static const struct clk_ops jh7110_clk_gmd_ops = {
293         .enable = jh7110_clk_enable,
294         .disable = jh7110_clk_disable,
295         .is_enabled = jh7110_clk_is_enabled,
296         .recalc_rate = jh7110_clk_recalc_rate,
297         .determine_rate = jh7110_clk_determine_rate,
298         .get_parent = jh7110_clk_get_parent,
299         .set_parent = jh7110_clk_set_parent,
300         .set_rate = jh7110_clk_set_rate,
301         .debug_init = jh7110_clk_debug_init,
302 };
303
304 static const struct clk_ops jh7110_clk_inv_ops = {
305         .get_phase = jh7110_clk_get_phase,
306         .set_phase = jh7110_clk_set_phase,
307         .debug_init = jh7110_clk_debug_init,
308 };
309
310 const struct clk_ops *starfive_jh7110_clk_ops(u32 max)
311 {
312         const struct clk_ops *ops;
313
314         if (max & JH7110_CLK_DIV_MASK) {
315                 if (max & JH7110_CLK_MUX_MASK) {
316                         if (max & JH7110_CLK_ENABLE)
317                                 ops = &jh7110_clk_gmd_ops;
318                         else
319                                 ops = &jh7110_clk_mdiv_ops;
320                 } else if (max & JH7110_CLK_ENABLE)
321                         ops = &jh7110_clk_gdiv_ops;
322                 else
323                         ops = &jh7110_clk_div_ops;
324         } else if (max & JH7110_CLK_MUX_MASK) {
325                 if (max & JH7110_CLK_ENABLE)
326                         ops = &jh7110_clk_gmux_ops;
327                 else
328                         ops = &jh7110_clk_mux_ops;
329         } else if (max & JH7110_CLK_ENABLE)
330                 ops = &jh7110_clk_gate_ops;
331         else
332                 ops = &jh7110_clk_inv_ops;
333
334         return ops;
335 }
336 EXPORT_SYMBOL_GPL(starfive_jh7110_clk_ops);
337
338 static struct clk_hw *jh7110_clk_get(struct of_phandle_args *clkspec,
339                                                 void *data)
340 {
341         struct jh7110_clk_priv *priv = data;
342         unsigned int idx = clkspec->args[0];
343
344         if (idx < JH7110_PLL0_OUT)
345                 return &priv->reg[idx].hw;
346
347         if (idx < JH7110_CLK_END) {
348 #ifdef CONFIG_CLK_STARFIVE_JH7110_PLL
349                 if ((idx == JH7110_PLL0_OUT) || (idx == JH7110_PLL2_OUT))
350                         return &priv->pll_priv[PLL_OF(idx)].hw;
351 #endif
352                 return priv->pll[PLL_OF(idx)];
353         }
354
355         return ERR_PTR(-EINVAL);
356 }
357
358
359 static int __init clk_starfive_jh7110_probe(struct platform_device *pdev)
360 {
361         struct jh7110_clk_priv *priv;
362         int ret = 0;
363
364         priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg, JH7110_PLL0_OUT),
365                                         GFP_KERNEL);
366         if (!priv)
367                 return -ENOMEM;
368
369         spin_lock_init(&priv->rmw_lock);
370         priv->dev = &pdev->dev;
371
372 #ifdef CONFIG_CLK_STARFIVE_JH7110_PLL
373         ret = clk_starfive_jh7110_pll_init(pdev, priv->pll_priv);
374         if (ret)
375                 return ret;
376 #endif
377
378         ret = clk_starfive_jh7110_sys_init(pdev, priv);
379         if (ret)
380                 return ret;
381
382 /* set PLL0 default rate */
383 #ifdef CONFIG_CLK_STARFIVE_JH7110_PLL
384         if (PLL0_DEFAULT_FREQ) {
385                 struct clk *pll0_clk = priv->pll_priv[PLL0_INDEX].hw.clk;
386                 struct clk *cpu_root = priv->reg[JH7110_CPU_ROOT].hw.clk;
387                 struct clk *osc_clk = clk_get(&pdev->dev, "osc");
388
389                 if (IS_ERR(osc_clk))
390                         dev_err(&pdev->dev, "get osc_clk failed\n");
391
392                 if (PLL0_DEFAULT_FREQ >= PLL0_FREQ_1500_VALUE) {
393                         struct clk *cpu_core = priv->reg[JH7110_CPU_CORE].hw.clk;
394
395                         if (clk_set_rate(cpu_core, clk_get_rate(pll0_clk) / 2)) {
396                                 dev_err(&pdev->dev, "set cpu_core rate failed\n");
397                                 goto failed_set;
398                         }
399                 }
400
401                 if (clk_set_parent(cpu_root, osc_clk)) {
402                         dev_err(&pdev->dev, "set parent to osc_clk failed\n");
403                         goto failed_set;
404                 }
405
406                 if (clk_set_rate(pll0_clk, PLL0_DEFAULT_FREQ))
407                         dev_err(&pdev->dev, "set pll0 rate failed\n");
408
409                 if (clk_set_parent(cpu_root, pll0_clk))
410                         dev_err(&pdev->dev, "set parent to pll0_clk failed\n");
411
412 failed_set:
413                 clk_put(osc_clk);
414         }
415 #endif
416
417         ret = clk_starfive_jh7110_stg_init(pdev, priv);
418         if (ret)
419                 return ret;
420
421         ret = clk_starfive_jh7110_aon_init(pdev, priv);
422         if (ret)
423                 return ret;
424
425         ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_clk_get, priv);
426         if (ret)
427                 return ret;
428
429         dev_info(&pdev->dev, "starfive JH7110 clkgen init successfully.");
430         return 0;
431 }
432
433 static const struct of_device_id clk_starfive_jh7110_match[] = {
434         {.compatible = "starfive,jh7110-clkgen"},
435         { /* sentinel */ }
436 };
437
438 static struct platform_driver clk_starfive_jh7110_driver = {
439         .driver = {
440                 .name = "clk-starfive-jh7110",
441                 .of_match_table = clk_starfive_jh7110_match,
442         },
443 };
444 builtin_platform_driver_probe(clk_starfive_jh7110_driver,
445                         clk_starfive_jh7110_probe);
446
447 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
448 MODULE_DESCRIPTION("StarFive JH7110 sysgen clock driver");
449 MODULE_LICENSE("GPL");