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