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