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