blob: 542d577eaa6f667ba4fb31590eee01b034b22007 [file] [log] [blame]
Sam Protsenko8a0f6342024-01-10 21:09:03 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2016 Samsung Electronics
4 * Copyright (C) 2023 Linaro Ltd.
5 *
6 * Authors:
7 * Thomas Abraham <thomas.ab@samsung.com>
8 * Sam Protsenko <semen.protsenko@linaro.org>
9 *
10 * This file contains the utility functions to register the pll clocks.
11 */
12
13#include <asm/io.h>
14#include <div64.h>
15#include <malloc.h>
16#include <clk-uclass.h>
17#include <dm/device.h>
18#include <clk.h>
19#include "clk.h"
20
21#define UBOOT_DM_CLK_SAMSUNG_PLL0822X "samsung_clk_pll0822x"
22#define UBOOT_DM_CLK_SAMSUNG_PLL0831X "samsung_clk_pll0831x"
23
24struct samsung_clk_pll {
25 struct clk clk;
26 void __iomem *con_reg;
27 enum samsung_pll_type type;
28};
29
30#define to_clk_pll(_clk) container_of(_clk, struct samsung_clk_pll, clk)
31
32/*
33 * PLL0822x Clock Type
34 */
35
36#define PLL0822X_MDIV_MASK 0x3ff
37#define PLL0822X_PDIV_MASK 0x3f
38#define PLL0822X_SDIV_MASK 0x7
39#define PLL0822X_MDIV_SHIFT 16
40#define PLL0822X_PDIV_SHIFT 8
41#define PLL0822X_SDIV_SHIFT 0
42
43static unsigned long samsung_pll0822x_recalc_rate(struct clk *clk)
44{
45 struct samsung_clk_pll *pll = to_clk_pll(clk);
46 u32 mdiv, pdiv, sdiv, pll_con3;
47 u64 fvco = clk_get_parent_rate(clk);
48
49 pll_con3 = readl_relaxed(pll->con_reg);
50 mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK;
51 pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK;
52 sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK;
53
54 fvco *= mdiv;
55 do_div(fvco, (pdiv << sdiv));
56 return (unsigned long)fvco;
57}
58
59static const struct clk_ops samsung_pll0822x_clk_min_ops = {
60 .get_rate = samsung_pll0822x_recalc_rate,
61};
62
63/*
64 * PLL0831x Clock Type
65 */
66
67#define PLL0831X_KDIV_MASK 0xffff
68#define PLL0831X_MDIV_MASK 0x1ff
69#define PLL0831X_PDIV_MASK 0x3f
70#define PLL0831X_SDIV_MASK 0x7
71#define PLL0831X_MDIV_SHIFT 16
72#define PLL0831X_PDIV_SHIFT 8
73#define PLL0831X_SDIV_SHIFT 0
74#define PLL0831X_KDIV_SHIFT 0
75
76static unsigned long samsung_pll0831x_recalc_rate(struct clk *clk)
77{
78 struct samsung_clk_pll *pll = to_clk_pll(clk);
79 u32 mdiv, pdiv, sdiv, pll_con3, pll_con5;
80 s16 kdiv;
81 u64 fvco = clk_get_parent_rate(clk);
82
83 pll_con3 = readl_relaxed(pll->con_reg);
84 pll_con5 = readl_relaxed(pll->con_reg + 8);
85 mdiv = (pll_con3 >> PLL0831X_MDIV_SHIFT) & PLL0831X_MDIV_MASK;
86 pdiv = (pll_con3 >> PLL0831X_PDIV_SHIFT) & PLL0831X_PDIV_MASK;
87 sdiv = (pll_con3 >> PLL0831X_SDIV_SHIFT) & PLL0831X_SDIV_MASK;
88 kdiv = (s16)((pll_con5 >> PLL0831X_KDIV_SHIFT) & PLL0831X_KDIV_MASK);
89
90 fvco *= (mdiv << 16) + kdiv;
91 do_div(fvco, (pdiv << sdiv));
92 fvco >>= 16;
93
94 return (unsigned long)fvco;
95}
96
97static const struct clk_ops samsung_pll0831x_clk_min_ops = {
98 .get_rate = samsung_pll0831x_recalc_rate,
99};
100
101static struct clk *_samsung_clk_register_pll(void __iomem *base,
102 const struct samsung_pll_clock *pll_clk)
103{
104 struct samsung_clk_pll *pll;
105 struct clk *clk;
106 const char *drv_name;
107 int ret;
108
109 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
110 if (!pll)
111 return ERR_PTR(-ENOMEM);
112
113 pll->con_reg = base + pll_clk->con_offset;
114 pll->type = pll_clk->type;
115 clk = &pll->clk;
116 clk->flags = pll_clk->flags;
117
118 switch (pll_clk->type) {
119 case pll_0822x:
120 drv_name = UBOOT_DM_CLK_SAMSUNG_PLL0822X;
121 break;
122 case pll_0831x:
123 drv_name = UBOOT_DM_CLK_SAMSUNG_PLL0831X;
124 break;
125 default:
126 kfree(pll);
127 return ERR_PTR(-ENODEV);
128 }
129
130 ret = clk_register(clk, drv_name, pll_clk->name, pll_clk->parent_name);
131 if (ret) {
132 kfree(pll);
133 return ERR_PTR(ret);
134 }
135
136 return clk;
137}
138
Sam Protsenko62112352024-03-07 20:18:57 -0600139void samsung_clk_register_pll(void __iomem *base, unsigned int cmu_id,
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600140 const struct samsung_pll_clock *clk_list,
141 unsigned int nr_clk)
142{
143 unsigned int cnt;
144
145 for (cnt = 0; cnt < nr_clk; cnt++) {
146 struct clk *clk;
147 const struct samsung_pll_clock *pll_clk;
Sam Protsenko62112352024-03-07 20:18:57 -0600148 unsigned long clk_id;
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600149
150 pll_clk = &clk_list[cnt];
151 clk = _samsung_clk_register_pll(base, pll_clk);
Sam Protsenko62112352024-03-07 20:18:57 -0600152 clk_id = SAMSUNG_TO_CLK_ID(cmu_id, pll_clk->id);
153 clk_dm(clk_id, clk);
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600154 }
155}
156
157U_BOOT_DRIVER(samsung_pll0822x_clk) = {
158 .name = UBOOT_DM_CLK_SAMSUNG_PLL0822X,
159 .id = UCLASS_CLK,
160 .ops = &samsung_pll0822x_clk_min_ops,
161 .flags = DM_FLAG_PRE_RELOC,
162};
163
164U_BOOT_DRIVER(samsung_pll0831x_clk) = {
165 .name = UBOOT_DM_CLK_SAMSUNG_PLL0831X,
166 .id = UCLASS_CLK,
167 .ops = &samsung_pll0831x_clk_min_ops,
168 .flags = DM_FLAG_PRE_RELOC,
169};