xref: /freebsd/sys/dev/clk/clk.c (revision 78ae60b4)
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 #include "opt_platform.h"
29 #include <sys/param.h>
30 #include <sys/conf.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/queue.h>
34 #include <sys/kobj.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/sbuf.h>
40 #include <sys/sysctl.h>
41 #include <sys/systm.h>
42 #include <sys/sx.h>
43 
44 #ifdef FDT
45 #include <dev/fdt/fdt_common.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48 #endif
49 #include <dev/clk/clk.h>
50 
51 SYSCTL_NODE(_hw, OID_AUTO, clock, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
52     "Clocks");
53 
54 MALLOC_DEFINE(M_CLOCK, "clocks", "Clock framework");
55 
56 /* Forward declarations. */
57 struct clk;
58 struct clknodenode;
59 struct clkdom;
60 
61 typedef TAILQ_HEAD(clknode_list, clknode) clknode_list_t;
62 typedef TAILQ_HEAD(clkdom_list, clkdom) clkdom_list_t;
63 
64 /* Default clock methods. */
65 static int clknode_method_init(struct clknode *clk, device_t dev);
66 static int clknode_method_recalc_freq(struct clknode *clk, uint64_t *freq);
67 static int clknode_method_set_freq(struct clknode *clk, uint64_t fin,
68     uint64_t *fout, int flags, int *stop);
69 static int clknode_method_set_gate(struct clknode *clk, bool enable);
70 static int clknode_method_set_mux(struct clknode *clk, int idx);
71 
72 /*
73  * Clock controller methods.
74  */
75 static clknode_method_t clknode_methods[] = {
76 	CLKNODEMETHOD(clknode_init,		clknode_method_init),
77 	CLKNODEMETHOD(clknode_recalc_freq,	clknode_method_recalc_freq),
78 	CLKNODEMETHOD(clknode_set_freq,		clknode_method_set_freq),
79 	CLKNODEMETHOD(clknode_set_gate,		clknode_method_set_gate),
80 	CLKNODEMETHOD(clknode_set_mux,		clknode_method_set_mux),
81 
82 	CLKNODEMETHOD_END
83 };
84 DEFINE_CLASS_0(clknode, clknode_class, clknode_methods, 0);
85 
86 /*
87  * Clock node - basic element for modeling SOC clock graph.  It holds the clock
88  * provider's data about the clock, and the links for the clock's membership in
89  * various lists.
90  */
91 struct clknode {
92 	KOBJ_FIELDS;
93 
94 	/* Clock nodes topology. */
95 	struct clkdom 		*clkdom;	/* Owning clock domain */
96 	TAILQ_ENTRY(clknode)	clkdom_link;	/* Domain list entry */
97 	TAILQ_ENTRY(clknode)	clklist_link;	/* Global list entry */
98 
99 	/* String based parent list. */
100 	const char		**parent_names;	/* Array of parent names */
101 	int			parent_cnt;	/* Number of parents */
102 	int			parent_idx;	/* Parent index or -1 */
103 
104 	/* Cache for already resolved names. */
105 	struct clknode		**parents;	/* Array of potential parents */
106 	struct clknode		*parent;	/* Current parent */
107 
108 	/* Parent/child relationship links. */
109 	clknode_list_t		children;	/* List of our children */
110 	TAILQ_ENTRY(clknode)	sibling_link; 	/* Our entry in parent's list */
111 
112 	/* Details of this device. */
113 	void			*softc;		/* Instance softc */
114 	const char		*name;		/* Globally unique name */
115 	intptr_t		id;		/* Per domain unique id */
116 	int			flags;		/* CLK_FLAG_*  */
117 	struct sx		lock;		/* Lock for this clock */
118 	int			ref_cnt;	/* Reference counter */
119 	int			enable_cnt;	/* Enabled counter */
120 
121 	/* Cached values. */
122 	uint64_t		freq;		/* Actual frequency */
123 
124 	struct sysctl_ctx_list	sysctl_ctx;
125 };
126 
127 /*
128  *  Per consumer data, information about how a consumer is using a clock node.
129  *  A pointer to this structure is used as a handle in the consumer interface.
130  */
131 struct clk {
132 	device_t		dev;
133 	struct clknode		*clknode;
134 	int			enable_cnt;
135 };
136 
137 /*
138  * Clock domain - a group of clocks provided by one clock device.
139  */
140 struct clkdom {
141 	device_t 		dev; 	/* Link to provider device */
142 	TAILQ_ENTRY(clkdom)	link;		/* Global domain list entry */
143 	clknode_list_t		clknode_list;	/* All clocks in the domain */
144 
145 #ifdef FDT
146 	clknode_ofw_mapper_func	*ofw_mapper;	/* Find clock using FDT xref */
147 #endif
148 };
149 
150 /*
151  * The system-wide list of clock domains.
152  */
153 static clkdom_list_t clkdom_list = TAILQ_HEAD_INITIALIZER(clkdom_list);
154 
155 /*
156  * Each clock node is linked on a system-wide list and can be searched by name.
157  */
158 static clknode_list_t clknode_list = TAILQ_HEAD_INITIALIZER(clknode_list);
159 
160 /*
161  * Locking - we use three levels of locking:
162  * - First, topology lock is taken.  This one protect all lists.
163  * - Second level is per clknode lock.  It protects clknode data.
164  * - Third level is outside of this file, it protect clock device registers.
165  * First two levels use sleepable locks; clock device can use mutex or sx lock.
166  */
167 static struct sx		clk_topo_lock;
168 SX_SYSINIT(clock_topology, &clk_topo_lock, "Clock topology lock");
169 
170 #define CLK_TOPO_SLOCK()	sx_slock(&clk_topo_lock)
171 #define CLK_TOPO_XLOCK()	sx_xlock(&clk_topo_lock)
172 #define CLK_TOPO_UNLOCK()	sx_unlock(&clk_topo_lock)
173 #define CLK_TOPO_ASSERT()	sx_assert(&clk_topo_lock, SA_LOCKED)
174 #define CLK_TOPO_XASSERT()	sx_assert(&clk_topo_lock, SA_XLOCKED)
175 
176 #define CLKNODE_SLOCK(_sc)	sx_slock(&((_sc)->lock))
177 #define CLKNODE_XLOCK(_sc)	sx_xlock(&((_sc)->lock))
178 #define CLKNODE_UNLOCK(_sc)	sx_unlock(&((_sc)->lock))
179 
180 static void clknode_adjust_parent(struct clknode *clknode, int idx);
181 
182 enum clknode_sysctl_type {
183 	CLKNODE_SYSCTL_PARENT,
184 	CLKNODE_SYSCTL_PARENTS_LIST,
185 	CLKNODE_SYSCTL_CHILDREN_LIST,
186 	CLKNODE_SYSCTL_FREQUENCY,
187 	CLKNODE_SYSCTL_GATE,
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_MPSAFE,
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 	kobjop_desc_t kobj_desc;
534 	kobj_method_t *kobj_method;
535 
536 	KASSERT(def->name != NULL, ("clock name is NULL"));
537 	KASSERT(def->name[0] != '\0', ("clock name is empty"));
538 	if (def->flags & CLK_NODE_LINKED) {
539 		KASSERT(def->parent_cnt == 0,
540 		 ("Linked clock must not have parents"));
541 		KASSERT(clknode_class->size== 0,
542 		 ("Linked clock cannot have own softc"));
543 	}
544 
545 	/* Process duplicated clocks */
546 	CLK_TOPO_SLOCK();
547 	clknode = clknode_find_by_name(def->name);
548 	CLK_TOPO_UNLOCK();
549 	if (clknode !=  NULL) {
550 		if (!(clknode->flags & CLK_NODE_LINKED) &&
551 		    def->flags & CLK_NODE_LINKED) {
552 			/*
553 			 * New clock is linked and real already exists.
554 			 * Do nothing and return real node. It is in right
555 			 * domain, enqueued in right lists and fully initialized.
556 			 */
557 			return (clknode);
558 		} else if (clknode->flags & CLK_NODE_LINKED &&
559 		   !(def->flags & CLK_NODE_LINKED)) {
560 			/*
561 			 * New clock is real but linked already exists.
562 			 * Remove old linked node from originating domain
563 			 * (real clock must be owned by another) and from
564 			 * global names link (it will be added back into it
565 			 * again in following clknode_register()). Then reuse
566 			 * original clknode structure and reinitialize it
567 			 * with new dat. By this, all lists containing this
568 			 * node remains valid, but the new node virtually
569 			 * replace the linked one.
570 			 */
571 			KASSERT(clkdom != clknode->clkdom,
572 			    ("linked clock must be from another "
573 			    "domain that real one"));
574 			TAILQ_REMOVE(&clkdom->clknode_list, clknode,
575 			    clkdom_link);
576 			TAILQ_REMOVE(&clknode_list, clknode, clklist_link);
577 			replaced = true;
578 		} else if (clknode->flags & CLK_NODE_LINKED &&
579 		   def->flags & CLK_NODE_LINKED) {
580 			/*
581 			 * Both clocks are linked.
582 			 * Return old one, so we hold only one copy od link.
583 			 */
584 			return (clknode);
585 		} else {
586 			/* Both clocks are real */
587 			panic("Duplicated clock registration: %s\n", def->name);
588 		}
589 	} else {
590 		/* Create clknode object and initialize it. */
591 		clknode = malloc(sizeof(struct clknode), M_CLOCK,
592 		    M_WAITOK | M_ZERO);
593 		sx_init(&clknode->lock, "Clocknode lock");
594 		TAILQ_INIT(&clknode->children);
595 		replaced = false;
596 	}
597 
598 	kobj_init((kobj_t)clknode, (kobj_class_t)clknode_class);
599 
600 	/* Allocate softc if required. */
601 	if (clknode_class->size > 0) {
602 		clknode->softc = malloc(clknode_class->size,
603 		    M_CLOCK, M_WAITOK | M_ZERO);
604 	}
605 
606 	/* Prepare array for ptrs to parent clocks. */
607 	clknode->parents = malloc(sizeof(struct clknode *) * def->parent_cnt,
608 	    M_CLOCK, M_WAITOK | M_ZERO);
609 
610 	/* Copy all strings unless they're flagged as static. */
611 	if (def->flags & CLK_NODE_STATIC_STRINGS) {
612 		clknode->name = def->name;
613 		clknode->parent_names = def->parent_names;
614 	} else {
615 		clknode->name = strdup(def->name, M_CLOCK);
616 		clknode->parent_names =
617 		    strdup_list(def->parent_names, def->parent_cnt);
618 	}
619 
620 	/* Rest of init. */
621 	clknode->id = def->id;
622 	clknode->clkdom = clkdom;
623 	clknode->flags = def->flags;
624 	clknode->parent_cnt = def->parent_cnt;
625 	clknode->parent = NULL;
626 	clknode->parent_idx = CLKNODE_IDX_NONE;
627 
628 	if (replaced)
629 		return (clknode);
630 
631 	sysctl_ctx_init(&clknode->sysctl_ctx);
632 	clknode_oid = SYSCTL_ADD_NODE(&clknode->sysctl_ctx,
633 	    SYSCTL_STATIC_CHILDREN(_hw_clock),
634 	    OID_AUTO, clknode->name,
635 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "A clock node");
636 
637 	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
638 	    SYSCTL_CHILDREN(clknode_oid),
639 	    OID_AUTO, "frequency",
640 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
641 	    clknode, CLKNODE_SYSCTL_FREQUENCY, clknode_sysctl,
642 	    "A",
643 	    "The clock frequency");
644 
645 	/* Install gate handler only if clknode have 'set_gate' method */
646 	kobj_desc = &clknode_set_gate_desc;
647 	kobj_method = kobj_lookup_method(((kobj_t)clknode)->ops->cls, NULL,
648 	    kobj_desc);
649 	if (kobj_method != &kobj_desc->deflt &&
650 	    kobj_method->func != (kobjop_t)clknode_method_set_gate) {
651 		SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
652 		    SYSCTL_CHILDREN(clknode_oid),
653 		    OID_AUTO, "gate",
654 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
655 		    clknode, CLKNODE_SYSCTL_GATE, clknode_sysctl,
656 		    "A",
657 		    "The clock gate status");
658 	}
659 
660 	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
661 	    SYSCTL_CHILDREN(clknode_oid),
662 	    OID_AUTO, "parent",
663 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
664 	    clknode, CLKNODE_SYSCTL_PARENT, clknode_sysctl,
665 	    "A",
666 	    "The clock parent");
667 	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
668 	    SYSCTL_CHILDREN(clknode_oid),
669 	    OID_AUTO, "parents",
670 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
671 	    clknode, CLKNODE_SYSCTL_PARENTS_LIST, clknode_sysctl,
672 	    "A",
673 	    "The clock parents list");
674 	SYSCTL_ADD_PROC(&clknode->sysctl_ctx,
675 	    SYSCTL_CHILDREN(clknode_oid),
676 	    OID_AUTO, "childrens",
677 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
678 	    clknode, CLKNODE_SYSCTL_CHILDREN_LIST, clknode_sysctl,
679 	    "A",
680 	    "The clock childrens list");
681 	SYSCTL_ADD_INT(&clknode->sysctl_ctx,
682 	    SYSCTL_CHILDREN(clknode_oid),
683 	    OID_AUTO, "enable_cnt",
684 	    CTLFLAG_RD, &clknode->enable_cnt, 0, "The clock enable counter");
685 
686 	return (clknode);
687 }
688 
689 /*
690  * Register clock object into clock domain hierarchy.
691  */
692 struct clknode *
693 clknode_register(struct clkdom * clkdom, struct clknode *clknode)
694 {
695 	int rv;
696 
697 	/* Skip already registered linked node */
698 	if (clknode->flags & CLK_NODE_REGISTERED)
699 		return(clknode);
700 
701 	rv = CLKNODE_INIT(clknode, clknode_get_device(clknode));
702 	if (rv != 0) {
703 		printf(" CLKNODE_INIT failed: %d\n", rv);
704 		return (NULL);
705 	}
706 
707 	TAILQ_INSERT_TAIL(&clkdom->clknode_list, clknode, clkdom_link);
708 	clknode->flags |= CLK_NODE_REGISTERED;
709 	return (clknode);
710 }
711 
712 
713 static void
714 clknode_finish(void *dummy)
715 {
716 	struct clknode *clknode;
717 
718 	CLK_TOPO_SLOCK();
719 	TAILQ_FOREACH(clknode, &clknode_list, clklist_link) {
720 		if (clknode->flags & CLK_NODE_LINKED)
721 			printf("Unresolved linked clock found: %s\n",
722 			    clknode->name);
723 	}
724 	CLK_TOPO_UNLOCK();
725 }
726 /*
727  * Clock providers interface.
728  */
729 
730 /*
731  * Reparent clock node.
732  */
733 static void
734 clknode_adjust_parent(struct clknode *clknode, int idx)
735 {
736 
737 	CLK_TOPO_XASSERT();
738 
739 	if (clknode->parent_cnt == 0)
740 		return;
741 	if ((idx == CLKNODE_IDX_NONE) || (idx >= clknode->parent_cnt))
742 		panic("%s: Invalid parent index %d for clock %s",
743 		    __func__, idx, clknode->name);
744 
745 	if (clknode->parents[idx] == NULL)
746 		panic("%s: Invalid parent index %d for clock %s",
747 		    __func__, idx, clknode->name);
748 
749 	/* Remove me from old children list. */
750 	if (clknode->parent != NULL) {
751 		TAILQ_REMOVE(&clknode->parent->children, clknode, sibling_link);
752 	}
753 
754 	/* Insert into children list of new parent. */
755 	clknode->parent_idx = idx;
756 	clknode->parent = clknode->parents[idx];
757 	TAILQ_INSERT_TAIL(&clknode->parent->children, clknode, sibling_link);
758 }
759 
760 /*
761  * Set parent index - init function.
762  */
763 void
764 clknode_init_parent_idx(struct clknode *clknode, int idx)
765 {
766 
767 	if (clknode->parent_cnt == 0) {
768 		clknode->parent_idx = CLKNODE_IDX_NONE;
769 		clknode->parent = NULL;
770 		return;
771 	}
772 	if ((idx == CLKNODE_IDX_NONE) ||
773 	    (idx >= clknode->parent_cnt) ||
774 	    (clknode->parent_names[idx] == NULL))
775 		panic("%s: Invalid parent index %d for clock %s",
776 		    __func__, idx, clknode->name);
777 	clknode->parent_idx = idx;
778 }
779 
780 int
781 clknode_set_parent_by_idx(struct clknode *clknode, int idx)
782 {
783 	int rv;
784 	uint64_t freq;
785 	int  oldidx;
786 
787 	/* We have exclusive topology lock, node lock is not needed. */
788 	CLK_TOPO_XASSERT();
789 
790 	if (clknode->parent_cnt == 0)
791 		return (0);
792 
793 	if (clknode->parent_idx == idx)
794 		return (0);
795 
796 	oldidx = clknode->parent_idx;
797 	clknode_adjust_parent(clknode, idx);
798 	rv = CLKNODE_SET_MUX(clknode, idx);
799 	if (rv != 0) {
800 		clknode_adjust_parent(clknode, oldidx);
801 		return (rv);
802 	}
803 	rv = clknode_get_freq(clknode->parent, &freq);
804 	if (rv != 0)
805 		return (rv);
806 	rv = clknode_refresh_cache(clknode, freq);
807 	return (rv);
808 }
809 
810 int
811 clknode_set_parent_by_name(struct clknode *clknode, const char *name)
812 {
813 	int rv;
814 	uint64_t freq;
815 	int  oldidx, idx;
816 
817 	/* We have exclusive topology lock, node lock is not needed. */
818 	CLK_TOPO_XASSERT();
819 
820 	if (clknode->parent_cnt == 0)
821 		return (0);
822 
823 	/*
824 	 * If this node doesnt have mux, then passthrough request to parent.
825 	 * This feature is used in clock domain initialization and allows us to
826 	 * set clock source and target frequency on the tail node of the clock
827 	 * chain.
828 	 */
829 	if (clknode->parent_cnt == 1) {
830 		rv = clknode_set_parent_by_name(clknode->parent, name);
831 		return (rv);
832 	}
833 
834 	for (idx = 0; idx < clknode->parent_cnt; idx++) {
835 		if (clknode->parent_names[idx] == NULL)
836 			continue;
837 		if (strcmp(clknode->parent_names[idx], name) == 0)
838 			break;
839 	}
840 	if (idx >= clknode->parent_cnt) {
841 		return (ENXIO);
842 	}
843 	if (clknode->parent_idx == idx)
844 		return (0);
845 
846 	oldidx = clknode->parent_idx;
847 	clknode_adjust_parent(clknode, idx);
848 	rv = CLKNODE_SET_MUX(clknode, idx);
849 	if (rv != 0) {
850 		clknode_adjust_parent(clknode, oldidx);
851 		CLKNODE_UNLOCK(clknode);
852 		return (rv);
853 	}
854 	rv = clknode_get_freq(clknode->parent, &freq);
855 	if (rv != 0)
856 		return (rv);
857 	rv = clknode_refresh_cache(clknode, freq);
858 	return (rv);
859 }
860 
861 struct clknode *
862 clknode_get_parent(struct clknode *clknode)
863 {
864 
865 	return (clknode->parent);
866 }
867 
868 const char *
869 clknode_get_name(struct clknode *clknode)
870 {
871 
872 	return (clknode->name);
873 }
874 
875 const char **
876 clknode_get_parent_names(struct clknode *clknode)
877 {
878 
879 	return (clknode->parent_names);
880 }
881 
882 int
883 clknode_get_parents_num(struct clknode *clknode)
884 {
885 
886 	return (clknode->parent_cnt);
887 }
888 
889 int
890 clknode_get_parent_idx(struct clknode *clknode)
891 {
892 
893 	return (clknode->parent_idx);
894 }
895 
896 int
897 clknode_get_flags(struct clknode *clknode)
898 {
899 
900 	return (clknode->flags);
901 }
902 
903 
904 void *
905 clknode_get_softc(struct clknode *clknode)
906 {
907 
908 	return (clknode->softc);
909 }
910 
911 device_t
912 clknode_get_device(struct clknode *clknode)
913 {
914 
915 	return (clknode->clkdom->dev);
916 }
917 
918 #ifdef FDT
919 void
920 clkdom_set_ofw_mapper(struct clkdom * clkdom, clknode_ofw_mapper_func *map)
921 {
922 
923 	clkdom->ofw_mapper = map;
924 }
925 #endif
926 
927 /*
928  * Real consumers executive
929  */
930 int
931 clknode_get_freq(struct clknode *clknode, uint64_t *freq)
932 {
933 	int rv;
934 
935 	CLK_TOPO_ASSERT();
936 
937 	/* Use cached value, if it exists. */
938 	*freq  = clknode->freq;
939 	if (*freq != 0)
940 		return (0);
941 
942 	/* Get frequency from parent, if the clock has a parent. */
943 	if (clknode->parent_cnt > 0) {
944 		rv = clknode_get_freq(clknode->parent, freq);
945 		if (rv != 0) {
946 			return (rv);
947 		}
948 	}
949 
950 	/* And recalculate my output frequency. */
951 	CLKNODE_XLOCK(clknode);
952 	rv = CLKNODE_RECALC_FREQ(clknode, freq);
953 	if (rv != 0) {
954 		CLKNODE_UNLOCK(clknode);
955 		printf("Cannot get frequency for clk: %s, error: %d\n",
956 		    clknode->name, rv);
957 		return (rv);
958 	}
959 
960 	/* Save new frequency to cache. */
961 	clknode->freq = *freq;
962 	CLKNODE_UNLOCK(clknode);
963 	return (0);
964 }
965 
966 static int
967 _clknode_set_freq(struct clknode *clknode, uint64_t *freq, int flags,
968     int enablecnt)
969 {
970 	int rv, done;
971 	uint64_t parent_freq;
972 
973 	/* We have exclusive topology lock, node lock is not needed. */
974 	CLK_TOPO_XASSERT();
975 
976 	/* Check for no change */
977 	if (clknode->freq == *freq)
978 		return (0);
979 
980 	parent_freq = 0;
981 
982 	/*
983 	 * We can set frequency only if
984 	 *   clock is disabled
985 	 * OR
986 	 *   clock is glitch free and is enabled by calling consumer only
987 	 */
988 	if ((flags & CLK_SET_DRYRUN) == 0 &&
989 	    clknode->enable_cnt > 1 &&
990 	    clknode->enable_cnt > enablecnt &&
991 	    (clknode->flags & CLK_NODE_GLITCH_FREE) == 0) {
992 		return (EBUSY);
993 	}
994 
995 	/* Get frequency from parent, if the clock has a parent. */
996 	if (clknode->parent_cnt > 0) {
997 		rv = clknode_get_freq(clknode->parent, &parent_freq);
998 		if (rv != 0) {
999 			return (rv);
1000 		}
1001 	}
1002 
1003 	/* Set frequency for this clock. */
1004 	rv = CLKNODE_SET_FREQ(clknode, parent_freq, freq, flags, &done);
1005 	if (rv != 0) {
1006 		printf("Cannot set frequency for clk: %s, error: %d\n",
1007 		    clknode->name, rv);
1008 		if ((flags & CLK_SET_DRYRUN) == 0)
1009 			clknode_refresh_cache(clknode, parent_freq);
1010 		return (rv);
1011 	}
1012 
1013 	if (done) {
1014 		/* Success - invalidate frequency cache for all children. */
1015 		if ((flags & CLK_SET_DRYRUN) == 0) {
1016 			clknode->freq = *freq;
1017 			/* Clock might have reparent during set_freq */
1018 			if (clknode->parent_cnt > 0) {
1019 				rv = clknode_get_freq(clknode->parent,
1020 				    &parent_freq);
1021 				if (rv != 0) {
1022 					return (rv);
1023 				}
1024 			}
1025 			clknode_refresh_cache(clknode, parent_freq);
1026 		}
1027 	} else if (clknode->parent != NULL) {
1028 		/* Nothing changed, pass request to parent. */
1029 		rv = _clknode_set_freq(clknode->parent, freq, flags,
1030 		    enablecnt);
1031 	} else {
1032 		/* End of chain without action. */
1033 		printf("Cannot set frequency for clk: %s, end of chain\n",
1034 		    clknode->name);
1035 		rv = ENXIO;
1036 	}
1037 
1038 	return (rv);
1039 }
1040 
1041 int
1042 clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
1043     int enablecnt)
1044 {
1045 
1046 	return (_clknode_set_freq(clknode, &freq, flags, enablecnt));
1047 }
1048 
1049 int
1050 clknode_test_freq(struct clknode *clknode, uint64_t freq, int flags,
1051     int enablecnt, uint64_t *out_freq)
1052 {
1053 	int rv;
1054 
1055 	rv = _clknode_set_freq(clknode, &freq, flags | CLK_SET_DRYRUN,
1056 	    enablecnt);
1057 	if (out_freq != NULL)
1058 		*out_freq = freq;
1059 
1060 	return (rv);
1061 }
1062 
1063 int
1064 clknode_enable(struct clknode *clknode)
1065 {
1066 	int rv;
1067 
1068 	CLK_TOPO_ASSERT();
1069 
1070 	/* Enable clock for each node in chain, starting from source. */
1071 	if (clknode->parent_cnt > 0) {
1072 		rv = clknode_enable(clknode->parent);
1073 		if (rv != 0) {
1074 			return (rv);
1075 		}
1076 	}
1077 
1078 	/* Handle this node */
1079 	CLKNODE_XLOCK(clknode);
1080 	if (clknode->enable_cnt == 0) {
1081 		rv = CLKNODE_SET_GATE(clknode, 1);
1082 		if (rv != 0) {
1083 			CLKNODE_UNLOCK(clknode);
1084 			return (rv);
1085 		}
1086 	}
1087 	clknode->enable_cnt++;
1088 	CLKNODE_UNLOCK(clknode);
1089 	return (0);
1090 }
1091 
1092 int
1093 clknode_disable(struct clknode *clknode)
1094 {
1095 	int rv;
1096 
1097 	CLK_TOPO_ASSERT();
1098 	rv = 0;
1099 
1100 	CLKNODE_XLOCK(clknode);
1101 	/* Disable clock for each node in chain, starting from consumer. */
1102 	if ((clknode->enable_cnt == 1) &&
1103 	    ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) {
1104 		rv = CLKNODE_SET_GATE(clknode, 0);
1105 		if (rv != 0) {
1106 			CLKNODE_UNLOCK(clknode);
1107 			return (rv);
1108 		}
1109 	}
1110 	clknode->enable_cnt--;
1111 	CLKNODE_UNLOCK(clknode);
1112 
1113 	if (clknode->parent_cnt > 0) {
1114 		rv = clknode_disable(clknode->parent);
1115 	}
1116 	return (rv);
1117 }
1118 
1119 int
1120 clknode_stop(struct clknode *clknode, int depth)
1121 {
1122 	int rv;
1123 
1124 	CLK_TOPO_ASSERT();
1125 	rv = 0;
1126 
1127 	CLKNODE_XLOCK(clknode);
1128 	/* The first node cannot be enabled. */
1129 	if ((clknode->enable_cnt != 0) && (depth == 0)) {
1130 		CLKNODE_UNLOCK(clknode);
1131 		return (EBUSY);
1132 	}
1133 	/* Stop clock for each node in chain, starting from consumer. */
1134 	if ((clknode->enable_cnt == 0) &&
1135 	    ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) {
1136 		rv = CLKNODE_SET_GATE(clknode, 0);
1137 		if (rv != 0) {
1138 			CLKNODE_UNLOCK(clknode);
1139 			return (rv);
1140 		}
1141 	}
1142 	CLKNODE_UNLOCK(clknode);
1143 
1144 	if (clknode->parent_cnt > 0)
1145 		rv = clknode_stop(clknode->parent, depth + 1);
1146 	return (rv);
1147 }
1148 
1149 /* --------------------------------------------------------------------------
1150  *
1151  * Clock consumers interface.
1152  *
1153  */
1154 /* Helper function for clk_get*() */
1155 static clk_t
1156 clk_create(struct clknode *clknode, device_t dev)
1157 {
1158 	struct clk *clk;
1159 
1160 	CLK_TOPO_ASSERT();
1161 
1162 	clk =  malloc(sizeof(struct clk), M_CLOCK, M_WAITOK);
1163 	clk->dev = dev;
1164 	clk->clknode = clknode;
1165 	clk->enable_cnt = 0;
1166 	clknode->ref_cnt++;
1167 
1168 	return (clk);
1169 }
1170 
1171 int
1172 clk_get_freq(clk_t clk, uint64_t *freq)
1173 {
1174 	int rv;
1175 	struct clknode *clknode;
1176 
1177 	clknode = clk->clknode;
1178 	KASSERT(clknode->ref_cnt > 0,
1179 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1180 
1181 	CLK_TOPO_SLOCK();
1182 	rv = clknode_get_freq(clknode, freq);
1183 	CLK_TOPO_UNLOCK();
1184 	return (rv);
1185 }
1186 
1187 int
1188 clk_set_freq(clk_t clk, uint64_t freq, int flags)
1189 {
1190 	int rv;
1191 	struct clknode *clknode;
1192 
1193 	flags &= CLK_SET_USER_MASK;
1194 	clknode = clk->clknode;
1195 	KASSERT(clknode->ref_cnt > 0,
1196 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1197 
1198 	CLK_TOPO_XLOCK();
1199 	rv = clknode_set_freq(clknode, freq, flags, clk->enable_cnt);
1200 	CLK_TOPO_UNLOCK();
1201 	return (rv);
1202 }
1203 
1204 int
1205 clk_test_freq(clk_t clk, uint64_t freq, int flags)
1206 {
1207 	int rv;
1208 	struct clknode *clknode;
1209 
1210 	flags &= CLK_SET_USER_MASK;
1211 	clknode = clk->clknode;
1212 	KASSERT(clknode->ref_cnt > 0,
1213 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1214 
1215 	CLK_TOPO_XLOCK();
1216 	rv = clknode_set_freq(clknode, freq, flags | CLK_SET_DRYRUN, 0);
1217 	CLK_TOPO_UNLOCK();
1218 	return (rv);
1219 }
1220 
1221 int
1222 clk_get_parent(clk_t clk, clk_t *parent)
1223 {
1224 	struct clknode *clknode;
1225 	struct clknode *parentnode;
1226 
1227 	clknode = clk->clknode;
1228 	KASSERT(clknode->ref_cnt > 0,
1229 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1230 
1231 	CLK_TOPO_SLOCK();
1232 	parentnode = clknode_get_parent(clknode);
1233 	if (parentnode == NULL) {
1234 		CLK_TOPO_UNLOCK();
1235 		return (ENODEV);
1236 	}
1237 	*parent = clk_create(parentnode, clk->dev);
1238 	CLK_TOPO_UNLOCK();
1239 	return (0);
1240 }
1241 
1242 int
1243 clk_set_parent_by_clk(clk_t clk, clk_t parent)
1244 {
1245 	int rv;
1246 	struct clknode *clknode;
1247 	struct clknode *parentnode;
1248 
1249 	clknode = clk->clknode;
1250 	parentnode = parent->clknode;
1251 	KASSERT(clknode->ref_cnt > 0,
1252 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1253 	KASSERT(parentnode->ref_cnt > 0,
1254 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1255 	CLK_TOPO_XLOCK();
1256 	rv = clknode_set_parent_by_name(clknode, parentnode->name);
1257 	CLK_TOPO_UNLOCK();
1258 	return (rv);
1259 }
1260 
1261 int
1262 clk_enable(clk_t clk)
1263 {
1264 	int rv;
1265 	struct clknode *clknode;
1266 
1267 	clknode = clk->clknode;
1268 	KASSERT(clknode->ref_cnt > 0,
1269 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1270 	CLK_TOPO_SLOCK();
1271 	rv = clknode_enable(clknode);
1272 	if (rv == 0)
1273 		clk->enable_cnt++;
1274 	CLK_TOPO_UNLOCK();
1275 	return (rv);
1276 }
1277 
1278 int
1279 clk_disable(clk_t clk)
1280 {
1281 	int rv;
1282 	struct clknode *clknode;
1283 
1284 	clknode = clk->clknode;
1285 	KASSERT(clknode->ref_cnt > 0,
1286 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1287 	KASSERT(clk->enable_cnt > 0,
1288 	   ("Attempt to disable already disabled clock: %s\n", clknode->name));
1289 	CLK_TOPO_SLOCK();
1290 	rv = clknode_disable(clknode);
1291 	if (rv == 0)
1292 		clk->enable_cnt--;
1293 	CLK_TOPO_UNLOCK();
1294 	return (rv);
1295 }
1296 
1297 int
1298 clk_stop(clk_t clk)
1299 {
1300 	int rv;
1301 	struct clknode *clknode;
1302 
1303 	clknode = clk->clknode;
1304 	KASSERT(clknode->ref_cnt > 0,
1305 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1306 	KASSERT(clk->enable_cnt == 0,
1307 	   ("Attempt to stop already enabled clock: %s\n", clknode->name));
1308 
1309 	CLK_TOPO_SLOCK();
1310 	rv = clknode_stop(clknode, 0);
1311 	CLK_TOPO_UNLOCK();
1312 	return (rv);
1313 }
1314 
1315 int
1316 clk_release(clk_t clk)
1317 {
1318 	struct clknode *clknode;
1319 
1320 	clknode = clk->clknode;
1321 	KASSERT(clknode->ref_cnt > 0,
1322 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1323 	CLK_TOPO_SLOCK();
1324 	while (clk->enable_cnt > 0) {
1325 		clknode_disable(clknode);
1326 		clk->enable_cnt--;
1327 	}
1328 	CLKNODE_XLOCK(clknode);
1329 	clknode->ref_cnt--;
1330 	CLKNODE_UNLOCK(clknode);
1331 	CLK_TOPO_UNLOCK();
1332 
1333 	free(clk, M_CLOCK);
1334 	return (0);
1335 }
1336 
1337 const char *
1338 clk_get_name(clk_t clk)
1339 {
1340 	const char *name;
1341 	struct clknode *clknode;
1342 
1343 	clknode = clk->clknode;
1344 	KASSERT(clknode->ref_cnt > 0,
1345 	   ("Attempt to access unreferenced clock: %s\n", clknode->name));
1346 	name = clknode_get_name(clknode);
1347 	return (name);
1348 }
1349 
1350 int
1351 clk_get_by_name(device_t dev, const char *name, clk_t *clk)
1352 {
1353 	struct clknode *clknode;
1354 
1355 	CLK_TOPO_SLOCK();
1356 	clknode = clknode_find_by_name(name);
1357 	if (clknode == NULL) {
1358 		CLK_TOPO_UNLOCK();
1359 		return (ENODEV);
1360 	}
1361 	*clk = clk_create(clknode, dev);
1362 	CLK_TOPO_UNLOCK();
1363 	return (0);
1364 }
1365 
1366 int
1367 clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk)
1368 {
1369 	struct clknode *clknode;
1370 
1371 	CLK_TOPO_SLOCK();
1372 
1373 	clknode = clknode_find_by_id(clkdom, id);
1374 	if (clknode == NULL) {
1375 		CLK_TOPO_UNLOCK();
1376 		return (ENODEV);
1377 	}
1378 	*clk = clk_create(clknode, dev);
1379 	CLK_TOPO_UNLOCK();
1380 
1381 	return (0);
1382 }
1383 
1384 #ifdef FDT
1385 
1386 static void
1387 clk_set_assigned_parent(device_t dev, clk_t clk, int idx)
1388 {
1389 	clk_t parent;
1390 	const char *pname;
1391 	int rv;
1392 
1393 	rv = clk_get_by_ofw_index_prop(dev, 0,
1394 	    "assigned-clock-parents", idx, &parent);
1395 	if (rv != 0) {
1396 		device_printf(dev,
1397 		    "cannot get parent at idx %d\n", idx);
1398 		return;
1399 	}
1400 
1401 	pname = clk_get_name(parent);
1402 	rv = clk_set_parent_by_clk(clk, parent);
1403 	if (rv != 0)
1404 		device_printf(dev,
1405 		    "Cannot set parent %s for clock %s\n",
1406 		    pname, clk_get_name(clk));
1407 	else if (bootverbose)
1408 		device_printf(dev, "Set %s as the parent of %s\n",
1409 		    pname, clk_get_name(clk));
1410 	clk_release(parent);
1411 }
1412 
1413 static void
1414 clk_set_assigned_rates(device_t dev, clk_t clk, uint32_t freq)
1415 {
1416 	int rv;
1417 
1418 	rv = clk_set_freq(clk, freq, CLK_SET_ROUND_DOWN | CLK_SET_ROUND_UP);
1419 	if (rv != 0) {
1420 		device_printf(dev, "Failed to set %s to a frequency of %u\n",
1421 		    clk_get_name(clk), freq);
1422 		return;
1423 	}
1424 	if (bootverbose)
1425 		device_printf(dev, "Set %s to %u\n",
1426 		    clk_get_name(clk), freq);
1427 }
1428 
1429 int
1430 clk_set_assigned(device_t dev, phandle_t node)
1431 {
1432 	clk_t clk;
1433 	uint32_t *rates;
1434 	int rv, nclocks, nrates, nparents, i;
1435 
1436 	rv = ofw_bus_parse_xref_list_get_length(node,
1437 	    "assigned-clocks", "#clock-cells", &nclocks);
1438 
1439 	if (rv != 0) {
1440 		if (rv != ENOENT)
1441 			device_printf(dev,
1442 			    "cannot parse assigned-clock property\n");
1443 		return (rv);
1444 	}
1445 
1446 	nrates = OF_getencprop_alloc_multi(node, "assigned-clock-rates",
1447 	    sizeof(*rates), (void **)&rates);
1448 	if (nrates <= 0)
1449 		nrates = 0;
1450 
1451 	if (ofw_bus_parse_xref_list_get_length(node,
1452 	    "assigned-clock-parents", "#clock-cells", &nparents) != 0)
1453 		nparents = -1;
1454 	for (i = 0; i < nclocks; i++) {
1455 		/* First get the clock we are supposed to modify */
1456 		rv = clk_get_by_ofw_index_prop(dev, 0, "assigned-clocks",
1457 		    i, &clk);
1458 		if (rv != 0) {
1459 			if (bootverbose)
1460 				device_printf(dev,
1461 				    "cannot get assigned clock at idx %d\n",
1462 				    i);
1463 			continue;
1464 		}
1465 
1466 		/* First set it's parent if needed */
1467 		if (i < nparents)
1468 			clk_set_assigned_parent(dev, clk, i);
1469 
1470 		/* Then set a new frequency */
1471 		if (i < nrates && rates[i] != 0)
1472 			clk_set_assigned_rates(dev, clk, rates[i]);
1473 
1474 		clk_release(clk);
1475 	}
1476 	if (rates != NULL)
1477 		OF_prop_free(rates);
1478 
1479 	return (0);
1480 }
1481 
1482 int
1483 clk_get_by_ofw_index_prop(device_t dev, phandle_t cnode, const char *prop, int idx, clk_t *clk)
1484 {
1485 	phandle_t parent, *cells;
1486 	device_t clockdev;
1487 	int ncells, rv;
1488 	struct clkdom *clkdom;
1489 	struct clknode *clknode;
1490 
1491 	*clk = NULL;
1492 	if (cnode <= 0)
1493 		cnode = ofw_bus_get_node(dev);
1494 	if (cnode <= 0) {
1495 		device_printf(dev, "%s called on not ofw based device\n",
1496 		 __func__);
1497 		return (ENXIO);
1498 	}
1499 
1500 
1501 	rv = ofw_bus_parse_xref_list_alloc(cnode, prop, "#clock-cells", idx,
1502 	    &parent, &ncells, &cells);
1503 	if (rv != 0) {
1504 		return (rv);
1505 	}
1506 
1507 	clockdev = OF_device_from_xref(parent);
1508 	if (clockdev == NULL) {
1509 		rv = ENODEV;
1510 		goto done;
1511 	}
1512 
1513 	CLK_TOPO_SLOCK();
1514 	clkdom = clkdom_get_by_dev(clockdev);
1515 	if (clkdom == NULL){
1516 		CLK_TOPO_UNLOCK();
1517 		rv = ENXIO;
1518 		goto done;
1519 	}
1520 
1521 	rv = clkdom->ofw_mapper(clkdom, ncells, cells, &clknode);
1522 	if (rv == 0) {
1523 		*clk = clk_create(clknode, dev);
1524 	}
1525 	CLK_TOPO_UNLOCK();
1526 
1527 done:
1528 	if (cells != NULL)
1529 		OF_prop_free(cells);
1530 	return (rv);
1531 }
1532 
1533 int
1534 clk_get_by_ofw_index(device_t dev, phandle_t cnode, int idx, clk_t *clk)
1535 {
1536 	return (clk_get_by_ofw_index_prop(dev, cnode, "clocks", idx, clk));
1537 }
1538 
1539 int
1540 clk_get_by_ofw_name(device_t dev, phandle_t cnode, const char *name, clk_t *clk)
1541 {
1542 	int rv, idx;
1543 
1544 	if (cnode <= 0)
1545 		cnode = ofw_bus_get_node(dev);
1546 	if (cnode <= 0) {
1547 		device_printf(dev, "%s called on not ofw based device\n",
1548 		 __func__);
1549 		return (ENXIO);
1550 	}
1551 	rv = ofw_bus_find_string_index(cnode, "clock-names", name, &idx);
1552 	if (rv != 0)
1553 		return (rv);
1554 	return (clk_get_by_ofw_index(dev, cnode, idx, clk));
1555 }
1556 
1557 /* --------------------------------------------------------------------------
1558  *
1559  * Support functions for parsing various clock related OFW things.
1560  */
1561 
1562 /*
1563  * Get "clock-output-names" and  (optional) "clock-indices" lists.
1564  * Both lists are allocated using M_OFWPROP specifier.
1565  *
1566  * Returns number of items or 0.
1567  */
1568 int
1569 clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names,
1570 	uint32_t **indices)
1571 {
1572 	int name_items, rv;
1573 
1574 	*out_names = NULL;
1575 	*indices = NULL;
1576 	if (!OF_hasprop(node, "clock-output-names"))
1577 		return (0);
1578 	rv = ofw_bus_string_list_to_array(node, "clock-output-names",
1579 	    out_names);
1580 	if (rv <= 0)
1581 		return (0);
1582 	name_items = rv;
1583 
1584 	if (!OF_hasprop(node, "clock-indices"))
1585 		return (name_items);
1586 	rv = OF_getencprop_alloc_multi(node, "clock-indices", sizeof (uint32_t),
1587 	    (void **)indices);
1588 	if (rv != name_items) {
1589 		device_printf(dev, " Size of 'clock-output-names' and "
1590 		    "'clock-indices' differs\n");
1591 		OF_prop_free(*out_names);
1592 		OF_prop_free(*indices);
1593 		return (0);
1594 	}
1595 	return (name_items);
1596 }
1597 
1598 /*
1599  * Get output clock name for single output clock node.
1600  */
1601 int
1602 clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name)
1603 {
1604 	const char **out_names;
1605 	const char  *tmp_name;
1606 	int rv;
1607 
1608 	*name = NULL;
1609 	if (!OF_hasprop(node, "clock-output-names")) {
1610 		tmp_name  = ofw_bus_get_name(dev);
1611 		if (tmp_name == NULL)
1612 			return (ENXIO);
1613 		*name = strdup(tmp_name, M_OFWPROP);
1614 		return (0);
1615 	}
1616 	rv = ofw_bus_string_list_to_array(node, "clock-output-names",
1617 	    &out_names);
1618 	if (rv != 1) {
1619 		OF_prop_free(out_names);
1620 		device_printf(dev, "Malformed 'clock-output-names' property\n");
1621 		return (ENXIO);
1622 	}
1623 	*name = strdup(out_names[0], M_OFWPROP);
1624 	OF_prop_free(out_names);
1625 	return (0);
1626 }
1627 #endif
1628 
1629 static int
1630 clkdom_sysctl(SYSCTL_HANDLER_ARGS)
1631 {
1632 	struct clkdom *clkdom = arg1;
1633 	struct clknode *clknode;
1634 	struct sbuf *sb;
1635 	int ret;
1636 
1637 	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
1638 	if (sb == NULL)
1639 		return (ENOMEM);
1640 
1641 	CLK_TOPO_SLOCK();
1642 	TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
1643 		sbuf_printf(sb, "%s ", clknode->name);
1644 	}
1645 	CLK_TOPO_UNLOCK();
1646 
1647 	ret = sbuf_finish(sb);
1648 	sbuf_delete(sb);
1649 	return (ret);
1650 }
1651 
1652 static int
1653 clknode_sysctl(SYSCTL_HANDLER_ARGS)
1654 {
1655 	struct clknode *clknode, *children;
1656 	enum clknode_sysctl_type type = arg2;
1657 	struct sbuf *sb;
1658 	const char **parent_names;
1659 	uint64_t freq;
1660 	bool enable;
1661 	int ret, i;
1662 
1663 	clknode = arg1;
1664 	sb = sbuf_new_for_sysctl(NULL, NULL, 512, req);
1665 	if (sb == NULL)
1666 		return (ENOMEM);
1667 
1668 	CLK_TOPO_SLOCK();
1669 	switch (type) {
1670 	case CLKNODE_SYSCTL_PARENT:
1671 		if (clknode->parent)
1672 			sbuf_printf(sb, "%s", clknode->parent->name);
1673 		break;
1674 	case CLKNODE_SYSCTL_PARENTS_LIST:
1675 		parent_names = clknode_get_parent_names(clknode);
1676 		for (i = 0; i < clknode->parent_cnt; i++)
1677 			sbuf_printf(sb, "%s ", parent_names[i]);
1678 		break;
1679 	case CLKNODE_SYSCTL_CHILDREN_LIST:
1680 		TAILQ_FOREACH(children, &(clknode->children), sibling_link) {
1681 			sbuf_printf(sb, "%s ", children->name);
1682 		}
1683 		break;
1684 	case CLKNODE_SYSCTL_FREQUENCY:
1685 		ret = clknode_get_freq(clknode, &freq);
1686 		if (ret == 0)
1687 			sbuf_printf(sb, "%ju ", (uintmax_t)freq);
1688 		else
1689 			sbuf_printf(sb, "Error: %d ", ret);
1690 		break;
1691 	case CLKNODE_SYSCTL_GATE:
1692 		ret = CLKNODE_GET_GATE(clknode, &enable);
1693 		if (ret == 0)
1694 			sbuf_printf(sb, enable ? "enabled": "disabled");
1695 		else if (ret == ENXIO)
1696 			sbuf_printf(sb, "unimplemented");
1697 		else if (ret == ENOENT)
1698 			sbuf_printf(sb, "unreadable");
1699 		else
1700 			sbuf_printf(sb, "Error: %d ", ret);
1701 		break;
1702 	}
1703 	CLK_TOPO_UNLOCK();
1704 
1705 	ret = sbuf_finish(sb);
1706 	sbuf_delete(sb);
1707 	return (ret);
1708 }
1709