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 #pragma once 23 24 #ifdef __cplusplus 25 26 #include <l4/devices/clocks.h> 27 #include <l4/devices/hw_register_block.h> 28 #include <l4/sys/types.h> 29 #include <stdint.h> 30 31 /* Forward declaration. */ 32 33 class Clock_base; 34 35 36 37 /* Register access type. */ 38 39 class Cpm_regs 40 { 41 protected: 42 Hw::Register_block<32> _regs; 43 Clock_base **_clocks; 44 45 public: 46 explicit Cpm_regs(l4_addr_t addr, Clock_base *clocks[]); 47 48 // Utility methods. 49 50 uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); 51 void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); 52 53 Clock_base *get_clock(int num); 54 }; 55 56 57 58 // Register field abstraction. 59 60 class Field 61 { 62 uint32_t reg; 63 uint32_t mask; 64 uint8_t bit; 65 bool defined; 66 uint32_t _asserted = 0, _deasserted = 0; 67 68 public: 69 explicit Field() 70 : defined(false) 71 { 72 } 73 74 explicit Field(uint32_t reg, uint32_t mask, uint32_t bit, 75 bool inverted = false) 76 : reg(reg), mask(mask), bit(bit), defined(true) 77 { 78 if (inverted) 79 _deasserted = mask; 80 else 81 _asserted = mask; 82 } 83 84 uint32_t get_field(Cpm_regs ®s); 85 void set_field(Cpm_regs ®s, uint32_t value); 86 87 uint32_t get_asserted() { return _asserted; } 88 uint32_t get_deasserted() { return _deasserted; } 89 90 bool is_defined() { return defined; } 91 uint32_t get_limit() { return mask; } 92 93 // Undefined field object. 94 95 static Field undefined; 96 }; 97 98 99 100 // Clock sources. 101 102 class Mux 103 { 104 int _num_inputs; 105 enum Clock_identifiers *_inputs, _input; 106 107 public: 108 explicit Mux(int num_inputs, enum Clock_identifiers inputs[]) 109 : _num_inputs(num_inputs), _inputs(inputs) 110 { 111 } 112 113 explicit Mux(enum Clock_identifiers input) 114 : _num_inputs(1), _inputs(&_input) 115 { 116 _input = input; 117 } 118 119 explicit Mux() 120 : _num_inputs(0), _inputs(NULL) 121 { 122 } 123 124 int get_number() { return _num_inputs; } 125 enum Clock_identifiers get_input(int num); 126 }; 127 128 129 130 // Controllable clock source. 131 132 class Source 133 { 134 Mux _inputs; 135 Field _source; 136 137 public: 138 explicit Source(Mux inputs, Field source) 139 : _inputs(inputs), _source(source) 140 { 141 } 142 143 explicit Source(Mux inputs) 144 : _inputs(inputs) 145 { 146 } 147 148 explicit Source() 149 { 150 } 151 152 int get_number() { return _inputs.get_number(); } 153 enum Clock_identifiers get_input(int num) { return _inputs.get_input(num); } 154 155 // Clock source. 156 157 uint8_t get_source(Cpm_regs ®s); 158 void set_source(Cpm_regs ®s, uint8_t source); 159 enum Clock_identifiers get_source_clock(Cpm_regs ®s); 160 void set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock); 161 162 // Clock source frequency. 163 164 uint64_t get_frequency(Cpm_regs ®s); 165 }; 166 167 168 169 // Common clock control. 170 171 class Control_base 172 { 173 public: 174 virtual ~Control_base(); 175 176 virtual void change_disable(Cpm_regs ®s); 177 virtual void change_enable(Cpm_regs ®s); 178 179 virtual void wait_busy(Cpm_regs ®s) = 0; 180 virtual int have_clock(Cpm_regs ®s) = 0; 181 virtual void start_clock(Cpm_regs ®s) = 0; 182 virtual void stop_clock(Cpm_regs ®s) = 0; 183 }; 184 185 186 187 // Clock control. 188 189 class Control : public Control_base 190 { 191 Field _gate, _change_enable, _busy; 192 193 public: 194 explicit Control(Field gate, 195 Field change_enable = Field::undefined, 196 Field busy = Field::undefined) 197 : _gate(gate), _change_enable(change_enable), _busy(busy) 198 { 199 } 200 201 explicit Control() 202 : _gate(Field::undefined), _change_enable(Field::undefined), 203 _busy(Field::undefined) 204 { 205 } 206 207 // Clock control. 208 209 void change_disable(Cpm_regs ®s); 210 void change_enable(Cpm_regs ®s); 211 212 void wait_busy(Cpm_regs ®s); 213 int have_clock(Cpm_regs ®s); 214 void start_clock(Cpm_regs ®s); 215 void stop_clock(Cpm_regs ®s); 216 217 // Undefined control object. 218 219 static Control undefined; 220 }; 221 222 223 224 // PLL control. 225 226 class Control_pll : public Control_base 227 { 228 Field _enable, _stable, _bypass; 229 230 // Frequency change sequence state. 231 232 bool _enabled = false; 233 234 // PLL_specific control. 235 236 int have_pll(Cpm_regs ®s); 237 int pll_enabled(Cpm_regs ®s); 238 239 public: 240 explicit Control_pll(Field enable, Field stable, Field bypass) 241 : _enable(enable), _stable(stable), _bypass(bypass) 242 { 243 } 244 245 // Clock control. 246 247 int pll_bypassed(Cpm_regs ®s); 248 249 void pll_bypass(Cpm_regs ®s); 250 void pll_engage(Cpm_regs ®s); 251 252 void change_disable(Cpm_regs ®s); 253 void change_enable(Cpm_regs ®s); 254 255 void wait_busy(Cpm_regs ®s); 256 int have_clock(Cpm_regs ®s); 257 void start_clock(Cpm_regs ®s); 258 void stop_clock(Cpm_regs ®s); 259 }; 260 261 262 263 // Frequency transformation. 264 265 class Divider_base 266 { 267 public: 268 virtual ~Divider_base(); 269 270 // Output frequency. 271 272 virtual uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency) = 0; 273 virtual int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency) = 0; 274 275 // Other operations. 276 277 virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]) = 0; 278 virtual int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) = 0; 279 }; 280 281 282 283 // Fixed divider. 284 285 class Divider_fixed : public Divider_base 286 { 287 uint32_t _value; 288 289 public: 290 explicit Divider_fixed(uint32_t value) 291 : _value(value) 292 { 293 } 294 295 // Output frequency. 296 297 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 298 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 299 300 // Other operations. 301 302 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 303 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 304 }; 305 306 307 308 // Simple divider for regular clocks. 309 310 class Divider : public Divider_base 311 { 312 Field _divider; 313 314 public: 315 explicit Divider(Field divider) 316 : _divider(divider) 317 { 318 } 319 320 explicit Divider() 321 : _divider(Field::undefined) 322 { 323 } 324 325 // Clock divider. 326 327 uint32_t get_divider(Cpm_regs ®s); 328 void set_divider(Cpm_regs ®s, uint32_t divider); 329 330 // Output frequency. 331 332 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 333 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 334 335 // Other operations. 336 337 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 338 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 339 }; 340 341 342 343 // Divider for PLLs. 344 345 class Divider_pll : public Divider_base 346 { 347 Field _multiplier, _input_divider, _output_divider0, _output_divider1; 348 double _intermediate_min, _intermediate_max; 349 bool _adjust_by_one; 350 351 // General frequency modifiers. 352 353 uint32_t get_multiplier(Cpm_regs ®s); 354 void set_multiplier(Cpm_regs ®s, uint32_t multiplier); 355 uint32_t get_input_divider(Cpm_regs ®s); 356 void set_input_divider(Cpm_regs ®s, uint32_t divider); 357 uint32_t get_output_divider(Cpm_regs ®s); 358 void set_output_divider(Cpm_regs ®s, uint32_t divider); 359 360 public: 361 362 // Double output divider constructor. 363 364 explicit Divider_pll(Field multiplier, Field input_divider, 365 Field output_divider0, Field output_divider1, 366 double intermediate_min, double intermediate_max, 367 bool adjust_by_one) 368 : _multiplier(multiplier), _input_divider(input_divider), 369 _output_divider0(output_divider0), _output_divider1(output_divider1), 370 _intermediate_min(intermediate_min), _intermediate_max(intermediate_max), 371 _adjust_by_one(adjust_by_one) 372 { 373 } 374 375 // Single output divider constructor. 376 377 explicit Divider_pll(Field multiplier, Field input_divider, 378 Field output_divider, 379 double intermediate_min, double intermediate_max, 380 bool adjust_by_one) 381 : _multiplier(multiplier), _input_divider(input_divider), 382 _output_divider0(output_divider), _output_divider1(Field::undefined), 383 _intermediate_min(intermediate_min), _intermediate_max(intermediate_max), 384 _adjust_by_one(adjust_by_one) 385 { 386 } 387 388 // Output frequency. 389 390 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 391 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 392 393 // Other operations. 394 395 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 396 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 397 }; 398 399 400 401 // Divider for I2S clocks. 402 403 class Divider_i2s : public Divider_base 404 { 405 Field _multiplier, _divider_N, _divider_D, _auto_N, _auto_D; 406 407 // General frequency modifiers. 408 409 uint32_t get_multiplier(Cpm_regs ®s); 410 uint32_t get_divider_N(Cpm_regs ®s); 411 uint32_t get_divider_D(Cpm_regs ®s); 412 413 public: 414 explicit Divider_i2s(Field multiplier, Field divider_N, Field divider_D, 415 Field auto_N, Field auto_D) 416 : _multiplier(multiplier), _divider_N(divider_N), _divider_D(divider_D), 417 _auto_N(auto_N), _auto_D(auto_D) 418 { 419 } 420 421 // Output frequency. 422 423 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 424 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 425 426 // Other operations. 427 428 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 429 430 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 431 }; 432 433 434 435 // Common clock abstraction. 436 437 class Clock_base 438 { 439 public: 440 virtual ~Clock_base(); 441 442 virtual const char *clock_type() { return "unset"; } 443 444 // Clock control. 445 446 virtual int have_clock(Cpm_regs ®s) = 0; 447 virtual void start_clock(Cpm_regs ®s) = 0; 448 virtual void stop_clock(Cpm_regs ®s) = 0; 449 450 // Output frequency. 451 452 virtual uint64_t get_frequency(Cpm_regs ®s) = 0; 453 }; 454 455 456 457 // Null (absent or undefined) clock abstraction. 458 459 class Clock_null : public Clock_base 460 { 461 public: 462 const char *clock_type() { return "null"; } 463 464 // Clock control. 465 466 int have_clock(Cpm_regs ®s); 467 void start_clock(Cpm_regs ®s); 468 void stop_clock(Cpm_regs ®s); 469 470 // Output frequency. 471 472 uint64_t get_frequency(Cpm_regs ®s); 473 }; 474 475 476 477 // Passive (root or input) clock without any source of its own. 478 479 class Clock_passive : public Clock_base 480 { 481 protected: 482 uint64_t _frequency; 483 484 public: 485 explicit Clock_passive(uint64_t frequency) 486 : _frequency(frequency) 487 { 488 } 489 490 const char *clock_type() { return "passive"; } 491 492 // Clock control. 493 494 virtual int have_clock(Cpm_regs ®s); 495 virtual void start_clock(Cpm_regs ®s); 496 virtual void stop_clock(Cpm_regs ®s); 497 498 // Output frequency. 499 500 uint64_t get_frequency(Cpm_regs ®s); 501 }; 502 503 504 505 class Clock_controlled : public Clock_base 506 { 507 protected: 508 virtual Control_base &_get_control() = 0; 509 510 public: 511 512 // Clock control. 513 514 virtual int have_clock(Cpm_regs ®s); 515 virtual void start_clock(Cpm_regs ®s); 516 virtual void stop_clock(Cpm_regs ®s); 517 }; 518 519 520 521 // An actively managed clock with source. 522 523 class Clock_active : public Clock_controlled 524 { 525 protected: 526 Source _source; 527 528 public: 529 explicit Clock_active(Source source) 530 : _source(source) 531 { 532 } 533 534 virtual ~Clock_active(); 535 536 // Clock source. 537 538 virtual uint8_t get_source(Cpm_regs ®s); 539 virtual void set_source(Cpm_regs ®s, uint8_t source); 540 enum Clock_identifiers get_source_clock(Cpm_regs ®s); 541 void set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock); 542 543 // Clock source frequency. 544 545 virtual uint64_t get_source_frequency(Cpm_regs ®s); 546 547 // Output frequency. 548 549 virtual uint64_t get_frequency(Cpm_regs ®s); 550 }; 551 552 553 554 // Divided clock interface. 555 556 class Clock_divided_base : public Clock_active 557 { 558 protected: 559 virtual Divider_base &_get_divider() = 0; 560 561 public: 562 explicit Clock_divided_base(Source source) 563 : Clock_active(source) 564 { 565 } 566 567 virtual ~Clock_divided_base(); 568 569 virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 570 virtual int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 571 572 // Output frequency. 573 574 virtual uint64_t get_frequency(Cpm_regs ®s); 575 virtual int set_frequency(Cpm_regs ®s, uint64_t frequency); 576 }; 577 578 579 580 // PLL description. 581 582 class Pll : public Clock_divided_base 583 { 584 Control_pll _control; 585 Divider_pll _divider; 586 587 virtual Control_base &_get_control() { return _control; } 588 virtual Divider_base &_get_divider() { return _divider; } 589 590 public: 591 explicit Pll(Source source, Control_pll control, Divider_pll divider) 592 : Clock_divided_base(source), _control(control), _divider(divider) 593 { 594 } 595 596 virtual ~Pll(); 597 598 const char *clock_type() { return "pll"; } 599 600 // Output frequency. 601 602 uint64_t get_frequency(Cpm_regs ®s); 603 int set_frequency(Cpm_regs ®s, uint64_t frequency); 604 }; 605 606 607 608 // Plain clock description. 609 610 class Clock : public Clock_active 611 { 612 Control _control; 613 614 virtual Control_base &_get_control() { return _control; } 615 616 public: 617 explicit Clock(Source source, Control control) 618 : Clock_active(source), _control(control) 619 { 620 } 621 622 explicit Clock(Source source) 623 : Clock_active(source) 624 { 625 } 626 627 const char *clock_type() { return "clock"; } 628 }; 629 630 631 632 // Divided clock description. 633 634 class Clock_divided : public Clock_divided_base 635 { 636 Control _control; 637 Divider _divider; 638 639 virtual Control_base &_get_control() { return _control; } 640 virtual Divider_base &_get_divider() { return _divider; } 641 642 public: 643 explicit Clock_divided(Source source, Control control, Divider divider) 644 : Clock_divided_base(source), _control(control), _divider(divider) 645 { 646 } 647 648 explicit Clock_divided(Source source, Divider divider) 649 : Clock_divided_base(source), _control(Control::undefined), _divider(divider) 650 { 651 } 652 653 const char *clock_type() { return "divided"; } 654 }; 655 656 657 658 // Fixed divider clock description. 659 660 class Clock_divided_fixed : public Clock_divided_base 661 { 662 Control _control; 663 Divider_fixed _divider; 664 665 virtual Control_base &_get_control() { return _control; } 666 virtual Divider_base &_get_divider() { return _divider; } 667 668 public: 669 explicit Clock_divided_fixed(Source source, Divider_fixed divider) 670 : Clock_divided_base(source), _control(Control::undefined), _divider(divider) 671 { 672 } 673 674 const char *clock_type() { return "fix_div"; } 675 }; 676 677 678 679 // I2S clock description. 680 681 class Clock_divided_i2s : public Clock_divided_base 682 { 683 Control _control; 684 Divider_i2s _divider; 685 686 virtual Control_base &_get_control() { return _control; } 687 virtual Divider_base &_get_divider() { return _divider; } 688 689 public: 690 explicit Clock_divided_i2s(Source source, Control control, Divider_i2s divider) 691 : Clock_divided_base(source), _control(control), _divider(divider) 692 { 693 } 694 695 const char *clock_type() { return "i2s"; } 696 }; 697 698 #endif /* __cplusplus */