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