starfive: refresh patches
[openwrt/staging/981213.git] / target / linux / starfive / patches-6.1 / 0032-clk-starfive-Add-StarFive-JH7110-PLL-clock-driver.patch
1 From 0bc7aa28dcdee75a52b1874a02dfbf0107c2d448 Mon Sep 17 00:00:00 2001
2 From: Xingyu Wu <xingyu.wu@starfivetech.com>
3 Date: Fri, 17 Feb 2023 17:30:09 +0800
4 Subject: [PATCH 032/122] clk: starfive: Add StarFive JH7110 PLL clock driver
5
6 Add driver for the StarFive JH7110 PLL clock controller
7 and they work by reading and setting syscon registers.
8
9 Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
10 ---
11 MAINTAINERS | 6 +
12 drivers/clk/starfive/Kconfig | 8 +
13 drivers/clk/starfive/Makefile | 1 +
14 .../clk/starfive/clk-starfive-jh7110-pll.c | 427 ++++++++++++++++++
15 .../clk/starfive/clk-starfive-jh7110-pll.h | 293 ++++++++++++
16 5 files changed, 735 insertions(+)
17 create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.c
18 create mode 100644 drivers/clk/starfive/clk-starfive-jh7110-pll.h
19
20 --- a/MAINTAINERS
21 +++ b/MAINTAINERS
22 @@ -19657,6 +19657,12 @@ M: Emil Renner Berthing <kernel@esmil.dk
23 S: Maintained
24 F: arch/riscv/boot/dts/starfive/
25
26 +STARFIVE JH7110 PLL CLOCK DRIVER
27 +M: Xingyu Wu <xingyu.wu@starfivetech.com>
28 +S: Supported
29 +F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
30 +F: drivers/clk/starfive/clk-starfive-jh7110-pll.*
31 +
32 STARFIVE JH71X0 CLOCK DRIVERS
33 M: Emil Renner Berthing <kernel@esmil.dk>
34 M: Hal Feng <hal.feng@starfivetech.com>
35 --- a/drivers/clk/starfive/Kconfig
36 +++ b/drivers/clk/starfive/Kconfig
37 @@ -21,6 +21,14 @@ config CLK_STARFIVE_JH7100_AUDIO
38 Say Y or M here to support the audio clocks on the StarFive JH7100
39 SoC.
40
41 +config CLK_STARFIVE_JH7110_PLL
42 + bool "StarFive JH7110 PLL clock support"
43 + depends on ARCH_STARFIVE || COMPILE_TEST
44 + default ARCH_STARFIVE
45 + help
46 + Say yes here to support the PLL clock controller on the
47 + StarFive JH7110 SoC.
48 +
49 config CLK_STARFIVE_JH7110_SYS
50 bool "StarFive JH7110 system clock support"
51 depends on ARCH_STARFIVE || COMPILE_TEST
52 --- a/drivers/clk/starfive/Makefile
53 +++ b/drivers/clk/starfive/Makefile
54 @@ -4,5 +4,6 @@ obj-$(CONFIG_CLK_STARFIVE_JH71X0) += clk
55 obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o
56 obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o
57
58 +obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o
59 obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o
60 obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
61 --- /dev/null
62 +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c
63 @@ -0,0 +1,427 @@
64 +// SPDX-License-Identifier: GPL-2.0
65 +/*
66 + * StarFive JH7110 PLL Clock Generator Driver
67 + *
68 + * Copyright (C) 2023 StarFive Technology Co., Ltd.
69 + *
70 + * This driver is about to register JH7110 PLL clock generator and support ops.
71 + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2.
72 + * Each PLL clocks work in integer mode or fraction mode by some dividers,
73 + * and the configuration registers and dividers are set in several syscon registers.
74 + * The formula for calculating frequency is:
75 + * Fvco = Fref * (NI + NF) / M / Q1
76 + * Fref: OSC source clock rate
77 + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0].
78 + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999.
79 + * M: frequency dividing ratio of pre-divider, set by prediv[5:0].
80 + * Q1: frequency dividing ratio of post divider, set by postdiv1[1:0], Q1= 1,2,4,8.
81 + */
82 +
83 +#include <linux/clk-provider.h>
84 +#include <linux/debugfs.h>
85 +#include <linux/device.h>
86 +#include <linux/kernel.h>
87 +#include <linux/mfd/syscon.h>
88 +#include <linux/platform_device.h>
89 +#include <linux/regmap.h>
90 +
91 +#include <dt-bindings/clock/starfive,jh7110-crg.h>
92 +
93 +#include "clk-starfive-jh7110-pll.h"
94 +
95 +static struct jh7110_clk_pll_data *jh7110_pll_data_from(struct clk_hw *hw)
96 +{
97 + return container_of(hw, struct jh7110_clk_pll_data, hw);
98 +}
99 +
100 +static struct jh7110_clk_pll_priv *jh7110_pll_priv_from(struct jh7110_clk_pll_data *data)
101 +{
102 + return container_of(data, struct jh7110_clk_pll_priv, data[data->idx]);
103 +}
104 +
105 +/* Read register value from syscon and calculate PLL(x) frequency */
106 +static unsigned long jh7110_pll_get_freq(struct jh7110_clk_pll_data *data,
107 + unsigned long parent_rate)
108 +{
109 + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
110 + struct jh7110_pll_syscon_offset *offset = &data->offset;
111 + struct jh7110_pll_syscon_mask *mask = &data->mask;
112 + struct jh7110_pll_syscon_shift *shift = &data->shift;
113 + unsigned long freq = 0;
114 + unsigned long frac_cal;
115 + u32 dacpd;
116 + u32 dsmpd;
117 + u32 fbdiv;
118 + u32 prediv;
119 + u32 postdiv1;
120 + u32 frac;
121 + u32 reg_val;
122 +
123 + if (regmap_read(priv->syscon_regmap, offset->dacpd, &reg_val))
124 + goto read_error;
125 + dacpd = (reg_val & mask->dacpd) >> shift->dacpd;
126 +
127 + if (regmap_read(priv->syscon_regmap, offset->dsmpd, &reg_val))
128 + goto read_error;
129 + dsmpd = (reg_val & mask->dsmpd) >> shift->dsmpd;
130 +
131 + if (regmap_read(priv->syscon_regmap, offset->fbdiv, &reg_val))
132 + goto read_error;
133 + fbdiv = (reg_val & mask->fbdiv) >> shift->fbdiv;
134 + /* fbdiv value should be 8 to 4095 */
135 + if (fbdiv < 8)
136 + goto read_error;
137 +
138 + if (regmap_read(priv->syscon_regmap, offset->prediv, &reg_val))
139 + goto read_error;
140 + prediv = (reg_val & mask->prediv) >> shift->prediv;
141 +
142 + if (regmap_read(priv->syscon_regmap, offset->postdiv1, &reg_val))
143 + goto read_error;
144 + /* postdiv1 = 2 ^ reg_val */
145 + postdiv1 = 1 << ((reg_val & mask->postdiv1) >> shift->postdiv1);
146 +
147 + if (regmap_read(priv->syscon_regmap, offset->frac, &reg_val))
148 + goto read_error;
149 + frac = (reg_val & mask->frac) >> shift->frac;
150 +
151 + /*
152 + * Integer Mode (Both 1) or Fraction Mode (Both 0).
153 + * And the decimal places are counted by expanding them by
154 + * a factor of STARFIVE_PLL_FRAC_PATR_SIZE.
155 + */
156 + if (dacpd == 1 && dsmpd == 1)
157 + frac_cal = 0;
158 + else if (dacpd == 0 && dsmpd == 0)
159 + frac_cal = (unsigned long)frac * STARFIVE_PLL_FRAC_PATR_SIZE / (1 << 24);
160 + else
161 + goto read_error;
162 +
163 + /* Fvco = Fref * (NI + NF) / M / Q1 */
164 + freq = parent_rate / STARFIVE_PLL_FRAC_PATR_SIZE *
165 + (fbdiv * STARFIVE_PLL_FRAC_PATR_SIZE + frac_cal) / prediv / postdiv1;
166 +
167 +read_error:
168 + return freq;
169 +}
170 +
171 +static unsigned long jh7110_pll_rate_sub_fabs(unsigned long rate1, unsigned long rate2)
172 +{
173 + return rate1 > rate2 ? (rate1 - rate2) : (rate2 - rate1);
174 +}
175 +
176 +/* Select the appropriate frequency from the already configured registers value */
177 +static void jh7110_pll_select_near_freq_id(struct jh7110_clk_pll_data *data,
178 + unsigned long rate)
179 +{
180 + const struct starfive_pll_syscon_value *syscon_val;
181 + unsigned int id;
182 + unsigned int pll_arry_size;
183 + unsigned long rate_diff;
184 +
185 + if (data->idx == JH7110_CLK_PLL0_OUT)
186 + pll_arry_size = ARRAY_SIZE(jh7110_pll0_syscon_freq);
187 + else if (data->idx == JH7110_CLK_PLL1_OUT)
188 + pll_arry_size = ARRAY_SIZE(jh7110_pll1_syscon_freq);
189 + else
190 + pll_arry_size = ARRAY_SIZE(jh7110_pll2_syscon_freq);
191 +
192 + /* compare the frequency one by one from small to large in order */
193 + for (id = 0; id < pll_arry_size; id++) {
194 + if (data->idx == JH7110_CLK_PLL0_OUT)
195 + syscon_val = &jh7110_pll0_syscon_freq[id];
196 + else if (data->idx == JH7110_CLK_PLL1_OUT)
197 + syscon_val = &jh7110_pll1_syscon_freq[id];
198 + else
199 + syscon_val = &jh7110_pll2_syscon_freq[id];
200 +
201 + if (rate == syscon_val->freq)
202 + goto match_end;
203 +
204 + /* select near frequency */
205 + if (rate < syscon_val->freq) {
206 + /* The last frequency is closer to the target rate than this time. */
207 + if (id > 0)
208 + if (rate_diff < jh7110_pll_rate_sub_fabs(rate, syscon_val->freq))
209 + id--;
210 +
211 + goto match_end;
212 + } else {
213 + rate_diff = jh7110_pll_rate_sub_fabs(rate, syscon_val->freq);
214 + }
215 + }
216 +
217 +match_end:
218 + data->freq_select_idx = id;
219 +}
220 +
221 +static int jh7110_pll_set_freq_syscon(struct jh7110_clk_pll_data *data)
222 +{
223 + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
224 + struct jh7110_pll_syscon_offset *offset = &data->offset;
225 + struct jh7110_pll_syscon_mask *mask = &data->mask;
226 + struct jh7110_pll_syscon_shift *shift = &data->shift;
227 + unsigned int freq_idx = data->freq_select_idx;
228 + const struct starfive_pll_syscon_value *syscon_val;
229 + int ret;
230 +
231 + if (data->idx == JH7110_CLK_PLL0_OUT)
232 + syscon_val = &jh7110_pll0_syscon_freq[freq_idx];
233 + else if (data->idx == JH7110_CLK_PLL1_OUT)
234 + syscon_val = &jh7110_pll1_syscon_freq[freq_idx];
235 + else
236 + syscon_val = &jh7110_pll2_syscon_freq[freq_idx];
237 +
238 + ret = regmap_update_bits(priv->syscon_regmap, offset->dacpd, mask->dacpd,
239 + (syscon_val->dacpd << shift->dacpd));
240 + if (ret)
241 + goto set_failed;
242 +
243 + ret = regmap_update_bits(priv->syscon_regmap, offset->dsmpd, mask->dsmpd,
244 + (syscon_val->dsmpd << shift->dsmpd));
245 + if (ret)
246 + goto set_failed;
247 +
248 + ret = regmap_update_bits(priv->syscon_regmap, offset->prediv, mask->prediv,
249 + (syscon_val->prediv << shift->prediv));
250 + if (ret)
251 + goto set_failed;
252 +
253 + ret = regmap_update_bits(priv->syscon_regmap, offset->fbdiv, mask->fbdiv,
254 + (syscon_val->fbdiv << shift->fbdiv));
255 + if (ret)
256 + goto set_failed;
257 +
258 + ret = regmap_update_bits(priv->syscon_regmap, offset->postdiv1, mask->postdiv1,
259 + ((syscon_val->postdiv1 >> 1) << shift->postdiv1));
260 + if (ret)
261 + goto set_failed;
262 +
263 + /* frac: Integer Mode (Both 1) or Fraction Mode (Both 0) */
264 + if (syscon_val->dacpd == 0 && syscon_val->dsmpd == 0)
265 + ret = regmap_update_bits(priv->syscon_regmap, offset->frac, mask->frac,
266 + (syscon_val->frac << shift->frac));
267 + else if (syscon_val->dacpd != syscon_val->dsmpd)
268 + ret = -EINVAL;
269 +
270 +set_failed:
271 + return ret;
272 +}
273 +
274 +static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
275 +{
276 + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
277 +
278 + return jh7110_pll_get_freq(data, parent_rate);
279 +}
280 +
281 +static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
282 +{
283 + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
284 +
285 + jh7110_pll_select_near_freq_id(data, req->rate);
286 +
287 + if (data->idx == JH7110_CLK_PLL0_OUT)
288 + req->rate = jh7110_pll0_syscon_freq[data->freq_select_idx].freq;
289 + else if (data->idx == JH7110_CLK_PLL1_OUT)
290 + req->rate = jh7110_pll1_syscon_freq[data->freq_select_idx].freq;
291 + else
292 + req->rate = jh7110_pll2_syscon_freq[data->freq_select_idx].freq;
293 +
294 + return 0;
295 +}
296 +
297 +static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate,
298 + unsigned long parent_rate)
299 +{
300 + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
301 +
302 + return jh7110_pll_set_freq_syscon(data);
303 +}
304 +
305 +#ifdef CONFIG_DEBUG_FS
306 +static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry)
307 +{
308 + static const struct debugfs_reg32 jh7110_clk_pll_reg = {
309 + .name = "CTRL",
310 + .offset = 0,
311 + };
312 + struct jh7110_clk_pll_data *data = jh7110_pll_data_from(hw);
313 + struct jh7110_clk_pll_priv *priv = jh7110_pll_priv_from(data);
314 + struct debugfs_regset32 *regset;
315 +
316 + regset = devm_kzalloc(priv->dev, sizeof(*regset), GFP_KERNEL);
317 + if (!regset)
318 + return;
319 +
320 + regset->regs = &jh7110_clk_pll_reg;
321 + regset->nregs = 1;
322 +
323 + debugfs_create_regset32("registers", 0400, dentry, regset);
324 +}
325 +#else
326 +#define jh7110_pll_debug_init NULL
327 +#endif
328 +
329 +static const struct clk_ops jh7110_pll_ops = {
330 + .recalc_rate = jh7110_pll_recalc_rate,
331 + .determine_rate = jh7110_pll_determine_rate,
332 + .set_rate = jh7110_pll_set_rate,
333 + .debug_init = jh7110_pll_debug_init,
334 +};
335 +
336 +/* get offset, mask and shift of PLL(x) syscon */
337 +static int jh7110_pll_data_get(struct jh7110_clk_pll_data *data, int index)
338 +{
339 + struct jh7110_pll_syscon_offset *offset = &data->offset;
340 + struct jh7110_pll_syscon_mask *mask = &data->mask;
341 + struct jh7110_pll_syscon_shift *shift = &data->shift;
342 +
343 + if (index == JH7110_CLK_PLL0_OUT) {
344 + offset->dacpd = STARFIVE_JH7110_PLL0_DACPD_OFFSET;
345 + offset->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_OFFSET;
346 + offset->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_OFFSET;
347 + offset->frac = STARFIVE_JH7110_PLL0_FRAC_OFFSET;
348 + offset->prediv = STARFIVE_JH7110_PLL0_PREDIV_OFFSET;
349 + offset->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET;
350 +
351 + mask->dacpd = STARFIVE_JH7110_PLL0_DACPD_MASK;
352 + mask->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_MASK;
353 + mask->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_MASK;
354 + mask->frac = STARFIVE_JH7110_PLL0_FRAC_MASK;
355 + mask->prediv = STARFIVE_JH7110_PLL0_PREDIV_MASK;
356 + mask->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_MASK;
357 +
358 + shift->dacpd = STARFIVE_JH7110_PLL0_DACPD_SHIFT;
359 + shift->dsmpd = STARFIVE_JH7110_PLL0_DSMPD_SHIFT;
360 + shift->fbdiv = STARFIVE_JH7110_PLL0_FBDIV_SHIFT;
361 + shift->frac = STARFIVE_JH7110_PLL0_FRAC_SHIFT;
362 + shift->prediv = STARFIVE_JH7110_PLL0_PREDIV_SHIFT;
363 + shift->postdiv1 = STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT;
364 +
365 + } else if (index == JH7110_CLK_PLL1_OUT) {
366 + offset->dacpd = STARFIVE_JH7110_PLL1_DACPD_OFFSET;
367 + offset->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_OFFSET;
368 + offset->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_OFFSET;
369 + offset->frac = STARFIVE_JH7110_PLL1_FRAC_OFFSET;
370 + offset->prediv = STARFIVE_JH7110_PLL1_PREDIV_OFFSET;
371 + offset->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET;
372 +
373 + mask->dacpd = STARFIVE_JH7110_PLL1_DACPD_MASK;
374 + mask->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_MASK;
375 + mask->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_MASK;
376 + mask->frac = STARFIVE_JH7110_PLL1_FRAC_MASK;
377 + mask->prediv = STARFIVE_JH7110_PLL1_PREDIV_MASK;
378 + mask->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_MASK;
379 +
380 + shift->dacpd = STARFIVE_JH7110_PLL1_DACPD_SHIFT;
381 + shift->dsmpd = STARFIVE_JH7110_PLL1_DSMPD_SHIFT;
382 + shift->fbdiv = STARFIVE_JH7110_PLL1_FBDIV_SHIFT;
383 + shift->frac = STARFIVE_JH7110_PLL1_FRAC_SHIFT;
384 + shift->prediv = STARFIVE_JH7110_PLL1_PREDIV_SHIFT;
385 + shift->postdiv1 = STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT;
386 +
387 + } else if (index == JH7110_CLK_PLL2_OUT) {
388 + offset->dacpd = STARFIVE_JH7110_PLL2_DACPD_OFFSET;
389 + offset->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_OFFSET;
390 + offset->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_OFFSET;
391 + offset->frac = STARFIVE_JH7110_PLL2_FRAC_OFFSET;
392 + offset->prediv = STARFIVE_JH7110_PLL2_PREDIV_OFFSET;
393 + offset->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET;
394 +
395 + mask->dacpd = STARFIVE_JH7110_PLL2_DACPD_MASK;
396 + mask->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_MASK;
397 + mask->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_MASK;
398 + mask->frac = STARFIVE_JH7110_PLL2_FRAC_MASK;
399 + mask->prediv = STARFIVE_JH7110_PLL2_PREDIV_MASK;
400 + mask->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_MASK;
401 +
402 + shift->dacpd = STARFIVE_JH7110_PLL2_DACPD_SHIFT;
403 + shift->dsmpd = STARFIVE_JH7110_PLL2_DSMPD_SHIFT;
404 + shift->fbdiv = STARFIVE_JH7110_PLL2_FBDIV_SHIFT;
405 + shift->frac = STARFIVE_JH7110_PLL2_FRAC_SHIFT;
406 + shift->prediv = STARFIVE_JH7110_PLL2_PREDIV_SHIFT;
407 + shift->postdiv1 = STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT;
408 +
409 + } else {
410 + return -ENOENT;
411 + }
412 +
413 + return 0;
414 +}
415 +
416 +static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data)
417 +{
418 + struct jh7110_clk_pll_priv *priv = data;
419 + unsigned int idx = clkspec->args[0];
420 +
421 + if (idx < JH7110_PLLCLK_END)
422 + return &priv->data[idx].hw;
423 +
424 + return ERR_PTR(-EINVAL);
425 +}
426 +
427 +static int jh7110_pll_probe(struct platform_device *pdev)
428 +{
429 + const char *pll_name[JH7110_PLLCLK_END] = {
430 + "pll0_out",
431 + "pll1_out",
432 + "pll2_out"
433 + };
434 + struct jh7110_clk_pll_priv *priv;
435 + struct jh7110_clk_pll_data *data;
436 + int ret;
437 + unsigned int idx;
438 +
439 + priv = devm_kzalloc(&pdev->dev, struct_size(priv, data, JH7110_PLLCLK_END),
440 + GFP_KERNEL);
441 + if (!priv)
442 + return -ENOMEM;
443 +
444 + priv->dev = &pdev->dev;
445 + priv->syscon_regmap = syscon_node_to_regmap(priv->dev->of_node->parent);
446 + if (IS_ERR(priv->syscon_regmap))
447 + return PTR_ERR(priv->syscon_regmap);
448 +
449 + for (idx = 0; idx < JH7110_PLLCLK_END; idx++) {
450 + struct clk_parent_data parents = {
451 + .index = 0,
452 + };
453 + struct clk_init_data init = {
454 + .name = pll_name[idx],
455 + .ops = &jh7110_pll_ops,
456 + .parent_data = &parents,
457 + .num_parents = 1,
458 + .flags = 0,
459 + };
460 +
461 + data = &priv->data[idx];
462 +
463 + ret = jh7110_pll_data_get(data, idx);
464 + if (ret)
465 + return ret;
466 +
467 + data->hw.init = &init;
468 + data->idx = idx;
469 +
470 + ret = devm_clk_hw_register(&pdev->dev, &data->hw);
471 + if (ret)
472 + return ret;
473 + }
474 +
475 + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv);
476 +}
477 +
478 +static const struct of_device_id jh7110_pll_match[] = {
479 + { .compatible = "starfive,jh7110-pll" },
480 + { /* sentinel */ }
481 +};
482 +MODULE_DEVICE_TABLE(of, jh7110_pll_match);
483 +
484 +static struct platform_driver jh7110_pll_driver = {
485 + .driver = {
486 + .name = "clk-starfive-jh7110-pll",
487 + .of_match_table = jh7110_pll_match,
488 + },
489 +};
490 +builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);
491 --- /dev/null
492 +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.h
493 @@ -0,0 +1,293 @@
494 +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
495 +/*
496 + * StarFive JH7110 PLL Clock Generator Driver
497 + *
498 + * Copyright (C) 2023 StarFive Technology Co., Ltd.
499 + */
500 +
501 +#ifndef _CLK_STARFIVE_JH7110_PLL_H_
502 +#define _CLK_STARFIVE_JH7110_PLL_H_
503 +
504 +#include <linux/bits.h>
505 +
506 +/* The decimal places are counted by expanding them by a factor of STARFIVE_PLL_FRAC_PATR_SIZE */
507 +#define STARFIVE_PLL_FRAC_PATR_SIZE 1000
508 +
509 +#define STARFIVE_JH7110_PLL0_DACPD_OFFSET 0x18
510 +#define STARFIVE_JH7110_PLL0_DACPD_SHIFT 24
511 +#define STARFIVE_JH7110_PLL0_DACPD_MASK BIT(24)
512 +#define STARFIVE_JH7110_PLL0_DSMPD_OFFSET 0x18
513 +#define STARFIVE_JH7110_PLL0_DSMPD_SHIFT 25
514 +#define STARFIVE_JH7110_PLL0_DSMPD_MASK BIT(25)
515 +#define STARFIVE_JH7110_PLL0_FBDIV_OFFSET 0x1c
516 +#define STARFIVE_JH7110_PLL0_FBDIV_SHIFT 0
517 +#define STARFIVE_JH7110_PLL0_FBDIV_MASK GENMASK(11, 0)
518 +#define STARFIVE_JH7110_PLL0_FRAC_OFFSET 0x20
519 +#define STARFIVE_JH7110_PLL0_FRAC_SHIFT 0
520 +#define STARFIVE_JH7110_PLL0_FRAC_MASK GENMASK(23, 0)
521 +#define STARFIVE_JH7110_PLL0_POSTDIV1_OFFSET 0x20
522 +#define STARFIVE_JH7110_PLL0_POSTDIV1_SHIFT 28
523 +#define STARFIVE_JH7110_PLL0_POSTDIV1_MASK GENMASK(29, 28)
524 +#define STARFIVE_JH7110_PLL0_PREDIV_OFFSET 0x24
525 +#define STARFIVE_JH7110_PLL0_PREDIV_SHIFT 0
526 +#define STARFIVE_JH7110_PLL0_PREDIV_MASK GENMASK(5, 0)
527 +
528 +#define STARFIVE_JH7110_PLL1_DACPD_OFFSET 0x24
529 +#define STARFIVE_JH7110_PLL1_DACPD_SHIFT 15
530 +#define STARFIVE_JH7110_PLL1_DACPD_MASK BIT(15)
531 +#define STARFIVE_JH7110_PLL1_DSMPD_OFFSET 0x24
532 +#define STARFIVE_JH7110_PLL1_DSMPD_SHIFT 16
533 +#define STARFIVE_JH7110_PLL1_DSMPD_MASK BIT(16)
534 +#define STARFIVE_JH7110_PLL1_FBDIV_OFFSET 0x24
535 +#define STARFIVE_JH7110_PLL1_FBDIV_SHIFT 17
536 +#define STARFIVE_JH7110_PLL1_FBDIV_MASK GENMASK(28, 17)
537 +#define STARFIVE_JH7110_PLL1_FRAC_OFFSET 0x28
538 +#define STARFIVE_JH7110_PLL1_FRAC_SHIFT 0
539 +#define STARFIVE_JH7110_PLL1_FRAC_MASK GENMASK(23, 0)
540 +#define STARFIVE_JH7110_PLL1_POSTDIV1_OFFSET 0x28
541 +#define STARFIVE_JH7110_PLL1_POSTDIV1_SHIFT 28
542 +#define STARFIVE_JH7110_PLL1_POSTDIV1_MASK GENMASK(29, 28)
543 +#define STARFIVE_JH7110_PLL1_PREDIV_OFFSET 0x2c
544 +#define STARFIVE_JH7110_PLL1_PREDIV_SHIFT 0
545 +#define STARFIVE_JH7110_PLL1_PREDIV_MASK GENMASK(5, 0)
546 +
547 +#define STARFIVE_JH7110_PLL2_DACPD_OFFSET 0x2c
548 +#define STARFIVE_JH7110_PLL2_DACPD_SHIFT 15
549 +#define STARFIVE_JH7110_PLL2_DACPD_MASK BIT(15)
550 +#define STARFIVE_JH7110_PLL2_DSMPD_OFFSET 0x2c
551 +#define STARFIVE_JH7110_PLL2_DSMPD_SHIFT 16
552 +#define STARFIVE_JH7110_PLL2_DSMPD_MASK BIT(16)
553 +#define STARFIVE_JH7110_PLL2_FBDIV_OFFSET 0x2c
554 +#define STARFIVE_JH7110_PLL2_FBDIV_SHIFT 17
555 +#define STARFIVE_JH7110_PLL2_FBDIV_MASK GENMASK(28, 17)
556 +#define STARFIVE_JH7110_PLL2_FRAC_OFFSET 0x30
557 +#define STARFIVE_JH7110_PLL2_FRAC_SHIFT 0
558 +#define STARFIVE_JH7110_PLL2_FRAC_MASK GENMASK(23, 0)
559 +#define STARFIVE_JH7110_PLL2_POSTDIV1_OFFSET 0x30
560 +#define STARFIVE_JH7110_PLL2_POSTDIV1_SHIFT 28
561 +#define STARFIVE_JH7110_PLL2_POSTDIV1_MASK GENMASK(29, 28)
562 +#define STARFIVE_JH7110_PLL2_PREDIV_OFFSET 0x34
563 +#define STARFIVE_JH7110_PLL2_PREDIV_SHIFT 0
564 +#define STARFIVE_JH7110_PLL2_PREDIV_MASK GENMASK(5, 0)
565 +
566 +struct jh7110_pll_syscon_offset {
567 + unsigned int dacpd;
568 + unsigned int dsmpd;
569 + unsigned int fbdiv;
570 + unsigned int frac;
571 + unsigned int prediv;
572 + unsigned int postdiv1;
573 +};
574 +
575 +struct jh7110_pll_syscon_mask {
576 + u32 dacpd;
577 + u32 dsmpd;
578 + u32 fbdiv;
579 + u32 frac;
580 + u32 prediv;
581 + u32 postdiv1;
582 +};
583 +
584 +struct jh7110_pll_syscon_shift {
585 + char dacpd;
586 + char dsmpd;
587 + char fbdiv;
588 + char frac;
589 + char prediv;
590 + char postdiv1;
591 +};
592 +
593 +struct jh7110_clk_pll_data {
594 + struct clk_hw hw;
595 + unsigned int idx;
596 + unsigned int freq_select_idx;
597 +
598 + struct jh7110_pll_syscon_offset offset;
599 + struct jh7110_pll_syscon_mask mask;
600 + struct jh7110_pll_syscon_shift shift;
601 +};
602 +
603 +struct jh7110_clk_pll_priv {
604 + struct device *dev;
605 + struct regmap *syscon_regmap;
606 + struct jh7110_clk_pll_data data[];
607 +};
608 +
609 +struct starfive_pll_syscon_value {
610 + unsigned long freq;
611 + u32 prediv;
612 + u32 fbdiv;
613 + u32 postdiv1;
614 +/* Both daxpd and dsmpd set 1 while integer mode */
615 +/* Both daxpd and dsmpd set 0 while fraction mode */
616 + u32 dacpd;
617 + u32 dsmpd;
618 +/* frac value should be decimals multiplied by 2^24 */
619 + u32 frac;
620 +};
621 +
622 +enum starfive_pll0_freq_index {
623 + PLL0_FREQ_375 = 0,
624 + PLL0_FREQ_500,
625 + PLL0_FREQ_625,
626 + PLL0_FREQ_750,
627 + PLL0_FREQ_875,
628 + PLL0_FREQ_1000,
629 + PLL0_FREQ_1250,
630 + PLL0_FREQ_1375,
631 + PLL0_FREQ_1500,
632 + PLL0_FREQ_MAX
633 +};
634 +
635 +enum starfive_pll1_freq_index {
636 + PLL1_FREQ_1066 = 0,
637 + PLL1_FREQ_1200,
638 + PLL1_FREQ_1400,
639 + PLL1_FREQ_1600,
640 + PLL1_FREQ_MAX
641 +};
642 +
643 +enum starfive_pll2_freq_index {
644 + PLL2_FREQ_1188 = 0,
645 + PLL2_FREQ_12288,
646 + PLL2_FREQ_MAX
647 +};
648 +
649 +/*
650 + * Because the pll frequency is relatively fixed,
651 + * it cannot be set arbitrarily, so it needs a specific configuration.
652 + * PLL0 frequency should be multiple of 125MHz (USB frequency).
653 + */
654 +static const struct starfive_pll_syscon_value
655 + jh7110_pll0_syscon_freq[PLL0_FREQ_MAX] = {
656 + [PLL0_FREQ_375] = {
657 + .freq = 375000000,
658 + .prediv = 8,
659 + .fbdiv = 125,
660 + .postdiv1 = 1,
661 + .dacpd = 1,
662 + .dsmpd = 1,
663 + },
664 + [PLL0_FREQ_500] = {
665 + .freq = 500000000,
666 + .prediv = 6,
667 + .fbdiv = 125,
668 + .postdiv1 = 1,
669 + .dacpd = 1,
670 + .dsmpd = 1,
671 + },
672 + [PLL0_FREQ_625] = {
673 + .freq = 625000000,
674 + .prediv = 24,
675 + .fbdiv = 625,
676 + .postdiv1 = 1,
677 + .dacpd = 1,
678 + .dsmpd = 1,
679 + },
680 + [PLL0_FREQ_750] = {
681 + .freq = 750000000,
682 + .prediv = 4,
683 + .fbdiv = 125,
684 + .postdiv1 = 1,
685 + .dacpd = 1,
686 + .dsmpd = 1,
687 + },
688 + [PLL0_FREQ_875] = {
689 + .freq = 875000000,
690 + .prediv = 24,
691 + .fbdiv = 875,
692 + .postdiv1 = 1,
693 + .dacpd = 1,
694 + .dsmpd = 1,
695 + },
696 + [PLL0_FREQ_1000] = {
697 + .freq = 1000000000,
698 + .prediv = 3,
699 + .fbdiv = 125,
700 + .postdiv1 = 1,
701 + .dacpd = 1,
702 + .dsmpd = 1,
703 + },
704 + [PLL0_FREQ_1250] = {
705 + .freq = 1250000000,
706 + .prediv = 12,
707 + .fbdiv = 625,
708 + .postdiv1 = 1,
709 + .dacpd = 1,
710 + .dsmpd = 1,
711 + },
712 + [PLL0_FREQ_1375] = {
713 + .freq = 1375000000,
714 + .prediv = 24,
715 + .fbdiv = 1375,
716 + .postdiv1 = 1,
717 + .dacpd = 1,
718 + .dsmpd = 1,
719 + },
720 + [PLL0_FREQ_1500] = {
721 + .freq = 1500000000,
722 + .prediv = 2,
723 + .fbdiv = 125,
724 + .postdiv1 = 1,
725 + .dacpd = 1,
726 + .dsmpd = 1,
727 + },
728 +};
729 +
730 +static const struct starfive_pll_syscon_value
731 + jh7110_pll1_syscon_freq[PLL1_FREQ_MAX] = {
732 + [PLL1_FREQ_1066] = {
733 + .freq = 1066000000,
734 + .prediv = 12,
735 + .fbdiv = 533,
736 + .postdiv1 = 1,
737 + .dacpd = 1,
738 + .dsmpd = 1,
739 + },
740 + [PLL1_FREQ_1200] = {
741 + .freq = 1200000000,
742 + .prediv = 1,
743 + .fbdiv = 50,
744 + .postdiv1 = 1,
745 + .dacpd = 1,
746 + .dsmpd = 1,
747 + },
748 + [PLL1_FREQ_1400] = {
749 + .freq = 1400000000,
750 + .prediv = 6,
751 + .fbdiv = 350,
752 + .postdiv1 = 1,
753 + .dacpd = 1,
754 + .dsmpd = 1,
755 + },
756 + [PLL1_FREQ_1600] = {
757 + .freq = 1600000000,
758 + .prediv = 3,
759 + .fbdiv = 200,
760 + .postdiv1 = 1,
761 + .dacpd = 1,
762 + .dsmpd = 1,
763 + },
764 +};
765 +
766 +static const struct starfive_pll_syscon_value
767 + jh7110_pll2_syscon_freq[PLL2_FREQ_MAX] = {
768 + [PLL2_FREQ_1188] = {
769 + .freq = 1188000000,
770 + .prediv = 2,
771 + .fbdiv = 99,
772 + .postdiv1 = 1,
773 + .dacpd = 1,
774 + .dsmpd = 1,
775 + },
776 + [PLL2_FREQ_12288] = {
777 + .freq = 1228800000,
778 + .prediv = 5,
779 + .fbdiv = 256,
780 + .postdiv1 = 1,
781 + .dacpd = 1,
782 + .dsmpd = 1,
783 + },
784 +};
785 +
786 +#endif