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