1 /* 2 * Common clock functionality. 3 * 4 * Copyright (C) 2023, 2024 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/hw_mmio_register_block.h> 23 24 #include "cpm-common.h" 25 #include <math.h> 26 #include <stdio.h> 27 28 29 30 // Register access. 31 32 Cpm_regs::Cpm_regs(l4_addr_t addr, Clock_base *clocks[]) 33 : _clocks(clocks) 34 { 35 _regs = new Hw::Mmio_register_block<32>(addr); 36 } 37 38 // Utility methods. 39 40 uint32_t 41 Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 42 { 43 return (_regs[reg] & (mask << shift)) >> shift; 44 } 45 46 void 47 Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 48 { 49 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 50 } 51 52 Clock_base * 53 Cpm_regs::get_clock(int num) 54 { 55 return _clocks[num]; 56 } 57 58 59 60 // Field methods. 61 62 uint32_t 63 Field::get_field(Cpm_regs ®s) 64 { 65 if (defined) 66 { 67 // With an encoding table, use the encoded value as index to obtain the 68 // genuine value. 69 70 if (table != NULL) 71 return table[regs.get_field(reg, mask, bit)]; 72 else 73 return regs.get_field(reg, mask, bit) + adjustment; 74 } 75 else 76 return 0; 77 } 78 79 void 80 Field::set_field(Cpm_regs ®s, uint32_t value) 81 { 82 if (defined) 83 { 84 // With an encoding table, find the index of the presented value. 85 86 if (table != NULL) 87 { 88 for (uint32_t i = 0; i < mask; i++) 89 if (table[i] == value) 90 regs.set_field(reg, mask, bit, i); 91 } 92 else 93 regs.set_field(reg, mask, bit, value >= adjustment ? value - adjustment : 0); 94 } 95 } 96 97 // Undefined field. 98 99 Field Field::undefined; 100 101 102 103 // Clock sources. 104 105 enum Clock_identifiers 106 Mux::get_input(int num) 107 { 108 if (num < _num_inputs) 109 return _inputs[num]; 110 else 111 return Clock_none; 112 } 113 114 115 116 // Clock sources. 117 118 uint8_t 119 Source::get_source(Cpm_regs ®s) 120 { 121 if (_source.is_defined()) 122 return _source.get_field(regs); 123 else 124 return 0; 125 } 126 127 void 128 Source::set_source(Cpm_regs ®s, uint8_t source) 129 { 130 if (!_source.is_defined()) 131 return; 132 133 _source.set_field(regs, source); 134 } 135 136 enum Clock_identifiers 137 Source::get_source_clock(Cpm_regs ®s) 138 { 139 return get_input(get_number() == 1 ? 0 : get_source(regs)); 140 } 141 142 void 143 Source::set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock) 144 { 145 for (int source = 0; source < _inputs.get_number(); source++) 146 if (get_input(source) == clock) 147 _source.set_field(regs, source); 148 } 149 150 // Clock source frequencies. 151 152 uint64_t 153 Source::get_frequency(Cpm_regs ®s) 154 { 155 enum Clock_identifiers input = get_source_clock(regs); 156 157 if (input != Clock_none) 158 return regs.get_clock(input)->get_frequency(regs); 159 else 160 return 0; 161 } 162 163 164 165 // Clock control. 166 167 Control_base::~Control_base() 168 { 169 } 170 171 void 172 Control_base::change_disable(Cpm_regs ®s) 173 { 174 (void) regs; 175 } 176 177 void 178 Control_base::change_enable(Cpm_regs ®s) 179 { 180 (void) regs; 181 } 182 183 int 184 Control::have_clock(Cpm_regs ®s) 185 { 186 bool enabled_via_gate, enabled_via_stop; 187 188 if (_gate.is_defined()) 189 enabled_via_gate = _gate.get_field(regs) == _gate.get_asserted(); 190 else 191 enabled_via_gate = true; 192 193 if (_stop.is_defined()) 194 enabled_via_stop = _stop.get_field(regs) == _stop.get_asserted(); 195 else 196 enabled_via_stop = true; 197 198 return enabled_via_gate && enabled_via_stop; 199 } 200 201 void 202 Control::start_clock(Cpm_regs ®s) 203 { 204 if (_gate.is_defined()) 205 _gate.set_field(regs, _gate.get_asserted()); 206 207 if (_stop.is_defined()) 208 _stop.set_field(regs, _stop.get_asserted()); 209 } 210 211 void 212 Control::stop_clock(Cpm_regs ®s) 213 { 214 if (_gate.is_defined()) 215 _gate.set_field(regs, _gate.get_deasserted()); 216 217 if (_stop.is_defined()) 218 _stop.set_field(regs, _stop.get_deasserted()); 219 } 220 221 void 222 Control::wait_busy(Cpm_regs ®s) 223 { 224 if (_busy.is_defined()) 225 while (_busy.get_field(regs)); 226 } 227 228 void 229 Control::change_disable(Cpm_regs ®s) 230 { 231 if (_change_enable.is_defined()) 232 _change_enable.set_field(regs, 0); 233 } 234 235 void 236 Control::change_enable(Cpm_regs ®s) 237 { 238 if (_change_enable.is_defined()) 239 _change_enable.set_field(regs, 1); 240 } 241 242 // Undefined control. 243 244 Control Control::undefined; 245 246 247 248 // PLL-specific control. 249 250 int 251 Control_pll::have_pll(Cpm_regs ®s) 252 { 253 return _stable.get_field(regs); 254 } 255 256 int 257 Control_pll::pll_enabled(Cpm_regs ®s) 258 { 259 return _enable.get_field(regs); 260 } 261 262 int 263 Control_pll::pll_bypassed(Cpm_regs ®s) 264 { 265 return _bypass.get_field(regs); 266 } 267 268 void 269 Control_pll::pll_bypass(Cpm_regs ®s) 270 { 271 _bypass.set_field(regs, 1); 272 } 273 274 void 275 Control_pll::pll_engage(Cpm_regs ®s) 276 { 277 _bypass.set_field(regs, 0); 278 } 279 280 // Clock control. 281 282 int 283 Control_pll::have_clock(Cpm_regs ®s) 284 { 285 return have_pll(regs) && pll_enabled(regs); 286 } 287 288 void 289 Control_pll::start_clock(Cpm_regs ®s) 290 { 291 _enable.set_field(regs, 1); 292 while (!have_pll(regs)); 293 } 294 295 void 296 Control_pll::stop_clock(Cpm_regs ®s) 297 { 298 _enable.set_field(regs, 0); 299 while (have_pll(regs)); 300 } 301 302 void 303 Control_pll::wait_busy(Cpm_regs ®s) 304 { 305 // NOTE: Could wait for some kind of stable or "lock" signal, but the chips 306 // provide all sorts of differing signals. 307 308 (void) regs; 309 } 310 311 void 312 Control_pll::change_disable(Cpm_regs ®s) 313 { 314 if (_enabled) 315 start_clock(regs); 316 } 317 318 void 319 Control_pll::change_enable(Cpm_regs ®s) 320 { 321 // NOTE: Since the X1600 manual warns of changing the frequency while enabled, 322 // it is easier to just stop and then start the PLL again. 323 324 _enabled = have_clock(regs); 325 326 if (_enabled) 327 stop_clock(regs); 328 } 329 330 331 332 // Clock dividers. 333 334 Divider_base::~Divider_base() 335 { 336 } 337 338 339 340 // Fixed divider. 341 342 uint64_t 343 Divider_fixed::get_frequency(Cpm_regs ®s, uint64_t source_frequency) 344 { 345 (void) regs; 346 return source_frequency / _value; 347 } 348 349 int 350 Divider_fixed::set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency) 351 { 352 (void) regs; (void) source_frequency; (void) frequency; 353 return 0; 354 } 355 356 int 357 Divider_fixed::get_parameters(Cpm_regs ®s, uint32_t parameters[]) 358 { 359 (void) regs; 360 parameters[0] = _value; 361 return 1; 362 } 363 364 int 365 Divider_fixed::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) 366 { 367 (void) regs; (void) num_parameters; (void) parameters; 368 return 0; 369 } 370 371 372 373 // Simple divider for regular clocks. 374 375 uint32_t 376 Divider::get_divider(Cpm_regs ®s) 377 { 378 if (_divider.is_defined()) 379 return _scale * (_divider.get_field(regs) + 1); 380 else 381 return 1; 382 } 383 384 void 385 Divider::set_divider(Cpm_regs ®s, uint32_t divider) 386 { 387 if (_divider.is_defined()) 388 _divider.set_field(regs, divider / _scale - 1); 389 } 390 391 // Output clock frequencies. 392 393 uint64_t 394 Divider::get_frequency(Cpm_regs ®s, uint64_t source_frequency) 395 { 396 return source_frequency / get_divider(regs); 397 } 398 399 int 400 Divider::set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency) 401 { 402 set_divider(regs, (uint32_t) round((double) source_frequency / (double) frequency)); 403 return 1; 404 } 405 406 int 407 Divider::get_parameters(Cpm_regs ®s, uint32_t parameters[]) 408 { 409 parameters[0] = get_divider(regs); 410 return 1; 411 } 412 413 int 414 Divider::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) 415 { 416 if (num_parameters) 417 { 418 set_divider(regs, parameters[0]); 419 return 1; 420 } 421 422 return 0; 423 } 424 425 426 427 // Common divider functionality. 428 429 static int is_integer(double x) 430 { 431 double target = round(x) * 1000; 432 double rounded = floor(x * 1000); 433 434 return (target - 100 < rounded) && (rounded < target + 100); 435 } 436 437 static double getscale_part(double x) 438 { 439 double part = x - floor(x); 440 441 if (part > 0.5) 442 return 1 / (1 - part); 443 else if (part > 0) 444 return 1 / part; 445 else 446 return 1; 447 } 448 449 static double getscale(double x) 450 { 451 double scale = getscale_part(x); 452 453 if (is_integer(scale)) 454 return scale; 455 else 456 return scale * getscale(scale); 457 } 458 459 static void get_divider_operands(double frequency, double source_frequency, 460 double *multiplier, double *divider) 461 { 462 double ratio = frequency / source_frequency; 463 double scale = getscale(ratio); 464 465 *multiplier = scale * ratio; 466 *divider = scale; 467 } 468 469 static void reduce_divider_operands(uint32_t *m, uint32_t *n, uint32_t m_limit, 470 uint32_t n_limit) 471 { 472 while ((*m > m_limit) && (*n > n_limit) && (*m > 1) && (*n > 1)) 473 { 474 *m >>= 1; 475 *n >>= 1; 476 } 477 } 478 479 480 481 #define zero_as_one(X) ((X) ? (X) : 1) 482 483 // Feedback multiplier. 484 485 uint32_t 486 Divider_pll::get_multiplier(Cpm_regs ®s) 487 { 488 return zero_as_one(_multiplier.get_field(regs)); 489 } 490 491 void 492 Divider_pll::set_multiplier(Cpm_regs ®s, uint32_t multiplier) 493 { 494 _multiplier.set_field(regs, multiplier); 495 } 496 497 // Input divider. 498 499 uint32_t 500 Divider_pll::get_input_divider(Cpm_regs ®s) 501 { 502 return zero_as_one(_input_divider.get_field(regs)); 503 } 504 505 void 506 Divider_pll::set_input_divider(Cpm_regs ®s, uint32_t divider) 507 { 508 _input_divider.set_field(regs, divider); 509 } 510 511 // Output dividers. 512 513 uint32_t 514 Divider_pll::get_output_divider(Cpm_regs ®s) 515 { 516 uint32_t d0, d1; 517 518 d0 = zero_as_one(_output_divider0.get_field(regs)); 519 d1 = _output_divider1.is_defined() ? 520 zero_as_one(_output_divider1.get_field(regs)) : 1; 521 522 return d0 * d1; 523 } 524 525 void 526 Divider_pll::set_output_divider(Cpm_regs ®s, uint32_t divider) 527 { 528 uint32_t d0, d1; 529 530 // Assert 1 as a minimum. 531 532 if (!divider) 533 divider = 1; 534 535 // Attempt to set any single divider. 536 537 if (!_output_divider1.is_defined()) 538 { 539 _output_divider0.set_field(regs, divider); 540 return; 541 } 542 543 // For two-divider implementations such as the X1600, divider 0 must be less 544 // than or equal to divider 1. 545 546 if (divider < _output_divider1.get_limit()) 547 { 548 d0 = 1; 549 d1 = divider; 550 } 551 else 552 { 553 d0 = (uint32_t) floor(sqrt(divider)); 554 d1 = divider / d0; 555 } 556 557 _output_divider0.set_field(regs, d0); 558 _output_divider1.set_field(regs, d1); 559 } 560 561 uint64_t 562 Divider_pll::get_frequency(Cpm_regs ®s, uint64_t source_frequency) 563 { 564 return (source_frequency * get_multiplier(regs)) / 565 (get_input_divider(regs) * get_output_divider(regs)); 566 } 567 568 int 569 Divider_pll::set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency) 570 { 571 double intermediate_multiplier, intermediate_input_divider; 572 uint32_t output_min, output_max, output0, output1; 573 uint32_t multiplier, input_divider, output_divider; 574 575 // Define the range for the output dividers using the intermediate frequency 576 // range applying to each chip, this being the result of the multiplier and 577 // input divider. 578 579 output_min = (uint32_t) ceil(_intermediate_min / frequency); 580 output_max = (uint32_t) floor(_intermediate_max / frequency); 581 582 // Distribute the divider across the input and output dividers. 583 584 output_divider = output_min; 585 586 while (output_divider <= output_max) 587 { 588 bool usable_divider; 589 590 // Test divider constraints. 591 592 if (_output_divider1.is_defined()) 593 { 594 output0 = (uint32_t) floor(sqrt(output_divider)); 595 output1 = (uint32_t) floor(output_divider / output0); 596 597 usable_divider = ((output0 * output1 == output_divider) && 598 (output0 <= _output_divider0.get_limit()) && 599 (output1 <= _output_divider1.get_limit())); 600 } 601 else 602 usable_divider = output_divider <= _output_divider0.get_limit(); 603 604 // Apply any usable divider. 605 606 if (usable_divider) 607 { 608 // Calculate the other parameters. Start by working back from the desired 609 // output frequency to obtain an intermediate frequency using the proposed 610 // divider. 611 612 double intermediate_frequency = frequency * output_divider; 613 614 // Calculate the required multiplier and divider. 615 616 get_divider_operands(intermediate_frequency, source_frequency, 617 &intermediate_multiplier, &intermediate_input_divider); 618 619 multiplier = (uint32_t) round(intermediate_multiplier); 620 input_divider = (uint32_t) round(intermediate_input_divider); 621 622 // Attempt to reduce the multiplier and divider to usable values. 623 624 uint32_t multiplier_limit = _multiplier.get_limit(); 625 uint32_t input_divider_limit = _input_divider.get_limit(); 626 627 reduce_divider_operands(&multiplier, &input_divider, 628 multiplier_limit, input_divider_limit); 629 630 if ((multiplier <= multiplier_limit) && (input_divider <= input_divider_limit)) 631 { 632 set_multiplier(regs, multiplier); 633 set_input_divider(regs, input_divider); 634 set_output_divider(regs, output_divider); 635 636 return 1; 637 } 638 } 639 640 output_divider++; 641 } 642 643 return 0; 644 } 645 646 int 647 Divider_pll::get_parameters(Cpm_regs ®s, uint32_t parameters[]) 648 { 649 parameters[0] = get_multiplier(regs); 650 parameters[1] = get_input_divider(regs); 651 parameters[2] = get_output_divider(regs); 652 return 3; 653 } 654 655 int 656 Divider_pll::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) 657 { 658 if (num_parameters > 2) 659 { 660 set_multiplier(regs, parameters[0]); 661 set_input_divider(regs, parameters[1]); 662 set_output_divider(regs, parameters[2]); 663 664 return 3; 665 } 666 667 return 0; 668 } 669 670 671 672 // I2S clock divider. 673 674 uint32_t 675 Divider_i2s::get_multiplier(Cpm_regs ®s) 676 { 677 return _multiplier.get_field(regs); 678 } 679 680 uint32_t 681 Divider_i2s::get_divider_N(Cpm_regs ®s) 682 { 683 return _divider_N.get_field(regs); 684 } 685 686 uint32_t 687 Divider_i2s::get_divider_D(Cpm_regs ®s) 688 { 689 return _divider_D.get_field(regs); 690 } 691 692 uint64_t 693 Divider_i2s::get_frequency(Cpm_regs ®s, uint64_t source_frequency) 694 { 695 /* NOTE: Assuming that this is the formula, given that the manual does not 696 really describe how D is used. */ 697 698 return (source_frequency * get_multiplier(regs)) / 699 (get_divider_N(regs) * get_divider_D(regs)); 700 } 701 702 int 703 Divider_i2s::set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency) 704 { 705 double m, n; 706 707 get_divider_operands(frequency, source_frequency, &m, &n); 708 709 uint32_t multiplier = (uint32_t) round(m); 710 uint32_t divider = (uint32_t) round(n); 711 712 reduce_divider_operands(&multiplier, ÷r, 713 _multiplier.get_limit(), 714 _divider_N.get_limit()); 715 716 // Test for operand within limits and the N >= 2M constraint. 717 718 if ((multiplier <= _multiplier.get_limit()) && (divider <= _divider_N.get_limit()) && 719 (divider >= 2 * multiplier)) 720 { 721 /* NOTE: Setting D to 1. Even though it seems that D might also be used, 722 it does not seem necessary in practice, and the documentation is 723 unclear about its use. */ 724 725 uint32_t parameters[] = {multiplier, divider, 1}; 726 727 set_parameters(regs, 3, parameters); 728 return 1; 729 } 730 731 return 0; 732 } 733 734 int 735 Divider_i2s::get_parameters(Cpm_regs ®s, uint32_t parameters[]) 736 { 737 parameters[0] = get_multiplier(regs); 738 parameters[1] = get_divider_N(regs); 739 parameters[2] = get_divider_D(regs); 740 return 3; 741 } 742 743 int 744 Divider_i2s::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) 745 { 746 if (num_parameters == 1) 747 { 748 // Set automatic N and D value calculation if only one parameter is given. 749 750 _auto_N.set_field(regs, 0); 751 _auto_D.set_field(regs, 0); 752 _multiplier.set_field(regs, parameters[0]); 753 754 return 1; 755 } 756 else if (num_parameters > 1) 757 { 758 // Require N >= 2M, returning otherwise. 759 760 if (parameters[1] < 2 * parameters[0]) 761 return 0; 762 763 // Set automatic D value calculation if only two parameters are given. 764 765 _auto_N.set_field(regs, 1); 766 _auto_D.set_field(regs, (num_parameters == 2) ? 0 : 1); 767 768 _multiplier.set_field(regs, parameters[0]); 769 _divider_N.set_field(regs, parameters[1]); 770 771 // Set D explicitly if given. 772 773 if (num_parameters > 2) 774 _divider_D.set_field(regs, parameters[2]); 775 776 return num_parameters; 777 } 778 779 return 0; 780 } 781 782 783 784 // Clock interface. 785 786 Clock_base::~Clock_base() 787 { 788 } 789 790 791 792 // Null clock. 793 794 int 795 Clock_null::have_clock(Cpm_regs ®s) 796 { 797 (void) regs; 798 return false; 799 } 800 801 void 802 Clock_null::start_clock(Cpm_regs ®s) 803 { 804 (void) regs; 805 } 806 807 void 808 Clock_null::stop_clock(Cpm_regs ®s) 809 { 810 (void) regs; 811 } 812 813 // Output clock frequencies. 814 815 uint64_t 816 Clock_null::get_frequency(Cpm_regs ®s) 817 { 818 (void) regs; 819 return 0; 820 } 821 822 823 824 // Passive clock. 825 826 int 827 Clock_passive::have_clock(Cpm_regs ®s) 828 { 829 (void) regs; 830 return true; 831 } 832 833 void 834 Clock_passive::start_clock(Cpm_regs ®s) 835 { 836 (void) regs; 837 } 838 839 void 840 Clock_passive::stop_clock(Cpm_regs ®s) 841 { 842 (void) regs; 843 } 844 845 // Output clock frequencies. 846 847 uint64_t 848 Clock_passive::get_frequency(Cpm_regs ®s) 849 { 850 (void) regs; 851 return _frequency; 852 } 853 854 855 856 // Clock control. 857 858 int 859 Clock_controlled::have_clock(Cpm_regs ®s) 860 { 861 return _get_control().have_clock(regs); 862 } 863 864 void 865 Clock_controlled::start_clock(Cpm_regs ®s) 866 { 867 _get_control().start_clock(regs); 868 } 869 870 void 871 Clock_controlled::stop_clock(Cpm_regs ®s) 872 { 873 _get_control().stop_clock(regs); 874 } 875 876 877 878 // Active clock interface. 879 880 Clock_active::~Clock_active() 881 { 882 } 883 884 // Clock sources. 885 886 uint8_t 887 Clock_active::get_source(Cpm_regs ®s) 888 { 889 return _source.get_source(regs); 890 } 891 892 void 893 Clock_active::set_source(Cpm_regs ®s, uint8_t source) 894 { 895 _get_control().change_enable(regs); 896 _source.set_source(regs, source); 897 _get_control().wait_busy(regs); 898 _get_control().change_disable(regs); 899 } 900 901 enum Clock_identifiers 902 Clock_active::get_source_clock(Cpm_regs ®s) 903 { 904 return _source.get_source_clock(regs); 905 } 906 907 void 908 Clock_active::set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock) 909 { 910 _source.set_source_clock(regs, clock); 911 } 912 913 // Clock source frequencies. 914 915 uint64_t 916 Clock_active::get_source_frequency(Cpm_regs ®s) 917 { 918 return _source.get_frequency(regs); 919 } 920 921 // Output clock frequencies. 922 923 uint64_t 924 Clock_active::get_frequency(Cpm_regs ®s) 925 { 926 return get_source_frequency(regs); 927 } 928 929 930 931 // Divided clock interface. 932 933 Clock_divided_base::~Clock_divided_base() 934 { 935 } 936 937 // Output clock frequencies. 938 939 uint64_t 940 Clock_divided_base::get_frequency(Cpm_regs ®s) 941 { 942 return _get_divider().get_frequency(regs, get_source_frequency(regs)); 943 } 944 945 int 946 Clock_divided_base::set_frequency(Cpm_regs ®s, uint64_t frequency) 947 { 948 _get_control().change_enable(regs); 949 int result = _get_divider().set_frequency(regs, get_source_frequency(regs), frequency); 950 _get_control().wait_busy(regs); 951 _get_control().change_disable(regs); 952 953 return result; 954 } 955 956 int 957 Clock_divided_base::get_parameters(Cpm_regs ®s, uint32_t parameters[]) 958 { 959 return _get_divider().get_parameters(regs, parameters); 960 } 961 962 int 963 Clock_divided_base::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) 964 { 965 _get_control().change_enable(regs); 966 int n = _get_divider().set_parameters(regs, num_parameters, parameters); 967 _get_control().wait_busy(regs); 968 _get_control().change_disable(regs); 969 970 return n; 971 } 972 973 974 975 // PLL functionality. 976 977 Pll::~Pll() 978 { 979 } 980 981 uint64_t 982 Pll::get_frequency(Cpm_regs ®s) 983 { 984 if (!_control.pll_bypassed(regs)) 985 return _divider.get_frequency(regs, get_source_frequency(regs)); 986 else 987 return get_source_frequency(regs); 988 } 989 990 int 991 Pll::set_frequency(Cpm_regs ®s, uint64_t frequency) 992 { 993 int result = Clock_divided_base::set_frequency(regs, frequency); 994 _control.pll_engage(regs); 995 996 return result; 997 }