1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Toshiba Visconti PLL driver |
4 | * |
5 | * Copyright (c) 2021 TOSHIBA CORPORATION |
6 | * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation |
7 | * |
8 | * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> |
9 | */ |
10 | |
11 | #include <linux/bitfield.h> |
12 | #include <linux/clk-provider.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/io.h> |
16 | |
17 | #include "pll.h" |
18 | |
19 | struct visconti_pll { |
20 | struct clk_hw hw; |
21 | void __iomem *pll_base; |
22 | spinlock_t *lock; |
23 | unsigned long flags; |
24 | const struct visconti_pll_rate_table *rate_table; |
25 | size_t rate_count; |
26 | struct visconti_pll_provider *ctx; |
27 | }; |
28 | |
29 | #define PLL_CONF_REG 0x0000 |
30 | #define PLL_CTRL_REG 0x0004 |
31 | #define PLL_FRACMODE_REG 0x0010 |
32 | #define PLL_INTIN_REG 0x0014 |
33 | #define PLL_FRACIN_REG 0x0018 |
34 | #define PLL_REFDIV_REG 0x001c |
35 | #define PLL_POSTDIV_REG 0x0020 |
36 | |
37 | #define PLL_CONFIG_SEL BIT(0) |
38 | #define PLL_PLLEN BIT(4) |
39 | #define PLL_BYPASS BIT(16) |
40 | #define PLL_INTIN_MASK GENMASK(11, 0) |
41 | #define PLL_FRACIN_MASK GENMASK(23, 0) |
42 | #define PLL_REFDIV_MASK GENMASK(5, 0) |
43 | #define PLL_POSTDIV_MASK GENMASK(2, 0) |
44 | |
45 | #define PLL0_FRACMODE_DACEN BIT(4) |
46 | #define PLL0_FRACMODE_DSMEN BIT(0) |
47 | |
48 | #define PLL_CREATE_FRACMODE(table) (table->dacen << 4 | table->dsmen) |
49 | #define PLL_CREATE_OSTDIV(table) (table->postdiv2 << 4 | table->postdiv1) |
50 | |
51 | static inline struct visconti_pll *to_visconti_pll(struct clk_hw *hw) |
52 | { |
53 | return container_of(hw, struct visconti_pll, hw); |
54 | } |
55 | |
56 | static void visconti_pll_get_params(struct visconti_pll *pll, |
57 | struct visconti_pll_rate_table *rate_table) |
58 | { |
59 | u32 postdiv, val; |
60 | |
61 | val = readl(addr: pll->pll_base + PLL_FRACMODE_REG); |
62 | |
63 | rate_table->dacen = FIELD_GET(PLL0_FRACMODE_DACEN, val); |
64 | rate_table->dsmen = FIELD_GET(PLL0_FRACMODE_DSMEN, val); |
65 | |
66 | rate_table->fracin = readl(addr: pll->pll_base + PLL_FRACIN_REG) & PLL_FRACIN_MASK; |
67 | rate_table->intin = readl(addr: pll->pll_base + PLL_INTIN_REG) & PLL_INTIN_MASK; |
68 | rate_table->refdiv = readl(addr: pll->pll_base + PLL_REFDIV_REG) & PLL_REFDIV_MASK; |
69 | |
70 | postdiv = readl(addr: pll->pll_base + PLL_POSTDIV_REG); |
71 | rate_table->postdiv1 = postdiv & PLL_POSTDIV_MASK; |
72 | rate_table->postdiv2 = (postdiv >> 4) & PLL_POSTDIV_MASK; |
73 | } |
74 | |
75 | static const struct visconti_pll_rate_table *visconti_get_pll_settings(struct visconti_pll *pll, |
76 | unsigned long rate) |
77 | { |
78 | const struct visconti_pll_rate_table *rate_table = pll->rate_table; |
79 | int i; |
80 | |
81 | for (i = 0; i < pll->rate_count; i++) |
82 | if (rate == rate_table[i].rate) |
83 | return &rate_table[i]; |
84 | |
85 | return NULL; |
86 | } |
87 | |
88 | static unsigned long visconti_get_pll_rate_from_data(struct visconti_pll *pll, |
89 | const struct visconti_pll_rate_table *rate) |
90 | { |
91 | const struct visconti_pll_rate_table *rate_table = pll->rate_table; |
92 | int i; |
93 | |
94 | for (i = 0; i < pll->rate_count; i++) |
95 | if (memcmp(p: &rate_table[i].dacen, q: &rate->dacen, |
96 | size: sizeof(*rate) - sizeof(unsigned long)) == 0) |
97 | return rate_table[i].rate; |
98 | |
99 | /* set default */ |
100 | return rate_table[0].rate; |
101 | } |
102 | |
103 | static long visconti_pll_round_rate(struct clk_hw *hw, |
104 | unsigned long rate, unsigned long *prate) |
105 | { |
106 | struct visconti_pll *pll = to_visconti_pll(hw); |
107 | const struct visconti_pll_rate_table *rate_table = pll->rate_table; |
108 | int i; |
109 | |
110 | /* Assumming rate_table is in descending order */ |
111 | for (i = 0; i < pll->rate_count; i++) |
112 | if (rate >= rate_table[i].rate) |
113 | return rate_table[i].rate; |
114 | |
115 | /* return minimum supported value */ |
116 | return rate_table[i - 1].rate; |
117 | } |
118 | |
119 | static unsigned long visconti_pll_recalc_rate(struct clk_hw *hw, |
120 | unsigned long parent_rate) |
121 | { |
122 | struct visconti_pll *pll = to_visconti_pll(hw); |
123 | struct visconti_pll_rate_table rate_table; |
124 | |
125 | memset(&rate_table, 0, sizeof(rate_table)); |
126 | visconti_pll_get_params(pll, rate_table: &rate_table); |
127 | |
128 | return visconti_get_pll_rate_from_data(pll, rate: &rate_table); |
129 | } |
130 | |
131 | static int visconti_pll_set_params(struct visconti_pll *pll, |
132 | const struct visconti_pll_rate_table *rate_table) |
133 | { |
134 | writel(PLL_CREATE_FRACMODE(rate_table), addr: pll->pll_base + PLL_FRACMODE_REG); |
135 | writel(PLL_CREATE_OSTDIV(rate_table), addr: pll->pll_base + PLL_POSTDIV_REG); |
136 | writel(val: rate_table->intin, addr: pll->pll_base + PLL_INTIN_REG); |
137 | writel(val: rate_table->fracin, addr: pll->pll_base + PLL_FRACIN_REG); |
138 | writel(val: rate_table->refdiv, addr: pll->pll_base + PLL_REFDIV_REG); |
139 | |
140 | return 0; |
141 | } |
142 | |
143 | static int visconti_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
144 | unsigned long parent_rate) |
145 | { |
146 | struct visconti_pll *pll = to_visconti_pll(hw); |
147 | const struct visconti_pll_rate_table *rate_table; |
148 | |
149 | rate_table = visconti_get_pll_settings(pll, rate); |
150 | if (!rate_table) |
151 | return -EINVAL; |
152 | |
153 | return visconti_pll_set_params(pll, rate_table); |
154 | } |
155 | |
156 | static int visconti_pll_is_enabled(struct clk_hw *hw) |
157 | { |
158 | struct visconti_pll *pll = to_visconti_pll(hw); |
159 | u32 reg; |
160 | |
161 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
162 | |
163 | return (reg & PLL_PLLEN); |
164 | } |
165 | |
166 | static int visconti_pll_enable(struct clk_hw *hw) |
167 | { |
168 | struct visconti_pll *pll = to_visconti_pll(hw); |
169 | const struct visconti_pll_rate_table *rate_table = pll->rate_table; |
170 | unsigned long flags; |
171 | u32 reg; |
172 | |
173 | if (visconti_pll_is_enabled(hw)) |
174 | return 0; |
175 | |
176 | spin_lock_irqsave(pll->lock, flags); |
177 | |
178 | writel(PLL_CONFIG_SEL, addr: pll->pll_base + PLL_CONF_REG); |
179 | |
180 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
181 | reg |= PLL_BYPASS; |
182 | writel(val: reg, addr: pll->pll_base + PLL_CTRL_REG); |
183 | |
184 | visconti_pll_set_params(pll, rate_table: &rate_table[0]); |
185 | |
186 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
187 | reg &= ~PLL_PLLEN; |
188 | writel(val: reg, addr: pll->pll_base + PLL_CTRL_REG); |
189 | |
190 | udelay(1); |
191 | |
192 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
193 | reg |= PLL_PLLEN; |
194 | writel(val: reg, addr: pll->pll_base + PLL_CTRL_REG); |
195 | |
196 | udelay(40); |
197 | |
198 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
199 | reg &= ~PLL_BYPASS; |
200 | writel(val: reg, addr: pll->pll_base + PLL_CTRL_REG); |
201 | |
202 | spin_unlock_irqrestore(lock: pll->lock, flags); |
203 | |
204 | return 0; |
205 | } |
206 | |
207 | static void visconti_pll_disable(struct clk_hw *hw) |
208 | { |
209 | struct visconti_pll *pll = to_visconti_pll(hw); |
210 | unsigned long flags; |
211 | u32 reg; |
212 | |
213 | if (!visconti_pll_is_enabled(hw)) |
214 | return; |
215 | |
216 | spin_lock_irqsave(pll->lock, flags); |
217 | |
218 | writel(PLL_CONFIG_SEL, addr: pll->pll_base + PLL_CONF_REG); |
219 | |
220 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
221 | reg |= PLL_BYPASS; |
222 | writel(val: reg, addr: pll->pll_base + PLL_CTRL_REG); |
223 | |
224 | reg = readl(addr: pll->pll_base + PLL_CTRL_REG); |
225 | reg &= ~PLL_PLLEN; |
226 | writel(val: reg, addr: pll->pll_base + PLL_CTRL_REG); |
227 | |
228 | spin_unlock_irqrestore(lock: pll->lock, flags); |
229 | } |
230 | |
231 | static const struct clk_ops visconti_pll_ops = { |
232 | .enable = visconti_pll_enable, |
233 | .disable = visconti_pll_disable, |
234 | .is_enabled = visconti_pll_is_enabled, |
235 | .round_rate = visconti_pll_round_rate, |
236 | .recalc_rate = visconti_pll_recalc_rate, |
237 | .set_rate = visconti_pll_set_rate, |
238 | }; |
239 | |
240 | static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, |
241 | const char *name, |
242 | const char *parent_name, |
243 | int offset, |
244 | const struct visconti_pll_rate_table *rate_table, |
245 | spinlock_t *lock) |
246 | { |
247 | struct clk_init_data init; |
248 | struct visconti_pll *pll; |
249 | struct clk_hw *pll_hw_clk; |
250 | size_t len; |
251 | int ret; |
252 | |
253 | pll = kzalloc(size: sizeof(*pll), GFP_KERNEL); |
254 | if (!pll) |
255 | return ERR_PTR(error: -ENOMEM); |
256 | |
257 | init.name = name; |
258 | init.flags = CLK_IGNORE_UNUSED; |
259 | init.parent_names = &parent_name; |
260 | init.num_parents = 1; |
261 | |
262 | for (len = 0; rate_table[len].rate != 0; ) |
263 | len++; |
264 | pll->rate_count = len; |
265 | pll->rate_table = kmemdup(p: rate_table, |
266 | size: pll->rate_count * sizeof(struct visconti_pll_rate_table), |
267 | GFP_KERNEL); |
268 | WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n" , __func__, name); |
269 | |
270 | init.ops = &visconti_pll_ops; |
271 | pll->hw.init = &init; |
272 | pll->pll_base = ctx->reg_base + offset; |
273 | pll->lock = lock; |
274 | pll->ctx = ctx; |
275 | |
276 | pll_hw_clk = &pll->hw; |
277 | ret = clk_hw_register(NULL, hw: &pll->hw); |
278 | if (ret) { |
279 | pr_err("failed to register pll clock %s : %d\n" , name, ret); |
280 | kfree(objp: pll->rate_table); |
281 | kfree(objp: pll); |
282 | pll_hw_clk = ERR_PTR(error: ret); |
283 | } |
284 | |
285 | return pll_hw_clk; |
286 | } |
287 | |
288 | static void visconti_pll_add_lookup(struct visconti_pll_provider *ctx, |
289 | struct clk_hw *hw_clk, |
290 | unsigned int id) |
291 | { |
292 | if (id) |
293 | ctx->clk_data.hws[id] = hw_clk; |
294 | } |
295 | |
296 | void __init visconti_register_plls(struct visconti_pll_provider *ctx, |
297 | const struct visconti_pll_info *list, |
298 | unsigned int nr_plls, |
299 | spinlock_t *lock) |
300 | { |
301 | int idx; |
302 | |
303 | for (idx = 0; idx < nr_plls; idx++, list++) { |
304 | struct clk_hw *clk; |
305 | |
306 | clk = visconti_register_pll(ctx, |
307 | name: list->name, |
308 | parent_name: list->parent, |
309 | offset: list->base_reg, |
310 | rate_table: list->rate_table, |
311 | lock); |
312 | if (IS_ERR(ptr: clk)) { |
313 | pr_err("failed to register clock %s\n" , list->name); |
314 | continue; |
315 | } |
316 | |
317 | visconti_pll_add_lookup(ctx, hw_clk: clk, id: list->id); |
318 | } |
319 | } |
320 | |
321 | struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np, |
322 | void __iomem *base, |
323 | unsigned long nr_plls) |
324 | { |
325 | struct visconti_pll_provider *ctx; |
326 | int i; |
327 | |
328 | ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_plls), GFP_KERNEL); |
329 | if (!ctx) |
330 | return ERR_PTR(error: -ENOMEM); |
331 | |
332 | ctx->node = np; |
333 | ctx->reg_base = base; |
334 | ctx->clk_data.num = nr_plls; |
335 | |
336 | for (i = 0; i < nr_plls; ++i) |
337 | ctx->clk_data.hws[i] = ERR_PTR(error: -ENOENT); |
338 | |
339 | return ctx; |
340 | } |
341 | |