• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &&
258 		    !dm_ofnode_pre_reloc(offset_to_ofnode(offset)))
259 			continue;
260 
261 		ret = device_bind_driver_to_node(dev, "clk-a10", name,
262 						 offset_to_ofnode(offset),
263 						 NULL);
264 		if (ret)
265 			return ret;
266 	}
267 
268 	return 0;
269 }
270 
socfpga_a10_clk_probe(struct udevice * dev)271 static int socfpga_a10_clk_probe(struct udevice *dev)
272 {
273 	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
274 	const void *fdt = gd->fdt_blob;
275 	int offset = dev_of_offset(dev);
276 
277 	clk_get_bulk(dev, &plat->clks);
278 
279 	socfpga_a10_handoff_workaround(dev);
280 
281 	if (!fdt_node_check_compatible(fdt, offset,
282 				       "altr,socfpga-a10-pll-clock")) {
283 		/* Main PLL has 3 upstream clock */
284 		if (plat->clks.count == 3)
285 			plat->type = SOCFPGA_A10_CLK_MAIN_PLL;
286 		else
287 			plat->type = SOCFPGA_A10_CLK_PER_PLL;
288 	} else if (!fdt_node_check_compatible(fdt, offset,
289 					      "altr,socfpga-a10-perip-clk")) {
290 		plat->type = SOCFPGA_A10_CLK_PERIP_CLK;
291 	} else if (!fdt_node_check_compatible(fdt, offset,
292 					      "altr,socfpga-a10-gate-clk")) {
293 		plat->type = SOCFPGA_A10_CLK_GATE_CLK;
294 	} else {
295 		plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
296 	}
297 
298 	return 0;
299 }
300 
socfpga_a10_ofdata_to_platdata(struct udevice * dev)301 static int socfpga_a10_ofdata_to_platdata(struct udevice *dev)
302 {
303 	struct socfpga_a10_clk_platdata *plat = dev_get_platdata(dev);
304 	struct socfpga_a10_clk_platdata *pplat;
305 	struct udevice *pdev;
306 	const void *fdt = gd->fdt_blob;
307 	unsigned int divreg[3], gatereg[2];
308 	int ret, offset = dev_of_offset(dev);
309 	u32 regs;
310 
311 	regs = dev_read_u32_default(dev, "reg", 0x0);
312 
313 	if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) {
314 		plat->regs = devfdt_get_addr(dev);
315 	} else {
316 		pdev = dev_get_parent(dev);
317 		if (!pdev)
318 			return -ENODEV;
319 
320 		pplat = dev_get_platdata(pdev);
321 		if (!pplat)
322 			return -EINVAL;
323 
324 		plat->ctl_reg = regs;
325 		plat->regs = pplat->regs;
326 	}
327 
328 	plat->type = SOCFPGA_A10_CLK_UNKNOWN_CLK;
329 
330 	plat->fix_div = dev_read_u32_default(dev, "fixed-divider", 1);
331 
332 	ret = dev_read_u32_array(dev, "div-reg", divreg, ARRAY_SIZE(divreg));
333 	if (!ret) {
334 		plat->div_reg = divreg[0];
335 		plat->div_len = divreg[2];
336 		plat->div_off = divreg[1];
337 	}
338 
339 	ret = dev_read_u32_array(dev, "clk-gate", gatereg, ARRAY_SIZE(gatereg));
340 	if (!ret) {
341 		plat->gate_reg = gatereg[0];
342 		plat->gate_bit = gatereg[1];
343 	}
344 
345 	return 0;
346 }
347 
348 static const struct udevice_id socfpga_a10_clk_match[] = {
349 	{ .compatible = "altr,clk-mgr" },
350 	{}
351 };
352 
353 U_BOOT_DRIVER(socfpga_a10_clk) = {
354 	.name		= "clk-a10",
355 	.id		= UCLASS_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 	.ofdata_to_platdata = socfpga_a10_ofdata_to_platdata,
361 
362 	.platdata_auto_alloc_size = sizeof(struct socfpga_a10_clk_platdata),
363 };
364