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