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