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