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$");
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/sbuf.h>
42#include <sys/sysctl.h>
43#include <sys/systm.h>
44#include <sys/sx.h>
45
46#ifdef FDT
47#include <dev/fdt/fdt_common.h>
48#include <dev/ofw/ofw_bus.h>
49#include <dev/ofw/ofw_bus_subr.h>
50#endif
51#include <dev/extres/clk/clk.h>
52
53SYSCTL_NODE(_hw, OID_AUTO, clock, CTLFLAG_RD, NULL, "Clocks");
54
55MALLOC_DEFINE(M_CLOCK, "clocks", "Clock framework");
56
57/* Forward declarations. */
58struct clk;
59struct clknodenode;
60struct clkdom;
61
62typedef TAILQ_HEAD(clknode_list, clknode) clknode_list_t;
63typedef TAILQ_HEAD(clkdom_list, clkdom) clkdom_list_t;
64
65/* Default clock methods. */
66static int clknode_method_init(struct clknode *clk, device_t dev);
67static int clknode_method_recalc_freq(struct clknode *clk, uint64_t *freq);
68static int clknode_method_set_freq(struct clknode *clk, uint64_t fin,
69    uint64_t *fout, int flags, int *stop);
70static int clknode_method_set_gate(struct clknode *clk, bool enable);
71static int clknode_method_set_mux(struct clknode *clk, int idx);
72
73/*
74 * Clock controller methods.
75 */
76static clknode_method_t clknode_methods[] = {
77	CLKNODEMETHOD(clknode_init,		clknode_method_init),
78	CLKNODEMETHOD(clknode_recalc_freq,	clknode_method_recalc_freq),
79	CLKNODEMETHOD(clknode_set_freq,		clknode_method_set_freq),
80	CLKNODEMETHOD(clknode_set_gate,		clknode_method_set_gate),
81	CLKNODEMETHOD(clknode_set_mux,		clknode_method_set_mux),
82
83	CLKNODEMETHOD_END
84};
85DEFINE_CLASS_0(clknode, clknode_class, clknode_methods, 0);
86
87/*
88 * Clock node - basic element for modeling SOC clock graph.  It holds the clock
89 * provider's data about the clock, and the links for the clock's membership in
90 * various lists.
91 */
92struct clknode {
93	KOBJ_FIELDS;
94
95	/* Clock nodes topology. */
96	struct clkdom 		*clkdom;	/* Owning clock domain */
97	TAILQ_ENTRY(clknode)	clkdom_link;	/* Domain list entry */
98	TAILQ_ENTRY(clknode)	clklist_link;	/* Global list entry */
99
100	/* String based parent list. */
101	const char		**parent_names;	/* Array of parent names */
102	int			parent_cnt;	/* Number of parents */
103	int			parent_idx;	/* Parent index or -1 */
104
105	/* Cache for already resolved names. */
106	struct clknode		**parents;	/* Array of potential parents */
107	struct clknode		*parent;	/* Current parent */
108
109	/* Parent/child relationship links. */
110	clknode_list_t		children;	/* List of our children */
111	TAILQ_ENTRY(clknode)	sibling_link; 	/* Our entry in parent's list */
112
113	/* Details of this device. */
114	void			*softc;		/* Instance softc */
115	const char		*name;		/* Globally unique name */
116	intptr_t		id;		/* Per domain unique id */
117	int			flags;		/* CLK_FLAG_*  */
118	struct sx		lock;		/* Lock for this clock */
119	int			ref_cnt;	/* Reference counter */
120	int			enable_cnt;	/* Enabled counter */
121
122	/* Cached values. */
123	uint64_t		freq;		/* Actual frequency */
124
125	struct sysctl_ctx_list	sysctl_ctx;
126};
127
128/*
129 *  Per consumer data, information about how a consumer is using a clock node.
130 *  A pointer to this structure is used as a handle in the consumer interface.
131 */
132struct clk {
133	device_t		dev;
134	struct clknode		*clknode;
135	int			enable_cnt;
136};
137
138/*
139 * Clock domain - a group of clocks provided by one clock device.
140 */
141struct clkdom {
142	device_t 		dev; 	/* Link to provider device */
143	TAILQ_ENTRY(clkdom)	link;		/* Global domain list entry */
144	clknode_list_t		clknode_list;	/* All clocks in the domain */
145
146#ifdef FDT
147	clknode_ofw_mapper_func	*ofw_mapper;	/* Find clock using FDT xref */
148#endif
149};
150
151/*
152 * The system-wide list of clock domains.
153 */
154static clkdom_list_t clkdom_list = TAILQ_HEAD_INITIALIZER(clkdom_list);
155
156/*
157 * Each clock node is linked on a system-wide list and can be searched by name.
158 */
159static clknode_list_t clknode_list = TAILQ_HEAD_INITIALIZER(clknode_list);
160
161/*
162 * Locking - we use three levels of locking:
163 * - First, topology lock is taken.  This one protect all lists.
164 * - Second level is per clknode lock.  It protects clknode data.
165 * - Third level is outside of this file, it protect clock device registers.
166 * First two levels use sleepable locks; clock device can use mutex or sx lock.
167 */
168static struct sx		clk_topo_lock;
169SX_SYSINIT(clock_topology, &clk_topo_lock, "Clock topology lock");
170
171#define CLK_TOPO_SLOCK()	sx_slock(&clk_topo_lock)
172#define CLK_TOPO_XLOCK()	sx_xlock(&clk_topo_lock)
173#define CLK_TOPO_UNLOCK()	sx_unlock(&clk_topo_lock)
174#define CLK_TOPO_ASSERT()	sx_assert(&clk_topo_lock, SA_LOCKED)
175#define CLK_TOPO_XASSERT()	sx_assert(&clk_topo_lock, SA_XLOCKED)
176
177#define CLKNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
178#define CLKNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
179#define CLKNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
180
181static void clknode_adjust_parent(struct clknode *clknode, int idx);
182
183enum clknode_sysctl_type {
184	CLKNODE_SYSCTL_PARENT,
185	CLKNODE_SYSCTL_PARENTS_LIST,
186	CLKNODE_SYSCTL_CHILDREN_LIST,
187};
188
189static int clknode_sysctl(SYSCTL_HANDLER_ARGS);
190static int clkdom_sysctl(SYSCTL_HANDLER_ARGS);
191
192static void clknode_finish(void *dummy);
193SYSINIT(clknode_finish, SI_SUB_LAST, SI_ORDER_ANY, clknode_finish, NULL);
194
195/*
196 * Default clock methods for base class.
197 */
198static int
199clknode_method_init(struct clknode *clknode, device_t dev)
200{
201
202	return (0);
203}
204
205static int
206clknode_method_recalc_freq(struct clknode *clknode, uint64_t *freq)
207{
208
209	return (0);
210}
211
212static int
213clknode_method_set_freq(struct clknode *clknode, uint64_t fin,  uint64_t *fout,
214   int flags, int *stop)
215{
216
217	*stop = 0;
218	return (0);
219}
220
221static int
222clknode_method_set_gate(struct clknode *clk, bool enable)
223{
224
225	return (0);
226}
227
228static int
229clknode_method_set_mux(struct clknode *clk, int idx)
230{
231
232	return (0);
233}
234
235/*
236 * Internal functions.
237 */
238
239/*
240 * Duplicate an array of parent names.
241 *
242 * Compute total size and allocate a single block which holds both the array of
243 * pointers to strings and the copied strings themselves.  Returns a pointer to
244 * the start of the block where the array of copied string pointers lives.
245 *
246 * XXX Revisit this, no need for the DECONST stuff.
247 */
248static const char **
249strdup_list(const char **names, int num)
250{
251	size_t len, slen;
252	const char **outptr, *ptr;
253	int i;
254
255	len = sizeof(char *) * num;
256	for (i = 0; i < num; i++) {
257		if (names[i] == NULL)
258			continue;
259		slen = strlen(names[i]);
260		if (slen == 0)
261			panic("Clock parent names array have empty string");
262		len += slen + 1;
263	}
264	outptr = malloc(len, M_CLOCK, M_WAITOK | M_ZERO);
265	ptr = (char *)(outptr + num);
266	for (i = 0; i < num; i++) {
267		if (names[i] == NULL)
268			continue;
269		outptr[i] = ptr;
270		slen = strlen(names[i]) + 1;
271		bcopy(names[i], __DECONST(void *, outptr[i]), slen);
272		ptr += slen;
273	}
274	return (outptr);
275}
276
277/*
278 * Recompute the cached frequency for this node and all its children.
279 */
280static int
281clknode_refresh_cache(struct clknode *clknode, uint64_t freq)
282{
283	int rv;
284	struct clknode *entry;
285
286	CLK_TOPO_XASSERT();
287
288	/* Compute generated frequency. */
289	rv = CLKNODE_RECALC_FREQ(clknode, &freq);
290	if (rv != 0) {
291		 /* XXX If an error happens while refreshing children
292		  * this leaves the world in a  partially-updated state.
293		  * Panic for now.
294		  */
295		panic("clknode_refresh_cache failed for '%s'\n",
296		    clknode->name);
297		return (rv);
298	}
299	/* Refresh cache for this node. */
300	clknode->freq = freq;
301
302	/* Refresh cache for all children. */
303	TAILQ_FOREACH(entry, &(clknode->children), sibling_link) {
304		rv = clknode_refresh_cache(entry, freq);
305		if (rv != 0)
306			return (rv);
307	}
308	return (0);
309}
310
311/*
312 * Public interface.
313 */
314
315struct clknode *
316clknode_find_by_name(const char *name)
317{
318	struct clknode *entry;
319
320	CLK_TOPO_ASSERT();
321
322	TAILQ_FOREACH(entry, &clknode_list, clklist_link) {
323		if (strcmp(entry->name, name) == 0)
324			return (entry);
325	}
326	return (NULL);
327}
328
329struct clknode *
330clknode_find_by_id(struct clkdom *clkdom, intptr_t id)
331{
332	struct clknode *entry;
333
334	CLK_TOPO_ASSERT();
335
336	TAILQ_FOREACH(entry, &clkdom->clknode_list, clkdom_link) {
337		if (entry->id ==  id)
338			return (entry);
339	}
340
341	return (NULL);
342}
343
344/* -------------------------------------------------------------------------- */
345/*
346 * Clock domain functions
347 */
348
349/* Find clock domain associated to device in global list. */
350struct clkdom *
351clkdom_get_by_dev(const device_t dev)
352{
353	struct clkdom *entry;
354
355	CLK_TOPO_ASSERT();
356
357	TAILQ_FOREACH(entry, &clkdom_list, link) {
358		if (entry->dev == dev)
359			return (entry);
360	}
361	return (NULL);
362}
363
364
365#ifdef FDT
366/* Default DT mapper. */
367static int
368clknode_default_ofw_map(struct clkdom *clkdom, uint32_t ncells,
369    phandle_t *cells, struct clknode **clk)
370{
371
372	CLK_TOPO_ASSERT();
373
374	if (ncells == 0)
375		*clk = clknode_find_by_id(clkdom, 1);
376	else if (ncells == 1)
377		*clk = clknode_find_by_id(clkdom, cells[0]);
378	else
379		return  (ERANGE);
380
381	if (*clk == NULL)
382		return (ENXIO);
383	return (0);
384}
385#endif
386
387/*
388 * Create a clock domain.  Returns with the topo lock held.
389 */
390struct clkdom *
391clkdom_create(device_t dev)
392{
393	struct clkdom *clkdom;
394
395	clkdom = malloc(sizeof(struct clkdom), M_CLOCK, M_WAITOK | M_ZERO);
396	clkdom->dev = dev;
397	TAILQ_INIT(&clkdom->clknode_list);
398#ifdef FDT
399	clkdom->ofw_mapper = clknode_default_ofw_map;
400#endif
401
402	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
403	  SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
404	  OID_AUTO, "clocks",
405	  CTLTYPE_STRING | CTLFLAG_RD,
406		    clkdom, 0, clkdom_sysctl,
407		    "A",
408		    "Clock list for the domain");
409
410	return (clkdom);
411}
412
413void
414clkdom_unlock(struct clkdom *clkdom)
415{
416
417	CLK_TOPO_UNLOCK();
418}
419
420void
421clkdom_xlock(struct clkdom *clkdom)
422{
423
424	CLK_TOPO_XLOCK();
425}
426
427/*
428 * Finalize initialization of clock domain.  Releases topo lock.
429 *
430 * XXX Revisit failure handling.
431 */
432int
433clkdom_finit(struct clkdom *clkdom)
434{
435	struct clknode *clknode;
436	int i, rv;
437#ifdef FDT
438	phandle_t node;
439
440
441	if ((node = ofw_bus_get_node(clkdom->dev)) == -1) {
442		device_printf(clkdom->dev,
443		    "%s called on not ofw based device\n", __func__);
444		return (ENXIO);
445	}
446#endif
447	rv = 0;
448
449	/* Make clock domain globally visible. */
450	CLK_TOPO_XLOCK();
451	TAILQ_INSERT_TAIL(&clkdom_list, clkdom, link);
452#ifdef FDT
453	OF_device_register_xref(OF_xref_from_node(node), clkdom->dev);
454#endif
455
456	/* Register all clock names into global list. */
457	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
458		TAILQ_INSERT_TAIL(&clknode_list, clknode, clklist_link);
459	}
460	/*
461	 * At this point all domain nodes must be registered and all
462	 * parents must be valid.
463	 */
464	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
465		if (clknode->parent_cnt == 0)
466			continue;
467		for (i = 0; i < clknode->parent_cnt; i++) {
468			if (clknode->parents[i] != NULL)
469				continue;
470			if (clknode->parent_names[i] == NULL)
471				continue;
472			clknode->parents[i] = clknode_find_by_name(
473			    clknode->parent_names[i]);
474			if (clknode->parents[i] == NULL) {
475				device_printf(clkdom->dev,
476				    "Clock %s have unknown parent: %s\n",
477				    clknode->name, clknode->parent_names[i]);
478				rv = ENODEV;
479			}
480		}
481
482		/* If parent index is not set yet... */
483		if (clknode->parent_idx == CLKNODE_IDX_NONE) {
484			device_printf(clkdom->dev,
485			    "Clock %s have not set parent idx\n",
486			    clknode->name);
487			rv = ENXIO;
488			continue;
489		}
490		if (clknode->parents[clknode->parent_idx] == NULL) {
491			device_printf(clkdom->dev,
492			    "Clock %s have unknown parent(idx %d): %s\n",
493			    clknode->name, clknode->parent_idx,
494			    clknode->parent_names[clknode->parent_idx]);
495			rv = ENXIO;
496			continue;
497		}
498		clknode_adjust_parent(clknode, clknode->parent_idx);
499	}
500	CLK_TOPO_UNLOCK();
501	return (rv);
502}
503
504/* Dump clock domain. */
505void
506clkdom_dump(struct clkdom * clkdom)
507{
508	struct clknode *clknode;
509	int rv;
510	uint64_t freq;
511
512	CLK_TOPO_SLOCK();
513	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
514		rv = clknode_get_freq(clknode, &freq);
515		printf("Clock: %s, parent: %s(%d), freq: %ju\n", clknode->name,
516		    clknode->parent == NULL ? "(NULL)" : clknode->parent->name,
517		    clknode->parent_idx,
518		    (uintmax_t)((rv == 0) ? freq: rv));
519	}
520	CLK_TOPO_UNLOCK();
521}
522
523/*
524 * Create and initialize clock object, but do not register it.
525 */
526struct clknode *
527clknode_create(struct clkdom * clkdom, clknode_class_t clknode_class,
528    const struct clknode_init_def *def)
529{
530	struct clknode *clknode;
531	struct sysctl_oid *clknode_oid;
532	bool replaced;
533
534	KASSERT(def->name != NULL, ("clock name is NULL"));
535	KASSERT(def->name[0] != '\0', ("clock name is empty"));
536	if (def->flags & CLK_NODE_LINKED) {
537		KASSERT(def->parent_cnt == 0,
538		 ("Linked clock must not have parents"));
539		KASSERT(clknode_class->size== 0,
540		 ("Linked clock cannot have own softc"));
541	}
542
543	/* Process duplicated clocks */
544	CLK_TOPO_SLOCK();
545	clknode = clknode_find_by_name(def->name);
546	CLK_TOPO_UNLOCK();
547	if (clknode !=  NULL) {
548		if (!(clknode->flags & CLK_NODE_LINKED) &&
549		    def->flags & CLK_NODE_LINKED) {
550			/*
551			 * New clock is linked and real already exists.
552			 * Do nothing and return real node. It is in right
553			 * domain, enqueued in right lists and fully initialized.
554			 */
555			return (clknode);
556		} else if (clknode->flags & CLK_NODE_LINKED &&
557		   !(def->flags & CLK_NODE_LINKED)) {
558			/*
559			 * New clock is real but linked already exists.
560			 * Remove old linked node from originating domain
561			 * (real clock must be owned by another) and from
562			 * global names link (it will be added back into it
563			 * again in following clknode_register()). Then reuse
564			 * original clknode structure and reinitialize it
565			 * with new dat. By this, all lists containing this
566			 * node remains valid, but the new node virtually
567			 * replace the linked one.
568			 */
569			KASSERT(clkdom != clknode->clkdom,
570			    ("linked clock must be from another "
571			    "domain that real one"));
572			TAILQ_REMOVE(&clkdom->clknode_list, clknode,
573			    clkdom_link);
574			TAILQ_REMOVE(&clknode_list, clknode, clklist_link);
575			replaced = true;
576		} else if (clknode->flags & CLK_NODE_LINKED &&
577		   def->flags & CLK_NODE_LINKED) {
578			/*
579			 * Both clocks are linked.
580			 * Return old one, so we hold only one copy od link.
581			 */
582			return (clknode);
583		} else {
584			/* Both clocks are real */
585			panic("Duplicated clock registration: %s\n", def->name);
586		}
587	} else {
588		/* Create clknode object and initialize it. */
589		clknode = malloc(sizeof(struct clknode), M_CLOCK,
590		    M_WAITOK | M_ZERO);
591		sx_init(&clknode->lock, "Clocknode lock");
592		TAILQ_INIT(&clknode->children);
593		replaced = false;
594	}
595
596	kobj_init((kobj_t)clknode, (kobj_class_t)clknode_class);
597
598	/* Allocate softc if required. */
599	if (clknode_class->size > 0) {
600		clknode->softc = malloc(clknode_class->size,
601		    M_CLOCK, M_WAITOK | M_ZERO);
602	}
603
604	/* Prepare array for ptrs to parent clocks. */
605	clknode->parents = malloc(sizeof(struct clknode *) * def->parent_cnt,
606	    M_CLOCK, M_WAITOK | M_ZERO);
607
608	/* Copy all strings unless they're flagged as static. */
609	if (def->flags & CLK_NODE_STATIC_STRINGS) {
610		clknode->name = def->name;
611		clknode->parent_names = def->parent_names;
612	} else {
613		clknode->name = strdup(def->name, M_CLOCK);
614		clknode->parent_names =
615		    strdup_list(def->parent_names, def->parent_cnt);
616	}
617
618	/* Rest of init. */
619	clknode->id = def->id;
620	clknode->clkdom = clkdom;
621	clknode->flags = def->flags;
622	clknode->parent_cnt = def->parent_cnt;
623	clknode->parent = NULL;
624	clknode->parent_idx = CLKNODE_IDX_NONE;
625
626	if (replaced)
627			return (clknode);
628
629	sysctl_ctx_init(&clknode->sysctl_ctx);
630	clknode_oid = SYSCTL_ADD_NODE(&clknode->sysctl_ctx,
631	    SYSCTL_STATIC_CHILDREN(_hw_clock),
632	    OID_AUTO, clknode->name,
633	    CTLFLAG_RD, 0, "A clock node");
634
635	SYSCTL_ADD_U64(&clknode->sysctl_ctx,
636	    SYSCTL_CHILDREN(clknode_oid),
637	    OID_AUTO, "frequency",
638	    CTLFLAG_RD, &clknode->freq, 0, "The clock frequency");
639	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
640	    SYSCTL_CHILDREN(clknode_oid),
641	    OID_AUTO, "parent",
642	    CTLTYPE_STRING | CTLFLAG_RD,
643	    clknode, CLKNODE_SYSCTL_PARENT, clknode_sysctl,
644	    "A",
645	    "The clock parent");
646	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
647	    SYSCTL_CHILDREN(clknode_oid),
648	    OID_AUTO, "parents",
649	    CTLTYPE_STRING | CTLFLAG_RD,
650	    clknode, CLKNODE_SYSCTL_PARENTS_LIST, clknode_sysctl,
651	    "A",
652	    "The clock parents list");
653	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
654	    SYSCTL_CHILDREN(clknode_oid),
655	    OID_AUTO, "childrens",
656	    CTLTYPE_STRING | CTLFLAG_RD,
657	    clknode, CLKNODE_SYSCTL_CHILDREN_LIST, clknode_sysctl,
658	    "A",
659	    "The clock childrens list");
660	SYSCTL_ADD_INT(&clknode->sysctl_ctx,
661	    SYSCTL_CHILDREN(clknode_oid),
662	    OID_AUTO, "enable_cnt",
663	    CTLFLAG_RD, &clknode->enable_cnt, 0, "The clock enable counter");
664
665	return (clknode);
666}
667
668/*
669 * Register clock object into clock domain hierarchy.
670 */
671struct clknode *
672clknode_register(struct clkdom * clkdom, struct clknode *clknode)
673{
674	int rv;
675
676	/* Skip already registered linked node */
677	if (clknode->flags & CLK_NODE_REGISTERED)
678		return(clknode);
679
680	rv = CLKNODE_INIT(clknode, clknode_get_device(clknode));
681	if (rv != 0) {
682		printf(" CLKNODE_INIT failed: %d\n", rv);
683		return (NULL);
684	}
685
686	TAILQ_INSERT_TAIL(&clkdom->clknode_list, clknode, clkdom_link);
687	clknode->flags |= CLK_NODE_REGISTERED;
688	return (clknode);
689}
690
691
692static void
693clknode_finish(void *dummy)
694{
695	struct clknode *clknode;
696
697	CLK_TOPO_SLOCK();
698	TAILQ_FOREACH(clknode, &clknode_list, clklist_link) {
699		if (clknode->flags & CLK_NODE_LINKED)
700			printf("Unresolved linked clock found: %s\n",
701			    clknode->name);
702	}
703	CLK_TOPO_UNLOCK();
704}
705/*
706 * Clock providers interface.
707 */
708
709/*
710 * Reparent clock node.
711 */
712static void
713clknode_adjust_parent(struct clknode *clknode, int idx)
714{
715
716	CLK_TOPO_XASSERT();
717
718	if (clknode->parent_cnt == 0)
719		return;
720	if ((idx == CLKNODE_IDX_NONE) || (idx >= clknode->parent_cnt))
721		panic("%s: Invalid parent index %d for clock %s",
722		    __func__, idx, clknode->name);
723
724	if (clknode->parents[idx] == NULL)
725		panic("%s: Invalid parent index %d for clock %s",
726		    __func__, idx, clknode->name);
727
728	/* Remove me from old children list. */
729	if (clknode->parent != NULL) {
730		TAILQ_REMOVE(&clknode->parent->children, clknode, sibling_link);
731	}
732
733	/* Insert into children list of new parent. */
734	clknode->parent_idx = idx;
735	clknode->parent = clknode->parents[idx];
736	TAILQ_INSERT_TAIL(&clknode->parent->children, clknode, sibling_link);
737}
738
739/*
740 * Set parent index - init function.
741 */
742void
743clknode_init_parent_idx(struct clknode *clknode, int idx)
744{
745
746	if (clknode->parent_cnt == 0) {
747		clknode->parent_idx = CLKNODE_IDX_NONE;
748		clknode->parent = NULL;
749		return;
750	}
751	if ((idx == CLKNODE_IDX_NONE) ||
752	    (idx >= clknode->parent_cnt) ||
753	    (clknode->parent_names[idx] == NULL))
754		panic("%s: Invalid parent index %d for clock %s",
755		    __func__, idx, clknode->name);
756	clknode->parent_idx = idx;
757}
758
759int
760clknode_set_parent_by_idx(struct clknode *clknode, int idx)
761{
762	int rv;
763	uint64_t freq;
764	int  oldidx;
765
766	/* We have exclusive topology lock, node lock is not needed. */
767	CLK_TOPO_XASSERT();
768
769	if (clknode->parent_cnt == 0)
770		return (0);
771
772	if (clknode->parent_idx == idx)
773		return (0);
774
775	oldidx = clknode->parent_idx;
776	clknode_adjust_parent(clknode, idx);
777	rv = CLKNODE_SET_MUX(clknode, idx);
778	if (rv != 0) {
779		clknode_adjust_parent(clknode, oldidx);
780		return (rv);
781	}
782	rv = clknode_get_freq(clknode->parent, &freq);
783	if (rv != 0)
784		return (rv);
785	rv = clknode_refresh_cache(clknode, freq);
786	return (rv);
787}
788
789int
790clknode_set_parent_by_name(struct clknode *clknode, const char *name)
791{
792	int rv;
793	uint64_t freq;
794	int  oldidx, idx;
795
796	/* We have exclusive topology lock, node lock is not needed. */
797	CLK_TOPO_XASSERT();
798
799	if (clknode->parent_cnt == 0)
800		return (0);
801
802	/*
803	 * If this node doesnt have mux, then passthrough request to parent.
804	 * This feature is used in clock domain initialization and allows us to
805	 * set clock source and target frequency on the tail node of the clock
806	 * chain.
807	 */
808	if (clknode->parent_cnt == 1) {
809		rv = clknode_set_parent_by_name(clknode->parent, name);
810		return (rv);
811	}
812
813	for (idx = 0; idx < clknode->parent_cnt; idx++) {
814		if (clknode->parent_names[idx] == NULL)
815			continue;
816		if (strcmp(clknode->parent_names[idx], name) == 0)
817			break;
818	}
819	if (idx >= clknode->parent_cnt) {
820		return (ENXIO);
821	}
822	if (clknode->parent_idx == idx)
823		return (0);
824
825	oldidx = clknode->parent_idx;
826	clknode_adjust_parent(clknode, idx);
827	rv = CLKNODE_SET_MUX(clknode, idx);
828	if (rv != 0) {
829		clknode_adjust_parent(clknode, oldidx);
830		CLKNODE_UNLOCK(clknode);
831		return (rv);
832	}
833	rv = clknode_get_freq(clknode->parent, &freq);
834	if (rv != 0)
835		return (rv);
836	rv = clknode_refresh_cache(clknode, freq);
837	return (rv);
838}
839
840struct clknode *
841clknode_get_parent(struct clknode *clknode)
842{
843
844	return (clknode->parent);
845}
846
847const char *
848clknode_get_name(struct clknode *clknode)
849{
850
851	return (clknode->name);
852}
853
854const char **
855clknode_get_parent_names(struct clknode *clknode)
856{
857
858	return (clknode->parent_names);
859}
860
861int
862clknode_get_parents_num(struct clknode *clknode)
863{
864
865	return (clknode->parent_cnt);
866}
867
868int
869clknode_get_parent_idx(struct clknode *clknode)
870{
871
872	return (clknode->parent_idx);
873}
874
875int
876clknode_get_flags(struct clknode *clknode)
877{
878
879	return (clknode->flags);
880}
881
882
883void *
884clknode_get_softc(struct clknode *clknode)
885{
886
887	return (clknode->softc);
888}
889
890device_t
891clknode_get_device(struct clknode *clknode)
892{
893
894	return (clknode->clkdom->dev);
895}
896
897#ifdef FDT
898void
899clkdom_set_ofw_mapper(struct clkdom * clkdom, clknode_ofw_mapper_func *map)
900{
901
902	clkdom->ofw_mapper = map;
903}
904#endif
905
906/*
907 * Real consumers executive
908 */
909int
910clknode_get_freq(struct clknode *clknode, uint64_t *freq)
911{
912	int rv;
913
914	CLK_TOPO_ASSERT();
915
916	/* Use cached value, if it exists. */
917	*freq  = clknode->freq;
918	if (*freq != 0)
919		return (0);
920
921	/* Get frequency from parent, if the clock has a parent. */
922	if (clknode->parent_cnt > 0) {
923		rv = clknode_get_freq(clknode->parent, freq);
924		if (rv != 0) {
925			return (rv);
926		}
927	}
928
929	/* And recalculate my output frequency. */
930	CLKNODE_XLOCK(clknode);
931	rv = CLKNODE_RECALC_FREQ(clknode, freq);
932	if (rv != 0) {
933		CLKNODE_UNLOCK(clknode);
934		printf("Cannot get frequency for clk: %s, error: %d\n",
935		    clknode->name, rv);
936		return (rv);
937	}
938
939	/* Save new frequency to cache. */
940	clknode->freq = *freq;
941	CLKNODE_UNLOCK(clknode);
942	return (0);
943}
944
945int
946clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
947    int enablecnt)
948{
949	int rv, done;
950	uint64_t parent_freq;
951
952	/* We have exclusive topology lock, node lock is not needed. */
953	CLK_TOPO_XASSERT();
954
955	/* Check for no change */
956	if (clknode->freq == freq)
957		return (0);
958
959	parent_freq = 0;
960
961	/*
962	 * We can set frequency only if
963	 *   clock is disabled
964	 * OR
965	 *   clock is glitch free and is enabled by calling consumer only
966	 */
967	if ((flags & CLK_SET_DRYRUN) == 0 &&
968	    clknode->enable_cnt > 1 &&
969	    clknode->enable_cnt > enablecnt &&
970	    (clknode->flags & CLK_NODE_GLITCH_FREE) == 0) {
971		return (EBUSY);
972	}
973
974	/* Get frequency from parent, if the clock has a parent. */
975	if (clknode->parent_cnt > 0) {
976		rv = clknode_get_freq(clknode->parent, &parent_freq);
977		if (rv != 0) {
978			return (rv);
979		}
980	}
981
982	/* Set frequency for this clock. */
983	rv = CLKNODE_SET_FREQ(clknode, parent_freq, &freq, flags, &done);
984	if (rv != 0) {
985		printf("Cannot set frequency for clk: %s, error: %d\n",
986		    clknode->name, rv);
987		if ((flags & CLK_SET_DRYRUN) == 0)
988			clknode_refresh_cache(clknode, parent_freq);
989		return (rv);
990	}
991
992	if (done) {
993		/* Success - invalidate frequency cache for all children. */
994		if ((flags & CLK_SET_DRYRUN) == 0) {
995			clknode->freq = freq;
996			/* Clock might have reparent during set_freq */
997			if (clknode->parent_cnt > 0) {
998				rv = clknode_get_freq(clknode->parent,
999				    &parent_freq);
1000				if (rv != 0) {
1001					return (rv);
1002				}
1003			}
1004			clknode_refresh_cache(clknode, parent_freq);
1005		}
1006	} else if (clknode->parent != NULL) {
1007		/* Nothing changed, pass request to parent. */
1008		rv = clknode_set_freq(clknode->parent, freq, flags, enablecnt);
1009	} else {
1010		/* End of chain without action. */
1011		printf("Cannot set frequency for clk: %s, end of chain\n",
1012		    clknode->name);
1013		rv = ENXIO;
1014	}
1015
1016	return (rv);
1017}
1018
1019int
1020clknode_enable(struct clknode *clknode)
1021{
1022	int rv;
1023
1024	CLK_TOPO_ASSERT();
1025
1026	/* Enable clock for each node in chain, starting from source. */
1027	if (clknode->parent_cnt > 0) {
1028		rv = clknode_enable(clknode->parent);
1029		if (rv != 0) {
1030			return (rv);
1031		}
1032	}
1033
1034	/* Handle this node */
1035	CLKNODE_XLOCK(clknode);
1036	if (clknode->enable_cnt == 0) {
1037		rv = CLKNODE_SET_GATE(clknode, 1);
1038		if (rv != 0) {
1039			CLKNODE_UNLOCK(clknode);
1040			return (rv);
1041		}
1042	}
1043	clknode->enable_cnt++;
1044	CLKNODE_UNLOCK(clknode);
1045	return (0);
1046}
1047
1048int
1049clknode_disable(struct clknode *clknode)
1050{
1051	int rv;
1052
1053	CLK_TOPO_ASSERT();
1054	rv = 0;
1055
1056	CLKNODE_XLOCK(clknode);
1057	/* Disable clock for each node in chain, starting from consumer. */
1058	if ((clknode->enable_cnt == 1) &&
1059	    ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) {
1060		rv = CLKNODE_SET_GATE(clknode, 0);
1061		if (rv != 0) {
1062			CLKNODE_UNLOCK(clknode);
1063			return (rv);
1064		}
1065	}
1066	clknode->enable_cnt--;
1067	CLKNODE_UNLOCK(clknode);
1068
1069	if (clknode->parent_cnt > 0) {
1070		rv = clknode_disable(clknode->parent);
1071	}
1072	return (rv);
1073}
1074
1075int
1076clknode_stop(struct clknode *clknode, int depth)
1077{
1078	int rv;
1079
1080	CLK_TOPO_ASSERT();
1081	rv = 0;
1082
1083	CLKNODE_XLOCK(clknode);
1084	/* The first node cannot be enabled. */
1085	if ((clknode->enable_cnt != 0) && (depth == 0)) {
1086		CLKNODE_UNLOCK(clknode);
1087		return (EBUSY);
1088	}
1089	/* Stop clock for each node in chain, starting from consumer. */
1090	if ((clknode->enable_cnt == 0) &&
1091	    ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) {
1092		rv = CLKNODE_SET_GATE(clknode, 0);
1093		if (rv != 0) {
1094			CLKNODE_UNLOCK(clknode);
1095			return (rv);
1096		}
1097	}
1098	CLKNODE_UNLOCK(clknode);
1099
1100	if (clknode->parent_cnt > 0)
1101		rv = clknode_stop(clknode->parent, depth + 1);
1102	return (rv);
1103}
1104
1105/* --------------------------------------------------------------------------
1106 *
1107 * Clock consumers interface.
1108 *
1109 */
1110/* Helper function for clk_get*() */
1111static clk_t
1112clk_create(struct clknode *clknode, device_t dev)
1113{
1114	struct clk *clk;
1115
1116	CLK_TOPO_ASSERT();
1117
1118	clk =  malloc(sizeof(struct clk), M_CLOCK, M_WAITOK);
1119	clk->dev = dev;
1120	clk->clknode = clknode;
1121	clk->enable_cnt = 0;
1122	clknode->ref_cnt++;
1123
1124	return (clk);
1125}
1126
1127int
1128clk_get_freq(clk_t clk, uint64_t *freq)
1129{
1130	int rv;
1131	struct clknode *clknode;
1132
1133	clknode = clk->clknode;
1134	KASSERT(clknode->ref_cnt > 0,
1135	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1136
1137	CLK_TOPO_SLOCK();
1138	rv = clknode_get_freq(clknode, freq);
1139	CLK_TOPO_UNLOCK();
1140	return (rv);
1141}
1142
1143int
1144clk_set_freq(clk_t clk, uint64_t freq, int flags)
1145{
1146	int rv;
1147	struct clknode *clknode;
1148
1149	flags &= CLK_SET_USER_MASK;
1150	clknode = clk->clknode;
1151	KASSERT(clknode->ref_cnt > 0,
1152	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1153
1154	CLK_TOPO_XLOCK();
1155	rv = clknode_set_freq(clknode, freq, flags, clk->enable_cnt);
1156	CLK_TOPO_UNLOCK();
1157	return (rv);
1158}
1159
1160int
1161clk_test_freq(clk_t clk, uint64_t freq, int flags)
1162{
1163	int rv;
1164	struct clknode *clknode;
1165
1166	flags &= CLK_SET_USER_MASK;
1167	clknode = clk->clknode;
1168	KASSERT(clknode->ref_cnt > 0,
1169	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1170
1171	CLK_TOPO_XLOCK();
1172	rv = clknode_set_freq(clknode, freq, flags | CLK_SET_DRYRUN, 0);
1173	CLK_TOPO_UNLOCK();
1174	return (rv);
1175}
1176
1177int
1178clk_get_parent(clk_t clk, clk_t *parent)
1179{
1180	struct clknode *clknode;
1181	struct clknode *parentnode;
1182
1183	clknode = clk->clknode;
1184	KASSERT(clknode->ref_cnt > 0,
1185	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1186
1187	CLK_TOPO_SLOCK();
1188	parentnode = clknode_get_parent(clknode);
1189	if (parentnode == NULL) {
1190		CLK_TOPO_UNLOCK();
1191		return (ENODEV);
1192	}
1193	*parent = clk_create(parentnode, clk->dev);
1194	CLK_TOPO_UNLOCK();
1195	return (0);
1196}
1197
1198int
1199clk_set_parent_by_clk(clk_t clk, clk_t parent)
1200{
1201	int rv;
1202	struct clknode *clknode;
1203	struct clknode *parentnode;
1204
1205	clknode = clk->clknode;
1206	parentnode = parent->clknode;
1207	KASSERT(clknode->ref_cnt > 0,
1208	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1209	KASSERT(parentnode->ref_cnt > 0,
1210	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1211	CLK_TOPO_XLOCK();
1212	rv = clknode_set_parent_by_name(clknode, parentnode->name);
1213	CLK_TOPO_UNLOCK();
1214	return (rv);
1215}
1216
1217int
1218clk_enable(clk_t clk)
1219{
1220	int rv;
1221	struct clknode *clknode;
1222
1223	clknode = clk->clknode;
1224	KASSERT(clknode->ref_cnt > 0,
1225	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1226	CLK_TOPO_SLOCK();
1227	rv = clknode_enable(clknode);
1228	if (rv == 0)
1229		clk->enable_cnt++;
1230	CLK_TOPO_UNLOCK();
1231	return (rv);
1232}
1233
1234int
1235clk_disable(clk_t clk)
1236{
1237	int rv;
1238	struct clknode *clknode;
1239
1240	clknode = clk->clknode;
1241	KASSERT(clknode->ref_cnt > 0,
1242	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1243	KASSERT(clk->enable_cnt > 0,
1244	   ("Attempt to disable already disabled clock: %s\n", clknode->name));
1245	CLK_TOPO_SLOCK();
1246	rv = clknode_disable(clknode);
1247	if (rv == 0)
1248		clk->enable_cnt--;
1249	CLK_TOPO_UNLOCK();
1250	return (rv);
1251}
1252
1253int
1254clk_stop(clk_t clk)
1255{
1256	int rv;
1257	struct clknode *clknode;
1258
1259	clknode = clk->clknode;
1260	KASSERT(clknode->ref_cnt > 0,
1261	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1262	KASSERT(clk->enable_cnt == 0,
1263	   ("Attempt to stop already enabled clock: %s\n", clknode->name));
1264
1265	CLK_TOPO_SLOCK();
1266	rv = clknode_stop(clknode, 0);
1267	CLK_TOPO_UNLOCK();
1268	return (rv);
1269}
1270
1271int
1272clk_release(clk_t clk)
1273{
1274	struct clknode *clknode;
1275
1276	clknode = clk->clknode;
1277	KASSERT(clknode->ref_cnt > 0,
1278	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1279	CLK_TOPO_SLOCK();
1280	while (clk->enable_cnt > 0) {
1281		clknode_disable(clknode);
1282		clk->enable_cnt--;
1283	}
1284	CLKNODE_XLOCK(clknode);
1285	clknode->ref_cnt--;
1286	CLKNODE_UNLOCK(clknode);
1287	CLK_TOPO_UNLOCK();
1288
1289	free(clk, M_CLOCK);
1290	return (0);
1291}
1292
1293const char *
1294clk_get_name(clk_t clk)
1295{
1296	const char *name;
1297	struct clknode *clknode;
1298
1299	clknode = clk->clknode;
1300	KASSERT(clknode->ref_cnt > 0,
1301	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1302	name = clknode_get_name(clknode);
1303	return (name);
1304}
1305
1306int
1307clk_get_by_name(device_t dev, const char *name, clk_t *clk)
1308{
1309	struct clknode *clknode;
1310
1311	CLK_TOPO_SLOCK();
1312	clknode = clknode_find_by_name(name);
1313	if (clknode == NULL) {
1314		CLK_TOPO_UNLOCK();
1315		return (ENODEV);
1316	}
1317	*clk = clk_create(clknode, dev);
1318	CLK_TOPO_UNLOCK();
1319	return (0);
1320}
1321
1322int
1323clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk)
1324{
1325	struct clknode *clknode;
1326
1327	CLK_TOPO_SLOCK();
1328
1329	clknode = clknode_find_by_id(clkdom, id);
1330	if (clknode == NULL) {
1331		CLK_TOPO_UNLOCK();
1332		return (ENODEV);
1333	}
1334	*clk = clk_create(clknode, dev);
1335	CLK_TOPO_UNLOCK();
1336
1337	return (0);
1338}
1339
1340#ifdef FDT
1341
1342static void
1343clk_set_assigned_parent(device_t dev, clk_t clk, int idx)
1344{
1345	clk_t parent;
1346	const char *pname;
1347	int rv;
1348
1349	rv = clk_get_by_ofw_index_prop(dev, 0,
1350	    "assigned-clock-parents", idx, &parent);
1351	if (rv != 0) {
1352		device_printf(dev,
1353		    "cannot get parent at idx %d\n", idx);
1354		return;
1355	}
1356
1357	pname = clk_get_name(parent);
1358	rv = clk_set_parent_by_clk(clk, parent);
1359	if (rv != 0)
1360		device_printf(dev,
1361		    "Cannot set parent %s for clock %s\n",
1362		    pname, clk_get_name(clk));
1363	else if (bootverbose)
1364		device_printf(dev, "Set %s as the parent of %s\n",
1365		    pname, clk_get_name(clk));
1366	clk_release(parent);
1367}
1368
1369static void
1370clk_set_assigned_rates(device_t dev, clk_t clk, uint32_t freq)
1371{
1372	int rv;
1373
1374	rv = clk_set_freq(clk, freq, CLK_SET_ROUND_DOWN | CLK_SET_ROUND_UP);
1375	if (rv != 0) {
1376		device_printf(dev, "Failed to set %s to a frequency of %u\n",
1377		    clk_get_name(clk), freq);
1378		return;
1379	}
1380	if (bootverbose)
1381		device_printf(dev, "Set %s to %u\n",
1382		    clk_get_name(clk), freq);
1383}
1384
1385int
1386clk_set_assigned(device_t dev, phandle_t node)
1387{
1388	clk_t clk;
1389	uint32_t *rates;
1390	int rv, nclocks, nrates, nparents, i;
1391
1392	rv = ofw_bus_parse_xref_list_get_length(node,
1393	    "assigned-clocks", "#clock-cells", &nclocks);
1394
1395	if (rv != 0) {
1396		if (rv != ENOENT)
1397			device_printf(dev,
1398			    "cannot parse assigned-clock property\n");
1399		return (rv);
1400	}
1401
1402	nrates = OF_getencprop_alloc_multi(node, "assigned-clock-rates",
1403	    sizeof(*rates), (void **)&rates);
1404	if (nrates <= 0)
1405		nrates = 0;
1406
1407	if (ofw_bus_parse_xref_list_get_length(node,
1408	    "assigned-clock-parents", "#clock-cells", &nparents) != 0)
1409		nparents = -1;
1410	for (i = 0; i < nclocks; i++) {
1411		/* First get the clock we are supposed to modify */
1412		rv = clk_get_by_ofw_index_prop(dev, 0, "assigned-clocks",
1413		    i, &clk);
1414		if (rv != 0) {
1415			if (bootverbose)
1416				device_printf(dev,
1417				    "cannot get assigned clock at idx %d\n",
1418				    i);
1419			continue;
1420		}
1421
1422		/* First set it's parent if needed */
1423		if (i < nparents)
1424			clk_set_assigned_parent(dev, clk, i);
1425
1426		/* Then set a new frequency */
1427		if (i < nrates && rates[i] != 0)
1428			clk_set_assigned_rates(dev, clk, rates[i]);
1429
1430		clk_release(clk);
1431	}
1432	if (rates != NULL)
1433		OF_prop_free(rates);
1434
1435	return (0);
1436}
1437
1438int
1439clk_get_by_ofw_index_prop(device_t dev, phandle_t cnode, const char *prop, int idx, clk_t *clk)
1440{
1441	phandle_t parent, *cells;
1442	device_t clockdev;
1443	int ncells, rv;
1444	struct clkdom *clkdom;
1445	struct clknode *clknode;
1446
1447	*clk = NULL;
1448	if (cnode <= 0)
1449		cnode = ofw_bus_get_node(dev);
1450	if (cnode <= 0) {
1451		device_printf(dev, "%s called on not ofw based device\n",
1452		 __func__);
1453		return (ENXIO);
1454	}
1455
1456
1457	rv = ofw_bus_parse_xref_list_alloc(cnode, prop, "#clock-cells", idx,
1458	    &parent, &ncells, &cells);
1459	if (rv != 0) {
1460		return (rv);
1461	}
1462
1463	clockdev = OF_device_from_xref(parent);
1464	if (clockdev == NULL) {
1465		rv = ENODEV;
1466		goto done;
1467	}
1468
1469	CLK_TOPO_SLOCK();
1470	clkdom = clkdom_get_by_dev(clockdev);
1471	if (clkdom == NULL){
1472		CLK_TOPO_UNLOCK();
1473		rv = ENXIO;
1474		goto done;
1475	}
1476
1477	rv = clkdom->ofw_mapper(clkdom, ncells, cells, &clknode);
1478	if (rv == 0) {
1479		*clk = clk_create(clknode, dev);
1480	}
1481	CLK_TOPO_UNLOCK();
1482
1483done:
1484	if (cells != NULL)
1485		OF_prop_free(cells);
1486	return (rv);
1487}
1488
1489int
1490clk_get_by_ofw_index(device_t dev, phandle_t cnode, int idx, clk_t *clk)
1491{
1492	return (clk_get_by_ofw_index_prop(dev, cnode, "clocks", idx, clk));
1493}
1494
1495int
1496clk_get_by_ofw_name(device_t dev, phandle_t cnode, const char *name, clk_t *clk)
1497{
1498	int rv, idx;
1499
1500	if (cnode <= 0)
1501		cnode = ofw_bus_get_node(dev);
1502	if (cnode <= 0) {
1503		device_printf(dev, "%s called on not ofw based device\n",
1504		 __func__);
1505		return (ENXIO);
1506	}
1507	rv = ofw_bus_find_string_index(cnode, "clock-names", name, &idx);
1508	if (rv != 0)
1509		return (rv);
1510	return (clk_get_by_ofw_index(dev, cnode, idx, clk));
1511}
1512
1513/* --------------------------------------------------------------------------
1514 *
1515 * Support functions for parsing various clock related OFW things.
1516 */
1517
1518/*
1519 * Get "clock-output-names" and  (optional) "clock-indices" lists.
1520 * Both lists are alocated using M_OFWPROP specifier.
1521 *
1522 * Returns number of items or 0.
1523 */
1524int
1525clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names,
1526	uint32_t **indices)
1527{
1528	int name_items, rv;
1529
1530	*out_names = NULL;
1531	*indices = NULL;
1532	if (!OF_hasprop(node, "clock-output-names"))
1533		return (0);
1534	rv = ofw_bus_string_list_to_array(node, "clock-output-names",
1535	    out_names);
1536	if (rv <= 0)
1537		return (0);
1538	name_items = rv;
1539
1540	if (!OF_hasprop(node, "clock-indices"))
1541		return (name_items);
1542	rv = OF_getencprop_alloc_multi(node, "clock-indices", sizeof (uint32_t),
1543	    (void **)indices);
1544	if (rv != name_items) {
1545		device_printf(dev, " Size of 'clock-output-names' and "
1546		    "'clock-indices' differs\n");
1547		OF_prop_free(*out_names);
1548		OF_prop_free(*indices);
1549		return (0);
1550	}
1551	return (name_items);
1552}
1553
1554/*
1555 * Get output clock name for single output clock node.
1556 */
1557int
1558clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name)
1559{
1560	const char **out_names;
1561	const char  *tmp_name;
1562	int rv;
1563
1564	*name = NULL;
1565	if (!OF_hasprop(node, "clock-output-names")) {
1566		tmp_name  = ofw_bus_get_name(dev);
1567		if (tmp_name == NULL)
1568			return (ENXIO);
1569		*name = strdup(tmp_name, M_OFWPROP);
1570		return (0);
1571	}
1572	rv = ofw_bus_string_list_to_array(node, "clock-output-names",
1573	    &out_names);
1574	if (rv != 1) {
1575		OF_prop_free(out_names);
1576		device_printf(dev, "Malformed 'clock-output-names' property\n");
1577		return (ENXIO);
1578	}
1579	*name = strdup(out_names[0], M_OFWPROP);
1580	OF_prop_free(out_names);
1581	return (0);
1582}
1583#endif
1584
1585static int
1586clkdom_sysctl(SYSCTL_HANDLER_ARGS)
1587{
1588	struct clkdom *clkdom = arg1;
1589	struct clknode *clknode;
1590	struct sbuf *sb;
1591	int ret;
1592
1593	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
1594	if (sb == NULL)
1595		return (ENOMEM);
1596
1597	CLK_TOPO_SLOCK();
1598	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
1599		sbuf_printf(sb, "%s ", clknode->name);
1600	}
1601	CLK_TOPO_UNLOCK();
1602
1603	ret = sbuf_finish(sb);
1604	sbuf_delete(sb);
1605	return (ret);
1606}
1607
1608static int
1609clknode_sysctl(SYSCTL_HANDLER_ARGS)
1610{
1611	struct clknode *clknode, *children;
1612	enum clknode_sysctl_type type = arg2;
1613	struct sbuf *sb;
1614	const char **parent_names;
1615	int ret, i;
1616
1617	clknode = arg1;
1618	sb = sbuf_new_for_sysctl(NULL, NULL, 512, req);
1619	if (sb == NULL)
1620		return (ENOMEM);
1621
1622	CLK_TOPO_SLOCK();
1623	switch (type) {
1624	case CLKNODE_SYSCTL_PARENT:
1625		if (clknode->parent)
1626			sbuf_printf(sb, "%s", clknode->parent->name);
1627		break;
1628	case CLKNODE_SYSCTL_PARENTS_LIST:
1629		parent_names = clknode_get_parent_names(clknode);
1630		for (i = 0; i < clknode->parent_cnt; i++)
1631			sbuf_printf(sb, "%s ", parent_names[i]);
1632		break;
1633	case CLKNODE_SYSCTL_CHILDREN_LIST:
1634		TAILQ_FOREACH(children, &(clknode->children), sibling_link) {
1635			sbuf_printf(sb, "%s ", children->name);
1636		}
1637		break;
1638	}
1639	CLK_TOPO_UNLOCK();
1640
1641	ret = sbuf_finish(sb);
1642	sbuf_delete(sb);
1643	return (ret);
1644}
1645