xref: /openbmc/linux/drivers/sh/clk/cpg.c (revision 8f28ca6b)
1 /*
2  * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
3  *
4  *  Copyright (C) 2010  Magnus Damm
5  *  Copyright (C) 2010 - 2012  Paul Mundt
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/clk.h>
12 #include <linux/compiler.h>
13 #include <linux/slab.h>
14 #include <linux/io.h>
15 #include <linux/sh_clk.h>
16 
17 #define CPG_CKSTP_BIT	BIT(8)
18 
sh_clk_read(struct clk * clk)19 static unsigned int sh_clk_read(struct clk *clk)
20 {
21 	if (clk->flags & CLK_ENABLE_REG_8BIT)
22 		return ioread8(clk->mapped_reg);
23 	else if (clk->flags & CLK_ENABLE_REG_16BIT)
24 		return ioread16(clk->mapped_reg);
25 
26 	return ioread32(clk->mapped_reg);
27 }
28 
sh_clk_write(int value,struct clk * clk)29 static void sh_clk_write(int value, struct clk *clk)
30 {
31 	if (clk->flags & CLK_ENABLE_REG_8BIT)
32 		iowrite8(value, clk->mapped_reg);
33 	else if (clk->flags & CLK_ENABLE_REG_16BIT)
34 		iowrite16(value, clk->mapped_reg);
35 	else
36 		iowrite32(value, clk->mapped_reg);
37 }
38 
sh_clk_mstp_enable(struct clk * clk)39 static int sh_clk_mstp_enable(struct clk *clk)
40 {
41 	sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
42 	if (clk->status_reg) {
43 		unsigned int (*read)(const void __iomem *addr);
44 		int i;
45 		void __iomem *mapped_status = (phys_addr_t)clk->status_reg -
46 			(phys_addr_t)clk->enable_reg + clk->mapped_reg;
47 
48 		if (clk->flags & CLK_ENABLE_REG_8BIT)
49 			read = ioread8;
50 		else if (clk->flags & CLK_ENABLE_REG_16BIT)
51 			read = ioread16;
52 		else
53 			read = ioread32;
54 
55 		for (i = 1000;
56 		     (read(mapped_status) & (1 << clk->enable_bit)) && i;
57 		     i--)
58 			cpu_relax();
59 		if (!i) {
60 			pr_err("cpg: failed to enable %p[%d]\n",
61 			       clk->enable_reg, clk->enable_bit);
62 			return -ETIMEDOUT;
63 		}
64 	}
65 	return 0;
66 }
67 
sh_clk_mstp_disable(struct clk * clk)68 static void sh_clk_mstp_disable(struct clk *clk)
69 {
70 	sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
71 }
72 
73 static struct sh_clk_ops sh_clk_mstp_clk_ops = {
74 	.enable		= sh_clk_mstp_enable,
75 	.disable	= sh_clk_mstp_disable,
76 	.recalc		= followparent_recalc,
77 };
78 
sh_clk_mstp_register(struct clk * clks,int nr)79 int __init sh_clk_mstp_register(struct clk *clks, int nr)
80 {
81 	struct clk *clkp;
82 	int ret = 0;
83 	int k;
84 
85 	for (k = 0; !ret && (k < nr); k++) {
86 		clkp = clks + k;
87 		clkp->ops = &sh_clk_mstp_clk_ops;
88 		ret |= clk_register(clkp);
89 	}
90 
91 	return ret;
92 }
93 
94 /*
95  * Div/mult table lookup helpers
96  */
clk_to_div_table(struct clk * clk)97 static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
98 {
99 	return clk->priv;
100 }
101 
clk_to_div_mult_table(struct clk * clk)102 static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
103 {
104 	return clk_to_div_table(clk)->div_mult_table;
105 }
106 
107 /*
108  * Common div ops
109  */
sh_clk_div_round_rate(struct clk * clk,unsigned long rate)110 static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
111 {
112 	return clk_rate_table_round(clk, clk->freq_table, rate);
113 }
114 
sh_clk_div_recalc(struct clk * clk)115 static unsigned long sh_clk_div_recalc(struct clk *clk)
116 {
117 	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
118 	unsigned int idx;
119 
120 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
121 			     table, clk->arch_flags ? &clk->arch_flags : NULL);
122 
123 	idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;
124 
125 	return clk->freq_table[idx].frequency;
126 }
127 
sh_clk_div_set_rate(struct clk * clk,unsigned long rate)128 static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
129 {
130 	struct clk_div_table *dt = clk_to_div_table(clk);
131 	unsigned long value;
132 	int idx;
133 
134 	idx = clk_rate_table_find(clk, clk->freq_table, rate);
135 	if (idx < 0)
136 		return idx;
137 
138 	value = sh_clk_read(clk);
139 	value &= ~(clk->div_mask << clk->enable_bit);
140 	value |= (idx << clk->enable_bit);
141 	sh_clk_write(value, clk);
142 
143 	/* XXX: Should use a post-change notifier */
144 	if (dt->kick)
145 		dt->kick(clk);
146 
147 	return 0;
148 }
149 
sh_clk_div_enable(struct clk * clk)150 static int sh_clk_div_enable(struct clk *clk)
151 {
152 	if (clk->div_mask == SH_CLK_DIV6_MSK) {
153 		int ret = sh_clk_div_set_rate(clk, clk->rate);
154 		if (ret < 0)
155 			return ret;
156 	}
157 
158 	sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
159 	return 0;
160 }
161 
sh_clk_div_disable(struct clk * clk)162 static void sh_clk_div_disable(struct clk *clk)
163 {
164 	unsigned int val;
165 
166 	val = sh_clk_read(clk);
167 	val |= CPG_CKSTP_BIT;
168 
169 	/*
170 	 * div6 clocks require the divisor field to be non-zero or the
171 	 * above CKSTP toggle silently fails. Ensure that the divisor
172 	 * array is reset to its initial state on disable.
173 	 */
174 	if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
175 		val |= clk->div_mask;
176 
177 	sh_clk_write(val, clk);
178 }
179 
180 static struct sh_clk_ops sh_clk_div_clk_ops = {
181 	.recalc		= sh_clk_div_recalc,
182 	.set_rate	= sh_clk_div_set_rate,
183 	.round_rate	= sh_clk_div_round_rate,
184 };
185 
186 static struct sh_clk_ops sh_clk_div_enable_clk_ops = {
187 	.recalc		= sh_clk_div_recalc,
188 	.set_rate	= sh_clk_div_set_rate,
189 	.round_rate	= sh_clk_div_round_rate,
190 	.enable		= sh_clk_div_enable,
191 	.disable	= sh_clk_div_disable,
192 };
193 
sh_clk_init_parent(struct clk * clk)194 static int __init sh_clk_init_parent(struct clk *clk)
195 {
196 	u32 val;
197 
198 	if (clk->parent)
199 		return 0;
200 
201 	if (!clk->parent_table || !clk->parent_num)
202 		return 0;
203 
204 	if (!clk->src_width) {
205 		pr_err("sh_clk_init_parent: cannot select parent clock\n");
206 		return -EINVAL;
207 	}
208 
209 	val  = (sh_clk_read(clk) >> clk->src_shift);
210 	val &= (1 << clk->src_width) - 1;
211 
212 	if (val >= clk->parent_num) {
213 		pr_err("sh_clk_init_parent: parent table size failed\n");
214 		return -EINVAL;
215 	}
216 
217 	clk_reparent(clk, clk->parent_table[val]);
218 	if (!clk->parent) {
219 		pr_err("sh_clk_init_parent: unable to set parent");
220 		return -EINVAL;
221 	}
222 
223 	return 0;
224 }
225 
sh_clk_div_register_ops(struct clk * clks,int nr,struct clk_div_table * table,struct sh_clk_ops * ops)226 static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
227 			struct clk_div_table *table, struct sh_clk_ops *ops)
228 {
229 	struct clk *clkp;
230 	void *freq_table;
231 	int nr_divs = table->div_mult_table->nr_divisors;
232 	int freq_table_size = sizeof(struct cpufreq_frequency_table);
233 	int ret = 0;
234 	int k;
235 
236 	freq_table_size *= (nr_divs + 1);
237 	freq_table = kcalloc(nr, freq_table_size, GFP_KERNEL);
238 	if (!freq_table) {
239 		pr_err("%s: unable to alloc memory\n", __func__);
240 		return -ENOMEM;
241 	}
242 
243 	for (k = 0; !ret && (k < nr); k++) {
244 		clkp = clks + k;
245 
246 		clkp->ops = ops;
247 		clkp->priv = table;
248 
249 		clkp->freq_table = freq_table + (k * freq_table_size);
250 		clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
251 
252 		ret = clk_register(clkp);
253 		if (ret == 0)
254 			ret = sh_clk_init_parent(clkp);
255 	}
256 
257 	return ret;
258 }
259 
260 /*
261  * div6 support
262  */
263 static int sh_clk_div6_divisors[64] = {
264 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
265 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
266 	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
267 	49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
268 };
269 
270 static struct clk_div_mult_table div6_div_mult_table = {
271 	.divisors = sh_clk_div6_divisors,
272 	.nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
273 };
274 
275 static struct clk_div_table sh_clk_div6_table = {
276 	.div_mult_table	= &div6_div_mult_table,
277 };
278 
sh_clk_div6_set_parent(struct clk * clk,struct clk * parent)279 static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
280 {
281 	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
282 	u32 value;
283 	int ret, i;
284 
285 	if (!clk->parent_table || !clk->parent_num)
286 		return -EINVAL;
287 
288 	/* Search the parent */
289 	for (i = 0; i < clk->parent_num; i++)
290 		if (clk->parent_table[i] == parent)
291 			break;
292 
293 	if (i == clk->parent_num)
294 		return -ENODEV;
295 
296 	ret = clk_reparent(clk, parent);
297 	if (ret < 0)
298 		return ret;
299 
300 	value = sh_clk_read(clk) &
301 		~(((1 << clk->src_width) - 1) << clk->src_shift);
302 
303 	sh_clk_write(value | (i << clk->src_shift), clk);
304 
305 	/* Rebuild the frequency table */
306 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
307 			     table, NULL);
308 
309 	return 0;
310 }
311 
312 static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
313 	.recalc		= sh_clk_div_recalc,
314 	.round_rate	= sh_clk_div_round_rate,
315 	.set_rate	= sh_clk_div_set_rate,
316 	.enable		= sh_clk_div_enable,
317 	.disable	= sh_clk_div_disable,
318 	.set_parent	= sh_clk_div6_set_parent,
319 };
320 
sh_clk_div6_register(struct clk * clks,int nr)321 int __init sh_clk_div6_register(struct clk *clks, int nr)
322 {
323 	return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
324 				       &sh_clk_div_enable_clk_ops);
325 }
326 
sh_clk_div6_reparent_register(struct clk * clks,int nr)327 int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
328 {
329 	return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
330 				       &sh_clk_div6_reparent_clk_ops);
331 }
332 
333 /*
334  * div4 support
335  */
sh_clk_div4_set_parent(struct clk * clk,struct clk * parent)336 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
337 {
338 	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
339 	u32 value;
340 	int ret;
341 
342 	/* we really need a better way to determine parent index, but for
343 	 * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
344 	 * no CLK_ENABLE_ON_INIT means external clock...
345 	 */
346 
347 	if (parent->flags & CLK_ENABLE_ON_INIT)
348 		value = sh_clk_read(clk) & ~(1 << 7);
349 	else
350 		value = sh_clk_read(clk) | (1 << 7);
351 
352 	ret = clk_reparent(clk, parent);
353 	if (ret < 0)
354 		return ret;
355 
356 	sh_clk_write(value, clk);
357 
358 	/* Rebiuld the frequency table */
359 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
360 			     table, &clk->arch_flags);
361 
362 	return 0;
363 }
364 
365 static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
366 	.recalc		= sh_clk_div_recalc,
367 	.set_rate	= sh_clk_div_set_rate,
368 	.round_rate	= sh_clk_div_round_rate,
369 	.enable		= sh_clk_div_enable,
370 	.disable	= sh_clk_div_disable,
371 	.set_parent	= sh_clk_div4_set_parent,
372 };
373 
sh_clk_div4_register(struct clk * clks,int nr,struct clk_div4_table * table)374 int __init sh_clk_div4_register(struct clk *clks, int nr,
375 				struct clk_div4_table *table)
376 {
377 	return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops);
378 }
379 
sh_clk_div4_enable_register(struct clk * clks,int nr,struct clk_div4_table * table)380 int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
381 				struct clk_div4_table *table)
382 {
383 	return sh_clk_div_register_ops(clks, nr, table,
384 				       &sh_clk_div_enable_clk_ops);
385 }
386 
sh_clk_div4_reparent_register(struct clk * clks,int nr,struct clk_div4_table * table)387 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
388 				struct clk_div4_table *table)
389 {
390 	return sh_clk_div_register_ops(clks, nr, table,
391 				       &sh_clk_div4_reparent_clk_ops);
392 }
393 
394 /* FSI-DIV */
fsidiv_recalc(struct clk * clk)395 static unsigned long fsidiv_recalc(struct clk *clk)
396 {
397 	u32 value;
398 
399 	value = __raw_readl(clk->mapping->base);
400 
401 	value >>= 16;
402 	if (value < 2)
403 		return clk->parent->rate;
404 
405 	return clk->parent->rate / value;
406 }
407 
fsidiv_round_rate(struct clk * clk,unsigned long rate)408 static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
409 {
410 	return clk_rate_div_range_round(clk, 1, 0xffff, rate);
411 }
412 
fsidiv_disable(struct clk * clk)413 static void fsidiv_disable(struct clk *clk)
414 {
415 	__raw_writel(0, clk->mapping->base);
416 }
417 
fsidiv_enable(struct clk * clk)418 static int fsidiv_enable(struct clk *clk)
419 {
420 	u32 value;
421 
422 	value  = __raw_readl(clk->mapping->base) >> 16;
423 	if (value < 2)
424 		return 0;
425 
426 	__raw_writel((value << 16) | 0x3, clk->mapping->base);
427 
428 	return 0;
429 }
430 
fsidiv_set_rate(struct clk * clk,unsigned long rate)431 static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
432 {
433 	int idx;
434 
435 	idx = (clk->parent->rate / rate) & 0xffff;
436 	if (idx < 2)
437 		__raw_writel(0, clk->mapping->base);
438 	else
439 		__raw_writel(idx << 16, clk->mapping->base);
440 
441 	return 0;
442 }
443 
444 static struct sh_clk_ops fsidiv_clk_ops = {
445 	.recalc		= fsidiv_recalc,
446 	.round_rate	= fsidiv_round_rate,
447 	.set_rate	= fsidiv_set_rate,
448 	.enable		= fsidiv_enable,
449 	.disable	= fsidiv_disable,
450 };
451 
sh_clk_fsidiv_register(struct clk * clks,int nr)452 int __init sh_clk_fsidiv_register(struct clk *clks, int nr)
453 {
454 	struct clk_mapping *map;
455 	int i;
456 
457 	for (i = 0; i < nr; i++) {
458 
459 		map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL);
460 		if (!map) {
461 			pr_err("%s: unable to alloc memory\n", __func__);
462 			return -ENOMEM;
463 		}
464 
465 		/* clks[i].enable_reg came from SH_CLK_FSIDIV() */
466 		map->phys		= (phys_addr_t)clks[i].enable_reg;
467 		map->len		= 8;
468 
469 		clks[i].enable_reg	= 0; /* remove .enable_reg */
470 		clks[i].ops		= &fsidiv_clk_ops;
471 		clks[i].mapping		= map;
472 
473 		clk_register(&clks[i]);
474 	}
475 
476 	return 0;
477 }
478