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