Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * AXI clkgen driver
  4 *
  5 * Copyright 2012-2013 Analog Devices Inc.
  6 *  Author: Lars-Peter Clausen <lars@metafoo.de>
 
 
 
  7 */
  8
  9#include <linux/platform_device.h>
 10#include <linux/clk.h>
 11#include <linux/clk-provider.h>
 
 12#include <linux/slab.h>
 13#include <linux/io.h>
 14#include <linux/of.h>
 15#include <linux/module.h>
 16#include <linux/err.h>
 17
 
 
 
 
 
 
 
 
 
 
 
 
 18#define AXI_CLKGEN_V2_REG_RESET		0x40
 19#define AXI_CLKGEN_V2_REG_CLKSEL	0x44
 20#define AXI_CLKGEN_V2_REG_DRP_CNTRL	0x70
 21#define AXI_CLKGEN_V2_REG_DRP_STATUS	0x74
 22
 23#define AXI_CLKGEN_V2_RESET_MMCM_ENABLE	BIT(1)
 24#define AXI_CLKGEN_V2_RESET_ENABLE	BIT(0)
 25
 26#define AXI_CLKGEN_V2_DRP_CNTRL_SEL	BIT(29)
 27#define AXI_CLKGEN_V2_DRP_CNTRL_READ	BIT(28)
 28
 29#define AXI_CLKGEN_V2_DRP_STATUS_BUSY	BIT(16)
 30
 31#define MMCM_REG_CLKOUT5_2	0x07
 32#define MMCM_REG_CLKOUT0_1	0x08
 33#define MMCM_REG_CLKOUT0_2	0x09
 34#define MMCM_REG_CLKOUT6_2	0x13
 35#define MMCM_REG_CLK_FB1	0x14
 36#define MMCM_REG_CLK_FB2	0x15
 37#define MMCM_REG_CLK_DIV	0x16
 38#define MMCM_REG_LOCK1		0x18
 39#define MMCM_REG_LOCK2		0x19
 40#define MMCM_REG_LOCK3		0x1a
 41#define MMCM_REG_POWER		0x28
 42#define MMCM_REG_FILTER1	0x4e
 43#define MMCM_REG_FILTER2	0x4f
 44
 45#define MMCM_CLKOUT_NOCOUNT	BIT(6)
 46
 47#define MMCM_CLK_DIV_DIVIDE	BIT(11)
 48#define MMCM_CLK_DIV_NOCOUNT	BIT(12)
 49
 50struct axi_clkgen_limits {
 51	unsigned int fpfd_min;
 52	unsigned int fpfd_max;
 53	unsigned int fvco_min;
 54	unsigned int fvco_max;
 55};
 56
 57struct axi_clkgen {
 58	void __iomem *base;
 
 59	struct clk_hw clk_hw;
 60	struct axi_clkgen_limits limits;
 61};
 62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 63static uint32_t axi_clkgen_lookup_filter(unsigned int m)
 64{
 65	switch (m) {
 66	case 0:
 67		return 0x01001990;
 68	case 1:
 69		return 0x01001190;
 70	case 2:
 71		return 0x01009890;
 72	case 3:
 73		return 0x01001890;
 74	case 4:
 75		return 0x01008890;
 76	case 5 ... 8:
 77		return 0x01009090;
 78	case 9 ... 11:
 79		return 0x01000890;
 80	case 12:
 81		return 0x08009090;
 82	case 13 ... 22:
 83		return 0x01001090;
 84	case 23 ... 36:
 85		return 0x01008090;
 86	case 37 ... 46:
 87		return 0x08001090;
 88	default:
 89		return 0x08008090;
 90	}
 91}
 92
 93static const uint32_t axi_clkgen_lock_table[] = {
 94	0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
 95	0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
 96	0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
 97	0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
 98	0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
 99	0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
100	0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
101	0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
102	0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
103};
104
105static uint32_t axi_clkgen_lookup_lock(unsigned int m)
106{
107	if (m < ARRAY_SIZE(axi_clkgen_lock_table))
108		return axi_clkgen_lock_table[m];
109	return 0x1f1f00fa;
110}
111
112static const struct axi_clkgen_limits axi_clkgen_zynqmp_default_limits = {
113	.fpfd_min = 10000,
114	.fpfd_max = 450000,
115	.fvco_min = 800000,
116	.fvco_max = 1600000,
117};
118
119static const struct axi_clkgen_limits axi_clkgen_zynq_default_limits = {
120	.fpfd_min = 10000,
121	.fpfd_max = 300000,
122	.fvco_min = 600000,
123	.fvco_max = 1200000,
124};
125
126static void axi_clkgen_calc_params(const struct axi_clkgen_limits *limits,
127	unsigned long fin, unsigned long fout,
128	unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
129{
130	unsigned long d, d_min, d_max, _d_min, _d_max;
131	unsigned long m, m_min, m_max;
132	unsigned long f, dout, best_f, fvco;
133	unsigned long fract_shift = 0;
134	unsigned long fvco_min_fract, fvco_max_fract;
135
136	fin /= 1000;
137	fout /= 1000;
138
139	best_f = ULONG_MAX;
140	*best_d = 0;
141	*best_m = 0;
142	*best_dout = 0;
143
144	d_min = max_t(unsigned long, DIV_ROUND_UP(fin, limits->fpfd_max), 1);
145	d_max = min_t(unsigned long, fin / limits->fpfd_min, 80);
146
147again:
148	fvco_min_fract = limits->fvco_min << fract_shift;
149	fvco_max_fract = limits->fvco_max << fract_shift;
150
151	m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1);
152	m_max = min_t(unsigned long, fvco_max_fract * d_max / fin, 64 << fract_shift);
153
154	for (m = m_min; m <= m_max; m++) {
155		_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max_fract));
156		_d_max = min(d_max, fin * m / fvco_min_fract);
157
158		for (d = _d_min; d <= _d_max; d++) {
159			fvco = fin * m / d;
160
161			dout = DIV_ROUND_CLOSEST(fvco, fout);
162			dout = clamp_t(unsigned long, dout, 1, 128 << fract_shift);
163			f = fvco / dout;
164			if (abs(f - fout) < abs(best_f - fout)) {
165				best_f = f;
166				*best_d = d;
167				*best_m = m << (3 - fract_shift);
168				*best_dout = dout << (3 - fract_shift);
169				if (best_f == fout)
170					return;
171			}
172		}
173	}
174
175	/* Lets see if we find a better setting in fractional mode */
176	if (fract_shift == 0) {
177		fract_shift = 3;
178		goto again;
179	}
180}
181
182struct axi_clkgen_div_params {
183	unsigned int low;
184	unsigned int high;
185	unsigned int edge;
186	unsigned int nocount;
187	unsigned int frac_en;
188	unsigned int frac;
189	unsigned int frac_wf_f;
190	unsigned int frac_wf_r;
191	unsigned int frac_phase;
192};
193
194static void axi_clkgen_calc_clk_params(unsigned int divider,
195	unsigned int frac_divider, struct axi_clkgen_div_params *params)
196{
 
 
 
 
197
198	memset(params, 0x0, sizeof(*params));
199
200	if (divider == 1) {
201		params->nocount = 1;
202		return;
203	}
204
205	if (frac_divider == 0) {
206		params->high = divider / 2;
207		params->edge = divider % 2;
208		params->low = divider - params->high;
209	} else {
210		params->frac_en = 1;
211		params->frac = frac_divider;
212
213		params->high = divider / 2;
214		params->edge = divider % 2;
215		params->low = params->high;
216
217		if (params->edge == 0) {
218			params->high--;
219			params->frac_wf_r = 1;
220		}
221
222		if (params->edge == 0 || frac_divider == 1)
223			params->low--;
224		if (((params->edge == 0) ^ (frac_divider == 1)) ||
225			(divider == 2 && frac_divider == 1))
226			params->frac_wf_f = 1;
227
228		params->frac_phase = params->edge * 4 + frac_divider / 2;
229	}
230}
231
232static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
233	unsigned int reg, unsigned int val)
234{
235	writel(val, axi_clkgen->base + reg);
236}
237
238static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
239	unsigned int reg, unsigned int *val)
240{
241	*val = readl(axi_clkgen->base + reg);
242}
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
245{
246	unsigned int timeout = 10000;
247	unsigned int val;
248
249	do {
250		axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val);
251	} while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout);
252
253	if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY)
254		return -EIO;
255
256	return val & 0xffff;
257}
258
259static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
260	unsigned int reg, unsigned int *val)
261{
262	unsigned int reg_val;
263	int ret;
264
265	ret = axi_clkgen_wait_non_busy(axi_clkgen);
266	if (ret < 0)
267		return ret;
268
269	reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ;
270	reg_val |= (reg << 16);
271
272	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
273
274	ret = axi_clkgen_wait_non_busy(axi_clkgen);
275	if (ret < 0)
276		return ret;
277
278	*val = ret;
279
280	return 0;
281}
282
283static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
284	unsigned int reg, unsigned int val, unsigned int mask)
285{
286	unsigned int reg_val = 0;
287	int ret;
288
289	ret = axi_clkgen_wait_non_busy(axi_clkgen);
290	if (ret < 0)
291		return ret;
292
293	if (mask != 0xffff) {
294		axi_clkgen_mmcm_read(axi_clkgen, reg, &reg_val);
295		reg_val &= ~mask;
296	}
297
298	reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask);
299
300	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
301
302	return 0;
303}
304
305static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
306	bool enable)
307{
308	unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
309
310	if (enable)
311		val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE;
312
313	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
314}
315
 
 
 
 
 
 
316static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
317{
318	return container_of(clk_hw, struct axi_clkgen, clk_hw);
319}
320
321static void axi_clkgen_set_div(struct axi_clkgen *axi_clkgen,
322	unsigned int reg1, unsigned int reg2, unsigned int reg3,
323	struct axi_clkgen_div_params *params)
324{
325	axi_clkgen_mmcm_write(axi_clkgen, reg1,
326		(params->high << 6) | params->low, 0xefff);
327	axi_clkgen_mmcm_write(axi_clkgen, reg2,
328		(params->frac << 12) | (params->frac_en << 11) |
329		(params->frac_wf_r << 10) | (params->edge << 7) |
330		(params->nocount << 6), 0x7fff);
331	if (reg3 != 0) {
332		axi_clkgen_mmcm_write(axi_clkgen, reg3,
333			(params->frac_phase << 11) | (params->frac_wf_f << 10), 0x3c00);
334	}
335}
336
337static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
338	unsigned long rate, unsigned long parent_rate)
339{
340	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
341	const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
342	unsigned int d, m, dout;
343	struct axi_clkgen_div_params params;
344	uint32_t power = 0;
 
 
345	uint32_t filter;
346	uint32_t lock;
347
348	if (parent_rate == 0 || rate == 0)
349		return -EINVAL;
350
351	axi_clkgen_calc_params(limits, parent_rate, rate, &d, &m, &dout);
352
353	if (d == 0 || dout == 0 || m == 0)
354		return -EINVAL;
355
356	if ((dout & 0x7) != 0 || (m & 0x7) != 0)
357		power |= 0x9800;
358
359	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_POWER, power, 0x9800);
360
361	filter = axi_clkgen_lookup_filter(m - 1);
362	lock = axi_clkgen_lookup_lock(m - 1);
363
364	axi_clkgen_calc_clk_params(dout >> 3, dout & 0x7, &params);
365	axi_clkgen_set_div(axi_clkgen,  MMCM_REG_CLKOUT0_1, MMCM_REG_CLKOUT0_2,
366		MMCM_REG_CLKOUT5_2, &params);
 
 
367
368	axi_clkgen_calc_clk_params(d, 0, &params);
369	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
370		(params.edge << 13) | (params.nocount << 12) |
371		(params.high << 6) | params.low, 0x3fff);
372
373	axi_clkgen_calc_clk_params(m >> 3, m & 0x7, &params);
374	axi_clkgen_set_div(axi_clkgen,  MMCM_REG_CLK_FB1, MMCM_REG_CLK_FB2,
375		MMCM_REG_CLKOUT6_2, &params);
 
 
376
377	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
378	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
379		(((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff);
380	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3,
381		(((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
382	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900);
383	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900);
384
385	return 0;
386}
387
388static int axi_clkgen_determine_rate(struct clk_hw *hw,
389				     struct clk_rate_request *req)
390{
391	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(hw);
392	const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
393	unsigned int d, m, dout;
394	unsigned long long tmp;
395
396	axi_clkgen_calc_params(limits, req->best_parent_rate, req->rate,
397			       &d, &m, &dout);
398
399	if (d == 0 || dout == 0 || m == 0)
400		return -EINVAL;
401
402	tmp = (unsigned long long)req->best_parent_rate * m;
403	tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
404
405	req->rate = min_t(unsigned long long, tmp, LONG_MAX);
406	return 0;
407}
408
409static unsigned int axi_clkgen_get_div(struct axi_clkgen *axi_clkgen,
410	unsigned int reg1, unsigned int reg2)
411{
412	unsigned int val1, val2;
413	unsigned int div;
414
415	axi_clkgen_mmcm_read(axi_clkgen, reg2, &val2);
416	if (val2 & MMCM_CLKOUT_NOCOUNT)
417		return 8;
418
419	axi_clkgen_mmcm_read(axi_clkgen, reg1, &val1);
420
421	div = (val1 & 0x3f) + ((val1 >> 6) & 0x3f);
422	div <<= 3;
423
424	if (val2 & MMCM_CLK_DIV_DIVIDE) {
425		if ((val2 & BIT(7)) && (val2 & 0x7000) != 0x1000)
426			div += 8;
427		else
428			div += 16;
429
430		div += (val2 >> 12) & 0x7;
431	}
432
433	return div;
434}
435
436static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
437	unsigned long parent_rate)
438{
439	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
440	unsigned int d, m, dout;
 
441	unsigned long long tmp;
442	unsigned int val;
443
444	dout = axi_clkgen_get_div(axi_clkgen, MMCM_REG_CLKOUT0_1,
445		MMCM_REG_CLKOUT0_2);
446	m = axi_clkgen_get_div(axi_clkgen, MMCM_REG_CLK_FB1,
447		MMCM_REG_CLK_FB2);
448
449	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &val);
450	if (val & MMCM_CLK_DIV_NOCOUNT)
451		d = 1;
452	else
453		d = (val & 0x3f) + ((val >> 6) & 0x3f);
454
455	if (d == 0 || dout == 0)
456		return 0;
457
458	tmp = (unsigned long long)parent_rate * m;
459	tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
460
461	return min_t(unsigned long long, tmp, ULONG_MAX);
 
 
 
462}
463
464static int axi_clkgen_enable(struct clk_hw *clk_hw)
465{
466	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
467
468	axi_clkgen_mmcm_enable(axi_clkgen, true);
469
470	return 0;
471}
472
473static void axi_clkgen_disable(struct clk_hw *clk_hw)
474{
475	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
476
477	axi_clkgen_mmcm_enable(axi_clkgen, false);
478}
479
480static int axi_clkgen_set_parent(struct clk_hw *clk_hw, u8 index)
481{
482	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
483
484	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, index);
485
486	return 0;
487}
488
489static u8 axi_clkgen_get_parent(struct clk_hw *clk_hw)
490{
491	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
492	unsigned int parent;
493
494	axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, &parent);
495
496	return parent;
497}
498
499static const struct clk_ops axi_clkgen_ops = {
500	.recalc_rate = axi_clkgen_recalc_rate,
501	.determine_rate = axi_clkgen_determine_rate,
502	.set_rate = axi_clkgen_set_rate,
503	.enable = axi_clkgen_enable,
504	.disable = axi_clkgen_disable,
505	.set_parent = axi_clkgen_set_parent,
506	.get_parent = axi_clkgen_get_parent,
507};
508
 
 
 
 
 
 
 
 
 
 
 
 
509static int axi_clkgen_probe(struct platform_device *pdev)
510{
511	const struct axi_clkgen_limits *dflt_limits;
512	struct axi_clkgen *axi_clkgen;
513	struct clk_init_data init;
514	const char *parent_names[2];
515	const char *clk_name;
516	struct clk *axi_clk;
517	unsigned int i;
518	int ret;
519
520	dflt_limits = device_get_match_data(&pdev->dev);
521	if (!dflt_limits)
 
 
 
522		return -ENODEV;
523
524	axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
525	if (!axi_clkgen)
526		return -ENOMEM;
527
528	axi_clkgen->base = devm_platform_ioremap_resource(pdev, 0);
 
 
 
529	if (IS_ERR(axi_clkgen->base))
530		return PTR_ERR(axi_clkgen->base);
531
532	init.num_parents = of_clk_get_parent_count(pdev->dev.of_node);
533
534	axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
535	if (!IS_ERR(axi_clk)) {
536		if (init.num_parents < 2 || init.num_parents > 3)
537			return -EINVAL;
538
539		init.num_parents -= 1;
540	} else {
541		/*
542		 * Legacy... So that old DTs which do not have clock-names still
543		 * work. In this case we don't explicitly enable the AXI bus
544		 * clock.
545		 */
546		if (PTR_ERR(axi_clk) != -ENOENT)
547			return PTR_ERR(axi_clk);
548		if (init.num_parents < 1 || init.num_parents > 2)
549			return -EINVAL;
550	}
551
552	for (i = 0; i < init.num_parents; i++) {
553		parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i);
554		if (!parent_names[i])
555			return -EINVAL;
556	}
557
558	memcpy(&axi_clkgen->limits, dflt_limits, sizeof(axi_clkgen->limits));
559
560	clk_name = pdev->dev.of_node->name;
561	of_property_read_string(pdev->dev.of_node, "clock-output-names",
562		&clk_name);
563
564	init.name = clk_name;
565	init.ops = &axi_clkgen_ops;
566	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
567	init.parent_names = parent_names;
 
