Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/drivers/clk/imx/clk-pllv3.c
Line
Count
Source
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 <asm/io.h>
8
#include <div64.h>
9
#include <malloc.h>
10
#include <clk-uclass.h>
11
#include <dm/device.h>
12
#include <dm/devres.h>
13
#include <dm/uclass.h>
14
#include <clk.h>
15
#include "clk.h"
16
#include <linux/err.h>
17
18
0
#define UBOOT_DM_CLK_IMX_PLLV3_GENERIC  "imx_clk_pllv3_generic"
19
0
#define UBOOT_DM_CLK_IMX_PLLV3_SYS  "imx_clk_pllv3_sys"
20
0
#define UBOOT_DM_CLK_IMX_PLLV3_USB  "imx_clk_pllv3_usb"
21
0
#define UBOOT_DM_CLK_IMX_PLLV3_AV "imx_clk_pllv3_av"
22
0
#define UBOOT_DM_CLK_IMX_PLLV3_ENET     "imx_clk_pllv3_enet"
23
0
#define UBOOT_DM_CLK_IMX_PLLV3_GENV2  "imx_clk_pllv3_genericv2"
24
25
#define PLL_NUM_OFFSET    0x10
26
#define PLL_DENOM_OFFSET  0x20
27
28
0
#define BM_PLL_POWER    (0x1 << 12)
29
0
#define BM_PLL_POWER_V2   (0x1 << 21)
30
0
#define BM_PLL_ENABLE   (0x1 << 13)
31
0
#define BM_PLL_LOCK   (0x1 << 31)
32
0
#define BM_PLL_LOCK_V2    (0x1 << 29)
33
34
struct clk_pllv3 {
35
  struct clk  clk;
36
  void __iomem  *base;
37
  u32   power_bit;
38
  bool    powerup_set;
39
  u32   lock_bit;
40
  u32   enable_bit;
41
  u32   div_mask;
42
  u32   div_shift;
43
  unsigned long   ref_clock;
44
};
45
46
0
#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
47
48
static ulong clk_pllv3_genericv2_get_rate(struct clk *clk)
49
0
{
50
0
  struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
51
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
52
53
0
  u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
54
55
0
  return (div == 0) ? parent_rate * 22 : parent_rate * 20;
56
0
}
57
58
static ulong clk_pllv3_genericv2_set_rate(struct clk *clk, ulong rate)
59
0
{
60
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
61
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
62
63
0
  u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
64
0
  u32 val = (div == 0) ? parent_rate * 22 : parent_rate * 20;
65
66
0
  if (rate == val)
67
0
    return 0;
68
69
0
  return -EINVAL;
70
0
}
71
72
static ulong clk_pllv3_generic_get_rate(struct clk *clk)
73
0
{
74
0
  struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
75
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
76
77
0
  u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
78
79
0
  return (div == 1) ? parent_rate * 22 : parent_rate * 20;
80
0
}
81
82
static ulong clk_pllv3_generic_set_rate(struct clk *clk, ulong rate)
83
0
{
84
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
85
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
86
0
  u32 val, div;
87
88
0
  if (rate == parent_rate * 22)
89
0
    div = 1;
90
0
  else if (rate == parent_rate * 20)
91
0
    div = 0;
92
0
  else
93
0
    return -EINVAL;
94
95
0
  val = readl(pll->base);
96
0
  val &= ~(pll->div_mask << pll->div_shift);
97
0
  val |= (div << pll->div_shift);
98
0
  writel(val, pll->base);
99
100
  /* Wait for PLL to lock */
101
0
  while (!(readl(pll->base) & pll->lock_bit))
102
0
    ;
103
104
0
  return 0;
105
0
}
106
107
static int clk_pllv3_generic_enable(struct clk *clk)
108
0
{
109
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
110
0
  u32 val;
111
112
0
  val = readl(pll->base);
113
0
  if (pll->powerup_set)
114
0
    val |= pll->power_bit;
115
0
  else
116
0
    val &= ~pll->power_bit;
117
118
0
  val |= pll->enable_bit;
119
120
0
  writel(val, pll->base);
121
122
0
  return 0;
123
0
}
124
125
static int clk_pllv3_generic_disable(struct clk *clk)
126
0
{
127
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
128
0
  u32 val;
129
130
0
  val = readl(pll->base);
131
0
  if (pll->powerup_set)
132
0
    val &= ~pll->power_bit;
133
0
  else
134
0
    val |= pll->power_bit;
135
136
0
  val &= ~pll->enable_bit;
137
138
0
  writel(val, pll->base);
139
140
0
  return 0;
141
0
}
142
143
static const struct clk_ops clk_pllv3_generic_ops = {
144
  .get_rate = clk_pllv3_generic_get_rate,
145
  .enable   = clk_pllv3_generic_enable,
146
  .disable  = clk_pllv3_generic_disable,
147
  .set_rate = clk_pllv3_generic_set_rate,
148
};
149
150
static 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
157
static ulong clk_pllv3_sys_get_rate(struct clk *clk)
158
0
{
159
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
160
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
161
0
  u32 div = readl(pll->base) & pll->div_mask;
162
163
0
  return parent_rate * div / 2;
164
0
}
165
166
static ulong clk_pllv3_sys_set_rate(struct clk *clk, ulong rate)
167
0
{
168
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
169
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
170
0
  unsigned long min_rate;
171
0
  unsigned long max_rate;
172
0
  u32 val, div;
173
174
0
  if (parent_rate == 0)
175
0
    return -EINVAL;
176
177
0
  min_rate = parent_rate * 54 / 2;
178
0
  max_rate = parent_rate * 108 / 2;
179
180
0
  if (rate < min_rate || rate > max_rate)
181
0
    return -EINVAL;
182
183
0
  div = rate * 2 / parent_rate;
184
0
  val = readl(pll->base);
185
0
  val &= ~pll->div_mask;
186
0
  val |= div;
187
0
  writel(val, pll->base);
188
189
  /* Wait for PLL to lock */
190
0
  while (!(readl(pll->base) & pll->lock_bit))
191
0
    ;
192
193
0
  return 0;
194
0
}
195
196
static const struct clk_ops clk_pllv3_sys_ops = {
197
  .enable   = clk_pllv3_generic_enable,
198
  .disable  = clk_pllv3_generic_disable,
199
  .get_rate = clk_pllv3_sys_get_rate,
200
  .set_rate = clk_pllv3_sys_set_rate,
201
};
202
203
static ulong clk_pllv3_av_get_rate(struct clk *clk)
204
0
{
205
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
206
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
207
0
  u32 mfn = readl(pll->base + PLL_NUM_OFFSET);
208
0
  u32 mfd = readl(pll->base + PLL_DENOM_OFFSET);
209
0
  u32 div = readl(pll->base) & pll->div_mask;
210
0
  u64 temp64 = (u64)parent_rate;
211
212
0
  if (mfd == 0)
213
0
    return -EIO;
214
215
0
  temp64 *= mfn;
216
0
  do_div(temp64, mfd);
217
218
0
  return parent_rate * div + (unsigned long)temp64;
219
0
}
220
221
static ulong clk_pllv3_av_set_rate(struct clk *clk, ulong rate)
222
0
{
223
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
224
0
  unsigned long parent_rate = clk_get_parent_rate(clk);
225
0
  unsigned long min_rate;
226
0
  unsigned long max_rate;
227
0
  u32 val, div;
228
0
  u32 mfn, mfd = 1000000;
229
0
  u32 max_mfd = 0x3FFFFFFF;
230
0
  u64 temp64;
231
232
0
  if (parent_rate == 0)
233
0
    return -EINVAL;
234
235
0
  min_rate = parent_rate * 27;
236
0
  max_rate = parent_rate * 54;
237
238
0
  if (rate < min_rate || rate > max_rate)
239
0
    return -EINVAL;
240
241
0
  if (parent_rate <= max_mfd)
242
0
    mfd = parent_rate;
243
244
0
  div = rate / parent_rate;
245
0
  temp64 = (u64)(rate - div * parent_rate);
246
0
  temp64 *= mfd;
247
0
  do_div(temp64, parent_rate);
248
0
  mfn = temp64;
249
250
0
  val = readl(pll->base);
251
0
  val &= ~pll->div_mask;
252
0
  val |= div;
253
0
  writel(val, pll->base);
254
0
  writel(mfn, pll->base + PLL_NUM_OFFSET);
255
0
  writel(mfd, pll->base + PLL_DENOM_OFFSET);
256
257
  /* Wait for PLL to lock */
258
0
  while (!(readl(pll->base) & pll->lock_bit))
259
0
    ;
260
261
0
  return 0;
262
0
}
263
264
static 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
271
static ulong clk_pllv3_enet_get_rate(struct clk *clk)
272
0
{
273
0
  struct clk_pllv3 *pll = to_clk_pllv3(clk);
274
275
0
  return pll->ref_clock;
276
0
}
277
278
static 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
284
struct clk *imx_clk_pllv3(struct udevice *dev, enum imx_pllv3_type type,
285
        const char *name, const char *parent_name,
286
        void __iomem *base, u32 div_mask)
