1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Marek Vasut <marex@denx.de>
9 #include <clk-uclass.h>
11 #include <dm/device_compat.h>
12 #include <dm/devres.h>
15 #include <linux/bitops.h>
17 #include <asm/arch/clock_manager.h>
19 enum socfpga_a10_clk_type {
20 SOCFPGA_A10_CLK_MAIN_PLL,
21 SOCFPGA_A10_CLK_PER_PLL,
22 SOCFPGA_A10_CLK_PERIP_CLK,
23 SOCFPGA_A10_CLK_GATE_CLK,
24 SOCFPGA_A10_CLK_UNKNOWN_CLK,
27 struct socfpga_a10_clk_plat {
28 enum socfpga_a10_clk_type type;
33 /* Control register */
35 /* Divider register */
39 /* Clock gating register */
44 static int socfpga_a10_clk_get_upstream(struct clk *clk, struct clk **upclk)
46 struct socfpga_a10_clk_plat *plat = dev_get_plat(clk->dev);
49 if (plat->clks.count == 0)
52 if (plat->clks.count == 1) {
53 *upclk = &plat->clks.clks[0];
58 dev_err(clk->dev, "Invalid control register\n");
62 reg = readl(plat->regs + plat->ctl_reg);
64 /* Assume PLLs are ON for now */
65 if (plat->type == SOCFPGA_A10_CLK_MAIN_PLL) {
66 reg = (reg >> 8) & 0x3;
68 } else if (plat->type == SOCFPGA_A10_CLK_PER_PLL) {
69 reg = (reg >> 8) & 0x3;
72 reg = (reg >> 16) & 0x7;
77 dev_err(clk->dev, "Invalid clock source\n");
81 *upclk = &plat->clks.clks[reg];
85 static int socfpga_a10_clk_endisable(struct clk *clk, bool enable)
87 struct socfpga_a10_clk_plat *plat = dev_get_plat(clk->dev);
88 struct clk *upclk = NULL;
91 if (!enable && plat->gate_reg)
92 clrbits_le32(plat->regs + plat->gate_reg, BIT(plat->gate_bit));
94 ret = socfpga_a10_clk_get_upstream(clk, &upclk);
105 if (enable && plat->gate_reg)
106 setbits_le32(plat->regs + plat->gate_reg, BIT(plat->gate_bit));
111 static int socfpga_a10_clk_enable(struct clk *clk)
113 return socfpga_a10_clk_endisable(clk, true);
116 static int socfpga_a10_clk_disable(struct clk *clk)
118 return socfpga_a10_clk_endisable(clk, false);
121 static ulong socfpga_a10_clk_get_rate(struct clk *clk)
123 struct socfpga_a10_clk_plat *plat = dev_get_plat(clk->dev);
124 struct clk *upclk = NULL;
125 ulong rate = 0, reg, numer, denom;
128 ret = socfpga_a10_clk_get_upstream(clk, &upclk);
132 rate = clk_get_rate(upclk);
134 if (plat->type == SOCFPGA_A10_CLK_MAIN_PLL) {
135 reg = readl(plat->regs + plat->ctl_reg + 4); /* VCO1 */
136 numer = reg & CLKMGR_MAINPLL_VCO1_NUMER_MSK;
137 denom = (reg >> CLKMGR_MAINPLL_VCO1_DENOM_LSB) &
138 CLKMGR_MAINPLL_VCO1_DENOM_MSK;
142 } else if (plat->type == SOCFPGA_A10_CLK_PER_PLL) {
143 reg = readl(plat->regs + plat->ctl_reg + 4); /* VCO1 */
144 numer = reg & CLKMGR_PERPLL_VCO1_NUMER_MSK;
145 denom = (reg >> CLKMGR_PERPLL_VCO1_DENOM_LSB) &
146 CLKMGR_PERPLL_VCO1_DENOM_MSK;
151 rate /= plat->fix_div;
153 if (plat->fix_div == 1 && plat->ctl_reg) {
154 reg = readl(plat->regs + plat->ctl_reg);
160 reg = readl(plat->regs + plat->div_reg);
161 reg >>= plat->div_off;
162 reg &= (1 << plat->div_len) - 1;
163 if (plat->type == SOCFPGA_A10_CLK_PERIP_CLK)
165 if (plat->type == SOCFPGA_A10_CLK_GATE_CLK)
173 static struct clk_ops socfpga_a10_clk_ops = {
174 .enable = socfpga_a10_clk_enable,
175 .disable = socfpga_a10_clk_disable,
176 .get_rate = socfpga_a10_clk_get_rate,
180 * This workaround tries to fix the massively broken generated "handoff" DT,
181 * which contains duplicate clock nodes without any connection to the clock
182 * manager DT node. Yet, those "handoff" DT nodes contain configuration of
183 * the fixed input clock of the Arria10 which are missing from the base DT
186 * This workaround sets up upstream clock for the fixed input clocks of the
187 * A10 described in the base DT such that they map to the fixed clock from
188 * the "handoff" DT. This does not fully match how the clock look on the
189 * A10, but it is the least intrusive way to fix this mess.
191 static void socfpga_a10_handoff_workaround(struct udevice *dev)
193 struct socfpga_a10_clk_plat *plat = dev_get_plat(dev);
194 const void *fdt = gd->fdt_blob;
195 struct clk_bulk *bulk = &plat->clks;
196 int i, ret, offset = dev_of_offset(dev);
197 static const char * const socfpga_a10_fixedclk_map[] = {
198 "osc1", "altera_arria10_hps_eosc1",
199 "cb_intosc_ls_clk", "altera_arria10_hps_cb_intosc_ls",
200 "f2s_free_clk", "altera_arria10_hps_f2h_free",
203 if (fdt_node_check_compatible(fdt, offset, "fixed-clock"))
206 for (i = 0; i < ARRAY_SIZE(socfpga_a10_fixedclk_map); i += 2)
207 if (!strcmp(dev->name, socfpga_a10_fixedclk_map[i]))
210 if (i == ARRAY_SIZE(socfpga_a10_fixedclk_map))
213 ret = uclass_get_device_by_name(UCLASS_CLK,
214 socfpga_a10_fixedclk_map[i + 1], &dev);
219 bulk->clks = devm_kcalloc(dev, bulk->count,
220 sizeof(struct clk), GFP_KERNEL);
224 ret = clk_request(dev, &bulk->clks[0]);
229 static int socfpga_a10_clk_bind(struct udevice *dev)
231 const void *fdt = gd->fdt_blob;
232 int offset = dev_of_offset(dev);
233 bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
237 for (offset = fdt_first_subnode(fdt, offset);
239 offset = fdt_next_subnode(fdt, offset)) {
240 name = fdt_get_name(fdt, offset, NULL);
244 if (!strcmp(name, "clocks")) {
245 offset = fdt_first_subnode(fdt, offset);
246 name = fdt_get_name(fdt, offset, NULL);
251 /* Filter out supported sub-clock */
252 if (fdt_node_check_compatible(fdt, offset,
253 "altr,socfpga-a10-pll-clock") &&
254 fdt_node_check_compatible(fdt, offset,
255 "altr,socfpga-a10-perip-clk") &&
256 fdt_node_check_compatible(fdt, offset,
257 "altr,socfpga-a10-gate-clk") &&
258 fdt_node_check_compatible(fdt, offset, "fixed-clock"))
261 if (pre_reloc_only &&
262 !ofnode_pre_reloc(offset_to_ofnode(offset)))
265 ret = device_bind_driver_to_node(dev, "clk-a10", name,
266 offset_to_ofnode(offset),
275 static int socfpga_a10_clk_probe(struct udevice *dev)
277 struct socfpga_a10_clk_plat *plat = dev_get_plat(dev);
278 struct socfpga_a10_clk_plat *pplat;
279 struct udevice *pdev;
280 const void *fdt = gd->fdt_blob;
281 int offset = dev_of_offset(dev);
283 clk_get_bulk(dev, &plat->clks);
285 socfpga_a10_handoff_workaround(dev);
287 if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
288 plat->regs = dev_read_addr(dev);
290 pdev = dev_get_parent(dev);
294 pplat = dev_get_plat(pdev);
298 plat->ctl_reg = dev_read_u32_default(dev, "reg", 0x0);
299 plat->regs = pplat->regs;
302 if (!fdt_node_check_compatible(fdt, offset,
303 "altr,socfpga-a10-pll-clock")) {
304 /* Main PLL has 3 upstream clock */
305 if (plat->clks.count == 3)
306 plat->type = SOCFPGA_A10_CLK_MAIN_PLL;
308 plat->type = SOCFPGA_A10_CLK_PER_PLL;
309 } else if (!fdt_node_check_compatible(fdt, offset,
310 "altr,socfpga-a10-perip-clk")) {
311 plat->type = SOCFPGA_A10_CLK_PERIP_CLK;
312 } else if (!fdt_node_check_compatible(fdt, offset,
313 "altr,socfpga-a10-gate-clk")) {
314 plat->type = SOCFPGA_A10_CLK_GATE_CLK;
316 plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
322 static int socfpga_a10_of_to_plat(struct udevice *dev)
324 struct socfpga_a10_clk_plat *plat = dev_get_plat(dev);
325 unsigned int divreg[3], gatereg[2];
328 plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
330 plat->fix_div = dev_read_u32_default(dev, "fixed-divider", 1);
332 ret = dev_read_u32_array(dev, "div-reg", divreg, ARRAY_SIZE(divreg));
334 plat->div_reg = divreg[0];
335 plat->div_len = divreg[2];
336 plat->div_off = divreg[1];
339 ret = dev_read_u32_array(dev, "clk-gate", gatereg, ARRAY_SIZE(gatereg));
341 plat->gate_reg = gatereg[0];
342 plat->gate_bit = gatereg[1];
348 static const struct udevice_id socfpga_a10_clk_match[] = {
349 { .compatible = "altr,clk-mgr" },
353 U_BOOT_DRIVER(socfpga_a10_clk) = {
356 .of_match = socfpga_a10_clk_match,
357 .ops = &socfpga_a10_clk_ops,
358 .bind = socfpga_a10_clk_bind,
359 .probe = socfpga_a10_clk_probe,
360 .of_to_plat = socfpga_a10_of_to_plat,
362 .plat_auto = sizeof(struct socfpga_a10_clk_plat),