568
569	axi_clkgen_mmcm_enable(axi_clkgen, false);
570
571	axi_clkgen->clk_hw.init = &init;
572	ret = devm_clk_hw_register(&pdev->dev, &axi_clkgen->clk_hw);
573	if (ret)
574		return ret;
575
576	return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
577					   &axi_clkgen->clk_hw);
578}
579
580static const struct of_device_id axi_clkgen_ids[] = {
581	{
582		.compatible = "adi,zynqmp-axi-clkgen-2.00.a",
583		.data = &axi_clkgen_zynqmp_default_limits,
584	},
585	{
586		.compatible = "adi,axi-clkgen-2.00.a",
587		.data = &axi_clkgen_zynq_default_limits,
588	},
589	{ }
590};
591MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
592
593static struct platform_driver axi_clkgen_driver = {
594	.driver = {
595		.name = "adi-axi-clkgen",
 
596		.of_match_table = axi_clkgen_ids,
597	},
598	.probe = axi_clkgen_probe,
 
599};
600module_platform_driver(axi_clkgen_driver);
601
602MODULE_LICENSE("GPL v2");
603MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
604MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");
v3.15
 
  1/*
  2 * AXI clkgen driver
  3 *
  4 * Copyright 2012-2013 Analog Devices Inc.
  5 *  Author: Lars-Peter Clausen <lars@metafoo.de>
  6 *
  7 * Licensed under the GPL-2.
  8 *
  9 */
 10
 11#include <linux/platform_device.h>
 
 12#include <linux/clk-provider.h>
 13#include <linux/clk.h>
 14#include <linux/slab.h>
 15#include <linux/io.h>
 16#include <linux/of.h>
 17#include <linux/module.h>
 18#include <linux/err.h>
 19
 20#define AXI_CLKGEN_V1_REG_UPDATE_ENABLE	0x04
 21#define AXI_CLKGEN_V1_REG_CLK_OUT1	0x08
 22#define AXI_CLKGEN_V1_REG_CLK_OUT2	0x0c
 23#define AXI_CLKGEN_V1_REG_CLK_DIV	0x10
 24#define AXI_CLKGEN_V1_REG_CLK_FB1	0x14
 25#define AXI_CLKGEN_V1_REG_CLK_FB2	0x18
 26#define AXI_CLKGEN_V1_REG_LOCK1		0x1c
 27#define AXI_CLKGEN_V1_REG_LOCK2		0x20
 28#define AXI_CLKGEN_V1_REG_LOCK3		0x24
 29#define AXI_CLKGEN_V1_REG_FILTER1	0x28
 30#define AXI_CLKGEN_V1_REG_FILTER2	0x2c
 31
 32#define AXI_CLKGEN_V2_REG_RESET		0x40
 
 33#define AXI_CLKGEN_V2_REG_DRP_CNTRL	0x70
 34#define AXI_CLKGEN_V2_REG_DRP_STATUS	0x74
 35
 36#define AXI_CLKGEN_V2_RESET_MMCM_ENABLE	BIT(1)
 37#define AXI_CLKGEN_V2_RESET_ENABLE	BIT(0)
 38
 39#define AXI_CLKGEN_V2_DRP_CNTRL_SEL	BIT(29)
 40#define AXI_CLKGEN_V2_DRP_CNTRL_READ	BIT(28)
 41
 42#define AXI_CLKGEN_V2_DRP_STATUS_BUSY	BIT(16)
 43
 
 44#define MMCM_REG_CLKOUT0_1	0x08
 45#define MMCM_REG_CLKOUT0_2	0x09
 
 46#define MMCM_REG_CLK_FB1	0x14
 47#define MMCM_REG_CLK_FB2	0x15
 48#define MMCM_REG_CLK_DIV	0x16
 49#define MMCM_REG_LOCK1		0x18
 50#define MMCM_REG_LOCK2		0x19
 51#define MMCM_REG_LOCK3		0x1a
 
 52#define MMCM_REG_FILTER1	0x4e
 53#define MMCM_REG_FILTER2	0x4f
 54
 55struct axi_clkgen;
 56
 57struct axi_clkgen_mmcm_ops {
 58	void (*enable)(struct axi_clkgen *axi_clkgen, bool enable);
 59	int (*write)(struct axi_clkgen *axi_clkgen, unsigned int reg,
 60		     unsigned int val, unsigned int mask);
 61	int (*read)(struct axi_clkgen *axi_clkgen, unsigned int reg,
 62		    unsigned int *val);
 
 
 63};
 64
 65struct axi_clkgen {
 66	void __iomem *base;
 67	const struct axi_clkgen_mmcm_ops *mmcm_ops;
 68	struct clk_hw clk_hw;
 
 69};
 70
 71static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
 72	bool enable)
 73{
 74	axi_clkgen->mmcm_ops->enable(axi_clkgen, enable);
 75}
 76
 77static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
 78	unsigned int reg, unsigned int val, unsigned int mask)
 79{
 80	return axi_clkgen->mmcm_ops->write(axi_clkgen, reg, val, mask);
 81}
 82
 83static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
 84	unsigned int reg, unsigned int *val)
 85{
 86	return axi_clkgen->mmcm_ops->read(axi_clkgen, reg, val);
 87}
 88
 89static uint32_t axi_clkgen_lookup_filter(unsigned int m)
 90{
 91	switch (m) {
 92	case 0:
 93		return 0x01001990;
 94	case 1:
 95		return 0x01001190;
 96	case 2:
 97		return 0x01009890;
 98	case 3:
 99		return 0x01001890;
100	case 4:
101		return 0x01008890;
102	case 5 ... 8:
103		return 0x01009090;
104	case 9 ... 11:
105		return 0x01000890;
106	case 12:
107		return 0x08009090;
108	case 13 ... 22:
109		return 0x01001090;
110	case 23 ... 36:
111		return 0x01008090;
112	case 37 ... 46:
113		return 0x08001090;
114	default:
115		return 0x08008090;
116	}
117}
118
119static const uint32_t axi_clkgen_lock_table[] = {
120	0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
121	0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
122	0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
123	0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
124	0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
125	0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
126	0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
127	0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
128	0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
129};
130
131static uint32_t axi_clkgen_lookup_lock(unsigned int m)
132{
133	if (m < ARRAY_SIZE(axi_clkgen_lock_table))
134		return axi_clkgen_lock_table[m];
135	return 0x1f1f00fa;
136}
137
138static const unsigned int fpfd_min = 10000;
139static const unsigned int fpfd_max = 300000;
140static const unsigned int fvco_min = 600000;
141static const unsigned int fvco_max = 1200000;
 
 
142
143static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
 
 
 
 
 
 
 
 
144	unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
145{
146	unsigned long d, d_min, d_max, _d_min, _d_max;
147	unsigned long m, m_min, m_max;
148	unsigned long f, dout, best_f, fvco;
 
 
149
150	fin /= 1000;
151	fout /= 1000;
152
153	best_f = ULONG_MAX;
154	*best_d = 0;
155	*best_m = 0;
156	*best_dout = 0;
157
158	d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
159	d_max = min_t(unsigned long, fin / fpfd_min, 80);
 
 
 
 
160
161	m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
162	m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
163
164	for (m = m_min; m <= m_max; m++) {
165		_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
166		_d_max = min(d_max, fin * m / fvco_min);
167
168		for (d = _d_min; d <= _d_max; d++) {
169			fvco = fin * m / d;
170
171			dout = DIV_ROUND_CLOSEST(fvco, fout);
172			dout = clamp_t(unsigned long, dout, 1, 128);
173			f = fvco / dout;
174			if (abs(f - fout) < abs(best_f - fout)) {
175				best_f = f;
176				*best_d = d;
177				*best_m = m;
178				*best_dout = dout;
179				if (best_f == fout)
180					return;
181			}
182		}
183	}
 
 
 
 
 
 
184}
185
186static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
187	unsigned int *high, unsigned int *edge, unsigned int *nocount)
 
 
 
 
 
 
 
 
 
 
 
 
188{
189	if (divider == 1)
190		*nocount = 1;
191	else
192		*nocount = 0;
193
194	*high = divider / 2;
195	*edge = divider % 2;
196	*low = divider - *high;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197}
198
199static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
200	unsigned int reg, unsigned int val)
201{
202	writel(val, axi_clkgen->base + reg);
203}
204
205static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
206	unsigned int reg, unsigned int *val)
207{
208	*val = readl(axi_clkgen->base + reg);
209}
210
211static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg)
212{
213	switch (reg) {
214	case MMCM_REG_CLKOUT0_1:
215		return AXI_CLKGEN_V1_REG_CLK_OUT1;
216	case MMCM_REG_CLKOUT0_2:
217		return AXI_CLKGEN_V1_REG_CLK_OUT2;
218	case MMCM_REG_CLK_FB1:
219		return AXI_CLKGEN_V1_REG_CLK_FB1;
220	case MMCM_REG_CLK_FB2:
221		return AXI_CLKGEN_V1_REG_CLK_FB2;
222	case MMCM_REG_CLK_DIV:
223		return AXI_CLKGEN_V1_REG_CLK_DIV;
224	case MMCM_REG_LOCK1:
225		return AXI_CLKGEN_V1_REG_LOCK1;
226	case MMCM_REG_LOCK2:
227		return AXI_CLKGEN_V1_REG_LOCK2;
228	case MMCM_REG_LOCK3:
229		return AXI_CLKGEN_V1_REG_LOCK3;
230	case MMCM_REG_FILTER1:
231		return AXI_CLKGEN_V1_REG_FILTER1;
232	case MMCM_REG_FILTER2:
233		return AXI_CLKGEN_V1_REG_FILTER2;
234	default:
235		return 0;
236	}
237}
238
239static int axi_clkgen_v1_mmcm_write(struct axi_clkgen *axi_clkgen,
240	unsigned int reg, unsigned int val, unsigned int mask)
241{
242	reg = axi_clkgen_v1_map_mmcm_reg(reg);
243	if (reg == 0)
244		return -EINVAL;
245
246	axi_clkgen_write(axi_clkgen, reg, val);
247
248	return 0;
249}
250
251static int axi_clkgen_v1_mmcm_read(struct axi_clkgen *axi_clkgen,
252	unsigned int reg, unsigned int *val)
253{
254	reg = axi_clkgen_v1_map_mmcm_reg(reg);
255	if (reg == 0)
256		return -EINVAL;
257
258	axi_clkgen_read(axi_clkgen, reg, val);
259
260	return 0;
261}
262
263static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen *axi_clkgen,
264	bool enable)
265{
266	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V1_REG_UPDATE_ENABLE, enable);
267}
268
269static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops = {
270	.write = axi_clkgen_v1_mmcm_write,
271	.read = axi_clkgen_v1_mmcm_read,
272	.enable = axi_clkgen_v1_mmcm_enable,
273};
274
275static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
276{
277	unsigned int timeout = 10000;
278	unsigned int val;
279
280	do {
281		axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val);
282	} while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout);
283
284	if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY)
285		return -EIO;
286
287	return val & 0xffff;
288}
289
290static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen,
291	unsigned int reg, unsigned int *val)
292{
293	unsigned int reg_val;
294	int ret;
295
296	ret = axi_clkgen_wait_non_busy(axi_clkgen);
297	if (ret < 0)
298		return ret;
299
300	reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ;
301	reg_val |= (reg << 16);
302
303	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
304
305	ret = axi_clkgen_wait_non_busy(axi_clkgen);
306	if (ret < 0)
307		return ret;
308
309	*val = ret;
310
311	return 0;
312}
313
314static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen,
315	unsigned int reg, unsigned int val, unsigned int mask)
316{
317	unsigned int reg_val = 0;
318	int ret;
319
320	ret = axi_clkgen_wait_non_busy(axi_clkgen);
321	if (ret < 0)
322		return ret;
323
324	if (mask != 0xffff) {
325		axi_clkgen_v2_mmcm_read(axi_clkgen, reg, &reg_val);
326		reg_val &= ~mask;
327	}
328
329	reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask);
330
331	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
332
333	return 0;
334}
335
336static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen,
337	bool enable)
338{
339	unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
340
341	if (enable)
342		val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE;
343
344	axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
345}
346
347static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops = {
348	.write = axi_clkgen_v2_mmcm_write,
349	.read = axi_clkgen_v2_mmcm_read,
350	.enable = axi_clkgen_v2_mmcm_enable,
351};
352
353static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
354{
355	return container_of(clk_hw, struct axi_clkgen, clk_hw);
356}
357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
359	unsigned long rate, unsigned long parent_rate)
360{
361	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
 
362	unsigned int d, m, dout;
363	unsigned int nocount;
364	unsigned int high;
365	unsigned int edge;
366	unsigned int low;
367	uint32_t filter;
368	uint32_t lock;
369
370	if (parent_rate == 0 || rate == 0)
371		return -EINVAL;
372
373	axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
374
375	if (d == 0 || dout == 0 || m == 0)
376		return -EINVAL;
377
 
 
 
 
 
378	filter = axi_clkgen_lookup_filter(m - 1);
379	lock = axi_clkgen_lookup_lock(m - 1);
380
381	axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
382	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_1,
383		(high << 6) | low, 0xefff);
384	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_2,
385		(edge << 7) | (nocount << 6), 0x03ff);
386
387	axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
388	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
389		(edge << 13) | (nocount << 12) | (high << 6) | low, 0x3fff);
 
