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