Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / drivers / clk / uniphier / clk-uniphier-core.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016-2017 Socionext Inc.
4  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5  */
6
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <dm/device_compat.h>
11 #include <linux/bitops.h>
12 #include <linux/bug.h>
13 #include <linux/io.h>
14 #include <linux/sizes.h>
15
16 #include "clk-uniphier.h"
17
18 /**
19  * struct uniphier_clk_priv - private data for UniPhier clock driver
20  *
21  * @base: base address of the clock provider
22  * @data: SoC specific data
23  */
24 struct uniphier_clk_priv {
25         struct udevice *dev;
26         void __iomem *base;
27         const struct uniphier_clk_data *data;
28 };
29
30 static void uniphier_clk_gate_enable(struct uniphier_clk_priv *priv,
31                                      const struct uniphier_clk_gate_data *gate)
32 {
33         u32 val;
34
35         val = readl(priv->base + gate->reg);
36         val |= BIT(gate->bit);
37         writel(val, priv->base + gate->reg);
38 }
39
40 static void uniphier_clk_mux_set_parent(struct uniphier_clk_priv *priv,
41                                         const struct uniphier_clk_mux_data *mux,
42                                         u8 id)
43 {
44         u32 val;
45         int i;
46
47         for (i = 0; i < mux->num_parents; i++) {
48                 if (mux->parent_ids[i] != id)
49                         continue;
50
51                 val = readl(priv->base + mux->reg);
52                 val &= ~mux->masks[i];
53                 val |= mux->vals[i];
54                 writel(val, priv->base + mux->reg);
55                 return;
56         }
57
58         WARN_ON(1);
59 }
60
61 static u8 uniphier_clk_mux_get_parent(struct uniphier_clk_priv *priv,
62                                       const struct uniphier_clk_mux_data *mux)
63 {
64         u32 val;
65         int i;
66
67         val = readl(priv->base + mux->reg);
68
69         for (i = 0; i < mux->num_parents; i++)
70                 if ((mux->masks[i] & val) == mux->vals[i])
71                         return mux->parent_ids[i];
72
73         dev_err(priv->dev, "invalid mux setting\n");
74
75         return UNIPHIER_CLK_ID_INVALID;
76 }
77
78 static const struct uniphier_clk_data *uniphier_clk_get_data(
79                                         struct uniphier_clk_priv *priv, u8 id)
80 {
81         const struct uniphier_clk_data *data;
82
83         for (data = priv->data; data->type != UNIPHIER_CLK_TYPE_END; data++)
84                 if (data->id == id)
85                         return data;
86
87         dev_err(priv->dev, "id=%u not found\n", id);
88
89         return NULL;
90 }
91
92 static const struct uniphier_clk_data *uniphier_clk_get_parent_data(
93                                         struct uniphier_clk_priv *priv,
94                                         const struct uniphier_clk_data *data)
95 {
96         const struct uniphier_clk_data *parent_data;
97         u8 parent_id = UNIPHIER_CLK_ID_INVALID;
98
99         switch (data->type) {
100         case UNIPHIER_CLK_TYPE_GATE:
101                 parent_id = data->data.gate.parent_id;
102                 break;
103         case UNIPHIER_CLK_TYPE_MUX:
104                 parent_id = uniphier_clk_mux_get_parent(priv, &data->data.mux);
105                 break;
106         default:
107                 break;
108         }
109
110         if (parent_id == UNIPHIER_CLK_ID_INVALID)
111                 return NULL;
112
113         parent_data = uniphier_clk_get_data(priv, parent_id);
114
115         WARN_ON(!parent_data);
116
117         return parent_data;
118 }
119
120 static void __uniphier_clk_enable(struct uniphier_clk_priv *priv,
121                                   const struct uniphier_clk_data *data)
122 {
123         const struct uniphier_clk_data *parent_data;
124
125         if (data->type == UNIPHIER_CLK_TYPE_GATE)
126                 uniphier_clk_gate_enable(priv, &data->data.gate);
127
128         parent_data = uniphier_clk_get_parent_data(priv, data);
129         if (!parent_data)
130                 return;
131
132         return __uniphier_clk_enable(priv, parent_data);
133 }
134
135 static int uniphier_clk_enable(struct clk *clk)
136 {
137         struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
138         const struct uniphier_clk_data *data;
139
140         data = uniphier_clk_get_data(priv, clk->id);
141         if (!data)
142                 return -ENODEV;
143
144         __uniphier_clk_enable(priv, data);
145
146         return 0;
147 }
148
149 static unsigned long __uniphier_clk_get_rate(
150                                         struct uniphier_clk_priv *priv,
151                                         const struct uniphier_clk_data *data)
152 {
153         const struct uniphier_clk_data *parent_data;
154
155         if (data->type == UNIPHIER_CLK_TYPE_FIXED_RATE)
156                 return data->data.rate.fixed_rate;
157
158         parent_data = uniphier_clk_get_parent_data(priv, data);
159         if (!parent_data)
160                 return 0;
161
162         return __uniphier_clk_get_rate(priv, parent_data);
163 }
164
165 static unsigned long uniphier_clk_get_rate(struct clk *clk)
166 {
167         struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
168         const struct uniphier_clk_data *data;
169
170         data = uniphier_clk_get_data(priv, clk->id);
171         if (!data)
172                 return -ENODEV;
173
174         return __uniphier_clk_get_rate(priv, data);
175 }
176
177 static unsigned long __uniphier_clk_set_rate(
178                                         struct uniphier_clk_priv *priv,
179                                         const struct uniphier_clk_data *data,
180                                         unsigned long rate, bool set)
181 {
182         const struct uniphier_clk_data *best_parent_data = NULL;
183         const struct uniphier_clk_data *parent_data;
184         unsigned long best_rate = 0;
185         unsigned long parent_rate;
186         u8 parent_id;
187         int i;
188
189         if (data->type == UNIPHIER_CLK_TYPE_FIXED_RATE)
190                 return data->data.rate.fixed_rate;
191
192         if (data->type == UNIPHIER_CLK_TYPE_GATE) {
193                 parent_data = uniphier_clk_get_parent_data(priv, data);
194                 if (!parent_data)
195                         return 0;
196
197                 return __uniphier_clk_set_rate(priv, parent_data, rate, set);
198         }
199
200         if (WARN_ON(data->type != UNIPHIER_CLK_TYPE_MUX))
201                 return -EINVAL;
202
203         for (i = 0; i < data->data.mux.num_parents; i++) {
204                 parent_id = data->data.mux.parent_ids[i];
205                 parent_data = uniphier_clk_get_data(priv, parent_id);
206                 if (WARN_ON(!parent_data))
207                         return -EINVAL;
208
209                 parent_rate = __uniphier_clk_set_rate(priv, parent_data, rate,
210                                                       false);
211
212                 if (parent_rate <= rate && best_rate < parent_rate) {
213                         best_rate = parent_rate;
214                         best_parent_data = parent_data;
215                 }
216         }
217
218         dev_dbg(priv->dev, "id=%u, best_rate=%lu\n", data->id, best_rate);
219
220         if (!best_parent_data)
221                 return -EINVAL;
222
223         if (!set)
224                 return best_rate;
225
226         uniphier_clk_mux_set_parent(priv, &data->data.mux,
227                                     best_parent_data->id);
228
229         return best_rate = __uniphier_clk_set_rate(priv, best_parent_data,
230                                                    rate, true);
231 }
232
233 static unsigned long uniphier_clk_set_rate(struct clk *clk, ulong rate)
234 {
235         struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
236         const struct uniphier_clk_data *data;
237
238         data = uniphier_clk_get_data(priv, clk->id);
239         if (!data)
240                 return -ENODEV;
241
242         return __uniphier_clk_set_rate(priv, data, rate, true);
243 }
244
245 static const struct clk_ops uniphier_clk_ops = {
246         .enable = uniphier_clk_enable,
247         .get_rate = uniphier_clk_get_rate,
248         .set_rate = uniphier_clk_set_rate,
249 };
250
251 static int uniphier_clk_probe(struct udevice *dev)
252 {
253         struct uniphier_clk_priv *priv = dev_get_priv(dev);
254         fdt_addr_t addr;
255
256         addr = devfdt_get_addr(dev->parent);
257         if (addr == FDT_ADDR_T_NONE)
258                 return -EINVAL;
259
260         priv->base = devm_ioremap(dev, addr, SZ_4K);
261         if (!priv->base)
262                 return -ENOMEM;
263
264         priv->dev = dev;
265         priv->data = (void *)dev_get_driver_data(dev);
266
267         return 0;
268 }
269
270 static const struct udevice_id uniphier_clk_match[] = {
271         /* System clock */
272         {
273                 .compatible = "socionext,uniphier-ld4-clock",
274                 .data = (ulong)uniphier_pxs2_sys_clk_data,
275         },
276         {
277                 .compatible = "socionext,uniphier-pro4-clock",
278                 .data = (ulong)uniphier_pxs2_sys_clk_data,
279         },
280         {
281                 .compatible = "socionext,uniphier-sld8-clock",
282                 .data = (ulong)uniphier_pxs2_sys_clk_data,
283         },
284         {
285                 .compatible = "socionext,uniphier-pro5-clock",
286                 .data = (ulong)uniphier_pxs2_sys_clk_data,
287         },
288         {
289                 .compatible = "socionext,uniphier-pxs2-clock",
290                 .data = (ulong)uniphier_pxs2_sys_clk_data,
291         },
292         {
293                 .compatible = "socionext,uniphier-ld11-clock",
294                 .data = (ulong)uniphier_ld20_sys_clk_data,
295         },
296         {
297                 .compatible = "socionext,uniphier-ld20-clock",
298                 .data = (ulong)uniphier_ld20_sys_clk_data,
299         },
300         {
301                 .compatible = "socionext,uniphier-pxs3-clock",
302                 .data = (ulong)uniphier_pxs3_sys_clk_data,
303         },
304         /* Media I/O clock */
305         {
306                 .compatible = "socionext,uniphier-ld4-mio-clock",
307                 .data = (ulong)uniphier_mio_clk_data,
308         },
309         {
310                 .compatible = "socionext,uniphier-pro4-mio-clock",
311                 .data = (ulong)uniphier_mio_clk_data,
312         },
313         {
314                 .compatible = "socionext,uniphier-sld8-mio-clock",
315                 .data = (ulong)uniphier_mio_clk_data,
316         },
317         {
318                 .compatible = "socionext,uniphier-pro5-sd-clock",
319                 .data = (ulong)uniphier_mio_clk_data,
320         },
321         {
322                 .compatible = "socionext,uniphier-pxs2-sd-clock",
323                 .data = (ulong)uniphier_mio_clk_data,
324         },
325         {
326                 .compatible = "socionext,uniphier-ld11-mio-clock",
327                 .data = (ulong)uniphier_mio_clk_data,
328         },
329         {
330                 .compatible = "socionext,uniphier-ld20-sd-clock",
331                 .data = (ulong)uniphier_mio_clk_data,
332         },
333         {
334                 .compatible = "socionext,uniphier-pxs3-sd-clock",
335                 .data = (ulong)uniphier_mio_clk_data,
336         },
337         { /* sentinel */ }
338 };
339
340 U_BOOT_DRIVER(uniphier_clk) = {
341         .name = "uniphier-clk",
342         .id = UCLASS_CLK,
343         .of_match = uniphier_clk_match,
344         .probe = uniphier_clk_probe,
345         .priv_auto_alloc_size = sizeof(struct uniphier_clk_priv),
346         .ops = &uniphier_clk_ops,
347 };