blob: 1568a1f4cd912e681c0c0af7ad4d599ab49fb2aa [file] [log] [blame]
Yanhong Wang5a85d052023-03-29 11:42:13 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2022-23 StarFive Technology Co., Ltd.
4 *
5 * Author: Yanhong Wang <yanhong.wang@starfivetech.com>
Xingyu Wu751e4402023-07-07 18:50:07 +08006 * Xingyu Wu <xingyu.wu@starfivetech.com>
Yanhong Wang5a85d052023-03-29 11:42:13 +08007 */
8
9#include <common.h>
10#include <asm/io.h>
11#include <malloc.h>
12#include <clk-uclass.h>
13#include <div64.h>
14#include <dm/device.h>
Xingyu Wu751e4402023-07-07 18:50:07 +080015#include <dm/read.h>
16#include <dt-bindings/clock/starfive,jh7110-crg.h>
Yanhong Wang5a85d052023-03-29 11:42:13 +080017#include <linux/bitops.h>
18#include <linux/clk-provider.h>
19#include <linux/delay.h>
20#include <linux/err.h>
21
Xingyu Wua3897e62023-07-07 18:50:11 +080022#include "clk.h"
23
Yanhong Wang5a85d052023-03-29 11:42:13 +080024#define UBOOT_DM_CLK_JH7110_PLLX "jh7110_clk_pllx"
25
26#define PLL_PD_OFF 1
27#define PLL_PD_ON 0
28
29#define CLK_DDR_BUS_MASK GENMASK(29, 24)
30#define CLK_DDR_BUS_OFFSET 0xAC
31#define CLK_DDR_BUS_OSC_DIV2 0
32#define CLK_DDR_BUS_PLL1_DIV2 1
33#define CLK_DDR_BUS_PLL1_DIV4 2
34#define CLK_DDR_BUS_PLL1_DIV8 3
35
Xingyu Wua3897e62023-07-07 18:50:11 +080036#define JH7110_PLL_ID_TRANS(id) ((id) + JH7110_EXTCLK_END)
37
Xingyu Wu751e4402023-07-07 18:50:07 +080038enum starfive_pll_type {
39 PLL0 = 0,
40 PLL1,
41 PLL2,
42 PLL_MAX = PLL2
43};
44
45struct starfive_pllx_rate {
46 u64 rate;
47 u32 prediv;
48 u32 fbdiv;
49 u32 frac;
50};
51
52struct starfive_pllx_offset {
53 u32 pd;
54 u32 prediv;
55 u32 fbdiv;
56 u32 frac;
57 u32 postdiv1;
58 u32 dacpd;
59 u32 dsmpd;
60 u32 pd_mask;
61 u32 prediv_mask;
62 u32 fbdiv_mask;
63 u32 frac_mask;
64 u32 postdiv1_mask;
65 u32 dacpd_mask;
66 u32 dsmpd_mask;
67};
68
69struct starfive_pllx_clk {
70 enum starfive_pll_type type;
71 const struct starfive_pllx_offset *offset;
72 const struct starfive_pllx_rate *rate_table;
73 int rate_count;
74 int flags;
75};
76
Yanhong Wang5a85d052023-03-29 11:42:13 +080077struct clk_jh7110_pllx {
78 struct clk clk;
79 void __iomem *base;
80 void __iomem *sysreg;
81 enum starfive_pll_type type;
82 const struct starfive_pllx_offset *offset;
83 const struct starfive_pllx_rate *rate_table;
84 int rate_count;
85};
86
87#define getbits_le32(addr, mask) ((in_le32(addr) & (mask)) >> __ffs((mask)))
88
89#define PLLX_SET(offset, mask, val) do {\
90 reg = readl((ulong *)((ulong)pll->base + (offset))); \
91 reg &= ~(mask); \
92 reg |= (mask) & ((val) << __ffs(mask)); \
93 writel(reg, (ulong *)((ulong)pll->base + (offset))); \
94 } while (0)
95
96#define PLLX_RATE(_rate, _pd, _fd) \
97 { \
98 .rate = (_rate), \
99 .prediv = (_pd), \
100 .fbdiv = (_fd), \
101 }
102
103#define to_clk_pllx(_clk) container_of(_clk, struct clk_jh7110_pllx, clk)
104
105static const struct starfive_pllx_rate jh7110_pll0_tbl[] = {
106 PLLX_RATE(375000000UL, 8, 125),
107 PLLX_RATE(500000000UL, 6, 125),
108 PLLX_RATE(625000000UL, 24, 625),
109 PLLX_RATE(750000000UL, 4, 125),
110 PLLX_RATE(875000000UL, 24, 875),
111 PLLX_RATE(1000000000UL, 3, 125),
112 PLLX_RATE(1250000000UL, 12, 625),
113 PLLX_RATE(1375000000UL, 24, 1375),
114 PLLX_RATE(1500000000UL, 2, 125),
115 PLLX_RATE(1625000000UL, 24, 1625),
116 PLLX_RATE(1750000000UL, 12, 875),
117 PLLX_RATE(1800000000UL, 3, 225),
118};
119
120static const struct starfive_pllx_rate jh7110_pll1_tbl[] = {
121 PLLX_RATE(1066000000UL, 12, 533),
122 PLLX_RATE(1200000000UL, 1, 50),
123 PLLX_RATE(1400000000UL, 6, 350),
124 PLLX_RATE(1600000000UL, 3, 200),
125};
126
127static const struct starfive_pllx_rate jh7110_pll2_tbl[] = {
128 PLLX_RATE(1228800000UL, 15, 768),
129 PLLX_RATE(1188000000UL, 2, 99),
130};
131
132static const struct starfive_pllx_offset jh7110_pll0_offset = {
133 .pd = 0x20,
134 .prediv = 0x24,
135 .fbdiv = 0x1c,
136 .frac = 0x20,
137 .postdiv1 = 0x20,
138 .dacpd = 0x18,
139 .dsmpd = 0x18,
140 .pd_mask = BIT(27),
141 .prediv_mask = GENMASK(5, 0),
142 .fbdiv_mask = GENMASK(11, 0),
143 .frac_mask = GENMASK(23, 0),
144 .postdiv1_mask = GENMASK(29, 28),
145 .dacpd_mask = BIT(24),
146 .dsmpd_mask = BIT(25)
147};
148
149static const struct starfive_pllx_offset jh7110_pll1_offset = {
150 .pd = 0x28,
151 .prediv = 0x2c,
152 .fbdiv = 0x24,
153 .frac = 0x28,
154 .postdiv1 = 0x28,
155 .dacpd = 0x24,
156 .dsmpd = 0x24,
157 .pd_mask = BIT(27),
158 .prediv_mask = GENMASK(5, 0),
159 .fbdiv_mask = GENMASK(28, 17),
160 .frac_mask = GENMASK(23, 0),
161 .postdiv1_mask = GENMASK(29, 28),
162 .dacpd_mask = BIT(15),
163 .dsmpd_mask = BIT(16)
164};
165
166static const struct starfive_pllx_offset jh7110_pll2_offset = {
167 .pd = 0x30,
168 .prediv = 0x34,
169 .fbdiv = 0x2c,
170 .frac = 0x30,
171 .postdiv1 = 0x30,
172 .dacpd = 0x2c,
173 .dsmpd = 0x2c,
174 .pd_mask = BIT(27),
175 .prediv_mask = GENMASK(5, 0),
176 .fbdiv_mask = GENMASK(28, 17),
177 .frac_mask = GENMASK(23, 0),
178 .postdiv1_mask = GENMASK(29, 28),
179 .dacpd_mask = BIT(15),
180 .dsmpd_mask = BIT(16)
181};
182
183struct starfive_pllx_clk starfive_jh7110_pll0 __initdata = {
184 .type = PLL0,
185 .offset = &jh7110_pll0_offset,
186 .rate_table = jh7110_pll0_tbl,
187 .rate_count = ARRAY_SIZE(jh7110_pll0_tbl),
188};
189
190struct starfive_pllx_clk starfive_jh7110_pll1 __initdata = {
191 .type = PLL1,
192 .offset = &jh7110_pll1_offset,
193 .rate_table = jh7110_pll1_tbl,
194 .rate_count = ARRAY_SIZE(jh7110_pll1_tbl),
195};
196
197struct starfive_pllx_clk starfive_jh7110_pll2 __initdata = {
198 .type = PLL2,
199 .offset = &jh7110_pll2_offset,
200 .rate_table = jh7110_pll2_tbl,
201 .rate_count = ARRAY_SIZE(jh7110_pll2_tbl),
202};
203
204static const struct starfive_pllx_rate *
205jh7110_get_pll_settings(struct clk_jh7110_pllx *pll, unsigned long rate)
206{
207 for (int i = 0; i < pll->rate_count; i++)
208 if (rate == pll->rate_table[i].rate)
209 return &pll->rate_table[i];
210
211 return NULL;
212}
213
214static void jh7110_pll_set_rate(struct clk_jh7110_pllx *pll,
215 const struct starfive_pllx_rate *rate)
216{
217 u32 reg;
218 bool set = (pll->type == PLL1) ? true : false;
219
220 if (set) {
221 reg = readl((ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET));
222 reg &= ~CLK_DDR_BUS_MASK;
223 reg |= CLK_DDR_BUS_OSC_DIV2 << __ffs(CLK_DDR_BUS_MASK);
224 writel(reg, (ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET));
225 }
226
227 PLLX_SET(pll->offset->pd, pll->offset->pd_mask, PLL_PD_OFF);
228 PLLX_SET(pll->offset->dacpd, pll->offset->dacpd_mask, 1);
229 PLLX_SET(pll->offset->dsmpd, pll->offset->dsmpd_mask, 1);
230 PLLX_SET(pll->offset->prediv, pll->offset->prediv_mask, rate->prediv);
231 PLLX_SET(pll->offset->fbdiv, pll->offset->fbdiv_mask, rate->fbdiv);
Hoegeun Kwondbc74612023-06-28 19:19:49 +0900232 PLLX_SET(pll->offset->postdiv1, pll->offset->postdiv1_mask, 0);
Yanhong Wang5a85d052023-03-29 11:42:13 +0800233 PLLX_SET(pll->offset->pd, pll->offset->pd_mask, PLL_PD_ON);
234
235 if (set) {
236 udelay(100);
237 reg = readl((ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET));
238 reg &= ~CLK_DDR_BUS_MASK;
239 reg |= CLK_DDR_BUS_PLL1_DIV2 << __ffs(CLK_DDR_BUS_MASK);
240 writel(reg, (ulong *)((ulong)pll->sysreg + CLK_DDR_BUS_OFFSET));
241 }
242}
243
244static ulong jh7110_pllx_recalc_rate(struct clk *clk)
245{
246 struct clk_jh7110_pllx *pll = to_clk_pllx(dev_get_clk_ptr(clk->dev));
247 u64 refclk = clk_get_parent_rate(clk);
248 u32 dacpd, dsmpd;
249 u32 prediv, fbdiv, postdiv1;
250 u64 frac;
251
252 dacpd = getbits_le32((ulong)pll->base + pll->offset->dacpd,
253 pll->offset->dacpd_mask);
254 dsmpd = getbits_le32((ulong)pll->base + pll->offset->dsmpd,
255 pll->offset->dsmpd_mask);
256 prediv = getbits_le32((ulong)pll->base + pll->offset->prediv,
257 pll->offset->prediv_mask);
258 fbdiv = getbits_le32((ulong)pll->base + pll->offset->fbdiv,
259 pll->offset->fbdiv_mask);
260 postdiv1 = 1 << getbits_le32((ulong)pll->base + pll->offset->postdiv1,
261 pll->offset->postdiv1_mask);
262 frac = (u64)getbits_le32((ulong)pll->base + pll->offset->frac,
263 pll->offset->frac_mask);
264
265 /* Integer Multiple Mode
266 * Both dacpd and dsmpd should be set as 1 while integer multiple mode.
267 *
268 * The frequency of outputs can be figured out as below.
269 *
270 * Fvco = Fref*Nl/M
271 * NI is integer frequency dividing ratio of feedback divider, set by fbdiv1[11:0] ,
272 * NI = 8, 9, 10, 12.13....4095
273 * M is frequency dividing ratio of pre-divider, set by prediv[5:0],M = 1,2...63
274 *
275 * Fclko1 = Fvco/Q1
276 * Q1 is frequency dividing ratio of post divider, set by postdiv1[1:0],Q1= 1,2,4,8
277 *
278 * Fraction Multiple Mode
279 *
280 * Both dacpd and dsmpd should be set as 0 while integer multiple mode.
281 *
282 * Fvco = Fref*(NI+NF)/M
283 * NI is integer frequency dividing ratio of feedback divider, set by fbdiv[11:0] ,
284 * NI = 8, 9, 10, 12.13....4095
285 * NF is fractional frequency dividing ratio, set by frac[23:0], NF =frac[23:0]/2^24= 0~0.99999994
286 * M is frequency dividing ratio of pre-divider, set by prediv[5:0],M = 1,2...63
287 *
288 * Fclko1 = Fvco/Q1
289 * Q1 is frequency dividing ratio of post divider, set by postdivl[1:0],Q1= 1,2,4,8
290 */
291 if (dacpd == 1 && dsmpd == 1)
292 frac = 0;
293 else if (dacpd == 0 && dsmpd == 0)
294 do_div(frac, 1 << 24);
295 else
296 return -EINVAL;
297
298 refclk *= (fbdiv + frac);
299 do_div(refclk, prediv * postdiv1);
300
301 return refclk;
302}
303
304static ulong jh7110_pllx_set_rate(struct clk *clk, ulong drate)
305{
306 struct clk_jh7110_pllx *pll = to_clk_pllx(dev_get_clk_ptr(clk->dev));
307 const struct starfive_pllx_rate *rate;
308
309 rate = jh7110_get_pll_settings(pll, drate);
310 if (!rate)
311 return -EINVAL;
312
313 jh7110_pll_set_rate(pll, rate);
314
315 return jh7110_pllx_recalc_rate(clk);
316}
317
Xingyu Wu751e4402023-07-07 18:50:07 +0800318static const struct clk_ops jh7110_clk_pllx_ops = {
Yanhong Wang5a85d052023-03-29 11:42:13 +0800319 .set_rate = jh7110_pllx_set_rate,
320 .get_rate = jh7110_pllx_recalc_rate,
321};
322
323struct clk *starfive_jh7110_pll(const char *name, const char *parent_name,
324 void __iomem *base, void __iomem *sysreg,
325 const struct starfive_pllx_clk *pll_clk)
326{
327 struct clk_jh7110_pllx *pll;
328 struct clk *clk;
329 int ret;
330
331 if (!pll_clk || !base || !sysreg)
332 return ERR_PTR(-EINVAL);
333
334 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
335 if (!pll)
336 return ERR_PTR(-ENOMEM);
337
338 pll->base = base;
339 pll->sysreg = sysreg;
340 pll->type = pll_clk->type;
341 pll->offset = pll_clk->offset;
342 pll->rate_table = pll_clk->rate_table;
343 pll->rate_count = pll_clk->rate_count;
344
345 clk = &pll->clk;
346 ret = clk_register(clk, UBOOT_DM_CLK_JH7110_PLLX, name, parent_name);
347 if (ret) {
348 kfree(pll);
349 return ERR_PTR(ret);
350 }
351
352 if (IS_ENABLED(CONFIG_SPL_BUILD) && pll->type == PLL0)
353 jh7110_pllx_set_rate(clk, 1000000000);
354
355 if (IS_ENABLED(CONFIG_SPL_BUILD) && pll->type == PLL2)
356 jh7110_pllx_set_rate(clk, 1188000000);
357
358 return clk;
359}
360
Xingyu Wu751e4402023-07-07 18:50:07 +0800361/* PLLx clock implementation */
Yanhong Wang5a85d052023-03-29 11:42:13 +0800362U_BOOT_DRIVER(jh7110_clk_pllx) = {
363 .name = UBOOT_DM_CLK_JH7110_PLLX,
364 .id = UCLASS_CLK,
Xingyu Wu751e4402023-07-07 18:50:07 +0800365 .ops = &jh7110_clk_pllx_ops,
366 .flags = DM_FLAG_PRE_RELOC,
367};
368
369static int jh7110_pll_clk_probe(struct udevice *dev)
370{
371 void __iomem *reg = (void __iomem *)dev_read_addr_ptr(dev->parent);
372 fdt_addr_t sysreg = ofnode_get_addr(ofnode_by_compatible(ofnode_null(),
373 "starfive,jh7110-syscrg"));
374
375 if (sysreg == FDT_ADDR_T_NONE)
376 return -EINVAL;
377
Xingyu Wua3897e62023-07-07 18:50:11 +0800378 clk_dm(JH7110_PLL_ID_TRANS(JH7110_SYSCLK_PLL0_OUT),
Xingyu Wu751e4402023-07-07 18:50:07 +0800379 starfive_jh7110_pll("pll0_out", "oscillator", reg,
380 (void __iomem *)sysreg, &starfive_jh7110_pll0));
Xingyu Wua3897e62023-07-07 18:50:11 +0800381 clk_dm(JH7110_PLL_ID_TRANS(JH7110_SYSCLK_PLL1_OUT),
Xingyu Wu751e4402023-07-07 18:50:07 +0800382 starfive_jh7110_pll("pll1_out", "oscillator", reg,
383 (void __iomem *)sysreg, &starfive_jh7110_pll1));
Xingyu Wua3897e62023-07-07 18:50:11 +0800384 clk_dm(JH7110_PLL_ID_TRANS(JH7110_SYSCLK_PLL2_OUT),
Xingyu Wu751e4402023-07-07 18:50:07 +0800385 starfive_jh7110_pll("pll2_out", "oscillator", reg,
386 (void __iomem *)sysreg, &starfive_jh7110_pll2));
387
388 return 0;
389}
390
Xingyu Wua3897e62023-07-07 18:50:11 +0800391static int jh7110_pll_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
392{
393 if (args->args_count > 1) {
394 debug("Invalid args_count: %d\n", args->args_count);
395 return -EINVAL;
396 }
397
398 if (args->args_count)
399 clk->id = JH7110_PLL_ID_TRANS(args->args[0]);
400 else
401 clk->id = 0;
402
403 return 0;
404}
405
Xingyu Wu751e4402023-07-07 18:50:07 +0800406static const struct udevice_id jh7110_pll_clk_of_match[] = {
407 { .compatible = "starfive,jh7110-pll", },
408 { }
409};
410
Xingyu Wua3897e62023-07-07 18:50:11 +0800411JH7110_CLK_OPS(pll);
412
Xingyu Wu751e4402023-07-07 18:50:07 +0800413/* PLL clk device */
414U_BOOT_DRIVER(jh7110_pll_clk) = {
415 .name = "jh7110_pll_clk",
416 .id = UCLASS_CLK,
417 .of_match = jh7110_pll_clk_of_match,
418 .probe = jh7110_pll_clk_probe,
Xingyu Wua3897e62023-07-07 18:50:11 +0800419 .ops = &jh7110_pll_clk_ops,
Yanhong Wang5a85d052023-03-29 11:42:13 +0800420};