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 
socfpga_a10_clk_get_upstream(struct clk * clk,struct clk ** upclk)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 
socfpga_a10_clk_endisable(struct clk * clk,bool enable)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 
socfpga_a10_clk_enable(struct clk * clk)107 static int socfpga_a10_clk_enable(struct clk *clk)
108 {
109 	return socfpga_a10_clk_endisable(clk, true);
110 }
111 
socfpga_a10_clk_disable(struct clk * clk)112 static int socfpga_a10_clk_disable(struct clk *clk)
113 {
114 	return socfpga_a10_clk_endisable(clk, false);
115 }
116 
socfpga_a10_clk_get_rate(struct clk * clk)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  */
socfpga_a10_handoff_workaround(struct udevice * dev)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 
socfpga_a10_clk_bind(struct udevice * dev)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 
socfpga_a10_clk_probe(struct udevice * dev)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 
socfpga_a10_ofdata_to_platdata(struct udevice * dev)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 };
363