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 153 // Clock source frequency. 154 155 uint32_t get_frequency(Cpm_regs ®s); 156 157 // Undefined source object. 158 159 static Source undefined; 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 // Undefined control. 213 214 static Control undefined; 215 }; 216 217 218 219 // PLL control. 220 221 class Control_pll : public Control_base 222 { 223 Field _enable, _stable, _bypass; 224 225 // PLL_specific control. 226 227 int have_pll(Cpm_regs ®s); 228 int pll_enabled(Cpm_regs ®s); 229 230 public: 231 explicit Control_pll(Field enable, Field stable, Field bypass) 232 : _enable(enable), _stable(stable), _bypass(bypass) 233 { 234 } 235 236 // Clock control. 237 238 int pll_bypassed(Cpm_regs ®s); 239 240 void wait_busy(Cpm_regs ®s); 241 int have_clock(Cpm_regs ®s); 242 void start_clock(Cpm_regs ®s); 243 void stop_clock(Cpm_regs ®s); 244 }; 245 246 247 248 // Frequency transformation. 249 250 class Divider_base 251 { 252 public: 253 virtual ~Divider_base(); 254 255 // Output frequency. 256 257 virtual uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency) = 0; 258 259 // Other operations. 260 261 virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]) = 0; 262 263 virtual void set_parameters(Cpm_regs ®s, 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 294 // Other operations. 295 296 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 297 298 void set_parameters(Cpm_regs ®s, uint32_t parameters[]); 299 300 // Undefined divider. 301 302 static Divider undefined; 303 }; 304 305 306 307 // Divider for PLLs. 308 309 class Divider_pll : public Divider_base 310 { 311 Field _multiplier, _input_divider, _output_divider0, _output_divider1; 312 313 public: 314 explicit Divider_pll(Field multiplier, Field input_divider, 315 Field output_divider0, Field output_divider1) 316 : _multiplier(multiplier), _input_divider(input_divider), 317 _output_divider0(output_divider0), _output_divider1(output_divider1) 318 { 319 } 320 321 // General frequency modifiers. 322 323 uint32_t get_multiplier(Cpm_regs ®s); 324 void set_multiplier(Cpm_regs ®s, uint32_t multiplier); 325 uint32_t get_input_divider(Cpm_regs ®s); 326 void set_input_divider(Cpm_regs ®s, uint32_t divider); 327 uint32_t get_output_divider(Cpm_regs ®s); 328 void set_output_divider(Cpm_regs ®s, uint32_t divider); 329 330 // Output frequency. 331 332 uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency); 333 334 // Other operations. 335 336 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 337 338 void set_parameters(Cpm_regs ®s, uint32_t parameters[]); 339 }; 340 341 342 343 // Divider for I2S clocks. 344 345 class Divider_i2s : public Divider_base 346 { 347 Field _multiplier, _divider_N, _divider_D; 348 349 public: 350 explicit Divider_i2s(Field multiplier, Field divider_N, 351 Field divider_D) 352 : _multiplier(multiplier), _divider_N(divider_N), 353 _divider_D(divider_D) 354 { 355 } 356 357 // General frequency modifiers. 358 359 uint32_t get_multiplier(Cpm_regs ®s); 360 uint32_t get_divider_N(Cpm_regs ®s); 361 uint32_t get_divider_D(Cpm_regs ®s); 362 363 // Output frequency. 364 365 uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency); 366 367 // Other operations. 368 369 int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 370 371 void set_parameters(Cpm_regs ®s, uint32_t parameters[]); 372 }; 373 374 375 376 // Common clock abstraction. 377 378 class Clock_base 379 { 380 public: 381 virtual ~Clock_base(); 382 383 virtual const char *clock_type() { return "unset"; } 384 385 // Clock control. 386 387 virtual int have_clock(Cpm_regs ®s) = 0; 388 virtual void start_clock(Cpm_regs ®s) = 0; 389 virtual void stop_clock(Cpm_regs ®s) = 0; 390 391 // Output frequency. 392 393 virtual uint32_t get_frequency(Cpm_regs ®s) = 0; 394 }; 395 396 397 398 // Null (absent or undefined) clock abstraction. 399 400 class Clock_null : public Clock_base 401 { 402 public: 403 const char *clock_type() { return "null"; } 404 405 // Clock control. 406 407 int have_clock(Cpm_regs ®s); 408 void start_clock(Cpm_regs ®s); 409 void stop_clock(Cpm_regs ®s); 410 411 // Output frequency. 412 413 uint32_t get_frequency(Cpm_regs ®s); 414 }; 415 416 417 418 // Passive (root or input) clock without any source of its own. 419 420 class Clock_passive : public Clock_base 421 { 422 public: 423 const char *clock_type() { return "passive"; } 424 425 // Clock control. 426 427 virtual int have_clock(Cpm_regs ®s); 428 virtual void start_clock(Cpm_regs ®s); 429 virtual void stop_clock(Cpm_regs ®s); 430 431 // Output frequency. 432 433 uint32_t get_frequency(Cpm_regs ®s); 434 }; 435 436 437 438 // An actively managed clock with source. 439 440 class Clock_active : public Clock_base 441 { 442 protected: 443 Source _source; 444 445 virtual Control_base &_get_control() = 0; 446 447 public: 448 explicit Clock_active(Source source) 449 : _source(source) 450 { 451 } 452 453 explicit Clock_active() 454 : _source(Source::undefined) 455 { 456 } 457 458 virtual ~Clock_active(); 459 460 // Clock control. 461 462 virtual int have_clock(Cpm_regs ®s); 463 virtual void start_clock(Cpm_regs ®s); 464 virtual void stop_clock(Cpm_regs ®s); 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 471 // Clock source frequency. 472 473 virtual uint32_t get_source_frequency(Cpm_regs ®s); 474 475 // Output frequency. 476 477 virtual uint32_t get_frequency(Cpm_regs ®s); 478 }; 479 480 481 482 // Divided clock interface. 483 484 class Clock_divided : public Clock_active 485 { 486 protected: 487 virtual Divider_base &_get_divider() = 0; 488 489 public: 490 explicit Clock_divided(Source source) 491 : Clock_active(source) 492 { 493 } 494 495 virtual ~Clock_divided(); 496 497 virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]); 498 499 virtual void set_parameters(Cpm_regs ®s, uint32_t parameters[]); 500 501 // Output frequency. 502 503 uint32_t get_frequency(Cpm_regs ®s); 504 }; 505 506 507 508 // PLL description. 509 510 class Pll : public Clock_divided 511 { 512 // Value storage. 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(source), _control(control), _divider(divider) 523 { 524 } 525 526 virtual ~Pll(); 527 528 const char *clock_type() { return "pll"; } 529 530 // General frequency modifiers. 531 532 uint32_t get_multiplier(Cpm_regs ®s); 533 void set_multiplier(Cpm_regs ®s, uint32_t multiplier); 534 uint32_t get_input_divider(Cpm_regs ®s); 535 void set_input_divider(Cpm_regs ®s, uint32_t divider); 536 uint32_t get_output_divider(Cpm_regs ®s); 537 void set_output_divider(Cpm_regs ®s, uint32_t divider); 538 539 // Output frequency. 540 541 uint32_t get_frequency(Cpm_regs ®s); 542 }; 543 544 545 546 // Clock description. 547 548 class Clock : public Clock_divided 549 { 550 // Value storage. 551 552 Control _control; 553 Divider _divider; 554 555 virtual Control_base &_get_control() { return _control; } 556 virtual Divider_base &_get_divider() { return _divider; } 557 558 public: 559 explicit Clock(Source source, 560 Control control = Control::undefined, 561 Divider divider = Divider::undefined) 562 : Clock_divided(source), _control(control), _divider(divider) 563 { 564 } 565 566 const char *clock_type() { return "divided"; } 567 568 // Clock divider. 569 570 uint32_t get_divider(Cpm_regs ®s); 571 void set_divider(Cpm_regs ®s, uint32_t divider); 572 }; 573 574 575 576 // I2S clock description. 577 578 class Clock_divided_i2s : public Clock_divided 579 { 580 // Value storage. 581 582 Control _control; 583 Divider_i2s _divider; 584 585 virtual Control_base &_get_control() { return _control; } 586 virtual Divider_base &_get_divider() { return _divider; } 587 588 public: 589 explicit Clock_divided_i2s(Source source, Control control, Divider_i2s divider) 590 : Clock_divided(source), _control(control), _divider(divider) 591 { 592 } 593 594 const char *clock_type() { return "i2s"; } 595 }; 596 597 #endif /* __cplusplus */