390
391	axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
392	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB1,
393		(high << 6) | low, 0xefff);
394	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB2,
395		(edge << 7) | (nocount << 6), 0x03ff);
396
397	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
398	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
399		(((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff);
400	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3,
401		(((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
402	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900);
403	axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900);
404
405	return 0;
406}
407
408static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
409	unsigned long *parent_rate)
410{
 
 
411	unsigned int d, m, dout;
 
412
413	axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
 
414
415	if (d == 0 || dout == 0 || m == 0)
416		return -EINVAL;
417
418	return *parent_rate / d * m / dout;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419}
420
421static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
422	unsigned long parent_rate)
423{
424	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
425	unsigned int d, m, dout;
426	unsigned int reg;
427	unsigned long long tmp;
 
428
429	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, &reg);
430	dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
431	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &reg);
432	d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
433	axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, &reg);
434	m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
 
 
 
 
435
436	if (d == 0 || dout == 0)
437		return 0;
438
439	tmp = (unsigned long long)(parent_rate / d) * m;
440	do_div(tmp, dout);
441
442	if (tmp > ULONG_MAX)
443		return ULONG_MAX;
444
445	return tmp;
446}
447
448static int axi_clkgen_enable(struct clk_hw *clk_hw)
449{
450	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
451
452	axi_clkgen_mmcm_enable(axi_clkgen, true);
453
454	return 0;
455}
456
457static void axi_clkgen_disable(struct clk_hw *clk_hw)
458{
459	struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
460
461	axi_clkgen_mmcm_enable(axi_clkgen, false);
462}
463
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464static const struct clk_ops axi_clkgen_ops = {
465	.recalc_rate = axi_clkgen_recalc_rate,
466	.round_rate = axi_clkgen_round_rate,
467	.set_rate = axi_clkgen_set_rate,
468	.enable = axi_clkgen_enable,
469	.disable = axi_clkgen_disable,
 
 
470};
471
472static const struct of_device_id axi_clkgen_ids[] = {
473	{
474		.compatible = "adi,axi-clkgen-1.00.a",
475		.data = &axi_clkgen_v1_mmcm_ops
476	}, {
477		.compatible = "adi,axi-clkgen-2.00.a",
478		.data = &axi_clkgen_v2_mmcm_ops,
479	},
480	{ },
481};
482MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
483
484static int axi_clkgen_probe(struct platform_device *pdev)
485{
486	const struct of_device_id *id;
487	struct axi_clkgen *axi_clkgen;
488	struct clk_init_data init;
489	const char *parent_name;
490	const char *clk_name;
491	struct resource *mem;
492	struct clk *clk;
 
493
494	if (!pdev->dev.of_node)
495		return -ENODEV;
496
497	id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
498	if (!id)
499		return -ENODEV;
500
501	axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
502	if (!axi_clkgen)
503		return -ENOMEM;
504
505	axi_clkgen->mmcm_ops = id->data;
506
507	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
508	axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
509	if (IS_ERR(axi_clkgen->base))
510		return PTR_ERR(axi_clkgen->base);
511
512	parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
513	if (!parent_name)
514		return -EINVAL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515
516	clk_name = pdev->dev.of_node->name;
517	of_property_read_string(pdev->dev.of_node, "clock-output-names",
518		&clk_name);
519
520	init.name = clk_name;
521	init.ops = &axi_clkgen_ops;
522	init.flags = CLK_SET_RATE_GATE;
523	init.parent_names = &parent_name;
524	init.num_parents = 1;
525
526	axi_clkgen_mmcm_enable(axi_clkgen, false);
527
528	axi_clkgen->clk_hw.init = &init;
529	clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
530	if (IS_ERR(clk))
531		return PTR_ERR(clk);
532
533	return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
534				    clk);
535}
536
537static int axi_clkgen_remove(struct platform_device *pdev)
538{
539	of_clk_del_provider(pdev->dev.of_node);
540
541	return 0;
542}
 
 
 
 
 
 
543
544static struct platform_driver axi_clkgen_driver = {
545	.driver = {
546		.name = "adi-axi-clkgen",
547		.owner = THIS_MODULE,
548		.of_match_table = axi_clkgen_ids,
549	},
550	.probe = axi_clkgen_probe,
551	.remove = axi_clkgen_remove,
552};
553module_platform_driver(axi_clkgen_driver);
554
555MODULE_LICENSE("GPL v2");
556MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
557MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");