clk.c revision 308324
1/*-
2 * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/dev/extres/clk/clk.c 308324 2016-11-05 04:17:32Z mmel $");
29
30#include "opt_platform.h"
31#include <sys/param.h>
32#include <sys/conf.h>
33#include <sys/bus.h>
34#include <sys/kernel.h>
35#include <sys/queue.h>
36#include <sys/kobj.h>
37#include <sys/malloc.h>
38#include <sys/mutex.h>
39#include <sys/limits.h>
40#include <sys/lock.h>
41#include <sys/sysctl.h>
42#include <sys/systm.h>
43#include <sys/sx.h>
44
45#ifdef FDT
46#include <dev/fdt/fdt_common.h>
47#include <dev/ofw/ofw_bus.h>
48#include <dev/ofw/ofw_bus_subr.h>
49#endif
50#include <dev/extres/clk/clk.h>
51
52MALLOC_DEFINE(M_CLOCK, "clocks", "Clock framework");
53
54/* Forward declarations. */
55struct clk;
56struct clknodenode;
57struct clkdom;
58
59typedef TAILQ_HEAD(clknode_list, clknode) clknode_list_t;
60typedef TAILQ_HEAD(clkdom_list, clkdom) clkdom_list_t;
61
62/* Default clock methods. */
63static int clknode_method_init(struct clknode *clk, device_t dev);
64static int clknode_method_recalc_freq(struct clknode *clk, uint64_t *freq);
65static int clknode_method_set_freq(struct clknode *clk, uint64_t fin,
66    uint64_t *fout, int flags, int *stop);
67static int clknode_method_set_gate(struct clknode *clk, bool enable);
68static int clknode_method_set_mux(struct clknode *clk, int idx);
69
70/*
71 * Clock controller methods.
72 */
73static clknode_method_t clknode_methods[] = {
74	CLKNODEMETHOD(clknode_init,		clknode_method_init),
75	CLKNODEMETHOD(clknode_recalc_freq,	clknode_method_recalc_freq),
76	CLKNODEMETHOD(clknode_set_freq,		clknode_method_set_freq),
77	CLKNODEMETHOD(clknode_set_gate,		clknode_method_set_gate),
78	CLKNODEMETHOD(clknode_set_mux,		clknode_method_set_mux),
79
80	CLKNODEMETHOD_END
81};
82DEFINE_CLASS_0(clknode, clknode_class, clknode_methods, 0);
83
84/*
85 * Clock node - basic element for modeling SOC clock graph.  It holds the clock
86 * provider's data about the clock, and the links for the clock's membership in
87 * various lists.
88 */
89struct clknode {
90	KOBJ_FIELDS;
91
92	/* Clock nodes topology. */
93	struct clkdom 		*clkdom;	/* Owning clock domain */
94	TAILQ_ENTRY(clknode)	clkdom_link;	/* Domain list entry */
95	TAILQ_ENTRY(clknode)	clklist_link;	/* Global list entry */
96
97	/* String based parent list. */
98	const char		**parent_names;	/* Array of parent names */
99	int			parent_cnt;	/* Number of parents */
100	int			parent_idx;	/* Parent index or -1 */
101
102	/* Cache for already resolved names. */
103	struct clknode		**parents;	/* Array of potential parents */
104	struct clknode		*parent;	/* Current parent */
105
106	/* Parent/child relationship links. */
107	clknode_list_t		children;	/* List of our children */
108	TAILQ_ENTRY(clknode)	sibling_link; 	/* Our entry in parent's list */
109
110	/* Details of this device. */
111	void			*softc;		/* Instance softc */
112	const char		*name;		/* Globally unique name */
113	intptr_t		id;		/* Per domain unique id */
114	int			flags;		/* CLK_FLAG_*  */
115	struct sx		lock;		/* Lock for this clock */
116	int			ref_cnt;	/* Reference counter */
117	int			enable_cnt;	/* Enabled counter */
118
119	/* Cached values. */
120	uint64_t		freq;		/* Actual frequency */
121};
122
123/*
124 *  Per consumer data, information about how a consumer is using a clock node.
125 *  A pointer to this structure is used as a handle in the consumer interface.
126 */
127struct clk {
128	device_t		dev;
129	struct clknode		*clknode;
130	int			enable_cnt;
131};
132
133/*
134 * Clock domain - a group of clocks provided by one clock device.
135 */
136struct clkdom {
137	device_t 		dev; 	/* Link to provider device */
138	TAILQ_ENTRY(clkdom)	link;		/* Global domain list entry */
139	clknode_list_t		clknode_list;	/* All clocks in the domain */
140
141#ifdef FDT
142	clknode_ofw_mapper_func	*ofw_mapper;	/* Find clock using FDT xref */
143#endif
144};
145
146/*
147 * The system-wide list of clock domains.
148 */
149static clkdom_list_t clkdom_list = TAILQ_HEAD_INITIALIZER(clkdom_list);
150
151/*
152 * Each clock node is linked on a system-wide list and can be searched by name.
153 */
154static clknode_list_t clknode_list = TAILQ_HEAD_INITIALIZER(clknode_list);
155
156/*
157 * Locking - we use three levels of locking:
158 * - First, topology lock is taken.  This one protect all lists.
159 * - Second level is per clknode lock.  It protects clknode data.
160 * - Third level is outside of this file, it protect clock device registers.
161 * First two levels use sleepable locks; clock device can use mutex or sx lock.
162 */
163static struct sx		clk_topo_lock;
164SX_SYSINIT(clock_topology, &clk_topo_lock, "Clock topology lock");
165
166#define CLK_TOPO_SLOCK()	sx_slock(&clk_topo_lock)
167#define CLK_TOPO_XLOCK()	sx_xlock(&clk_topo_lock)
168#define CLK_TOPO_UNLOCK()	sx_unlock(&clk_topo_lock)
169#define CLK_TOPO_ASSERT()	sx_assert(&clk_topo_lock, SA_LOCKED)
170#define CLK_TOPO_XASSERT()	sx_assert(&clk_topo_lock, SA_XLOCKED)
171
172#define CLKNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
173#define CLKNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
174#define CLKNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
175
176static void clknode_adjust_parent(struct clknode *clknode, int idx);
177
178/*
179 * Default clock methods for base class.
180 */
181static int
182clknode_method_init(struct clknode *clknode, device_t dev)
183{
184
185	return (0);
186}
187
188static int
189clknode_method_recalc_freq(struct clknode *clknode, uint64_t *freq)
190{
191
192	return (0);
193}
194
195static int
196clknode_method_set_freq(struct clknode *clknode, uint64_t fin,  uint64_t *fout,
197   int flags, int *stop)
198{
199
200	*stop = 0;
201	return (0);
202}
203
204static int
205clknode_method_set_gate(struct clknode *clk, bool enable)
206{
207
208	return (0);
209}
210
211static int
212clknode_method_set_mux(struct clknode *clk, int idx)
213{
214
215	return (0);
216}
217
218/*
219 * Internal functions.
220 */
221
222/*
223 * Duplicate an array of parent names.
224 *
225 * Compute total size and allocate a single block which holds both the array of
226 * pointers to strings and the copied strings themselves.  Returns a pointer to
227 * the start of the block where the array of copied string pointers lives.
228 *
229 * XXX Revisit this, no need for the DECONST stuff.
230 */
231static const char **
232strdup_list(const char **names, int num)
233{
234	size_t len, slen;
235	const char **outptr, *ptr;
236	int i;
237
238	len = sizeof(char *) * num;
239	for (i = 0; i < num; i++) {
240		if (names[i] == NULL)
241			continue;
242		slen = strlen(names[i]);
243		if (slen == 0)
244			panic("Clock parent names array have empty string");
245		len += slen + 1;
246	}
247	outptr = malloc(len, M_CLOCK, M_WAITOK | M_ZERO);
248	ptr = (char *)(outptr + num);
249	for (i = 0; i < num; i++) {
250		if (names[i] == NULL)
251			continue;
252		outptr[i] = ptr;
253		slen = strlen(names[i]) + 1;
254		bcopy(names[i], __DECONST(void *, outptr[i]), slen);
255		ptr += slen;
256	}
257	return (outptr);
258}
259
260/*
261 * Recompute the cached frequency for this node and all its children.
262 */
263static int
264clknode_refresh_cache(struct clknode *clknode, uint64_t freq)
265{
266	int rv;
267	struct clknode *entry;
268
269	CLK_TOPO_XASSERT();
270
271	/* Compute generated frequency. */
272	rv = CLKNODE_RECALC_FREQ(clknode, &freq);
273	if (rv != 0) {
274		 /* XXX If an error happens while refreshing children
275		  * this leaves the world in a  partially-updated state.
276		  * Panic for now.
277		  */
278		panic("clknode_refresh_cache failed for '%s'\n",
279		    clknode->name);
280		return (rv);
281	}
282	/* Refresh cache for this node. */
283	clknode->freq = freq;
284
285	/* Refresh cache for all children. */
286	TAILQ_FOREACH(entry, &(clknode->children), sibling_link) {
287		rv = clknode_refresh_cache(entry, freq);
288		if (rv != 0)
289			return (rv);
290	}
291	return (0);
292}
293
294/*
295 * Public interface.
296 */
297
298struct clknode *
299clknode_find_by_name(const char *name)
300{
301	struct clknode *entry;
302
303	CLK_TOPO_ASSERT();
304
305	TAILQ_FOREACH(entry, &clknode_list, clklist_link) {
306		if (strcmp(entry->name, name) == 0)
307			return (entry);
308	}
309	return (NULL);
310}
311
312struct clknode *
313clknode_find_by_id(struct clkdom *clkdom, intptr_t id)
314{
315	struct clknode *entry;
316
317	CLK_TOPO_ASSERT();
318
319	TAILQ_FOREACH(entry, &clkdom->clknode_list, clkdom_link) {
320		if (entry->id ==  id)
321			return (entry);
322	}
323
324	return (NULL);
325}
326
327/* -------------------------------------------------------------------------- */
328/*
329 * Clock domain functions
330 */
331
332/* Find clock domain associated to device in global list. */
333struct clkdom *
334clkdom_get_by_dev(const device_t dev)
335{
336	struct clkdom *entry;
337
338	CLK_TOPO_ASSERT();
339
340	TAILQ_FOREACH(entry, &clkdom_list, link) {
341		if (entry->dev == dev)
342			return (entry);
343	}
344	return (NULL);
345}
346
347
348#ifdef FDT
349/* Default DT mapper. */
350static int
351clknode_default_ofw_map(struct clkdom *clkdom, uint32_t ncells,
352    phandle_t *cells, struct clknode **clk)
353{
354
355	CLK_TOPO_ASSERT();
356
357	if (ncells == 0)
358		*clk = clknode_find_by_id(clkdom, 1);
359	else if (ncells == 1)
360		*clk = clknode_find_by_id(clkdom, cells[0]);
361	else
362		return  (ERANGE);
363
364	if (*clk == NULL)
365		return (ENXIO);
366	return (0);
367}
368#endif
369
370/*
371 * Create a clock domain.  Returns with the topo lock held.
372 */
373struct clkdom *
374clkdom_create(device_t dev)
375{
376	struct clkdom *clkdom;
377
378	clkdom = malloc(sizeof(struct clkdom), M_CLOCK, M_WAITOK | M_ZERO);
379	clkdom->dev = dev;
380	TAILQ_INIT(&clkdom->clknode_list);
381#ifdef FDT
382	clkdom->ofw_mapper = clknode_default_ofw_map;
383#endif
384
385	return (clkdom);
386}
387
388void
389clkdom_unlock(struct clkdom *clkdom)
390{
391
392	CLK_TOPO_UNLOCK();
393}
394
395void
396clkdom_xlock(struct clkdom *clkdom)
397{
398
399	CLK_TOPO_XLOCK();
400}
401
402/*
403 * Finalize initialization of clock domain.  Releases topo lock.
404 *
405 * XXX Revisit failure handling.
406 */
407int
408clkdom_finit(struct clkdom *clkdom)
409{
410	struct clknode *clknode;
411	int i, rv;
412#ifdef FDT
413	phandle_t node;
414
415
416	if ((node = ofw_bus_get_node(clkdom->dev)) == -1) {
417		device_printf(clkdom->dev,
418		    "%s called on not ofw based device\n", __func__);
419		return (ENXIO);
420	}
421#endif
422	rv = 0;
423
424	/* Make clock domain globally visible. */
425	CLK_TOPO_XLOCK();
426	TAILQ_INSERT_TAIL(&clkdom_list, clkdom, link);
427#ifdef FDT
428	OF_device_register_xref(OF_xref_from_node(node), clkdom->dev);
429#endif
430
431	/* Register all clock names into global list. */
432	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
433		TAILQ_INSERT_TAIL(&clknode_list, clknode, clklist_link);
434	}
435	/*
436	 * At this point all domain nodes must be registered and all
437	 * parents must be valid.
438	 */
439	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
440		if (clknode->parent_cnt == 0)
441			continue;
442		for (i = 0; i < clknode->parent_cnt; i++) {
443			if (clknode->parents[i] != NULL)
444				continue;
445			if (clknode->parent_names[i] == NULL)
446				continue;
447			clknode->parents[i] = clknode_find_by_name(
448			    clknode->parent_names[i]);
449			if (clknode->parents[i] == NULL) {
450				device_printf(clkdom->dev,
451				    "Clock %s have unknown parent: %s\n",
452				    clknode->name, clknode->parent_names[i]);
453				rv = ENODEV;
454			}
455		}
456
457		/* If parent index is not set yet... */
458		if (clknode->parent_idx == CLKNODE_IDX_NONE) {
459			device_printf(clkdom->dev,
460			    "Clock %s have not set parent idx\n",
461			    clknode->name);
462			rv = ENXIO;
463			continue;
464		}
465		if (clknode->parents[clknode->parent_idx] == NULL) {
466			device_printf(clkdom->dev,
467			    "Clock %s have unknown parent(idx %d): %s\n",
468			    clknode->name, clknode->parent_idx,
469			    clknode->parent_names[clknode->parent_idx]);
470			rv = ENXIO;
471			continue;
472		}
473		clknode_adjust_parent(clknode, clknode->parent_idx);
474	}
475	CLK_TOPO_UNLOCK();
476	return (rv);
477}
478
479/* Dump clock domain. */
480void
481clkdom_dump(struct clkdom * clkdom)
482{
483	struct clknode *clknode;
484	int rv;
485	uint64_t freq;
486
487	CLK_TOPO_SLOCK();
488	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
489		rv = clknode_get_freq(clknode, &freq);
490		printf("Clock: %s, parent: %s(%d), freq: %ju\n", clknode->name,
491		    clknode->parent == NULL ? "(NULL)" : clknode->parent->name,
492		    clknode->parent_idx,
493		    (uintmax_t)((rv == 0) ? freq: rv));
494	}
495	CLK_TOPO_UNLOCK();
496}
497
498/*
499 * Create and initialize clock object, but do not register it.
500 */
501struct clknode *
502clknode_create(struct clkdom * clkdom, clknode_class_t clknode_class,
503    const struct clknode_init_def *def)
504{
505	struct clknode *clknode;
506
507	KASSERT(def->name != NULL, ("clock name is NULL"));
508	KASSERT(def->name[0] != '\0', ("clock name is empty"));
509#ifdef   INVARIANTS
510	CLK_TOPO_SLOCK();
511	if (clknode_find_by_name(def->name) != NULL)
512		panic("Duplicated clock registration: %s\n", def->name);
513	CLK_TOPO_UNLOCK();
514#endif
515
516	/* Create object and initialize it. */
517	clknode = malloc(sizeof(struct clknode), M_CLOCK, M_WAITOK | M_ZERO);
518	kobj_init((kobj_t)clknode, (kobj_class_t)clknode_class);
519	sx_init(&clknode->lock, "Clocknode lock");
520
521	/* Allocate softc if required. */
522	if (clknode_class->size > 0) {
523		clknode->softc = malloc(clknode_class->size,
524		    M_CLOCK, M_WAITOK | M_ZERO);
525	}
526
527	/* Prepare array for ptrs to parent clocks. */
528	clknode->parents = malloc(sizeof(struct clknode *) * def->parent_cnt,
529	    M_CLOCK, M_WAITOK | M_ZERO);
530
531	/* Copy all strings unless they're flagged as static. */
532	if (def->flags & CLK_NODE_STATIC_STRINGS) {
533		clknode->name = def->name;
534		clknode->parent_names = def->parent_names;
535	} else {
536		clknode->name = strdup(def->name, M_CLOCK);
537		clknode->parent_names =
538		    strdup_list(def->parent_names, def->parent_cnt);
539	}
540
541	/* Rest of init. */
542	clknode->id = def->id;
543	clknode->clkdom = clkdom;
544	clknode->flags = def->flags;
545	clknode->parent_cnt = def->parent_cnt;
546	clknode->parent = NULL;
547	clknode->parent_idx = CLKNODE_IDX_NONE;
548	TAILQ_INIT(&clknode->children);
549
550	return (clknode);
551}
552
553/*
554 * Register clock object into clock domain hierarchy.
555 */
556struct clknode *
557clknode_register(struct clkdom * clkdom, struct clknode *clknode)
558{
559	int rv;
560
561	rv = CLKNODE_INIT(clknode, clknode_get_device(clknode));
562	if (rv != 0) {
563		printf(" CLKNODE_INIT failed: %d\n", rv);
564		return (NULL);
565	}
566
567	TAILQ_INSERT_TAIL(&clkdom->clknode_list, clknode, clkdom_link);
568
569	return (clknode);
570}
571
572/*
573 * Clock providers interface.
574 */
575
576/*
577 * Reparent clock node.
578 */
579static void
580clknode_adjust_parent(struct clknode *clknode, int idx)
581{
582
583	CLK_TOPO_XASSERT();
584
585	if (clknode->parent_cnt == 0)
586		return;
587	if ((idx == CLKNODE_IDX_NONE) || (idx >= clknode->parent_cnt))
588		panic("Invalid clock parent index\n");
589
590	if (clknode->parents[idx] == NULL)
591		panic("%s: Attempt to set invalid parent %d for clock %s",
592		    __func__, idx, clknode->name);
593
594	/* Remove me from old children list. */
595	if (clknode->parent != NULL) {
596		TAILQ_REMOVE(&clknode->parent->children, clknode, sibling_link);
597	}
598
599	/* Insert into children list of new parent. */
600	clknode->parent_idx = idx;
601	clknode->parent = clknode->parents[idx];
602	TAILQ_INSERT_TAIL(&clknode->parent->children, clknode, sibling_link);
603}
604
605/*
606 * Set parent index - init function.
607 */
608void
609clknode_init_parent_idx(struct clknode *clknode, int idx)
610{
611
612	if (clknode->parent_cnt == 0) {
613		clknode->parent_idx = CLKNODE_IDX_NONE;
614		clknode->parent = NULL;
615		return;
616	}
617	if ((idx == CLKNODE_IDX_NONE) ||
618	    (idx >= clknode->parent_cnt) ||
619	    (clknode->parent_names[idx] == NULL))
620		panic("%s: Invalid clock parent index: %d\n", __func__, idx);
621
622	clknode->parent_idx = idx;
623}
624
625int
626clknode_set_parent_by_idx(struct clknode *clknode, int idx)
627{
628	int rv;
629	uint64_t freq;
630	int  oldidx;
631
632	/* We have exclusive topology lock, node lock is not needed. */
633	CLK_TOPO_XASSERT();
634
635	if (clknode->parent_cnt == 0)
636		return (0);
637
638	if (clknode->parent_idx == idx)
639		return (0);
640
641	oldidx = clknode->parent_idx;
642	clknode_adjust_parent(clknode, idx);
643	rv = CLKNODE_SET_MUX(clknode, idx);
644	if (rv != 0) {
645		clknode_adjust_parent(clknode, oldidx);
646		return (rv);
647	}
648	rv = clknode_get_freq(clknode->parent, &freq);
649	if (rv != 0)
650		return (rv);
651	rv = clknode_refresh_cache(clknode, freq);
652	return (rv);
653}
654
655int
656clknode_set_parent_by_name(struct clknode *clknode, const char *name)
657{
658	int rv;
659	uint64_t freq;
660	int  oldidx, idx;
661
662	/* We have exclusive topology lock, node lock is not needed. */
663	CLK_TOPO_XASSERT();
664
665	if (clknode->parent_cnt == 0)
666		return (0);
667
668	/*
669	 * If this node doesnt have mux, then passthrough request to parent.
670	 * This feature is used in clock domain initialization and allows us to
671	 * set clock source and target frequency on the tail node of the clock
672	 * chain.
673	 */
674	if (clknode->parent_cnt == 1) {
675		rv = clknode_set_parent_by_name(clknode->parent, name);
676		return (rv);
677	}
678
679	for (idx = 0; idx < clknode->parent_cnt; idx++) {
680		if (clknode->parent_names[idx] == NULL)
681			continue;
682		if (strcmp(clknode->parent_names[idx], name) == 0)
683			break;
684	}
685	if (idx >= clknode->parent_cnt) {
686		return (ENXIO);
687	}
688	if (clknode->parent_idx == idx)
689		return (0);
690
691	oldidx = clknode->parent_idx;
692	clknode_adjust_parent(clknode, idx);
693	rv = CLKNODE_SET_MUX(clknode, idx);
694	if (rv != 0) {
695		clknode_adjust_parent(clknode, oldidx);
696		CLKNODE_UNLOCK(clknode);
697		return (rv);
698	}
699	rv = clknode_get_freq(clknode->parent, &freq);
700	if (rv != 0)
701		return (rv);
702	rv = clknode_refresh_cache(clknode, freq);
703	return (rv);
704}
705
706struct clknode *
707clknode_get_parent(struct clknode *clknode)
708{
709
710	return (clknode->parent);
711}
712
713const char *
714clknode_get_name(struct clknode *clknode)
715{
716
717	return (clknode->name);
718}
719
720const char **
721clknode_get_parent_names(struct clknode *clknode)
722{
723
724	return (clknode->parent_names);
725}
726
727int
728clknode_get_parents_num(struct clknode *clknode)
729{
730
731	return (clknode->parent_cnt);
732}
733
734int
735clknode_get_parent_idx(struct clknode *clknode)
736{
737
738	return (clknode->parent_idx);
739}
740
741int
742clknode_get_flags(struct clknode *clknode)
743{
744
745	return (clknode->flags);
746}
747
748
749void *
750clknode_get_softc(struct clknode *clknode)
751{
752
753	return (clknode->softc);
754}
755
756device_t
757clknode_get_device(struct clknode *clknode)
758{
759
760	return (clknode->clkdom->dev);
761}
762
763#ifdef FDT
764void
765clkdom_set_ofw_mapper(struct clkdom * clkdom, clknode_ofw_mapper_func *map)
766{
767
768	clkdom->ofw_mapper = map;
769}
770#endif
771
772/*
773 * Real consumers executive
774 */
775int
776clknode_get_freq(struct clknode *clknode, uint64_t *freq)
777{
778	int rv;
779
780	CLK_TOPO_ASSERT();
781
782	/* Use cached value, if it exists. */
783	*freq  = clknode->freq;
784	if (*freq != 0)
785		return (0);
786
787	/* Get frequency from parent, if the clock has a parent. */
788	if (clknode->parent_cnt > 0) {
789		rv = clknode_get_freq(clknode->parent, freq);
790		if (rv != 0) {
791			return (rv);
792		}
793	}
794
795	/* And recalculate my output frequency. */
796	CLKNODE_XLOCK(clknode);
797	rv = CLKNODE_RECALC_FREQ(clknode, freq);
798	if (rv != 0) {
799		CLKNODE_UNLOCK(clknode);
800		printf("Cannot get frequency for clk: %s, error: %d\n",
801		    clknode->name, rv);
802		return (rv);
803	}
804
805	/* Save new frequency to cache. */
806	clknode->freq = *freq;
807	CLKNODE_UNLOCK(clknode);
808	return (0);
809}
810
811int
812clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
813    int enablecnt)
814{
815	int rv, done;
816	uint64_t parent_freq;
817
818	/* We have exclusive topology lock, node lock is not needed. */
819	CLK_TOPO_XASSERT();
820
821	/* Check for no change */
822	if (clknode->freq == freq)
823		return (0);
824
825	parent_freq = 0;
826
827	/*
828	 * We can set frequency only if
829	 *   clock is disabled
830	 * OR
831	 *   clock is glitch free and is enabled by calling consumer only
832	 */
833	if ((clknode->enable_cnt > 1) &&
834	    ((clknode->enable_cnt > enablecnt) ||
835	    !(clknode->flags & CLK_NODE_GLITCH_FREE))) {
836		return (EBUSY);
837	}
838
839	/* Get frequency from parent, if the clock has a parent. */
840	if (clknode->parent_cnt > 0) {
841		rv = clknode_get_freq(clknode->parent, &parent_freq);
842		if (rv != 0) {
843			return (rv);
844		}
845	}
846
847	/* Set frequency for this clock. */
848	rv = CLKNODE_SET_FREQ(clknode, parent_freq, &freq, flags, &done);
849	if (rv != 0) {
850		printf("Cannot set frequency for clk: %s, error: %d\n",
851		    clknode->name, rv);
852		if ((flags & CLK_SET_DRYRUN) == 0)
853			clknode_refresh_cache(clknode, parent_freq);
854		return (rv);
855	}
856
857	if (done) {
858		/* Success - invalidate frequency cache for all children. */
859		clknode->freq = freq;
860		if ((flags & CLK_SET_DRYRUN) == 0)
861			clknode_refresh_cache(clknode, parent_freq);
862	} else if (clknode->parent != NULL) {
863		/* Nothing changed, pass request to parent. */
864		rv = clknode_set_freq(clknode->parent, freq, flags, enablecnt);
865	} else {
866		/* End of chain without action. */
867		printf("Cannot set frequency for clk: %s, end of chain\n",
868		    clknode->name);
869		rv = ENXIO;
870	}
871
872	return (rv);
873}
874
875int
876clknode_enable(struct clknode *clknode)
877{
878	int rv;
879
880	CLK_TOPO_ASSERT();
881
882	/* Enable clock for each node in chain, starting from source. */
883	if (clknode->parent_cnt > 0) {
884		rv = clknode_enable(clknode->parent);
885		if (rv != 0) {
886			return (rv);
887		}
888	}
889
890	/* Handle this node */
891	CLKNODE_XLOCK(clknode);
892	if (clknode->enable_cnt == 0) {
893		rv = CLKNODE_SET_GATE(clknode, 1);
894		if (rv != 0) {
895			CLKNODE_UNLOCK(clknode);
896			return (rv);
897		}
898	}
899	clknode->enable_cnt++;
900	CLKNODE_UNLOCK(clknode);
901	return (0);
902}
903
904int
905clknode_disable(struct clknode *clknode)
906{
907	int rv;
908
909	CLK_TOPO_ASSERT();
910	rv = 0;
911
912	CLKNODE_XLOCK(clknode);
913	/* Disable clock for each node in chain, starting from consumer. */
914	if ((clknode->enable_cnt == 1) &&
915	    ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) {
916		rv = CLKNODE_SET_GATE(clknode, 0);
917		if (rv != 0) {
918			CLKNODE_UNLOCK(clknode);
919			return (rv);
920		}
921	}
922	clknode->enable_cnt--;
923	CLKNODE_UNLOCK(clknode);
924
925	if (clknode->parent_cnt > 0) {
926		rv = clknode_disable(clknode->parent);
927	}
928	return (rv);
929}
930
931int
932clknode_stop(struct clknode *clknode, int depth)
933{
934	int rv;
935
936	CLK_TOPO_ASSERT();
937	rv = 0;
938
939	CLKNODE_XLOCK(clknode);
940	/* The first node cannot be enabled. */
941	if ((clknode->enable_cnt != 0) && (depth == 0)) {
942		CLKNODE_UNLOCK(clknode);
943		return (EBUSY);
944	}
945	/* Stop clock for each node in chain, starting from consumer. */
946	if ((clknode->enable_cnt == 0) &&
947	    ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) {
948		rv = CLKNODE_SET_GATE(clknode, 0);
949		if (rv != 0) {
950			CLKNODE_UNLOCK(clknode);
951			return (rv);
952		}
953	}
954	CLKNODE_UNLOCK(clknode);
955
956	if (clknode->parent_cnt > 0)
957		rv = clknode_stop(clknode->parent, depth + 1);
958	return (rv);
959}
960
961/* --------------------------------------------------------------------------
962 *
963 * Clock consumers interface.
964 *
965 */
966/* Helper function for clk_get*() */
967static clk_t
968clk_create(struct clknode *clknode, device_t dev)
969{
970	struct clk *clk;
971
972	CLK_TOPO_ASSERT();
973
974	clk =  malloc(sizeof(struct clk), M_CLOCK, M_WAITOK);
975	clk->dev = dev;
976	clk->clknode = clknode;
977	clk->enable_cnt = 0;
978	clknode->ref_cnt++;
979
980	return (clk);
981}
982
983int
984clk_get_freq(clk_t clk, uint64_t *freq)
985{
986	int rv;
987	struct clknode *clknode;
988
989	clknode = clk->clknode;
990	KASSERT(clknode->ref_cnt > 0,
991	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
992
993	CLK_TOPO_SLOCK();
994	rv = clknode_get_freq(clknode, freq);
995	CLK_TOPO_UNLOCK();
996	return (rv);
997}
998
999int
1000clk_set_freq(clk_t clk, uint64_t freq, int flags)
1001{
1002	int rv;
1003	struct clknode *clknode;
1004
1005	flags &= CLK_SET_USER_MASK;
1006	clknode = clk->clknode;
1007	KASSERT(clknode->ref_cnt > 0,
1008	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1009
1010	CLK_TOPO_XLOCK();
1011	rv = clknode_set_freq(clknode, freq, flags, clk->enable_cnt);
1012	CLK_TOPO_UNLOCK();
1013	return (rv);
1014}
1015
1016int
1017clk_test_freq(clk_t clk, uint64_t freq, int flags)
1018{
1019	int rv;
1020	struct clknode *clknode;
1021
1022	flags &= CLK_SET_USER_MASK;
1023	clknode = clk->clknode;
1024	KASSERT(clknode->ref_cnt > 0,
1025	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1026
1027	CLK_TOPO_XLOCK();
1028	rv = clknode_set_freq(clknode, freq, flags | CLK_SET_DRYRUN, 0);
1029	CLK_TOPO_UNLOCK();
1030	return (rv);
1031}
1032
1033int
1034clk_get_parent(clk_t clk, clk_t *parent)
1035{
1036	struct clknode *clknode;
1037	struct clknode *parentnode;
1038
1039	clknode = clk->clknode;
1040	KASSERT(clknode->ref_cnt > 0,
1041	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1042
1043	CLK_TOPO_SLOCK();
1044	parentnode = clknode_get_parent(clknode);
1045	if (parentnode == NULL) {
1046		CLK_TOPO_UNLOCK();
1047		return (ENODEV);
1048	}
1049	*parent = clk_create(parentnode, clk->dev);
1050	CLK_TOPO_UNLOCK();
1051	return (0);
1052}
1053
1054int
1055clk_set_parent_by_clk(clk_t clk, clk_t parent)
1056{
1057	int rv;
1058	struct clknode *clknode;
1059	struct clknode *parentnode;
1060
1061	clknode = clk->clknode;
1062	parentnode = parent->clknode;
1063	KASSERT(clknode->ref_cnt > 0,
1064	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1065	KASSERT(parentnode->ref_cnt > 0,
1066	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1067	CLK_TOPO_XLOCK();
1068	rv = clknode_set_parent_by_name(clknode, parentnode->name);
1069	CLK_TOPO_UNLOCK();
1070	return (rv);
1071}
1072
1073int
1074clk_enable(clk_t clk)
1075{
1076	int rv;
1077	struct clknode *clknode;
1078
1079	clknode = clk->clknode;
1080	KASSERT(clknode->ref_cnt > 0,
1081	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1082	CLK_TOPO_SLOCK();
1083	rv = clknode_enable(clknode);
1084	if (rv == 0)
1085		clk->enable_cnt++;
1086	CLK_TOPO_UNLOCK();
1087	return (rv);
1088}
1089
1090int
1091clk_disable(clk_t clk)
1092{
1093	int rv;
1094	struct clknode *clknode;
1095
1096	clknode = clk->clknode;
1097	KASSERT(clknode->ref_cnt > 0,
1098	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1099	KASSERT(clk->enable_cnt > 0,
1100	   ("Attempt to disable already disabled clock: %s\n", clknode->name));
1101	CLK_TOPO_SLOCK();
1102	rv = clknode_disable(clknode);
1103	if (rv == 0)
1104		clk->enable_cnt--;
1105	CLK_TOPO_UNLOCK();
1106	return (rv);
1107}
1108
1109int
1110clk_stop(clk_t clk)
1111{
1112	int rv;
1113	struct clknode *clknode;
1114
1115	clknode = clk->clknode;
1116	KASSERT(clknode->ref_cnt > 0,
1117	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1118	KASSERT(clk->enable_cnt == 0,
1119	   ("Attempt to stop already enabled clock: %s\n", clknode->name));
1120
1121	CLK_TOPO_SLOCK();
1122	rv = clknode_stop(clknode, 0);
1123	CLK_TOPO_UNLOCK();
1124	return (rv);
1125}
1126
1127int
1128clk_release(clk_t clk)
1129{
1130	struct clknode *clknode;
1131
1132	clknode = clk->clknode;
1133	KASSERT(clknode->ref_cnt > 0,
1134	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1135	CLK_TOPO_SLOCK();
1136	while (clk->enable_cnt > 0) {
1137		clknode_disable(clknode);
1138		clk->enable_cnt--;
1139	}
1140	CLKNODE_XLOCK(clknode);
1141	clknode->ref_cnt--;
1142	CLKNODE_UNLOCK(clknode);
1143	CLK_TOPO_UNLOCK();
1144
1145	free(clk, M_CLOCK);
1146	return (0);
1147}
1148
1149const char *
1150clk_get_name(clk_t clk)
1151{
1152	const char *name;
1153	struct clknode *clknode;
1154
1155	clknode = clk->clknode;
1156	KASSERT(clknode->ref_cnt > 0,
1157	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1158	name = clknode_get_name(clknode);
1159	return (name);
1160}
1161
1162int
1163clk_get_by_name(device_t dev, const char *name, clk_t *clk)
1164{
1165	struct clknode *clknode;
1166
1167	CLK_TOPO_SLOCK();
1168	clknode = clknode_find_by_name(name);
1169	if (clknode == NULL) {
1170		CLK_TOPO_UNLOCK();
1171		return (ENODEV);
1172	}
1173	*clk = clk_create(clknode, dev);
1174	CLK_TOPO_UNLOCK();
1175	return (0);
1176}
1177
1178int
1179clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk)
1180{
1181	struct clknode *clknode;
1182
1183	CLK_TOPO_SLOCK();
1184
1185	clknode = clknode_find_by_id(clkdom, id);
1186	if (clknode == NULL) {
1187		CLK_TOPO_UNLOCK();
1188		return (ENODEV);
1189	}
1190	*clk = clk_create(clknode, dev);
1191	CLK_TOPO_UNLOCK();
1192
1193	return (0);
1194}
1195
1196#ifdef FDT
1197
1198int
1199clk_get_by_ofw_index(device_t dev, phandle_t cnode, int idx, clk_t *clk)
1200{
1201	phandle_t parent, *cells;
1202	device_t clockdev;
1203	int ncells, rv;
1204	struct clkdom *clkdom;
1205	struct clknode *clknode;
1206
1207	*clk = NULL;
1208	if (cnode <= 0)
1209		cnode = ofw_bus_get_node(dev);
1210	if (cnode <= 0) {
1211		device_printf(dev, "%s called on not ofw based device\n",
1212		 __func__);
1213		return (ENXIO);
1214	}
1215
1216
1217	rv = ofw_bus_parse_xref_list_alloc(cnode, "clocks", "#clock-cells", idx,
1218	    &parent, &ncells, &cells);
1219	if (rv != 0) {
1220		return (rv);
1221	}
1222
1223	clockdev = OF_device_from_xref(parent);
1224	if (clockdev == NULL) {
1225		rv = ENODEV;
1226		goto done;
1227	}
1228
1229	CLK_TOPO_SLOCK();
1230	clkdom = clkdom_get_by_dev(clockdev);
1231	if (clkdom == NULL){
1232		CLK_TOPO_UNLOCK();
1233		rv = ENXIO;
1234		goto done;
1235	}
1236
1237	rv = clkdom->ofw_mapper(clkdom, ncells, cells, &clknode);
1238	if (rv == 0) {
1239		*clk = clk_create(clknode, dev);
1240	}
1241	CLK_TOPO_UNLOCK();
1242
1243done:
1244	if (cells != NULL)
1245		OF_prop_free(cells);
1246	return (rv);
1247}
1248
1249int
1250clk_get_by_ofw_name(device_t dev, phandle_t cnode, const char *name, clk_t *clk)
1251{
1252	int rv, idx;
1253
1254	if (cnode <= 0)
1255		cnode = ofw_bus_get_node(dev);
1256	if (cnode <= 0) {
1257		device_printf(dev, "%s called on not ofw based device\n",
1258		 __func__);
1259		return (ENXIO);
1260	}
1261	rv = ofw_bus_find_string_index(cnode, "clock-names", name, &idx);
1262	if (rv != 0)
1263		return (rv);
1264	return (clk_get_by_ofw_index(dev, cnode, idx, clk));
1265}
1266
1267/* --------------------------------------------------------------------------
1268 *
1269 * Support functions for parsing various clock related OFW things.
1270 */
1271
1272/*
1273 * Get "clock-output-names" and  (optional) "clock-indices" lists.
1274 * Both lists are alocated using M_OFWPROP specifier.
1275 *
1276 * Returns number of items or 0.
1277 */
1278int
1279clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names,
1280	uint32_t **indices)
1281{
1282	int name_items, rv;
1283
1284	*out_names = NULL;
1285	*indices = NULL;
1286	if (!OF_hasprop(node, "clock-output-names"))
1287		return (0);
1288	rv = ofw_bus_string_list_to_array(node, "clock-output-names",
1289	    out_names);
1290	if (rv <= 0)
1291		return (0);
1292	name_items = rv;
1293
1294	if (!OF_hasprop(node, "clock-indices"))
1295		return (name_items);
1296	rv = OF_getencprop_alloc(node, "clock-indices", sizeof (uint32_t),
1297	    (void **)indices);
1298	if (rv != name_items) {
1299		device_printf(dev, " Size of 'clock-output-names' and "
1300		    "'clock-indices' differs\n");
1301		OF_prop_free(*out_names);
1302		OF_prop_free(*indices);
1303		return (0);
1304	}
1305	return (name_items);
1306}
1307
1308/*
1309 * Get output clock name for single output clock node.
1310 */
1311int
1312clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name)
1313{
1314	const char **out_names;
1315	const char  *tmp_name;
1316	int rv;
1317
1318	*name = NULL;
1319	if (!OF_hasprop(node, "clock-output-names")) {
1320		tmp_name  = ofw_bus_get_name(dev);
1321		if (tmp_name == NULL)
1322			return (ENXIO);
1323		*name = strdup(tmp_name, M_OFWPROP);
1324		return (0);
1325	}
1326	rv = ofw_bus_string_list_to_array(node, "clock-output-names",
1327	    &out_names);
1328	if (rv != 1) {
1329		OF_prop_free(out_names);
1330		device_printf(dev, "Malformed 'clock-output-names' property\n");
1331		return (ENXIO);
1332	}
1333	*name = strdup(out_names[0], M_OFWPROP);
1334	OF_prop_free(out_names);
1335	return (0);
1336}
1337#endif
1338