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