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