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