612a1718dcb5c9667a598ff2332b2b5f479e7585
[platform/kernel/u-boot.git] / drivers / clk / altera / clk-arria10.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 Marek Vasut <marex@denx.de>
4  */
5
6 #include <common.h>
7 #include <asm/io.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <dm/lists.h>
11 #include <dm/util.h>
12
13 #include <asm/arch/clock_manager.h>
14
15 enum socfpga_a10_clk_type {
16         SOCFPGA_A10_CLK_MAIN_PLL,
17         SOCFPGA_A10_CLK_PER_PLL,
18         SOCFPGA_A10_CLK_PERIP_CLK,
19         SOCFPGA_A10_CLK_GATE_CLK,
20         SOCFPGA_A10_CLK_UNKNOWN_CLK,
21 };
22
23 struct socfpga_a10_clk_platdata {
24         enum socfpga_a10_clk_type type;
25         struct clk_bulk clks;
26         u32             regs;
27         /* Fixed divider */
28         u16             fix_div;
29         /* Control register */
30         u16             ctl_reg;
31         /* Divider register */
32         u16             div_reg;
33         u8              div_len;
34         u8              div_off;
35         /* Clock gating register */
36         u16             gate_reg;
37         u8              gate_bit;
38 };
39
40 static int socfpga_a10_clk_get_upstream(struct clk *clk, struct clk **upclk)
41 {
42         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(clk->dev);
43         u32 reg, maxval;
44
45         if (plat->clks.count == 0)
46                 return 0;
47
48         if (plat->clks.count == 1) {
49                 *upclk = &plat->clks.clks[0];
50                 return 0;
51         }
52
53         if (!plat->ctl_reg) {
54                 dev_err(clk->dev, "Invalid control register\n");
55                 return -EINVAL;
56         }
57
58         reg = readl(plat->regs + plat->ctl_reg);
59
60         /* Assume PLLs are ON for now */
61         if (plat->type == SOCFPGA_A10_CLK_MAIN_PLL) {
62                 reg = (reg >> 8) & 0x3;
63                 maxval = 2;
64         } else if (plat->type == SOCFPGA_A10_CLK_PER_PLL) {
65                 reg = (reg >> 8) & 0x3;
66                 maxval = 3;
67         } else {
68                 reg = (reg >> 16) & 0x7;
69                 maxval = 4;
70         }
71
72         if (reg > maxval) {
73                 dev_err(clk->dev, "Invalid clock source\n");
74                 return -EINVAL;
75         }
76
77         *upclk = &plat->clks.clks[reg];
78         return 0;
79 }
80
81 static int socfpga_a10_clk_endisable(struct clk *clk, bool enable)
82 {
83         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(clk->dev);
84         struct clk *upclk = NULL;
85         int ret;
86
87         if (!enable && plat->gate_reg)
88                 clrbits_le32(plat->regs + plat->gate_reg, BIT(plat->gate_bit));
89
90         ret = socfpga_a10_clk_get_upstream(clk, &upclk);
91         if (ret)
92                 return ret;
93
94         if (upclk) {
95                 if (enable)
96                         clk_enable(upclk);
97                 else
98                         clk_disable(upclk);
99         }
100
101         if (enable && plat->gate_reg)
102                 setbits_le32(plat->regs + plat->gate_reg, BIT(plat->gate_bit));
103
104         return 0;
105 }
106
107 static int socfpga_a10_clk_enable(struct clk *clk)
108 {
109         return socfpga_a10_clk_endisable(clk, true);
110 }
111
112 static int socfpga_a10_clk_disable(struct clk *clk)
113 {
114         return socfpga_a10_clk_endisable(clk, false);
115 }
116
117 static ulong socfpga_a10_clk_get_rate(struct clk *clk)
118 {
119         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(clk->dev);
120         struct clk *upclk = NULL;
121         ulong rate = 0, reg, numer, denom;
122         int ret;
123
124         ret = socfpga_a10_clk_get_upstream(clk, &upclk);
125         if (ret || !upclk)
126                 return 0;
127
128         rate = clk_get_rate(upclk);
129
130         if (plat->type == SOCFPGA_A10_CLK_MAIN_PLL) {
131                 reg = readl(plat->regs + plat->ctl_reg + 4);    /* VCO1 */
132                 numer = reg & CLKMGR_MAINPLL_VCO1_NUMER_MSK;
133                 denom = (reg >> CLKMGR_MAINPLL_VCO1_DENOM_LSB) &
134                         CLKMGR_MAINPLL_VCO1_DENOM_MSK;
135
136                 rate /= denom + 1;
137                 rate *= numer + 1;
138         } else if (plat->type == SOCFPGA_A10_CLK_PER_PLL) {
139                 reg = readl(plat->regs + plat->ctl_reg + 4);    /* VCO1 */
140                 numer = reg & CLKMGR_PERPLL_VCO1_NUMER_MSK;
141                 denom = (reg >> CLKMGR_PERPLL_VCO1_DENOM_LSB) &
142                         CLKMGR_PERPLL_VCO1_DENOM_MSK;
143
144                 rate /= denom + 1;
145                 rate *= numer + 1;
146         } else {
147                 rate /= plat->fix_div;
148
149                 if (plat->fix_div == 1 && plat->ctl_reg) {
150                         reg = readl(plat->regs + plat->ctl_reg);
151                         reg &= 0x7ff;
152                         rate /= reg + 1;
153                 }
154
155                 if (plat->div_reg) {
156                         reg = readl(plat->regs + plat->div_reg);
157                         reg >>= plat->div_off;
158                         reg &= (1 << plat->div_len) - 1;
159                         if (plat->type == SOCFPGA_A10_CLK_PERIP_CLK)
160                                 rate /= reg + 1;
161                         if (plat->type == SOCFPGA_A10_CLK_GATE_CLK)
162                                 rate /= 1 << reg;
163                 }
164         }
165
166         return rate;
167 }
168
169 static struct clk_ops socfpga_a10_clk_ops = {
170         .enable         = socfpga_a10_clk_enable,
171         .disable        = socfpga_a10_clk_disable,
172         .get_rate       = socfpga_a10_clk_get_rate,
173 };
174
175 /*
176  * This workaround tries to fix the massively broken generated "handoff" DT,
177  * which contains duplicate clock nodes without any connection to the clock
178  * manager DT node. Yet, those "handoff" DT nodes contain configuration of
179  * the fixed input clock of the Arria10 which are missing from the base DT
180  * for Arria10.
181  *
182  * This workaround sets up upstream clock for the fixed input clocks of the
183  * A10 described in the base DT such that they map to the fixed clock from
184  * the "handoff" DT. This does not fully match how the clock look on the
185  * A10, but it is the least intrusive way to fix this mess.
186  */
187 static void socfpga_a10_handoff_workaround(struct udevice *dev)
188 {
189         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
190         const void *fdt = gd->fdt_blob;
191         struct clk_bulk *bulk = &plat->clks;
192         int i, ret, offset = dev_of_offset(dev);
193         static const char * const socfpga_a10_fixedclk_map[] = {
194                 "osc1", "altera_arria10_hps_eosc1",
195                 "cb_intosc_ls_clk", "altera_arria10_hps_cb_intosc_ls",
196                 "f2s_free_clk", "altera_arria10_hps_f2h_free",
197         };
198
199         if (fdt_node_check_compatible(fdt, offset, "fixed-clock"))
200                 return;
201
202         for (i = 0; i < ARRAY_SIZE(socfpga_a10_fixedclk_map); i += 2)
203                 if (!strcmp(dev->name, socfpga_a10_fixedclk_map[i]))
204                         break;
205
206         if (i == ARRAY_SIZE(socfpga_a10_fixedclk_map))
207                 return;
208
209         ret = uclass_get_device_by_name(UCLASS_CLK,
210                                         socfpga_a10_fixedclk_map[i + 1], &dev);
211         if (ret)
212                 return;
213
214         bulk->count = 1;
215         bulk->clks = devm_kcalloc(dev, bulk->count,
216                                   sizeof(struct clk), GFP_KERNEL);
217         if (!bulk->clks)
218                 return;
219
220         ret = clk_request(dev, &bulk->clks[0]);
221         if (ret)
222                 free(bulk->clks);
223 }
224
225 static int socfpga_a10_clk_bind(struct udevice *dev)
226 {
227         const void *fdt = gd->fdt_blob;
228         int offset = dev_of_offset(dev);
229         bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
230         const char *name;
231         int ret;
232
233         for (offset = fdt_first_subnode(fdt, offset);
234              offset > 0;
235              offset = fdt_next_subnode(fdt, offset)) {
236                 name = fdt_get_name(fdt, offset, NULL);
237                 if (!name)
238                         return -EINVAL;
239
240                 if (!strcmp(name, "clocks")) {
241                         offset = fdt_first_subnode(fdt, offset);
242                         name = fdt_get_name(fdt, offset, NULL);
243                         if (!name)
244                                 return -EINVAL;
245                 }
246
247                 /* Filter out supported sub-clock */
248                 if (fdt_node_check_compatible(fdt, offset,
249                                               "altr,socfpga-a10-pll-clock") &&
250                     fdt_node_check_compatible(fdt, offset,
251                                               "altr,socfpga-a10-perip-clk") &&
252                     fdt_node_check_compatible(fdt, offset,
253                                               "altr,socfpga-a10-gate-clk") &&
254                     fdt_node_check_compatible(fdt, offset, "fixed-clock"))
255                         continue;
256
257                 if (pre_reloc_only && !dm_fdt_pre_reloc(fdt, offset))
258                         continue;
259
260                 ret = device_bind_driver_to_node(dev, "clk-a10", name,
261                                                  offset_to_ofnode(offset),
262                                                  NULL);
263                 if (ret)
264                         return ret;
265         }
266
267         return 0;
268 }
269
270 static int socfpga_a10_clk_probe(struct udevice *dev)
271 {
272         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
273         const void *fdt = gd->fdt_blob;
274         int offset = dev_of_offset(dev);
275
276         clk_get_bulk(dev, &plat->clks);
277
278         socfpga_a10_handoff_workaround(dev);
279
280         if (!fdt_node_check_compatible(fdt, offset,
281                                        "altr,socfpga-a10-pll-clock")) {
282                 /* Main PLL has 3 upstream clock */
283                 if (plat->clks.count == 3)
284                         plat->type = SOCFPGA_A10_CLK_MAIN_PLL;
285                 else
286                         plat->type = SOCFPGA_A10_CLK_PER_PLL;
287         } else if (!fdt_node_check_compatible(fdt, offset,
288                                               "altr,socfpga-a10-perip-clk")) {
289                 plat->type = SOCFPGA_A10_CLK_PERIP_CLK;
290         } else if (!fdt_node_check_compatible(fdt, offset,
291                                               "altr,socfpga-a10-gate-clk")) {
292                 plat->type = SOCFPGA_A10_CLK_GATE_CLK;
293         } else {
294                 plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
295         }
296
297         return 0;
298 }
299
300 static int socfpga_a10_ofdata_to_platdata(struct udevice *dev)
301 {
302         struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
303         struct socfpga_a10_clk_platdata *pplat;
304         struct udevice *pdev;
305         const void *fdt = gd->fdt_blob;
306         unsigned int divreg[3], gatereg[2];
307         int ret, offset = dev_of_offset(dev);
308         u32 regs;
309
310         regs = dev_read_u32_default(dev, "reg", 0x0);
311
312         if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
313                 plat->regs = devfdt_get_addr(dev);
314         } else {
315                 pdev = dev_get_parent(dev);
316                 if (!pdev)
317                         return -ENODEV;
318
319                 pplat = dev_get_platdata(pdev);
320                 if (!pplat)
321                         return -EINVAL;
322
323                 plat->ctl_reg = regs;
324                 plat->regs = pplat->regs;
325         }
326
327         plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
328
329         plat->fix_div = dev_read_u32_default(dev, "fixed-divider", 1);
330
331         ret = dev_read_u32_array(dev, "div-reg", divreg, ARRAY_SIZE(divreg));
332         if (!ret) {
333                 plat->div_reg = divreg[0];
334                 plat->div_len = divreg[2];
335                 plat->div_off = divreg[1];
336         }
337
338         ret = dev_read_u32_array(dev, "clk-gate", gatereg, ARRAY_SIZE(gatereg));
339         if (!ret) {
340                 plat->gate_reg = gatereg[0];
341                 plat->gate_bit = gatereg[1];
342         }
343
344         return 0;
345 }
346
347 static const struct udevice_id socfpga_a10_clk_match[] = {
348         { .compatible = "altr,clk-mgr" },
349         {}
350 };
351
352 U_BOOT_DRIVER(socfpga_a10_clk) = {
353         .name           = "clk-a10",
354         .id             = UCLASS_CLK,
355         .of_match       = socfpga_a10_clk_match,
356         .ops            = &socfpga_a10_clk_ops,
357         .bind           = socfpga_a10_clk_bind,
358         .probe          = socfpga_a10_clk_probe,
359         .ofdata_to_platdata = socfpga_a10_ofdata_to_platdata,
360
361         .platdata_auto_alloc_size = sizeof(struct socfpga_a10_clk_platdata),
362 };