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 int _scale; 314 315 public: 316 explicit Divider(Field divider, int scale = 1) 317 : _divider(divider), _scale(scale) 318 { 319 } 320 321 explicit Divider() 322 : _divider(Field::undefined), _scale(1) 323 { 324 } 325 326 // Clock divider. 327 328 uint32_t get_divider(Cpm_regs ®s); 329 void set_divider(Cpm_regs ®s, uint32_t divider); 330 331 // Output frequency. 332 333 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 334 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 335 336 // Other operations. 337 338 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 339 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 340 }; 341 342 343 344 // Divider for PLLs. 345 346 class Divider_pll : public Divider_base 347 { 348 Field _multiplier, _input_divider, _output_divider0, _output_divider1; 349 double _intermediate_min, _intermediate_max; 350 bool _adjust_by_one; 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 bool adjust_by_one) 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 _adjust_by_one(adjust_by_one) 373 { 374 } 375 376 // Single output divider constructor. 377 378 explicit Divider_pll(Field multiplier, Field input_divider, 379 Field output_divider, 380 double intermediate_min, double intermediate_max, 381 bool adjust_by_one) 382 : _multiplier(multiplier), _input_divider(input_divider), 383 _output_divider0(output_divider), _output_divider1(Field::undefined), 384 _intermediate_min(intermediate_min), _intermediate_max(intermediate_max), 385 _adjust_by_one(adjust_by_one) 386 { 387 } 388 389 // Output frequency. 390 391 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 392 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 393 394 // Other operations. 395 396 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 397 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 398 }; 399 400 401 402 // Divider for I2S clocks. 403 404 class Divider_i2s : public Divider_base 405 { 406 Field _multiplier, _divider_N, _divider_D, _auto_N, _auto_D; 407 408 // General frequency modifiers. 409 410 uint32_t get_multiplier(Cpm_regs ®s); 411 uint32_t get_divider_N(Cpm_regs ®s); 412 uint32_t get_divider_D(Cpm_regs ®s); 413 414 public: 415 explicit Divider_i2s(Field multiplier, Field divider_N, Field divider_D, 416 Field auto_N, Field auto_D) 417 : _multiplier(multiplier), _divider_N(divider_N), _divider_D(divider_D), 418 _auto_N(auto_N), _auto_D(auto_D) 419 { 420 } 421 422 // Output frequency. 423 424 uint64_t get_frequency(Cpm_regs ®s, uint64_t source_frequency); 425 int set_frequency(Cpm_regs ®s, uint64_t source_frequency, uint64_t frequency); 426 427 // Other operations. 428 429 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 430 431 int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 432 }; 433 434 435 436 // Common clock abstraction. 437 438 class Clock_base 439 { 440 public: 441 virtual ~Clock_base(); 442 443 virtual const char *clock_type() { return "unset"; } 444 445 // Clock control. 446 447 virtual int have_clock(Cpm_regs ®s) = 0; 448 virtual void start_clock(Cpm_regs ®s) = 0; 449 virtual void stop_clock(Cpm_regs ®s) = 0; 450 451 // Output frequency. 452 453 virtual uint64_t get_frequency(Cpm_regs ®s) = 0; 454 }; 455 456 457 458 // Null (absent or undefined) clock abstraction. 459 460 class Clock_null : public Clock_base 461 { 462 public: 463 const char *clock_type() { return "null"; } 464 465 // Clock control. 466 467 int have_clock(Cpm_regs ®s); 468 void start_clock(Cpm_regs ®s); 469 void stop_clock(Cpm_regs ®s); 470 471 // Output frequency. 472 473 uint64_t get_frequency(Cpm_regs ®s); 474 }; 475 476 477 478 // Passive (root or input) clock without any source of its own. 479 480 class Clock_passive : public Clock_base 481 { 482 protected: 483 uint64_t _frequency; 484 485 public: 486 explicit Clock_passive(uint64_t frequency) 487 : _frequency(frequency) 488 { 489 } 490 491 const char *clock_type() { return "passive"; } 492 493 // Clock control. 494 495 virtual int have_clock(Cpm_regs ®s); 496 virtual void start_clock(Cpm_regs ®s); 497 virtual void stop_clock(Cpm_regs ®s); 498 499 // Output frequency. 500 501 uint64_t get_frequency(Cpm_regs ®s); 502 }; 503 504 505 506 class Clock_controlled : public Clock_base 507 { 508 protected: 509 virtual Control_base &_get_control() = 0; 510 511 public: 512 513 // Clock control. 514 515 virtual int have_clock(Cpm_regs ®s); 516 virtual void start_clock(Cpm_regs ®s); 517 virtual void stop_clock(Cpm_regs ®s); 518 }; 519 520 521 522 // An actively managed clock with source. 523 524 class Clock_active : public Clock_controlled 525 { 526 protected: 527 Source _source; 528 529 public: 530 explicit Clock_active(Source source) 531 : _source(source) 532 { 533 } 534 535 virtual ~Clock_active(); 536 537 // Clock source. 538 539 virtual uint8_t get_source(Cpm_regs ®s); 540 virtual void set_source(Cpm_regs ®s, uint8_t source); 541 enum Clock_identifiers get_source_clock(Cpm_regs ®s); 542 void set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock); 543 544 // Clock source frequency. 545 546 virtual uint64_t get_source_frequency(Cpm_regs ®s); 547 548 // Output frequency. 549 550 virtual uint64_t get_frequency(Cpm_regs ®s); 551 }; 552 553 554 555 // Divided clock interface. 556 557 class Clock_divided_base : public Clock_active 558 { 559 protected: 560 virtual Divider_base &_get_divider() = 0; 561 562 public: 563 explicit Clock_divided_base(Source source) 564 : Clock_active(source) 565 { 566 } 567 568 virtual ~Clock_divided_base(); 569 570 virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 571 virtual int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); 572 573 // Output frequency. 574 575 virtual uint64_t get_frequency(Cpm_regs ®s); 576 virtual int set_frequency(Cpm_regs ®s, uint64_t frequency); 577 }; 578 579 580 581 // PLL description. 582 583 class Pll : public Clock_divided_base 584 { 585 Control_pll _control; 586 Divider_pll _divider; 587 588 virtual Control_base &_get_control() { return _control; } 589 virtual Divider_base &_get_divider() { return _divider; } 590 591 public: 592 explicit Pll(Source source, Control_pll control, Divider_pll divider) 593 : Clock_divided_base(source), _control(control), _divider(divider) 594 { 595 } 596 597 virtual ~Pll(); 598 599 const char *clock_type() { return "pll"; } 600 601 // Output frequency. 602 603 uint64_t get_frequency(Cpm_regs ®s); 604 int set_frequency(Cpm_regs ®s, uint64_t frequency); 605 }; 606 607 608 609 // Plain clock description. 610 611 class Clock : public Clock_active 612 { 613 Control _control; 614 615 virtual Control_base &_get_control() { return _control; } 616 617 public: 618 explicit Clock(Source source, Control control) 619 : Clock_active(source), _control(control) 620 { 621 } 622 623 explicit Clock(Source source) 624 : Clock_active(source) 625 { 626 } 627 628 const char *clock_type() { return "clock"; } 629 }; 630 631 632 633 // Divided clock description. 634 635 class Clock_divided : public Clock_divided_base 636 { 637 Control _control; 638 Divider _divider; 639 640 virtual Control_base &_get_control() { return _control; } 641 virtual Divider_base &_get_divider() { return _divider; } 642 643 public: 644 explicit Clock_divided(Source source, Control control, Divider divider) 645 : Clock_divided_base(source), _control(control), _divider(divider) 646 { 647 } 648 649 explicit Clock_divided(Source source, Divider divider) 650 : Clock_divided_base(source), _control(Control::undefined), _divider(divider) 651 { 652 } 653 654 const char *clock_type() { return "divided"; } 655 }; 656 657 658 659 // Fixed divider clock description. 660 661 class Clock_divided_fixed : public Clock_divided_base 662 { 663 Control _control; 664 Divider_fixed _divider; 665 666 virtual Control_base &_get_control() { return _control; } 667 virtual Divider_base &_get_divider() { return _divider; } 668 669 public: 670 explicit Clock_divided_fixed(Source source, Divider_fixed divider) 671 : Clock_divided_base(source), _control(Control::undefined), _divider(divider) 672 { 673 } 674 675 const char *clock_type() { return "fix_div"; } 676 }; 677 678 679 680 // I2S clock description. 681 682 class Clock_divided_i2s : public Clock_divided_base 683 { 684 Control _control; 685 Divider_i2s _divider; 686 687 virtual Control_base &_get_control() { return _control; } 688 virtual Divider_base &_get_divider() { return _divider; } 689 690 public: 691 explicit Clock_divided_i2s(Source source, Control control, Divider_i2s divider) 692 : Clock_divided_base(source), _control(control), _divider(divider) 693 { 694 } 695 696 const char *clock_type() { return "i2s"; } 697 }; 698 699 #endif /* __cplusplus */