xref: /freebsd-13.1/sys/dev/extres/clk/clk.c (revision 4e4e43dc)
1 /*-
2  * Copyright 2016 Michal Meloun <[email protected]>
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 
53 SYSCTL_NODE(_hw, OID_AUTO, clock, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
54     "Clocks");
55 
56 MALLOC_DEFINE(M_CLOCK, "clocks", "Clock framework");
57 
58 /* Forward declarations. */
59 struct clk;
60 struct clknodenode;
61 struct clkdom;
62 
63 typedef TAILQ_HEAD(clknode_list, clknode) clknode_list_t;
64 typedef TAILQ_HEAD(clkdom_list, clkdom) clkdom_list_t;
65 
66 /* Default clock methods. */
67 static int clknode_method_init(struct clknode *clk, device_t dev);
68 static int clknode_method_recalc_freq(struct clknode *clk, uint64_t *freq);
69 static int clknode_method_set_freq(struct clknode *clk, uint64_t fin,
70     uint64_t *fout, int flags, int *stop);
71 static int clknode_method_set_gate(struct clknode *clk, bool enable);
72 static int clknode_method_set_mux(struct clknode *clk, int idx);
73 
74 /*
75  * Clock controller methods.
76  */
77 static clknode_method_t clknode_methods[] = {
78 	CLKNODEMETHOD(clknode_init,		clknode_method_init),
79 	CLKNODEMETHOD(clknode_recalc_freq,	clknode_method_recalc_freq),
80 	CLKNODEMETHOD(clknode_set_freq,		clknode_method_set_freq),
81 	CLKNODEMETHOD(clknode_set_gate,		clknode_method_set_gate),
82 	CLKNODEMETHOD(clknode_set_mux,		clknode_method_set_mux),
83 
84 	CLKNODEMETHOD_END
85 };
86 DEFINE_CLASS_0(clknode, clknode_class, clknode_methods, 0);
87 
88 /*
89  * Clock node - basic element for modeling SOC clock graph.  It holds the clock
90  * provider's data about the clock, and the links for the clock's membership in
91  * various lists.
92  */
93 struct clknode {
94 	KOBJ_FIELDS;
95 
96 	/* Clock nodes topology. */
97 	struct clkdom 		*clkdom;	/* Owning clock domain */
98 	TAILQ_ENTRY(clknode)	clkdom_link;	/* Domain list entry */
99 	TAILQ_ENTRY(clknode)	clklist_link;	/* Global list entry */
100 
101 	/* String based parent list. */
102 	const char		**parent_names;	/* Array of parent names */
103 	int			parent_cnt;	/* Number of parents */
104 	int			parent_idx;	/* Parent index or -1 */
105 
106 	/* Cache for already resolved names. */
107 	struct clknode		**parents;	/* Array of potential parents */
108 	struct clknode		*parent;	/* Current parent */
109 
110 	/* Parent/child relationship links. */
111 	clknode_list_t		children;	/* List of our children */
112 	TAILQ_ENTRY(clknode)	sibling_link; 	/* Our entry in parent's list */
113 
114 	/* Details of this device. */
115 	void			*softc;		/* Instance softc */
116 	const char		*name;		/* Globally unique name */
117 	intptr_t		id;		/* Per domain unique id */
118 	int			flags;		/* CLK_FLAG_*  */
119 	struct sx		lock;		/* Lock for this clock */
120 	int			ref_cnt;	/* Reference counter */
121 	int			enable_cnt;	/* Enabled counter */
122 
123 	/* Cached values. */
124 	uint64_t		freq;		/* Actual frequency */
125 
126 	struct sysctl_ctx_list	sysctl_ctx;
127 };
128 
129 /*
130  *  Per consumer data, information about how a consumer is using a clock node.
131  *  A pointer to this structure is used as a handle in the consumer interface.
132  */
133 struct clk {
134 	device_t		dev;
135 	struct clknode		*clknode;
136 	int			enable_cnt;
137 };
138 
139 /*
140  * Clock domain - a group of clocks provided by one clock device.
141  */
142 struct clkdom {
143 	device_t 		dev; 	/* Link to provider device */
144 	TAILQ_ENTRY(clkdom)	link;		/* Global domain list entry */
145 	clknode_list_t		clknode_list;	/* All clocks in the domain */
146 
147 #ifdef FDT
148 	clknode_ofw_mapper_func	*ofw_mapper;	/* Find clock using FDT xref */
149 #endif
150 };
151 
152 /*
153  * The system-wide list of clock domains.
154  */
155 static clkdom_list_t clkdom_list = TAILQ_HEAD_INITIALIZER(clkdom_list);
156 
157 /*
158  * Each clock node is linked on a system-wide list and can be searched by name.
159  */
160 static clknode_list_t clknode_list = TAILQ_HEAD_INITIALIZER(clknode_list);
161 
162 /*
163  * Locking - we use three levels of locking:
164  * - First, topology lock is taken.  This one protect all lists.
165  * - Second level is per clknode lock.  It protects clknode data.
166  * - Third level is outside of this file, it protect clock device registers.
167  * First two levels use sleepable locks; clock device can use mutex or sx lock.
168  */
169 static struct sx		clk_topo_lock;
170 SX_SYSINIT(clock_topology, &clk_topo_lock, "Clock topology lock");
171 
172 #define CLK_TOPO_SLOCK()	sx_slock(&clk_topo_lock)
173 #define CLK_TOPO_XLOCK()	sx_xlock(&clk_topo_lock)
174 #define CLK_TOPO_UNLOCK()	sx_unlock(&clk_topo_lock)
175 #define CLK_TOPO_ASSERT()	sx_assert(&clk_topo_lock, SA_LOCKED)
176 #define CLK_TOPO_XASSERT()	sx_assert(&clk_topo_lock, SA_XLOCKED)
177 
178 #define CLKNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
179 #define CLKNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
180 #define CLKNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
181 
182 static void clknode_adjust_parent(struct clknode *clknode, int idx);
183 
184 enum clknode_sysctl_type {
185 	CLKNODE_SYSCTL_PARENT,
186 	CLKNODE_SYSCTL_PARENTS_LIST,
187 	CLKNODE_SYSCTL_CHILDREN_LIST,
188 };
189 
190 static int clknode_sysctl(SYSCTL_HANDLER_ARGS);
191 static int clkdom_sysctl(SYSCTL_HANDLER_ARGS);
192 
193 static void clknode_finish(void *dummy);
194 SYSINIT(clknode_finish, SI_SUB_LAST, SI_ORDER_ANY, clknode_finish, NULL);
195 
196 /*
197  * Default clock methods for base class.
198  */
199 static int
200 clknode_method_init(struct clknode *clknode, device_t dev)
201 {
202 
203 	return (0);
204 }
205 
206 static int
207 clknode_method_recalc_freq(struct clknode *clknode, uint64_t *freq)
208 {
209 
210 	return (0);
211 }
212 
213 static int
214 clknode_method_set_freq(struct clknode *clknode, uint64_t fin,  uint64_t *fout,
215    int flags, int *stop)
216 {
217 
218 	*stop = 0;
219 	return (0);
220 }
221 
222 static int
223 clknode_method_set_gate(struct clknode *clk, bool enable)
224 {
225 
226 	return (0);
227 }
228 
229 static int
230 clknode_method_set_mux(struct clknode *clk, int idx)
231 {
232 
233 	return (0);
234 }
235 
236 /*
237  * Internal functions.
238  */
239 
240 /*
241  * Duplicate an array of parent names.
242  *
243  * Compute total size and allocate a single block which holds both the array of
244  * pointers to strings and the copied strings themselves.  Returns a pointer to
245  * the start of the block where the array of copied string pointers lives.
246  *
247  * XXX Revisit this, no need for the DECONST stuff.
248  */
249 static const char **
250 strdup_list(const char **names, int num)
251 {
252 	size_t len, slen;
253 	const char **outptr, *ptr;
254 	int i;
255 
256 	len = sizeof(char *) * num;
257 	for (i = 0; i < num; i++) {
258 		if (names[i] == NULL)
259 			continue;
260 		slen = strlen(names[i]);
261 		if (slen == 0)
262 			panic("Clock parent names array have empty string");
263 		len += slen + 1;
264 	}
265 	outptr = malloc(len, M_CLOCK, M_WAITOK | M_ZERO);
266 	ptr = (char *)(outptr + num);
267 	for (i = 0; i < num; i++) {
268 		if (names[i] == NULL)
269 			continue;
270 		outptr[i] = ptr;
271 		slen = strlen(names[i]) + 1;
272 		bcopy(names[i], __DECONST(void *, outptr[i]), slen);
273 		ptr += slen;
274 	}
275 	return (outptr);
276 }
277 
278 /*
279  * Recompute the cached frequency for this node and all its children.
280  */
281 static int
282 clknode_refresh_cache(struct clknode *clknode, uint64_t freq)
283 {
284 	int rv;
285 	struct clknode *entry;
286 
287 	CLK_TOPO_XASSERT();
288 
289 	/* Compute generated frequency. */
290 	rv = CLKNODE_RECALC_FREQ(clknode, &freq);
291 	if (rv != 0) {
292 		 /* XXX If an error happens while refreshing children
293 		  * this leaves the world in a  partially-updated state.
294 		  * Panic for now.
295 		  */
296 		panic("clknode_refresh_cache failed for '%s'\n",
297 		    clknode->name);
298 		return (rv);
299 	}
300 	/* Refresh cache for this node. */
301 	clknode->freq = freq;
302 
303 	/* Refresh cache for all children. */
304 	TAILQ_FOREACH(entry, &(clknode->children), sibling_link) {
305 		rv = clknode_refresh_cache(entry, freq);
306 		if (rv != 0)
307 			return (rv);
308 	}
309 	return (0);
310 }
311 
312 /*
313  * Public interface.
314  */
315 
316 struct clknode *
317 clknode_find_by_name(const char *name)
318 {
319 	struct clknode *entry;
320 
321 	CLK_TOPO_ASSERT();
322 
323 	TAILQ_FOREACH(entry, &clknode_list, clklist_link) {
324 		if (strcmp(entry->name, name) == 0)
325 			return (entry);
326 	}
327 	return (NULL);
328 }
329 
330 struct clknode *
331 clknode_find_by_id(struct clkdom *clkdom, intptr_t id)
332 {
333 	struct clknode *entry;
334 
335 	CLK_TOPO_ASSERT();
336 
337 	TAILQ_FOREACH(entry, &clkdom->clknode_list, clkdom_link) {
338 		if (entry->id ==  id)
339 			return (entry);
340 	}
341 
342 	return (NULL);
343 }
344 
345 /* -------------------------------------------------------------------------- */
346 /*
347  * Clock domain functions
348  */
349 
350 /* Find clock domain associated to device in global list. */
351 struct clkdom *
352 clkdom_get_by_dev(const device_t dev)
353 {
354 	struct clkdom *entry;
355 
356 	CLK_TOPO_ASSERT();
357 
358 	TAILQ_FOREACH(entry, &clkdom_list, link) {
359 		if (entry->dev == dev)
360 			return (entry);
361 	}
362 	return (NULL);
363 }
364 
365 
366 #ifdef FDT
367 /* Default DT mapper. */
368 static int
369 clknode_default_ofw_map(struct clkdom *clkdom, uint32_t ncells,
370     phandle_t *cells, struct clknode **clk)
371 {
372 
373 	CLK_TOPO_ASSERT();
374 
375 	if (ncells == 0)
376 		*clk = clknode_find_by_id(clkdom, 1);
377 	else if (ncells == 1)
378 		*clk = clknode_find_by_id(clkdom, cells[0]);
379 	else
380 		return  (ERANGE);
381 
382 	if (*clk == NULL)
383 		return (ENXIO);
384 	return (0);
385 }
386 #endif
387 
388 /*
389  * Create a clock domain.  Returns with the topo lock held.
390  */
391 struct clkdom *
392 clkdom_create(device_t dev)
393 {
394 	struct clkdom *clkdom;
395 
396 	clkdom = malloc(sizeof(struct clkdom), M_CLOCK, M_WAITOK | M_ZERO);
397 	clkdom->dev = dev;
398 	TAILQ_INIT(&clkdom->clknode_list);
399 #ifdef FDT
400 	clkdom->ofw_mapper = clknode_default_ofw_map;
401 #endif
402 
403 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
404 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
405 	    OID_AUTO, "clocks",
406 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
407 	    clkdom, 0, clkdom_sysctl, "A",
408 	    "Clock list for the domain");
409 
410 	return (clkdom);
411 }
412 
413 void
414 clkdom_unlock(struct clkdom *clkdom)
415 {
416 
417 	CLK_TOPO_UNLOCK();
418 }
419 
420 void
421 clkdom_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  */
432 int
433 clkdom_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. */
505 void
506 clkdom_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  */
526 struct clknode *
527 clknode_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 | CTLFLAG_MPSAFE, 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 | CTLFLAG_NEEDGIANT,
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 | CTLFLAG_NEEDGIANT,
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 | CTLFLAG_NEEDGIANT,
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  */
671 struct clknode *
672 clknode_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 
692 static void
693 clknode_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  */
712 static void
713 clknode_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  */
742 void
743 clknode_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 
759 int
760 clknode_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 
789 int
790 clknode_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 
840 struct clknode *
841 clknode_get_parent(struct clknode *clknode)
842 {
843 
844 	return (clknode->parent);
845 }
846 
847 const char *
848 clknode_get_name(struct clknode *clknode)
849 {
850 
851 	return (clknode->name);
852 }
853 
854 const char **
855 clknode_get_parent_names(struct clknode *clknode)
856 {
857 
858 	return (clknode->parent_names);
859 }
860 
861 int
862 clknode_get_parents_num(struct clknode *clknode)
863 {
864 
865 	return (clknode->parent_cnt);
866 }
867 
868 int
869 clknode_get_parent_idx(struct clknode *clknode)
870 {
871 
872 	return (clknode->parent_idx);
873 }
874 
875 int
876 clknode_get_flags(struct clknode *clknode)
877 {
878 
879 	return (clknode->flags);
880 }
881 
882 
883 void *
884 clknode_get_softc(struct clknode *clknode)
885 {
886 
887 	return (clknode->softc);
888 }
889 
890 device_t
891 clknode_get_device(struct clknode *clknode)
892 {
893 
894 	return (clknode->clkdom->dev);
895 }
896 
897 #ifdef FDT
898 void
899 clkdom_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  */
909 int
910 clknode_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 
945 int
946 clknode_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 
1019 int
1020 clknode_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 
1048 int
1049 clknode_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 
1075 int
1076 clknode_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*() */
1111 static clk_t
1112 clk_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 
1127 int
1128 clk_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 
1143 int
1144 clk_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 
1160 int
1161 clk_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 
1177 int
1178 clk_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 
1198 int
1199 clk_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 
1217 int
1218 clk_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 
1234 int
1235 clk_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 
1253 int
1254 clk_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 
1271 int
1272 clk_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 
1293 const char *
1294 clk_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 
1306 int
1307 clk_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 
1322 int
1323 clk_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 
1342 static void
1343 clk_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 
1369 static void
1370 clk_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 
1385 int
1386 clk_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 
1438 int
1439 clk_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 
1483 done:
1484 	if (cells != NULL)
1485 		OF_prop_free(cells);
1486 	return (rv);
1487 }
1488 
1489 int
1490 clk_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 
1495 int
1496 clk_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  */
1524 int
1525 clk_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  */
1557 int
1558 clk_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 
1585 static int
1586 clkdom_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 
1608 static int
1609 clknode_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