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