imx8m: config: convert to bootm_size
[platform/kernel/u-boot.git] / drivers / clk / imx / clk-pllv3.c
1 // 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
7 #include <common.h>
8 #include <asm/io.h>
9 #include <div64.h>
10 #include <malloc.h>
11 #include <clk-uclass.h>
12 #include <dm/device.h>
13 #include <dm/devres.h>
14 #include <dm/uclass.h>
15 #include <clk.h>
16 #include "clk.h"
17 #include <linux/err.h>
18
19 #define UBOOT_DM_CLK_IMX_PLLV3_GENERIC  "imx_clk_pllv3_generic"
20 #define UBOOT_DM_CLK_IMX_PLLV3_SYS      "imx_clk_pllv3_sys"
21 #define UBOOT_DM_CLK_IMX_PLLV3_USB      "imx_clk_pllv3_usb"
22 #define UBOOT_DM_CLK_IMX_PLLV3_AV       "imx_clk_pllv3_av"
23
24 #define PLL_NUM_OFFSET          0x10
25 #define PLL_DENOM_OFFSET        0x20
26
27 #define BM_PLL_POWER            (0x1 << 12)
28 #define BM_PLL_ENABLE           (0x1 << 13)
29 #define BM_PLL_LOCK             (0x1 << 31)
30
31 struct clk_pllv3 {
32         struct clk      clk;
33         void __iomem    *base;
34         u32             power_bit;
35         bool            powerup_set;
36         u32             enable_bit;
37         u32             div_mask;
38         u32             div_shift;
39 };
40
41 #define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
42
43 static ulong clk_pllv3_generic_get_rate(struct clk *clk)
44 {
45         struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
46         unsigned long parent_rate = clk_get_parent_rate(clk);
47
48         u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
49
50         return (div == 1) ? parent_rate * 22 : parent_rate * 20;
51 }
52
53 static ulong clk_pllv3_generic_set_rate(struct clk *clk, ulong rate)
54 {
55         struct clk_pllv3 *pll = to_clk_pllv3(clk);
56         unsigned long parent_rate = clk_get_parent_rate(clk);
57         u32 val, div;
58
59         if (rate == parent_rate * 22)
60                 div = 1;
61         else if (rate == parent_rate * 20)
62                 div = 0;
63         else
64                 return -EINVAL;
65
66         val = readl(pll->base);
67         val &= ~(pll->div_mask << pll->div_shift);
68         val |= (div << pll->div_shift);
69         writel(val, pll->base);
70
71         /* Wait for PLL to lock */
72         while (!(readl(pll->base) & BM_PLL_LOCK))
73                 ;
74
75         return 0;
76 }
77
78 static int clk_pllv3_generic_enable(struct clk *clk)
79 {
80         struct clk_pllv3 *pll = to_clk_pllv3(clk);
81         u32 val;
82
83         val = readl(pll->base);
84         if (pll->powerup_set)
85                 val |= pll->power_bit;
86         else
87                 val &= ~pll->power_bit;
88
89         val |= pll->enable_bit;
90
91         writel(val, pll->base);
92
93         return 0;
94 }
95
96 static int clk_pllv3_generic_disable(struct clk *clk)
97 {
98         struct clk_pllv3 *pll = to_clk_pllv3(clk);
99         u32 val;
100
101         val = readl(pll->base);
102         if (pll->powerup_set)
103                 val &= ~pll->power_bit;
104         else
105                 val |= pll->power_bit;
106
107         val &= ~pll->enable_bit;
108
109         writel(val, pll->base);
110
111         return 0;
112 }
113
114 static const struct clk_ops clk_pllv3_generic_ops = {
115         .get_rate       = clk_pllv3_generic_get_rate,
116         .enable         = clk_pllv3_generic_enable,
117         .disable        = clk_pllv3_generic_disable,
118         .set_rate       = clk_pllv3_generic_set_rate,
119 };
120
121 static ulong clk_pllv3_sys_get_rate(struct clk *clk)
122 {
123         struct clk_pllv3 *pll = to_clk_pllv3(clk);
124         unsigned long parent_rate = clk_get_parent_rate(clk);
125         u32 div = readl(pll->base) & pll->div_mask;
126
127         return parent_rate * div / 2;
128 }
129
130 static ulong clk_pllv3_sys_set_rate(struct clk *clk, ulong rate)
131 {
132         struct clk_pllv3 *pll = to_clk_pllv3(clk);
133         unsigned long parent_rate = clk_get_parent_rate(clk);
134         unsigned long min_rate;
135         unsigned long max_rate;
136         u32 val, div;
137
138         if (parent_rate == 0)
139                 return -EINVAL;
140
141         min_rate = parent_rate * 54 / 2;
142         max_rate = parent_rate * 108 / 2;
143
144         if (rate < min_rate || rate > max_rate)
145                 return -EINVAL;
146
147         div = rate * 2 / parent_rate;
148         val = readl(pll->base);
149         val &= ~pll->div_mask;
150         val |= div;
151         writel(val, pll->base);
152
153         /* Wait for PLL to lock */
154         while (!(readl(pll->base) & BM_PLL_LOCK))
155                 ;
156
157         return 0;
158 }
159
160 static const struct clk_ops clk_pllv3_sys_ops = {
161         .enable         = clk_pllv3_generic_enable,
162         .disable        = clk_pllv3_generic_disable,
163         .get_rate       = clk_pllv3_sys_get_rate,
164         .set_rate       = clk_pllv3_sys_set_rate,
165 };
166
167 static ulong clk_pllv3_av_get_rate(struct clk *clk)
168 {
169         struct clk_pllv3 *pll = to_clk_pllv3(clk);
170         unsigned long parent_rate = clk_get_parent_rate(clk);
171         u32 mfn = readl(pll->base + PLL_NUM_OFFSET);
172         u32 mfd = readl(pll->base + PLL_DENOM_OFFSET);
173         u32 div = readl(pll->base) & pll->div_mask;
174         u64 temp64 = (u64)parent_rate;
175
176         if (mfd == 0)
177                 return -EIO;
178
179         temp64 *= mfn;
180         do_div(temp64, mfd);
181
182         return parent_rate * div + (unsigned long)temp64;
183 }
184
185 static ulong clk_pllv3_av_set_rate(struct clk *clk, ulong rate)
186 {
187         struct clk_pllv3 *pll = to_clk_pllv3(clk);
188         unsigned long parent_rate = clk_get_parent_rate(clk);
189         unsigned long min_rate;
190         unsigned long max_rate;
191         u32 val, div;
192         u32 mfn, mfd = 1000000;
193         u32 max_mfd = 0x3FFFFFFF;
194         u64 temp64;
195
196         if (parent_rate == 0)
197                 return -EINVAL;
198
199         min_rate = parent_rate * 27;
200         max_rate = parent_rate * 54;
201
202         if (rate < min_rate || rate > max_rate)
203                 return -EINVAL;
204
205         if (parent_rate <= max_mfd)
206                 mfd = parent_rate;
207
208         div = rate / parent_rate;
209         temp64 = (u64)(rate - div * parent_rate);
210         temp64 *= mfd;
211         do_div(temp64, parent_rate);
212         mfn = temp64;
213
214         val = readl(pll->base);
215         val &= ~pll->div_mask;
216         val |= div;
217         writel(val, pll->base);
218         writel(mfn, pll->base + PLL_NUM_OFFSET);
219         writel(mfd, pll->base + PLL_DENOM_OFFSET);
220
221         /* Wait for PLL to lock */
222         while (!(readl(pll->base) & BM_PLL_LOCK))
223                 ;
224
225         return 0;
226 }
227
228 static const struct clk_ops clk_pllv3_av_ops = {
229         .enable         = clk_pllv3_generic_enable,
230         .disable        = clk_pllv3_generic_disable,
231         .get_rate       = clk_pllv3_av_get_rate,
232         .set_rate       = clk_pllv3_av_set_rate,
233 };
234
235 struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
236                           const char *parent_name, void __iomem *base,
237                           u32 div_mask)
238 {
239         struct clk_pllv3 *pll;
240         struct clk *clk;
241         char *drv_name;
242         int ret;
243
244         pll = kzalloc(sizeof(*pll), GFP_KERNEL);
245         if (!pll)
246                 return ERR_PTR(-ENOMEM);
247
248         pll->power_bit = BM_PLL_POWER;
249         pll->enable_bit = BM_PLL_ENABLE;
250
251         switch (type) {
252         case IMX_PLLV3_GENERIC:
253                 drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC;
254                 pll->div_shift = 0;
255                 pll->powerup_set = false;
256                 break;
257         case IMX_PLLV3_SYS:
258                 drv_name = UBOOT_DM_CLK_IMX_PLLV3_SYS;
259                 pll->div_shift = 0;
260                 pll->powerup_set = false;
261                 break;
262         case IMX_PLLV3_USB:
263                 drv_name = UBOOT_DM_CLK_IMX_PLLV3_USB;
264                 pll->div_shift = 1;
265                 pll->powerup_set = true;
266                 break;
267         case IMX_PLLV3_AV:
268                 drv_name = UBOOT_DM_CLK_IMX_PLLV3_AV;
269                 pll->div_shift = 0;
270                 pll->powerup_set = false;
271                 break;
272         default:
273                 kfree(pll);
274                 return ERR_PTR(-ENOTSUPP);
275         }
276
277         pll->base = base;
278         pll->div_mask = div_mask;
279         clk = &pll->clk;
280
281         ret = clk_register(clk, drv_name, name, parent_name);
282         if (ret) {
283                 kfree(pll);
284                 return ERR_PTR(ret);
285         }
286
287         return clk;
288 }
289
290 U_BOOT_DRIVER(clk_pllv3_generic) = {
291         .name   = UBOOT_DM_CLK_IMX_PLLV3_GENERIC,
292         .id     = UCLASS_CLK,
293         .ops    = &clk_pllv3_generic_ops,
294         .flags = DM_FLAG_PRE_RELOC,
295 };
296
297 U_BOOT_DRIVER(clk_pllv3_sys) = {
298         .name   = UBOOT_DM_CLK_IMX_PLLV3_SYS,
299         .id     = UCLASS_CLK,
300         .ops    = &clk_pllv3_sys_ops,
301         .flags = DM_FLAG_PRE_RELOC,
302 };
303
304 U_BOOT_DRIVER(clk_pllv3_usb) = {
305         .name   = UBOOT_DM_CLK_IMX_PLLV3_USB,
306         .id     = UCLASS_CLK,
307         .ops    = &clk_pllv3_generic_ops,
308         .flags = DM_FLAG_PRE_RELOC,
309 };
310
311 U_BOOT_DRIVER(clk_pllv3_av) = {
312         .name   = UBOOT_DM_CLK_IMX_PLLV3_AV,
313         .id     = UCLASS_CLK,
314         .ops    = &clk_pllv3_av_ops,
315         .flags = DM_FLAG_PRE_RELOC,
316 };