1 /*
2  * OMAP2/3 clockdomain framework functions
3  *
4  * Copyright (C) 2008 Texas Instruments, Inc.
5  * Copyright (C) 2008 Nokia Corporation
6  *
7  * Written by Paul Walmsley and Jouni Högander
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 #ifdef CONFIG_OMAP_DEBUG_CLOCKDOMAIN
14 #  define DEBUG
15 #endif
16 
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/device.h>
20 #include <linux/list.h>
21 #include <linux/errno.h>
22 #include <linux/delay.h>
23 #include <linux/clk.h>
24 #include <linux/limits.h>
25 #include <linux/err.h>
26 
27 #include <linux/io.h>
28 
29 #include <linux/bitops.h>
30 
31 #include <mach/clock.h>
32 
33 #include "prm.h"
34 #include "prm-regbits-24xx.h"
35 #include "cm.h"
36 
37 #include <mach/powerdomain.h>
38 #include <mach/clockdomain.h>
39 
40 /* clkdm_list contains all registered struct clockdomains */
41 static LIST_HEAD(clkdm_list);
42 
43 /* clkdm_mutex protects clkdm_list add and del ops */
44 static DEFINE_MUTEX(clkdm_mutex);
45 
46 /* array of powerdomain deps to be added/removed when clkdm in hwsup mode */
47 static struct clkdm_pwrdm_autodep *autodeps;
48 
49 
50 /* Private functions */
51 
52 /*
53  * _autodep_lookup - resolve autodep pwrdm names to pwrdm pointers; store
54  * @autodep: struct clkdm_pwrdm_autodep * to resolve
55  *
56  * Resolve autodep powerdomain names to powerdomain pointers via
57  * pwrdm_lookup() and store the pointers in the autodep structure.  An
58  * "autodep" is a powerdomain sleep/wakeup dependency that is
59  * automatically added and removed whenever clocks in the associated
60  * clockdomain are enabled or disabled (respectively) when the
61  * clockdomain is in hardware-supervised mode.	Meant to be called
62  * once at clockdomain layer initialization, since these should remain
63  * fixed for a particular architecture.  No return value.
64  */
65 static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep)
66 {
67 	struct powerdomain *pwrdm;
68 
69 	if (!autodep)
70 		return;
71 
72 	if (!omap_chip_is(autodep->omap_chip))
73 		return;
74 
75 	pwrdm = pwrdm_lookup(autodep->pwrdm.name);
76 	if (!pwrdm) {
77 		pr_err("clockdomain: autodeps: powerdomain %s does not exist\n",
78 			 autodep->pwrdm.name);
79 		pwrdm = ERR_PTR(-ENOENT);
80 	}
81 	autodep->pwrdm.ptr = pwrdm;
82 }
83 
84 /*
85  * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
86  * @clkdm: struct clockdomain *
87  *
88  * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
89  * in hardware-supervised mode.  Meant to be called from clock framework
90  * when a clock inside clockdomain 'clkdm' is enabled.	No return value.
91  */
92 static void _clkdm_add_autodeps(struct clockdomain *clkdm)
93 {
94 	struct clkdm_pwrdm_autodep *autodep;
95 
96 	for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) {
97 		if (IS_ERR(autodep->pwrdm.ptr))
98 			continue;
99 
100 		if (!omap_chip_is(autodep->omap_chip))
101 			continue;
102 
103 		pr_debug("clockdomain: adding %s sleepdep/wkdep for "
104 			 "pwrdm %s\n", autodep->pwrdm.ptr->name,
105 			 clkdm->pwrdm.ptr->name);
106 
107 		pwrdm_add_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
108 		pwrdm_add_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
109 	}
110 }
111 
112 /*
113  * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
114  * @clkdm: struct clockdomain *
115  *
116  * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
117  * in hardware-supervised mode.  Meant to be called from clock framework
118  * when a clock inside clockdomain 'clkdm' is disabled.  No return value.
119  */
120 static void _clkdm_del_autodeps(struct clockdomain *clkdm)
121 {
122 	struct clkdm_pwrdm_autodep *autodep;
123 
124 	for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) {
125 		if (IS_ERR(autodep->pwrdm.ptr))
126 			continue;
127 
128 		if (!omap_chip_is(autodep->omap_chip))
129 			continue;
130 
131 		pr_debug("clockdomain: removing %s sleepdep/wkdep for "
132 			 "pwrdm %s\n", autodep->pwrdm.ptr->name,
133 			 clkdm->pwrdm.ptr->name);
134 
135 		pwrdm_del_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
136 		pwrdm_del_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
137 	}
138 }
139 
140 
141 static struct clockdomain *_clkdm_lookup(const char *name)
142 {
143 	struct clockdomain *clkdm, *temp_clkdm;
144 
145 	if (!name)
146 		return NULL;
147 
148 	clkdm = NULL;
149 
150 	list_for_each_entry(temp_clkdm, &clkdm_list, node) {
151 		if (!strcmp(name, temp_clkdm->name)) {
152 			clkdm = temp_clkdm;
153 			break;
154 		}
155 	}
156 
157 	return clkdm;
158 }
159 
160 
161 /* Public functions */
162 
163 /**
164  * clkdm_init - set up the clockdomain layer
165  * @clkdms: optional pointer to an array of clockdomains to register
166  * @init_autodeps: optional pointer to an array of autodeps to register
167  *
168  * Set up internal state.  If a pointer to an array of clockdomains
169  * was supplied, loop through the list of clockdomains, register all
170  * that are available on the current platform.	Similarly, if a
171  * pointer to an array of clockdomain-powerdomain autodependencies was
172  * provided, register those.  No return value.
173  */
174 void clkdm_init(struct clockdomain **clkdms,
175 		struct clkdm_pwrdm_autodep *init_autodeps)
176 {
177 	struct clockdomain **c = NULL;
178 	struct clkdm_pwrdm_autodep *autodep = NULL;
179 
180 	if (clkdms)
181 		for (c = clkdms; *c; c++)
182 			clkdm_register(*c);
183 
184 	autodeps = init_autodeps;
185 	if (autodeps)
186 		for (autodep = autodeps; autodep->pwrdm.ptr; autodep++)
187 			_autodep_lookup(autodep);
188 }
189 
190 /**
191  * clkdm_register - register a clockdomain
192  * @clkdm: struct clockdomain * to register
193  *
194  * Adds a clockdomain to the internal clockdomain list.
195  * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
196  * already registered by the provided name, or 0 upon success.
197  */
198 int clkdm_register(struct clockdomain *clkdm)
199 {
200 	int ret = -EINVAL;
201 	struct powerdomain *pwrdm;
202 
203 	if (!clkdm || !clkdm->name)
204 		return -EINVAL;
205 
206 	if (!omap_chip_is(clkdm->omap_chip))
207 		return -EINVAL;
208 
209 	pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
210 	if (!pwrdm) {
211 		pr_err("clockdomain: %s: powerdomain %s does not exist\n",
212 			clkdm->name, clkdm->pwrdm.name);
213 		return -EINVAL;
214 	}
215 	clkdm->pwrdm.ptr = pwrdm;
216 
217 	mutex_lock(&clkdm_mutex);
218 	/* Verify that the clockdomain is not already registered */
219 	if (_clkdm_lookup(clkdm->name)) {
220 		ret = -EEXIST;
221 		goto cr_unlock;
222 	}
223 
224 	list_add(&clkdm->node, &clkdm_list);
225 
226 	pwrdm_add_clkdm(pwrdm, clkdm);
227 
228 	pr_debug("clockdomain: registered %s\n", clkdm->name);
229 	ret = 0;
230 
231 cr_unlock:
232 	mutex_unlock(&clkdm_mutex);
233 
234 	return ret;
235 }
236 
237 /**
238  * clkdm_unregister - unregister a clockdomain
239  * @clkdm: struct clockdomain * to unregister
240  *
241  * Removes a clockdomain from the internal clockdomain list.  Returns
242  * -EINVAL if clkdm argument is NULL.
243  */
244 int clkdm_unregister(struct clockdomain *clkdm)
245 {
246 	if (!clkdm)
247 		return -EINVAL;
248 
249 	pwrdm_del_clkdm(clkdm->pwrdm.ptr, clkdm);
250 
251 	mutex_lock(&clkdm_mutex);
252 	list_del(&clkdm->node);
253 	mutex_unlock(&clkdm_mutex);
254 
255 	pr_debug("clockdomain: unregistered %s\n", clkdm->name);
256 
257 	return 0;
258 }
259 
260 /**
261  * clkdm_lookup - look up a clockdomain by name, return a pointer
262  * @name: name of clockdomain
263  *
264  * Find a registered clockdomain by its name.  Returns a pointer to the
265  * struct clockdomain if found, or NULL otherwise.
266  */
267 struct clockdomain *clkdm_lookup(const char *name)
268 {
269 	struct clockdomain *clkdm, *temp_clkdm;
270 
271 	if (!name)
272 		return NULL;
273 
274 	clkdm = NULL;
275 
276 	mutex_lock(&clkdm_mutex);
277 	list_for_each_entry(temp_clkdm, &clkdm_list, node) {
278 		if (!strcmp(name, temp_clkdm->name)) {
279 			clkdm = temp_clkdm;
280 			break;
281 		}
282 	}
283 	mutex_unlock(&clkdm_mutex);
284 
285 	return clkdm;
286 }
287 
288 /**
289  * clkdm_for_each - call function on each registered clockdomain
290  * @fn: callback function *
291  *
292  * Call the supplied function for each registered clockdomain.
293  * The callback function can return anything but 0 to bail
294  * out early from the iterator.  The callback function is called with
295  * the clkdm_mutex held, so no clockdomain structure manipulation
296  * functions should be called from the callback, although hardware
297  * clockdomain control functions are fine.  Returns the last return
298  * value of the callback function, which should be 0 for success or
299  * anything else to indicate failure; or -EINVAL if the function pointer
300  * is null.
301  */
302 int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
303 			void *user)
304 {
305 	struct clockdomain *clkdm;
306 	int ret = 0;
307 
308 	if (!fn)
309 		return -EINVAL;
310 
311 	mutex_lock(&clkdm_mutex);
312 	list_for_each_entry(clkdm, &clkdm_list, node) {
313 		ret = (*fn)(clkdm, user);
314 		if (ret)
315 			break;
316 	}
317 	mutex_unlock(&clkdm_mutex);
318 
319 	return ret;
320 }
321 
322 
323 /**
324  * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
325  * @clkdm: struct clockdomain *
326  *
327  * Return a pointer to the struct powerdomain that the specified clockdomain
328  * 'clkdm' exists in, or returns NULL if clkdm argument is NULL.
329  */
330 struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
331 {
332 	if (!clkdm)
333 		return NULL;
334 
335 	return clkdm->pwrdm.ptr;
336 }
337 
338 
339 /* Hardware clockdomain control */
340 
341 /**
342  * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
343  * @clk: struct clk * of a clockdomain
344  *
345  * Return the clockdomain's current state transition mode from the
346  * corresponding domain CM_CLKSTCTRL register.	Returns -EINVAL if clk
347  * is NULL or the current mode upon success.
348  */
349 static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
350 {
351 	u32 v;
352 
353 	if (!clkdm)
354 		return -EINVAL;
355 
356 	v = cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
357 	v &= clkdm->clktrctrl_mask;
358 	v >>= __ffs(clkdm->clktrctrl_mask);
359 
360 	return v;
361 }
362 
363 /**
364  * omap2_clkdm_sleep - force clockdomain sleep transition
365  * @clkdm: struct clockdomain *
366  *
367  * Instruct the CM to force a sleep transition on the specified
368  * clockdomain 'clkdm'.  Returns -EINVAL if clk is NULL or if
369  * clockdomain does not support software-initiated sleep; 0 upon
370  * success.
371  */
372 int omap2_clkdm_sleep(struct clockdomain *clkdm)
373 {
374 	if (!clkdm)
375 		return -EINVAL;
376 
377 	if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
378 		pr_debug("clockdomain: %s does not support forcing "
379 			 "sleep via software\n", clkdm->name);
380 		return -EINVAL;
381 	}
382 
383 	pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
384 
385 	if (cpu_is_omap24xx()) {
386 
387 		cm_set_mod_reg_bits(OMAP24XX_FORCESTATE,
388 				    clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL);
389 
390 	} else if (cpu_is_omap34xx()) {
391 
392 		u32 v = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP <<
393 			 __ffs(clkdm->clktrctrl_mask));
394 
395 		cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
396 				    clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
397 
398 	} else {
399 		BUG();
400 	};
401 
402 	return 0;
403 }
404 
405 /**
406  * omap2_clkdm_wakeup - force clockdomain wakeup transition
407  * @clkdm: struct clockdomain *
408  *
409  * Instruct the CM to force a wakeup transition on the specified
410  * clockdomain 'clkdm'.  Returns -EINVAL if clkdm is NULL or if the
411  * clockdomain does not support software-controlled wakeup; 0 upon
412  * success.
413  */
414 int omap2_clkdm_wakeup(struct clockdomain *clkdm)
415 {
416 	if (!clkdm)
417 		return -EINVAL;
418 
419 	if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
420 		pr_debug("clockdomain: %s does not support forcing "
421 			 "wakeup via software\n", clkdm->name);
422 		return -EINVAL;
423 	}
424 
425 	pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
426 
427 	if (cpu_is_omap24xx()) {
428 
429 		cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE,
430 				      clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL);
431 
432 	} else if (cpu_is_omap34xx()) {
433 
434 		u32 v = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP <<
435 			 __ffs(clkdm->clktrctrl_mask));
436 
437 		cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
438 				    clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
439 
440 	} else {
441 		BUG();
442 	};
443 
444 	return 0;
445 }
446 
447 /**
448  * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
449  * @clkdm: struct clockdomain *
450  *
451  * Allow the hardware to automatically switch the clockdomain into
452  * active or idle states, as needed by downstream clocks.  If the
453  * clockdomain has any downstream clocks enabled in the clock
454  * framework, wkdep/sleepdep autodependencies are added; this is so
455  * device drivers can read and write to the device.  No return value.
456  */
457 void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
458 {
459 	u32 v;
460 
461 	if (!clkdm)
462 		return;
463 
464 	if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
465 		pr_debug("clock: automatic idle transitions cannot be enabled "
466 			 "on clockdomain %s\n", clkdm->name);
467 		return;
468 	}
469 
470 	pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
471 		 clkdm->name);
472 
473 	if (atomic_read(&clkdm->usecount) > 0)
474 		_clkdm_add_autodeps(clkdm);
475 
476 	if (cpu_is_omap24xx())
477 		v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
478 	else if (cpu_is_omap34xx())
479 		v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
480 	else
481 		BUG();
482 
483 
484 	cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
485 			    v << __ffs(clkdm->clktrctrl_mask),
486 			    clkdm->pwrdm.ptr->prcm_offs,
487 			    CM_CLKSTCTRL);
488 
489 	pwrdm_clkdm_state_switch(clkdm);
490 }
491 
492 /**
493  * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
494  * @clkdm: struct clockdomain *
495  *
496  * Prevent the hardware from automatically switching the clockdomain
497  * into inactive or idle states.  If the clockdomain has downstream
498  * clocks enabled in the clock framework, wkdep/sleepdep
499  * autodependencies are removed.  No return value.
500  */
501 void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
502 {
503 	u32 v;
504 
505 	if (!clkdm)
506 		return;
507 
508 	if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
509 		pr_debug("clockdomain: automatic idle transitions cannot be "
510 			 "disabled on %s\n", clkdm->name);
511 		return;
512 	}
513 
514 	pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
515 		 clkdm->name);
516 
517 	if (cpu_is_omap24xx())
518 		v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
519 	else if (cpu_is_omap34xx())
520 		v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
521 	else
522 		BUG();
523 
524 	cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
525 			    v << __ffs(clkdm->clktrctrl_mask),
526 			    clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
527 
528 	if (atomic_read(&clkdm->usecount) > 0)
529 		_clkdm_del_autodeps(clkdm);
530 }
531 
532 
533 /* Clockdomain-to-clock framework interface code */
534 
535 /**
536  * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
537  * @clkdm: struct clockdomain *
538  * @clk: struct clk * of the enabled downstream clock
539  *
540  * Increment the usecount of this clockdomain 'clkdm' and ensure that
541  * it is awake.  Intended to be called by clk_enable() code.  If the
542  * clockdomain is in software-supervised idle mode, force the
543  * clockdomain to wake.  If the clockdomain is in hardware-supervised
544  * idle mode, add clkdm-pwrdm autodependencies, to ensure that devices
545  * in the clockdomain can be read from/written to by on-chip processors.
546  * Returns -EINVAL if passed null pointers; returns 0 upon success or
547  * if the clockdomain is in hwsup idle mode.
548  */
549 int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
550 {
551 	int v;
552 
553 	/*
554 	 * XXX Rewrite this code to maintain a list of enabled
555 	 * downstream clocks for debugging purposes?
556 	 */
557 
558 	if (!clkdm || !clk)
559 		return -EINVAL;
560 
561 	if (atomic_inc_return(&clkdm->usecount) > 1)
562 		return 0;
563 
564 	/* Clockdomain now has one enabled downstream clock */
565 
566 	pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
567 		 clk->name);
568 
569 	v = omap2_clkdm_clktrctrl_read(clkdm);
570 
571 	if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
572 	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
573 		_clkdm_add_autodeps(clkdm);
574 	else
575 		omap2_clkdm_wakeup(clkdm);
576 
577 	pwrdm_wait_transition(clkdm->pwrdm.ptr);
578 	pwrdm_clkdm_state_switch(clkdm);
579 
580 	return 0;
581 }
582 
583 /**
584  * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
585  * @clkdm: struct clockdomain *
586  * @clk: struct clk * of the disabled downstream clock
587  *
588  * Decrement the usecount of this clockdomain 'clkdm'. Intended to be
589  * called by clk_disable() code.  If the usecount goes to 0, put the
590  * clockdomain to sleep (software-supervised mode) or remove the
591  * clkdm-pwrdm autodependencies (hardware-supervised mode).  Returns
592  * -EINVAL if passed null pointers; -ERANGE if the clkdm usecount
593  * underflows and debugging is enabled; or returns 0 upon success or
594  * if the clockdomain is in hwsup idle mode.
595  */
596 int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
597 {
598 	int v;
599 
600 	/*
601 	 * XXX Rewrite this code to maintain a list of enabled
602 	 * downstream clocks for debugging purposes?
603 	 */
604 
605 	if (!clkdm || !clk)
606 		return -EINVAL;
607 
608 #ifdef DEBUG
609 	if (atomic_read(&clkdm->usecount) == 0) {
610 		WARN_ON(1); /* underflow */
611 		return -ERANGE;
612 	}
613 #endif
614 
615 	if (atomic_dec_return(&clkdm->usecount) > 0)
616 		return 0;
617 
618 	/* All downstream clocks of this clockdomain are now disabled */
619 
620 	pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
621 		 clk->name);
622 
623 	v = omap2_clkdm_clktrctrl_read(clkdm);
624 
625 	if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
626 	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
627 		_clkdm_del_autodeps(clkdm);
628 	else
629 		omap2_clkdm_sleep(clkdm);
630 
631 	pwrdm_clkdm_state_switch(clkdm);
632 
633 	return 0;
634 }
635 
636