clk.c revision 308324
1/*- 2 * Copyright 2016 Michal Meloun <mmel@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/dev/extres/clk/clk.c 308324 2016-11-05 04:17:32Z mmel $"); 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 52MALLOC_DEFINE(M_CLOCK, "clocks", "Clock framework"); 53 54/* Forward declarations. */ 55struct clk; 56struct clknodenode; 57struct clkdom; 58 59typedef TAILQ_HEAD(clknode_list, clknode) clknode_list_t; 60typedef TAILQ_HEAD(clkdom_list, clkdom) clkdom_list_t; 61 62/* Default clock methods. */ 63static int clknode_method_init(struct clknode *clk, device_t dev); 64static int clknode_method_recalc_freq(struct clknode *clk, uint64_t *freq); 65static int clknode_method_set_freq(struct clknode *clk, uint64_t fin, 66 uint64_t *fout, int flags, int *stop); 67static int clknode_method_set_gate(struct clknode *clk, bool enable); 68static int clknode_method_set_mux(struct clknode *clk, int idx); 69 70/* 71 * Clock controller methods. 72 */ 73static 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}; 82DEFINE_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 */ 89struct 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 */ 127struct 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 */ 136struct 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 */ 149static 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 */ 154static 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 */ 163static struct sx clk_topo_lock; 164SX_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 176static void clknode_adjust_parent(struct clknode *clknode, int idx); 177 178/* 179 * Default clock methods for base class. 180 */ 181static int 182clknode_method_init(struct clknode *clknode, device_t dev) 183{ 184 185 return (0); 186} 187 188static int 189clknode_method_recalc_freq(struct clknode *clknode, uint64_t *freq) 190{ 191 192 return (0); 193} 194 195static int 196clknode_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 204static int 205clknode_method_set_gate(struct clknode *clk, bool enable) 206{ 207 208 return (0); 209} 210 211static int 212clknode_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 */ 231static const char ** 232strdup_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 */ 263static int 264clknode_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 298struct clknode * 299clknode_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 312struct clknode * 313clknode_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. */ 333struct clkdom * 334clkdom_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. */ 350static int 351clknode_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 */ 373struct clkdom * 374clkdom_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 388void 389clkdom_unlock(struct clkdom *clkdom) 390{ 391 392 CLK_TOPO_UNLOCK(); 393} 394 395void 396clkdom_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 */ 407int 408clkdom_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. */ 480void 481clkdom_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 */ 501struct clknode * 502clknode_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 */ 556struct clknode * 557clknode_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 */ 579static void 580clknode_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("Invalid clock parent index\n"); 589 590 if (clknode->parents[idx] == NULL) 591 panic("%s: Attempt to set invalid parent %d for clock %s", 592 __func__, idx, clknode->name); 593 594 /* Remove me from old children list. */ 595 if (clknode->parent != NULL) { 596 TAILQ_REMOVE(&clknode->parent->children, clknode, sibling_link); 597 } 598 599 /* Insert into children list of new parent. */ 600 clknode->parent_idx = idx; 601 clknode->parent = clknode->parents[idx]; 602 TAILQ_INSERT_TAIL(&clknode->parent->children, clknode, sibling_link); 603} 604 605/* 606 * Set parent index - init function. 607 */ 608void 609clknode_init_parent_idx(struct clknode *clknode, int idx) 610{ 611 612 if (clknode->parent_cnt == 0) { 613 clknode->parent_idx = CLKNODE_IDX_NONE; 614 clknode->parent = NULL; 615 return; 616 } 617 if ((idx == CLKNODE_IDX_NONE) || 618 (idx >= clknode->parent_cnt) || 619 (clknode->parent_names[idx] == NULL)) 620 panic("%s: Invalid clock parent index: %d\n", __func__, idx); 621 622 clknode->parent_idx = idx; 623} 624 625int 626clknode_set_parent_by_idx(struct clknode *clknode, int idx) 627{ 628 int rv; 629 uint64_t freq; 630 int oldidx; 631 632 /* We have exclusive topology lock, node lock is not needed. */ 633 CLK_TOPO_XASSERT(); 634 635 if (clknode->parent_cnt == 0) 636 return (0); 637 638 if (clknode->parent_idx == idx) 639 return (0); 640 641 oldidx = clknode->parent_idx; 642 clknode_adjust_parent(clknode, idx); 643 rv = CLKNODE_SET_MUX(clknode, idx); 644 if (rv != 0) { 645 clknode_adjust_parent(clknode, oldidx); 646 return (rv); 647 } 648 rv = clknode_get_freq(clknode->parent, &freq); 649 if (rv != 0) 650 return (rv); 651 rv = clknode_refresh_cache(clknode, freq); 652 return (rv); 653} 654 655int 656clknode_set_parent_by_name(struct clknode *clknode, const char *name) 657{ 658 int rv; 659 uint64_t freq; 660 int oldidx, idx; 661 662 /* We have exclusive topology lock, node lock is not needed. */ 663 CLK_TOPO_XASSERT(); 664 665 if (clknode->parent_cnt == 0) 666 return (0); 667 668 /* 669 * If this node doesnt have mux, then passthrough request to parent. 670 * This feature is used in clock domain initialization and allows us to 671 * set clock source and target frequency on the tail node of the clock 672 * chain. 673 */ 674 if (clknode->parent_cnt == 1) { 675 rv = clknode_set_parent_by_name(clknode->parent, name); 676 return (rv); 677 } 678 679 for (idx = 0; idx < clknode->parent_cnt; idx++) { 680 if (clknode->parent_names[idx] == NULL) 681 continue; 682 if (strcmp(clknode->parent_names[idx], name) == 0) 683 break; 684 } 685 if (idx >= clknode->parent_cnt) { 686 return (ENXIO); 687 } 688 if (clknode->parent_idx == idx) 689 return (0); 690 691 oldidx = clknode->parent_idx; 692 clknode_adjust_parent(clknode, idx); 693 rv = CLKNODE_SET_MUX(clknode, idx); 694 if (rv != 0) { 695 clknode_adjust_parent(clknode, oldidx); 696 CLKNODE_UNLOCK(clknode); 697 return (rv); 698 } 699 rv = clknode_get_freq(clknode->parent, &freq); 700 if (rv != 0) 701 return (rv); 702 rv = clknode_refresh_cache(clknode, freq); 703 return (rv); 704} 705 706struct clknode * 707clknode_get_parent(struct clknode *clknode) 708{ 709 710 return (clknode->parent); 711} 712 713const char * 714clknode_get_name(struct clknode *clknode) 715{ 716 717 return (clknode->name); 718} 719 720const char ** 721clknode_get_parent_names(struct clknode *clknode) 722{ 723 724 return (clknode->parent_names); 725} 726 727int 728clknode_get_parents_num(struct clknode *clknode) 729{ 730 731 return (clknode->parent_cnt); 732} 733 734int 735clknode_get_parent_idx(struct clknode *clknode) 736{ 737 738 return (clknode->parent_idx); 739} 740 741int 742clknode_get_flags(struct clknode *clknode) 743{ 744 745 return (clknode->flags); 746} 747 748 749void * 750clknode_get_softc(struct clknode *clknode) 751{ 752 753 return (clknode->softc); 754} 755 756device_t 757clknode_get_device(struct clknode *clknode) 758{ 759 760 return (clknode->clkdom->dev); 761} 762 763#ifdef FDT 764void 765clkdom_set_ofw_mapper(struct clkdom * clkdom, clknode_ofw_mapper_func *map) 766{ 767 768 clkdom->ofw_mapper = map; 769} 770#endif 771 772/* 773 * Real consumers executive 774 */ 775int 776clknode_get_freq(struct clknode *clknode, uint64_t *freq) 777{ 778 int rv; 779 780 CLK_TOPO_ASSERT(); 781 782 /* Use cached value, if it exists. */ 783 *freq = clknode->freq; 784 if (*freq != 0) 785 return (0); 786 787 /* Get frequency from parent, if the clock has a parent. */ 788 if (clknode->parent_cnt > 0) { 789 rv = clknode_get_freq(clknode->parent, freq); 790 if (rv != 0) { 791 return (rv); 792 } 793 } 794 795 /* And recalculate my output frequency. */ 796 CLKNODE_XLOCK(clknode); 797 rv = CLKNODE_RECALC_FREQ(clknode, freq); 798 if (rv != 0) { 799 CLKNODE_UNLOCK(clknode); 800 printf("Cannot get frequency for clk: %s, error: %d\n", 801 clknode->name, rv); 802 return (rv); 803 } 804 805 /* Save new frequency to cache. */ 806 clknode->freq = *freq; 807 CLKNODE_UNLOCK(clknode); 808 return (0); 809} 810 811int 812clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags, 813 int enablecnt) 814{ 815 int rv, done; 816 uint64_t parent_freq; 817 818 /* We have exclusive topology lock, node lock is not needed. */ 819 CLK_TOPO_XASSERT(); 820 821 /* Check for no change */ 822 if (clknode->freq == freq) 823 return (0); 824 825 parent_freq = 0; 826 827 /* 828 * We can set frequency only if 829 * clock is disabled 830 * OR 831 * clock is glitch free and is enabled by calling consumer only 832 */ 833 if ((clknode->enable_cnt > 1) && 834 ((clknode->enable_cnt > enablecnt) || 835 !(clknode->flags & CLK_NODE_GLITCH_FREE))) { 836 return (EBUSY); 837 } 838 839 /* Get frequency from parent, if the clock has a parent. */ 840 if (clknode->parent_cnt > 0) { 841 rv = clknode_get_freq(clknode->parent, &parent_freq); 842 if (rv != 0) { 843 return (rv); 844 } 845 } 846 847 /* Set frequency for this clock. */ 848 rv = CLKNODE_SET_FREQ(clknode, parent_freq, &freq, flags, &done); 849 if (rv != 0) { 850 printf("Cannot set frequency for clk: %s, error: %d\n", 851 clknode->name, rv); 852 if ((flags & CLK_SET_DRYRUN) == 0) 853 clknode_refresh_cache(clknode, parent_freq); 854 return (rv); 855 } 856 857 if (done) { 858 /* Success - invalidate frequency cache for all children. */ 859 clknode->freq = freq; 860 if ((flags & CLK_SET_DRYRUN) == 0) 861 clknode_refresh_cache(clknode, parent_freq); 862 } else if (clknode->parent != NULL) { 863 /* Nothing changed, pass request to parent. */ 864 rv = clknode_set_freq(clknode->parent, freq, flags, enablecnt); 865 } else { 866 /* End of chain without action. */ 867 printf("Cannot set frequency for clk: %s, end of chain\n", 868 clknode->name); 869 rv = ENXIO; 870 } 871 872 return (rv); 873} 874 875int 876clknode_enable(struct clknode *clknode) 877{ 878 int rv; 879 880 CLK_TOPO_ASSERT(); 881 882 /* Enable clock for each node in chain, starting from source. */ 883 if (clknode->parent_cnt > 0) { 884 rv = clknode_enable(clknode->parent); 885 if (rv != 0) { 886 return (rv); 887 } 888 } 889 890 /* Handle this node */ 891 CLKNODE_XLOCK(clknode); 892 if (clknode->enable_cnt == 0) { 893 rv = CLKNODE_SET_GATE(clknode, 1); 894 if (rv != 0) { 895 CLKNODE_UNLOCK(clknode); 896 return (rv); 897 } 898 } 899 clknode->enable_cnt++; 900 CLKNODE_UNLOCK(clknode); 901 return (0); 902} 903 904int 905clknode_disable(struct clknode *clknode) 906{ 907 int rv; 908 909 CLK_TOPO_ASSERT(); 910 rv = 0; 911 912 CLKNODE_XLOCK(clknode); 913 /* Disable clock for each node in chain, starting from consumer. */ 914 if ((clknode->enable_cnt == 1) && 915 ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) { 916 rv = CLKNODE_SET_GATE(clknode, 0); 917 if (rv != 0) { 918 CLKNODE_UNLOCK(clknode); 919 return (rv); 920 } 921 } 922 clknode->enable_cnt--; 923 CLKNODE_UNLOCK(clknode); 924 925 if (clknode->parent_cnt > 0) { 926 rv = clknode_disable(clknode->parent); 927 } 928 return (rv); 929} 930 931int 932clknode_stop(struct clknode *clknode, int depth) 933{ 934 int rv; 935 936 CLK_TOPO_ASSERT(); 937 rv = 0; 938 939 CLKNODE_XLOCK(clknode); 940 /* The first node cannot be enabled. */ 941 if ((clknode->enable_cnt != 0) && (depth == 0)) { 942 CLKNODE_UNLOCK(clknode); 943 return (EBUSY); 944 } 945 /* Stop clock for each node in chain, starting from consumer. */ 946 if ((clknode->enable_cnt == 0) && 947 ((clknode->flags & CLK_NODE_CANNOT_STOP) == 0)) { 948 rv = CLKNODE_SET_GATE(clknode, 0); 949 if (rv != 0) { 950 CLKNODE_UNLOCK(clknode); 951 return (rv); 952 } 953 } 954 CLKNODE_UNLOCK(clknode); 955 956 if (clknode->parent_cnt > 0) 957 rv = clknode_stop(clknode->parent, depth + 1); 958 return (rv); 959} 960 961/* -------------------------------------------------------------------------- 962 * 963 * Clock consumers interface. 964 * 965 */ 966/* Helper function for clk_get*() */ 967static clk_t 968clk_create(struct clknode *clknode, device_t dev) 969{ 970 struct clk *clk; 971 972 CLK_TOPO_ASSERT(); 973 974 clk = malloc(sizeof(struct clk), M_CLOCK, M_WAITOK); 975 clk->dev = dev; 976 clk->clknode = clknode; 977 clk->enable_cnt = 0; 978 clknode->ref_cnt++; 979 980 return (clk); 981} 982 983int 984clk_get_freq(clk_t clk, uint64_t *freq) 985{ 986 int rv; 987 struct clknode *clknode; 988 989 clknode = clk->clknode; 990 KASSERT(clknode->ref_cnt > 0, 991 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 992 993 CLK_TOPO_SLOCK(); 994 rv = clknode_get_freq(clknode, freq); 995 CLK_TOPO_UNLOCK(); 996 return (rv); 997} 998 999int 1000clk_set_freq(clk_t clk, uint64_t freq, int flags) 1001{ 1002 int rv; 1003 struct clknode *clknode; 1004 1005 flags &= CLK_SET_USER_MASK; 1006 clknode = clk->clknode; 1007 KASSERT(clknode->ref_cnt > 0, 1008 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1009 1010 CLK_TOPO_XLOCK(); 1011 rv = clknode_set_freq(clknode, freq, flags, clk->enable_cnt); 1012 CLK_TOPO_UNLOCK(); 1013 return (rv); 1014} 1015 1016int 1017clk_test_freq(clk_t clk, uint64_t freq, int flags) 1018{ 1019 int rv; 1020 struct clknode *clknode; 1021 1022 flags &= CLK_SET_USER_MASK; 1023 clknode = clk->clknode; 1024 KASSERT(clknode->ref_cnt > 0, 1025 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1026 1027 CLK_TOPO_XLOCK(); 1028 rv = clknode_set_freq(clknode, freq, flags | CLK_SET_DRYRUN, 0); 1029 CLK_TOPO_UNLOCK(); 1030 return (rv); 1031} 1032 1033int 1034clk_get_parent(clk_t clk, clk_t *parent) 1035{ 1036 struct clknode *clknode; 1037 struct clknode *parentnode; 1038 1039 clknode = clk->clknode; 1040 KASSERT(clknode->ref_cnt > 0, 1041 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1042 1043 CLK_TOPO_SLOCK(); 1044 parentnode = clknode_get_parent(clknode); 1045 if (parentnode == NULL) { 1046 CLK_TOPO_UNLOCK(); 1047 return (ENODEV); 1048 } 1049 *parent = clk_create(parentnode, clk->dev); 1050 CLK_TOPO_UNLOCK(); 1051 return (0); 1052} 1053 1054int 1055clk_set_parent_by_clk(clk_t clk, clk_t parent) 1056{ 1057 int rv; 1058 struct clknode *clknode; 1059 struct clknode *parentnode; 1060 1061 clknode = clk->clknode; 1062 parentnode = parent->clknode; 1063 KASSERT(clknode->ref_cnt > 0, 1064 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1065 KASSERT(parentnode->ref_cnt > 0, 1066 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1067 CLK_TOPO_XLOCK(); 1068 rv = clknode_set_parent_by_name(clknode, parentnode->name); 1069 CLK_TOPO_UNLOCK(); 1070 return (rv); 1071} 1072 1073int 1074clk_enable(clk_t clk) 1075{ 1076 int rv; 1077 struct clknode *clknode; 1078 1079 clknode = clk->clknode; 1080 KASSERT(clknode->ref_cnt > 0, 1081 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1082 CLK_TOPO_SLOCK(); 1083 rv = clknode_enable(clknode); 1084 if (rv == 0) 1085 clk->enable_cnt++; 1086 CLK_TOPO_UNLOCK(); 1087 return (rv); 1088} 1089 1090int 1091clk_disable(clk_t clk) 1092{ 1093 int rv; 1094 struct clknode *clknode; 1095 1096 clknode = clk->clknode; 1097 KASSERT(clknode->ref_cnt > 0, 1098 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1099 KASSERT(clk->enable_cnt > 0, 1100 ("Attempt to disable already disabled clock: %s\n", clknode->name)); 1101 CLK_TOPO_SLOCK(); 1102 rv = clknode_disable(clknode); 1103 if (rv == 0) 1104 clk->enable_cnt--; 1105 CLK_TOPO_UNLOCK(); 1106 return (rv); 1107} 1108 1109int 1110clk_stop(clk_t clk) 1111{ 1112 int rv; 1113 struct clknode *clknode; 1114 1115 clknode = clk->clknode; 1116 KASSERT(clknode->ref_cnt > 0, 1117 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1118 KASSERT(clk->enable_cnt == 0, 1119 ("Attempt to stop already enabled clock: %s\n", clknode->name)); 1120 1121 CLK_TOPO_SLOCK(); 1122 rv = clknode_stop(clknode, 0); 1123 CLK_TOPO_UNLOCK(); 1124 return (rv); 1125} 1126 1127int 1128clk_release(clk_t clk) 1129{ 1130 struct clknode *clknode; 1131 1132 clknode = clk->clknode; 1133 KASSERT(clknode->ref_cnt > 0, 1134 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1135 CLK_TOPO_SLOCK(); 1136 while (clk->enable_cnt > 0) { 1137 clknode_disable(clknode); 1138 clk->enable_cnt--; 1139 } 1140 CLKNODE_XLOCK(clknode); 1141 clknode->ref_cnt--; 1142 CLKNODE_UNLOCK(clknode); 1143 CLK_TOPO_UNLOCK(); 1144 1145 free(clk, M_CLOCK); 1146 return (0); 1147} 1148 1149const char * 1150clk_get_name(clk_t clk) 1151{ 1152 const char *name; 1153 struct clknode *clknode; 1154 1155 clknode = clk->clknode; 1156 KASSERT(clknode->ref_cnt > 0, 1157 ("Attempt to access unreferenced clock: %s\n", clknode->name)); 1158 name = clknode_get_name(clknode); 1159 return (name); 1160} 1161 1162int 1163clk_get_by_name(device_t dev, const char *name, clk_t *clk) 1164{ 1165 struct clknode *clknode; 1166 1167 CLK_TOPO_SLOCK(); 1168 clknode = clknode_find_by_name(name); 1169 if (clknode == NULL) { 1170 CLK_TOPO_UNLOCK(); 1171 return (ENODEV); 1172 } 1173 *clk = clk_create(clknode, dev); 1174 CLK_TOPO_UNLOCK(); 1175 return (0); 1176} 1177 1178int 1179clk_get_by_id(device_t dev, struct clkdom *clkdom, intptr_t id, clk_t *clk) 1180{ 1181 struct clknode *clknode; 1182 1183 CLK_TOPO_SLOCK(); 1184 1185 clknode = clknode_find_by_id(clkdom, id); 1186 if (clknode == NULL) { 1187 CLK_TOPO_UNLOCK(); 1188 return (ENODEV); 1189 } 1190 *clk = clk_create(clknode, dev); 1191 CLK_TOPO_UNLOCK(); 1192 1193 return (0); 1194} 1195 1196#ifdef FDT 1197 1198int 1199clk_get_by_ofw_index(device_t dev, phandle_t cnode, int idx, clk_t *clk) 1200{ 1201 phandle_t parent, *cells; 1202 device_t clockdev; 1203 int ncells, rv; 1204 struct clkdom *clkdom; 1205 struct clknode *clknode; 1206 1207 *clk = NULL; 1208 if (cnode <= 0) 1209 cnode = ofw_bus_get_node(dev); 1210 if (cnode <= 0) { 1211 device_printf(dev, "%s called on not ofw based device\n", 1212 __func__); 1213 return (ENXIO); 1214 } 1215 1216 1217 rv = ofw_bus_parse_xref_list_alloc(cnode, "clocks", "#clock-cells", idx, 1218 &parent, &ncells, &cells); 1219 if (rv != 0) { 1220 return (rv); 1221 } 1222 1223 clockdev = OF_device_from_xref(parent); 1224 if (clockdev == NULL) { 1225 rv = ENODEV; 1226 goto done; 1227 } 1228 1229 CLK_TOPO_SLOCK(); 1230 clkdom = clkdom_get_by_dev(clockdev); 1231 if (clkdom == NULL){ 1232 CLK_TOPO_UNLOCK(); 1233 rv = ENXIO; 1234 goto done; 1235 } 1236 1237 rv = clkdom->ofw_mapper(clkdom, ncells, cells, &clknode); 1238 if (rv == 0) { 1239 *clk = clk_create(clknode, dev); 1240 } 1241 CLK_TOPO_UNLOCK(); 1242 1243done: 1244 if (cells != NULL) 1245 OF_prop_free(cells); 1246 return (rv); 1247} 1248 1249int 1250clk_get_by_ofw_name(device_t dev, phandle_t cnode, const char *name, clk_t *clk) 1251{ 1252 int rv, idx; 1253 1254 if (cnode <= 0) 1255 cnode = ofw_bus_get_node(dev); 1256 if (cnode <= 0) { 1257 device_printf(dev, "%s called on not ofw based device\n", 1258 __func__); 1259 return (ENXIO); 1260 } 1261 rv = ofw_bus_find_string_index(cnode, "clock-names", name, &idx); 1262 if (rv != 0) 1263 return (rv); 1264 return (clk_get_by_ofw_index(dev, cnode, idx, clk)); 1265} 1266 1267/* -------------------------------------------------------------------------- 1268 * 1269 * Support functions for parsing various clock related OFW things. 1270 */ 1271 1272/* 1273 * Get "clock-output-names" and (optional) "clock-indices" lists. 1274 * Both lists are alocated using M_OFWPROP specifier. 1275 * 1276 * Returns number of items or 0. 1277 */ 1278int 1279clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names, 1280 uint32_t **indices) 1281{ 1282 int name_items, rv; 1283 1284 *out_names = NULL; 1285 *indices = NULL; 1286 if (!OF_hasprop(node, "clock-output-names")) 1287 return (0); 1288 rv = ofw_bus_string_list_to_array(node, "clock-output-names", 1289 out_names); 1290 if (rv <= 0) 1291 return (0); 1292 name_items = rv; 1293 1294 if (!OF_hasprop(node, "clock-indices")) 1295 return (name_items); 1296 rv = OF_getencprop_alloc(node, "clock-indices", sizeof (uint32_t), 1297 (void **)indices); 1298 if (rv != name_items) { 1299 device_printf(dev, " Size of 'clock-output-names' and " 1300 "'clock-indices' differs\n"); 1301 OF_prop_free(*out_names); 1302 OF_prop_free(*indices); 1303 return (0); 1304 } 1305 return (name_items); 1306} 1307 1308/* 1309 * Get output clock name for single output clock node. 1310 */ 1311int 1312clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name) 1313{ 1314 const char **out_names; 1315 const char *tmp_name; 1316 int rv; 1317 1318 *name = NULL; 1319 if (!OF_hasprop(node, "clock-output-names")) { 1320 tmp_name = ofw_bus_get_name(dev); 1321 if (tmp_name == NULL) 1322 return (ENXIO); 1323 *name = strdup(tmp_name, M_OFWPROP); 1324 return (0); 1325 } 1326 rv = ofw_bus_string_list_to_array(node, "clock-output-names", 1327 &out_names); 1328 if (rv != 1) { 1329 OF_prop_free(out_names); 1330 device_printf(dev, "Malformed 'clock-output-names' property\n"); 1331 return (ENXIO); 1332 } 1333 *name = strdup(out_names[0], M_OFWPROP); 1334 OF_prop_free(out_names); 1335 return (0); 1336} 1337#endif 1338