287
0
{
288
0
  struct clk_pllv3 *pll;
289
0
  struct clk *clk;
290
0
  char *drv_name;
291
0
  int ret;
292
293
0
  pll = kzalloc(sizeof(*pll), GFP_KERNEL);
294
0
  if (!pll)
295
0
    return ERR_PTR(-ENOMEM);
296
297
0
  pll->power_bit = BM_PLL_POWER;
298
0
  pll->enable_bit = BM_PLL_ENABLE;
299
0
  pll->lock_bit = BM_PLL_LOCK;
300
301
0
  switch (type) {
302
0
  case IMX_PLLV3_GENERIC:
303
0
    drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC;
304
0
    pll->div_shift = 0;
305
0
    pll->powerup_set = false;
306
0
    break;
307
0
  case IMX_PLLV3_GENERICV2:
308
0
    pll->power_bit = BM_PLL_POWER_V2;
309
0
    pll->lock_bit = BM_PLL_LOCK_V2;
310
0
    drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENV2;
311
0
    pll->div_shift = 0;
312
0
    pll->powerup_set = false;
313
0
    break;
314
0
  case IMX_PLLV3_SYS:
315
0
    drv_name = UBOOT_DM_CLK_IMX_PLLV3_SYS;
316
0
    pll->div_shift = 0;
317
0
    pll->powerup_set = false;
318
0
    break;
319
0
  case IMX_PLLV3_USB:
320
0
    drv_name = UBOOT_DM_CLK_IMX_PLLV3_USB;
321
0
    pll->div_shift = 1;
322
0
    pll->powerup_set = true;
323
0
    break;
324
0
  case IMX_PLLV3_AV:
325
0
    drv_name = UBOOT_DM_CLK_IMX_PLLV3_AV;
326
0
    pll->div_shift = 0;
327
0
    pll->powerup_set = false;
328
0
    break;
329
0
  case IMX_PLLV3_ENET:
330
0
    drv_name = UBOOT_DM_CLK_IMX_PLLV3_ENET;
331
0
    pll->ref_clock = 500000000;
332
0
    break;
333
0
  default:
334
0
    kfree(pll);
335
0
    return ERR_PTR(-EINVAL);
336
0
  }
337
338
0
  pll->base = base;
339
0
  pll->div_mask = div_mask;
340
0
  clk = &pll->clk;
341
342
0
  ret = clk_register(clk, drv_name, name,
343
0
         clk_resolve_parent_clk(dev, parent_name));
344
0
  if (ret) {
345
0
    kfree(pll);
346
0
    return ERR_PTR(ret);
347
0
  }
348
349
0
  return clk;
350
0
}
351
352
U_BOOT_DRIVER(clk_pllv3_generic) = {
353
  .name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC,
354
  .id = UCLASS_CLK,
355
  .ops  = &clk_pllv3_generic_ops,
356
  .flags = DM_FLAG_PRE_RELOC,
357
};
358
359
U_BOOT_DRIVER(clk_pllv3_genericv2) = {
360
  .name = UBOOT_DM_CLK_IMX_PLLV3_GENV2,
361
  .id = UCLASS_CLK,
362
  .ops  = &clk_pllv3_genericv2_ops,
363
  .flags = DM_FLAG_PRE_RELOC,
364
};
365
366
U_BOOT_DRIVER(clk_pllv3_sys) = {
367
  .name = UBOOT_DM_CLK_IMX_PLLV3_SYS,
368
  .id = UCLASS_CLK,
369
  .ops  = &clk_pllv3_sys_ops,
370
  .flags = DM_FLAG_PRE_RELOC,
371
};
372
373
U_BOOT_DRIVER(clk_pllv3_usb) = {
374
  .name = UBOOT_DM_CLK_IMX_PLLV3_USB,
375
  .id = UCLASS_CLK,
376
  .ops  = &clk_pllv3_generic_ops,
377
  .flags = DM_FLAG_PRE_RELOC,
378
};
379
380
U_BOOT_DRIVER(clk_pllv3_av) = {
381
  .name = UBOOT_DM_CLK_IMX_PLLV3_AV,
382
  .id = UCLASS_CLK,
383
  .ops  = &clk_pllv3_av_ops,
384
  .flags = DM_FLAG_PRE_RELOC,
385
};
386
387
U_BOOT_DRIVER(clk_pllv3_enet) = {
388
  .name = UBOOT_DM_CLK_IMX_PLLV3_ENET,
389
  .id = UCLASS_CLK,
390
  .ops  = &clk_pllv3_enet_ops,
391
};