blob: c6692f2f9f5adc1a126339ee2ce822b9449ea285 [file] [log] [blame]
Lukasz Majewski4de44bb2019-06-24 15:50:45 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 DENX Software Engineering
4 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5 */
6
Lukasz Majewski4de44bb2019-06-24 15:50:45 +02007#include <asm/io.h>
Giulio Benetti6713a012020-01-10 15:46:59 +01008#include <div64.h>
Lukasz Majewski4de44bb2019-06-24 15:50:45 +02009#include <malloc.h>
10#include <clk-uclass.h>
11#include <dm/device.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070012#include <dm/devres.h>
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020013#include <dm/uclass.h>
14#include <clk.h>
15#include "clk.h"
Simon Glassd66c5f72020-02-03 07:36:15 -070016#include <linux/err.h>
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020017
Giulio Benettiff331fa2020-01-10 15:46:53 +010018#define UBOOT_DM_CLK_IMX_PLLV3_GENERIC "imx_clk_pllv3_generic"
Giulio Benetti05bf7fd2020-01-10 15:46:58 +010019#define UBOOT_DM_CLK_IMX_PLLV3_SYS "imx_clk_pllv3_sys"
Giulio Benettiff331fa2020-01-10 15:46:53 +010020#define UBOOT_DM_CLK_IMX_PLLV3_USB "imx_clk_pllv3_usb"
Giulio Benetti6713a012020-01-10 15:46:59 +010021#define UBOOT_DM_CLK_IMX_PLLV3_AV "imx_clk_pllv3_av"
Lukasz Majewskib0f278b2020-02-24 14:55:25 +010022#define UBOOT_DM_CLK_IMX_PLLV3_ENET "imx_clk_pllv3_enet"
Jesse Taube4303cd12022-07-26 01:43:42 -040023#define UBOOT_DM_CLK_IMX_PLLV3_GENV2 "imx_clk_pllv3_genericv2"
Giulio Benetti6713a012020-01-10 15:46:59 +010024
25#define PLL_NUM_OFFSET 0x10
26#define PLL_DENOM_OFFSET 0x20
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020027
Giulio Benetti7dad7a32020-01-10 15:46:55 +010028#define BM_PLL_POWER (0x1 << 12)
Jesse Taube4303cd12022-07-26 01:43:42 -040029#define BM_PLL_POWER_V2 (0x1 << 21)
Giulio Benettieeef2742020-04-08 17:10:07 +020030#define BM_PLL_ENABLE (0x1 << 13)
Giulio Benetti8c25d1e2020-01-10 15:46:57 +010031#define BM_PLL_LOCK (0x1 << 31)
Jesse Taube4303cd12022-07-26 01:43:42 -040032#define BM_PLL_LOCK_V2 (0x1 << 29)
Giulio Benetti7dad7a32020-01-10 15:46:55 +010033
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020034struct clk_pllv3 {
35 struct clk clk;
36 void __iomem *base;
Giulio Benetti7dad7a32020-01-10 15:46:55 +010037 u32 power_bit;
38 bool powerup_set;
Jesse Taube4303cd12022-07-26 01:43:42 -040039 u32 lock_bit;
Giulio Benettieeef2742020-04-08 17:10:07 +020040 u32 enable_bit;
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020041 u32 div_mask;
42 u32 div_shift;
Lukasz Majewskib0f278b2020-02-24 14:55:25 +010043 unsigned long ref_clock;
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020044};
45
46#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
47
Jesse Taube4303cd12022-07-26 01:43:42 -040048static ulong clk_pllv3_genericv2_get_rate(struct clk *clk)
49{
50 struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
51 unsigned long parent_rate = clk_get_parent_rate(clk);
52
53 u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
54
55 return (div == 0) ? parent_rate * 22 : parent_rate * 20;
56}
57
58static ulong clk_pllv3_genericv2_set_rate(struct clk *clk, ulong rate)
59{
60 struct clk_pllv3 *pll = to_clk_pllv3(clk);
61 unsigned long parent_rate = clk_get_parent_rate(clk);
62
63 u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
64 u32 val = (div == 0) ? parent_rate * 22 : parent_rate * 20;
65
66 if (rate == val)
67 return 0;
68
69 return -EINVAL;
70}
71
Giulio Benettiff331fa2020-01-10 15:46:53 +010072static ulong clk_pllv3_generic_get_rate(struct clk *clk)
Lukasz Majewski4de44bb2019-06-24 15:50:45 +020073{
74 struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
75 unsigned long parent_rate = clk_get_parent_rate(clk);
76
77 u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
78
79 return (div == 1) ? parent_rate * 22 : parent_rate * 20;
80}
81
Giulio Benetti8c25d1e2020-01-10 15:46:57 +010082static ulong clk_pllv3_generic_set_rate(struct clk *clk, ulong rate)
83{
84 struct clk_pllv3 *pll = to_clk_pllv3(clk);
85 unsigned long parent_rate = clk_get_parent_rate(clk);
86 u32 val, div;
87
88 if (rate == parent_rate * 22)
89 div = 1;
90 else if (rate == parent_rate * 20)
91 div = 0;
92 else
93 return -EINVAL;
94
95 val = readl(pll->base);
96 val &= ~(pll->div_mask << pll->div_shift);
97 val |= (div << pll->div_shift);
98 writel(val, pll->base);
99
100 /* Wait for PLL to lock */
Jesse Taube4303cd12022-07-26 01:43:42 -0400101 while (!(readl(pll->base) & pll->lock_bit))
Giulio Benetti8c25d1e2020-01-10 15:46:57 +0100102 ;
103
104 return 0;
105}
106
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100107static int clk_pllv3_generic_enable(struct clk *clk)
108{
109 struct clk_pllv3 *pll = to_clk_pllv3(clk);
110 u32 val;
111
112 val = readl(pll->base);
113 if (pll->powerup_set)
114 val |= pll->power_bit;
115 else
116 val &= ~pll->power_bit;
Giulio Benettieeef2742020-04-08 17:10:07 +0200117
118 val |= pll->enable_bit;
119
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100120 writel(val, pll->base);
121
122 return 0;
123}
124
Giulio Benetti47e15642020-01-10 15:46:56 +0100125static int clk_pllv3_generic_disable(struct clk *clk)
126{
127 struct clk_pllv3 *pll = to_clk_pllv3(clk);
128 u32 val;
129
130 val = readl(pll->base);
131 if (pll->powerup_set)
132 val &= ~pll->power_bit;
133 else
134 val |= pll->power_bit;
Giulio Benettieeef2742020-04-08 17:10:07 +0200135
136 val &= ~pll->enable_bit;
137
Giulio Benetti47e15642020-01-10 15:46:56 +0100138 writel(val, pll->base);
139
140 return 0;
141}
142
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200143static const struct clk_ops clk_pllv3_generic_ops = {
Giulio Benettiff331fa2020-01-10 15:46:53 +0100144 .get_rate = clk_pllv3_generic_get_rate,
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100145 .enable = clk_pllv3_generic_enable,
Giulio Benetti47e15642020-01-10 15:46:56 +0100146 .disable = clk_pllv3_generic_disable,
Giulio Benetti8c25d1e2020-01-10 15:46:57 +0100147 .set_rate = clk_pllv3_generic_set_rate,
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200148};
149
Jesse Taube4303cd12022-07-26 01:43:42 -0400150static const struct clk_ops clk_pllv3_genericv2_ops = {
151 .get_rate = clk_pllv3_genericv2_get_rate,
152 .enable = clk_pllv3_generic_enable,
153 .disable = clk_pllv3_generic_disable,
154 .set_rate = clk_pllv3_genericv2_set_rate,
155};
156
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100157static ulong clk_pllv3_sys_get_rate(struct clk *clk)
158{
159 struct clk_pllv3 *pll = to_clk_pllv3(clk);
160 unsigned long parent_rate = clk_get_parent_rate(clk);
161 u32 div = readl(pll->base) & pll->div_mask;
162
163 return parent_rate * div / 2;
164}
165
166static ulong clk_pllv3_sys_set_rate(struct clk *clk, ulong rate)
167{
168 struct clk_pllv3 *pll = to_clk_pllv3(clk);
169 unsigned long parent_rate = clk_get_parent_rate(clk);
Giulio Benetticf4c04a2020-01-17 13:06:40 +0100170 unsigned long min_rate;
171 unsigned long max_rate;
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100172 u32 val, div;
173
Giulio Benetticf4c04a2020-01-17 13:06:40 +0100174 if (parent_rate == 0)
175 return -EINVAL;
176
177 min_rate = parent_rate * 54 / 2;
178 max_rate = parent_rate * 108 / 2;
179
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100180 if (rate < min_rate || rate > max_rate)
181 return -EINVAL;
182
183 div = rate * 2 / parent_rate;
184 val = readl(pll->base);
185 val &= ~pll->div_mask;
186 val |= div;
187 writel(val, pll->base);
188
189 /* Wait for PLL to lock */
Jesse Taube4303cd12022-07-26 01:43:42 -0400190 while (!(readl(pll->base) & pll->lock_bit))
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100191 ;
192
193 return 0;
194}
195
196static const struct clk_ops clk_pllv3_sys_ops = {
Wolfgang Denk62fb2b42021-09-27 17:42:39 +0200197 .enable = clk_pllv3_generic_enable,
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100198 .disable = clk_pllv3_generic_disable,
199 .get_rate = clk_pllv3_sys_get_rate,
200 .set_rate = clk_pllv3_sys_set_rate,
201};
202
Giulio Benetti6713a012020-01-10 15:46:59 +0100203static ulong clk_pllv3_av_get_rate(struct clk *clk)
204{
205 struct clk_pllv3 *pll = to_clk_pllv3(clk);
206 unsigned long parent_rate = clk_get_parent_rate(clk);
207 u32 mfn = readl(pll->base + PLL_NUM_OFFSET);
208 u32 mfd = readl(pll->base + PLL_DENOM_OFFSET);
209 u32 div = readl(pll->base) & pll->div_mask;
210 u64 temp64 = (u64)parent_rate;
211
Giulio Benetti2af750e2020-01-17 13:06:41 +0100212 if (mfd == 0)
213 return -EIO;
214
Giulio Benetti6713a012020-01-10 15:46:59 +0100215 temp64 *= mfn;
216 do_div(temp64, mfd);
217
218 return parent_rate * div + (unsigned long)temp64;
219}
220
221static ulong clk_pllv3_av_set_rate(struct clk *clk, ulong rate)
222{
223 struct clk_pllv3 *pll = to_clk_pllv3(clk);
224 unsigned long parent_rate = clk_get_parent_rate(clk);
Giulio Benettie4a55582020-01-17 13:06:42 +0100225 unsigned long min_rate;
226 unsigned long max_rate;
Giulio Benetti6713a012020-01-10 15:46:59 +0100227 u32 val, div;
228 u32 mfn, mfd = 1000000;
229 u32 max_mfd = 0x3FFFFFFF;
230 u64 temp64;
231
Giulio Benettie4a55582020-01-17 13:06:42 +0100232 if (parent_rate == 0)
233 return -EINVAL;
234
235 min_rate = parent_rate * 27;
236 max_rate = parent_rate * 54;
237
Giulio Benetti6713a012020-01-10 15:46:59 +0100238 if (rate < min_rate || rate > max_rate)
239 return -EINVAL;
240
241 if (parent_rate <= max_mfd)
242 mfd = parent_rate;
243
244 div = rate / parent_rate;
245 temp64 = (u64)(rate - div * parent_rate);
246 temp64 *= mfd;
247 do_div(temp64, parent_rate);
248 mfn = temp64;
249
250 val = readl(pll->base);
251 val &= ~pll->div_mask;
252 val |= div;
253 writel(val, pll->base);
254 writel(mfn, pll->base + PLL_NUM_OFFSET);
255 writel(mfd, pll->base + PLL_DENOM_OFFSET);
256
257 /* Wait for PLL to lock */
Jesse Taube4303cd12022-07-26 01:43:42 -0400258 while (!(readl(pll->base) & pll->lock_bit))
Giulio Benetti6713a012020-01-10 15:46:59 +0100259 ;
260
261 return 0;
262}
263
264static const struct clk_ops clk_pllv3_av_ops = {
265 .enable = clk_pllv3_generic_enable,
266 .disable = clk_pllv3_generic_disable,
267 .get_rate = clk_pllv3_av_get_rate,
268 .set_rate = clk_pllv3_av_set_rate,
269};
270
Lukasz Majewskib0f278b2020-02-24 14:55:25 +0100271static ulong clk_pllv3_enet_get_rate(struct clk *clk)
272{
273 struct clk_pllv3 *pll = to_clk_pllv3(clk);
274
275 return pll->ref_clock;
276}
277
278static const struct clk_ops clk_pllv3_enet_ops = {
279 .enable = clk_pllv3_generic_enable,
280 .disable = clk_pllv3_generic_disable,
281 .get_rate = clk_pllv3_enet_get_rate,
282};
283
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200284struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
285 const char *parent_name, void __iomem *base,
286 u32 div_mask)
287{
288 struct clk_pllv3 *pll;
289 struct clk *clk;
290 char *drv_name;
291 int ret;
292
293 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
294 if (!pll)
295 return ERR_PTR(-ENOMEM);
296
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100297 pll->power_bit = BM_PLL_POWER;
Giulio Benettieeef2742020-04-08 17:10:07 +0200298 pll->enable_bit = BM_PLL_ENABLE;
Jesse Taube4303cd12022-07-26 01:43:42 -0400299 pll->lock_bit = BM_PLL_LOCK;
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100300
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200301 switch (type) {
302 case IMX_PLLV3_GENERIC:
Giulio Benettiff331fa2020-01-10 15:46:53 +0100303 drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC;
Giulio Benetti670e5702020-01-10 15:46:54 +0100304 pll->div_shift = 0;
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100305 pll->powerup_set = false;
Giulio Benettiff331fa2020-01-10 15:46:53 +0100306 break;
Jesse Taube4303cd12022-07-26 01:43:42 -0400307 case IMX_PLLV3_GENERICV2:
308 pll->power_bit = BM_PLL_POWER_V2;
309 pll->lock_bit = BM_PLL_LOCK_V2;
310 drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENV2;
311 pll->div_shift = 0;
312 pll->powerup_set = false;
313 break;
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100314 case IMX_PLLV3_SYS:
315 drv_name = UBOOT_DM_CLK_IMX_PLLV3_SYS;
316 pll->div_shift = 0;
317 pll->powerup_set = false;
318 break;
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200319 case IMX_PLLV3_USB:
Giulio Benettiff331fa2020-01-10 15:46:53 +0100320 drv_name = UBOOT_DM_CLK_IMX_PLLV3_USB;
Giulio Benetti670e5702020-01-10 15:46:54 +0100321 pll->div_shift = 1;
Giulio Benetti7dad7a32020-01-10 15:46:55 +0100322 pll->powerup_set = true;
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200323 break;
Giulio Benetti6713a012020-01-10 15:46:59 +0100324 case IMX_PLLV3_AV:
325 drv_name = UBOOT_DM_CLK_IMX_PLLV3_AV;
326 pll->div_shift = 0;
327 pll->powerup_set = false;
328 break;
Lukasz Majewskib0f278b2020-02-24 14:55:25 +0100329 case IMX_PLLV3_ENET:
330 drv_name = UBOOT_DM_CLK_IMX_PLLV3_ENET;
331 pll->ref_clock = 500000000;
332 break;
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200333 default:
334 kfree(pll);
Simon Glass29ff16a2021-03-25 10:26:08 +1300335 return ERR_PTR(-EINVAL);
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200336 }
337
338 pll->base = base;
339 pll->div_mask = div_mask;
340 clk = &pll->clk;
341
342 ret = clk_register(clk, drv_name, name, parent_name);
343 if (ret) {
344 kfree(pll);
345 return ERR_PTR(ret);
346 }
347
348 return clk;
349}
350
351U_BOOT_DRIVER(clk_pllv3_generic) = {
Giulio Benettiff331fa2020-01-10 15:46:53 +0100352 .name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC,
353 .id = UCLASS_CLK,
354 .ops = &clk_pllv3_generic_ops,
355 .flags = DM_FLAG_PRE_RELOC,
356};
357
Jesse Taube4303cd12022-07-26 01:43:42 -0400358U_BOOT_DRIVER(clk_pllv3_genericv2) = {
359 .name = UBOOT_DM_CLK_IMX_PLLV3_GENV2,
360 .id = UCLASS_CLK,
361 .ops = &clk_pllv3_genericv2_ops,
362 .flags = DM_FLAG_PRE_RELOC,
363};
364
Giulio Benetti05bf7fd2020-01-10 15:46:58 +0100365U_BOOT_DRIVER(clk_pllv3_sys) = {
366 .name = UBOOT_DM_CLK_IMX_PLLV3_SYS,
367 .id = UCLASS_CLK,
368 .ops = &clk_pllv3_sys_ops,
369 .flags = DM_FLAG_PRE_RELOC,
370};
371
Giulio Benettiff331fa2020-01-10 15:46:53 +0100372U_BOOT_DRIVER(clk_pllv3_usb) = {
373 .name = UBOOT_DM_CLK_IMX_PLLV3_USB,
Lukasz Majewski4de44bb2019-06-24 15:50:45 +0200374 .id = UCLASS_CLK,
375 .ops = &clk_pllv3_generic_ops,
376 .flags = DM_FLAG_PRE_RELOC,
377};
Giulio Benetti6713a012020-01-10 15:46:59 +0100378
379U_BOOT_DRIVER(clk_pllv3_av) = {
380 .name = UBOOT_DM_CLK_IMX_PLLV3_AV,
381 .id = UCLASS_CLK,
382 .ops = &clk_pllv3_av_ops,
383 .flags = DM_FLAG_PRE_RELOC,
384};
Lukasz Majewskib0f278b2020-02-24 14:55:25 +0100385
386U_BOOT_DRIVER(clk_pllv3_enet) = {
387 .name = UBOOT_DM_CLK_IMX_PLLV3_ENET,
388 .id = UCLASS_CLK,
389 .ops = &clk_pllv3_enet_ops,
390};