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