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