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