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