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