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 #include <l4/devices/hw_mmio_register_block.h> 23 24 #include "cpm-common.h" 25 #include <math.h> 26 27 28 29 // Register access. 30 31 Cpm_regs::Cpm_regs(l4_addr_t addr, Clock_base *clocks[], 32 uint32_t exclk_freq) 33 : _clocks(clocks), exclk_freq(exclk_freq) 34 { 35 _regs = new Hw::Mmio_register_block<32>(addr); 36 } 37 38 // Utility methods. 39 40 uint32_t 41 Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 42 { 43 return (_regs[reg] & (mask << shift)) >> shift; 44 } 45 46 void 47 Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 48 { 49 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 50 } 51 52 Clock_base * 53 Cpm_regs::get_clock(int num) 54 { 55 return _clocks[num]; 56 } 57 58 59 60 // Field methods. 61 62 uint32_t 63 Field::get_field(Cpm_regs ®s) 64 { 65 if (defined) 66 return regs.get_field(reg, mask, bit); 67 else 68 return 0; 69 } 70 71 void 72 Field::set_field(Cpm_regs ®s, uint32_t value) 73 { 74 if (defined) 75 regs.set_field(reg, mask, bit, value); 76 } 77 78 // Undefined field. 79 80 Field Field::undefined; 81 82 83 84 // Clock sources. 85 86 enum Clock_identifiers 87 Mux::get_input(int num) 88 { 89 if (num < _num_inputs) 90 return _inputs[num]; 91 else 92 return Clock_undefined; 93 } 94 95 // Clock sources. 96 97 uint8_t 98 Source::get_source(Cpm_regs ®s) 99 { 100 if (_source.is_defined()) 101 return _source.get_field(regs); 102 else 103 return 0; 104 } 105 106 void 107 Source::set_source(Cpm_regs ®s, uint8_t source) 108 { 109 if (!_source.is_defined()) 110 return; 111 112 _source.set_field(regs, source); 113 } 114 115 // Clock source frequencies. 116 117 uint32_t 118 Source::get_frequency(Cpm_regs ®s) 119 { 120 // Clocks with one source yield that input frequency. 121 122 if (get_number() == 1) 123 return regs.get_clock(get_input(0))->get_frequency(regs); 124 125 // With multiple sources, obtain the selected source for the clock. 126 127 uint8_t source = get_source(regs); 128 enum Clock_identifiers input = get_input(source); 129 130 // Return the frequency of the source. 131 132 if (input != Clock_undefined) 133 return regs.get_clock(input)->get_frequency(regs); 134 else 135 return 0; 136 } 137 138 // Undefined source. 139 140 Source Source::undefined; 141 142 143 144 // Clock control. 145 146 Control_base::~Control_base() 147 { 148 } 149 150 void 151 Control_base::change_disable(Cpm_regs ®s) 152 { 153 (void) regs; 154 } 155 156 void 157 Control_base::change_enable(Cpm_regs ®s) 158 { 159 (void) regs; 160 } 161 162 int 163 Control::have_clock(Cpm_regs ®s) 164 { 165 if (_gate.is_defined()) 166 return !_gate.get_field(regs); 167 else 168 return true; 169 } 170 171 void 172 Control::start_clock(Cpm_regs ®s) 173 { 174 if (_gate.is_defined()) 175 _gate.set_field(regs, 0); 176 } 177 178 void 179 Control::stop_clock(Cpm_regs ®s) 180 { 181 if (_gate.is_defined()) 182 _gate.set_field(regs, 1); 183 } 184 185 void 186 Control::wait_busy(Cpm_regs ®s) 187 { 188 if (_busy.is_defined()) 189 while (_busy.get_field(regs)); 190 } 191 192 void 193 Control::change_disable(Cpm_regs ®s) 194 { 195 if (_change_enable.is_defined()) 196 _change_enable.set_field(regs, 0); 197 } 198 199 void 200 Control::change_enable(Cpm_regs ®s) 201 { 202 if (_change_enable.is_defined()) 203 _change_enable.set_field(regs, 1); 204 } 205 206 // Undefined control. 207 208 Control Control::undefined; 209 210 211 212 // PLL-specific control. 213 214 int 215 Control_pll::have_pll(Cpm_regs ®s) 216 { 217 return _stable.get_field(regs); 218 } 219 220 int 221 Control_pll::pll_enabled(Cpm_regs ®s) 222 { 223 return _enable.get_field(regs); 224 } 225 226 int 227 Control_pll::pll_bypassed(Cpm_regs ®s) 228 { 229 return _bypass.get_field(regs); 230 } 231 232 // Clock control. 233 234 int 235 Control_pll::have_clock(Cpm_regs ®s) 236 { 237 return have_pll(regs) && pll_enabled(regs); 238 } 239 240 void 241 Control_pll::start_clock(Cpm_regs ®s) 242 { 243 _enable.set_field(regs, 1); 244 while (!have_pll(regs)); 245 } 246 247 void 248 Control_pll::stop_clock(Cpm_regs ®s) 249 { 250 _enable.set_field(regs, 0); 251 while (have_pll(regs)); 252 } 253 254 void 255 Control_pll::wait_busy(Cpm_regs ®s) 256 { 257 if (pll_enabled(regs) && !pll_bypassed(regs)) 258 while (!have_pll(regs)); 259 } 260 261 262 263 // Clock dividers. 264 265 Divider_base::~Divider_base() 266 { 267 } 268 269 270 271 uint32_t 272 Divider::get_divider(Cpm_regs ®s) 273 { 274 if (_divider.is_defined()) 275 return _divider.get_field(regs) + 1; 276 else 277 return 1; 278 } 279 280 void 281 Divider::set_divider(Cpm_regs ®s, uint32_t divider) 282 { 283 if (_divider.is_defined()) 284 _divider.set_field(regs, divider - 1); 285 } 286 287 // Output clock frequencies. 288 289 uint32_t 290 Divider::get_frequency(Cpm_regs ®s, uint32_t source_frequency) 291 { 292 return source_frequency / get_divider(regs); 293 } 294 295 // Undefined divider. 296 297 Divider Divider::undefined; 298 299 300 301 // Feedback (13-bit) multiplier. 302 303 uint32_t 304 Divider_pll::get_multiplier(Cpm_regs ®s) 305 { 306 return _multiplier.get_field(regs) + 1; 307 } 308 309 void 310 Divider_pll::set_multiplier(Cpm_regs ®s, uint32_t multiplier) 311 { 312 _multiplier.set_field(regs, multiplier - 1); 313 } 314 315 // Input (6-bit) divider. 316 317 uint32_t 318 Divider_pll::get_input_divider(Cpm_regs ®s) 319 { 320 return _input_divider.get_field(regs) + 1; 321 } 322 323 void 324 Divider_pll::set_input_divider(Cpm_regs ®s, uint32_t divider) 325 { 326 _input_divider.set_field(regs, divider - 1); 327 } 328 329 // Output (dual 3-bit) dividers. 330 331 uint32_t 332 Divider_pll::get_output_divider(Cpm_regs ®s) 333 { 334 uint32_t d0 = _output_divider0.get_field(regs); 335 uint32_t d1 = _output_divider1.get_field(regs); 336 337 return d0 * d1; 338 } 339 340 void 341 Divider_pll::set_output_divider(Cpm_regs ®s, uint32_t divider) 342 { 343 // Assert 1 as a minimum. 344 // Divider 0 must be less than or equal to divider 1. 345 346 uint32_t d0 = (uint32_t) floor(sqrt(divider ? divider : 1)); 347 uint32_t d1 = divider / d0; 348 349 _output_divider0.set_field(regs, d0); 350 _output_divider1.set_field(regs, d1); 351 } 352 353 uint32_t 354 Divider_pll::get_frequency(Cpm_regs ®s, uint32_t source_frequency) 355 { 356 return (source_frequency * get_multiplier(regs)) / 357 (get_input_divider(regs) * get_output_divider(regs)); 358 } 359 360 void 361 Divider_pll::set_parameters(Cpm_regs ®s, uint32_t multiplier, 362 uint32_t in_divider, uint32_t out_divider) 363 { 364 set_multiplier(regs, multiplier); 365 set_input_divider(regs, in_divider); 366 set_output_divider(regs, out_divider); 367 } 368 369 370 371 // I2S clock divider. 372 373 uint32_t 374 Divider_i2s::get_multiplier(Cpm_regs ®s) 375 { 376 return _multiplier.get_field(regs); 377 } 378 379 uint32_t 380 Divider_i2s::get_divider_D(Cpm_regs ®s) 381 { 382 return _divider_D.get_field(regs); 383 } 384 385 uint32_t 386 Divider_i2s::get_divider_N(Cpm_regs ®s) 387 { 388 return _divider_N.get_field(regs); 389 } 390 391 uint32_t 392 Divider_i2s::get_frequency(Cpm_regs ®s, uint32_t source_frequency) 393 { 394 return (source_frequency * get_multiplier(regs)) / 395 (get_divider_N(regs) * get_divider_D(regs)); 396 } 397 398 void 399 Divider_i2s::set_parameters(Cpm_regs ®s, uint32_t multiplier, 400 uint32_t divider_N, uint32_t divider_D) 401 { 402 if (divider_N < 2 * multiplier) 403 return; 404 405 _multiplier.set_field(regs, multiplier); 406 _divider_N.set_field(regs, divider_N); 407 _divider_D.set_field(regs, divider_D); 408 } 409 410 411 412 // Clock interface. 413 414 Clock_base::~Clock_base() 415 { 416 } 417 418 419 420 // Null clock. 421 422 int 423 Clock_null::have_clock(Cpm_regs ®s) 424 { 425 (void) regs; 426 return false; 427 } 428 429 void 430 Clock_null::start_clock(Cpm_regs ®s) 431 { 432 (void) regs; 433 } 434 435 void 436 Clock_null::stop_clock(Cpm_regs ®s) 437 { 438 (void) regs; 439 } 440 441 // Output clock frequencies. 442 443 uint32_t 444 Clock_null::get_frequency(Cpm_regs ®s) 445 { 446 (void) regs; 447 return 0; 448 } 449 450 451 452 // Passive clock. 453 454 int 455 Clock_passive::have_clock(Cpm_regs ®s) 456 { 457 (void) regs; 458 return true; 459 } 460 461 void 462 Clock_passive::start_clock(Cpm_regs ®s) 463 { 464 (void) regs; 465 } 466 467 void 468 Clock_passive::stop_clock(Cpm_regs ®s) 469 { 470 (void) regs; 471 } 472 473 // Output clock frequencies. 474 475 uint32_t 476 Clock_passive::get_frequency(Cpm_regs ®s) 477 { 478 // NOTE: Return the external clock frequency. 479 480 return regs.exclk_freq; 481 } 482 483 484 485 // Active clock interface. 486 487 Clock_active::~Clock_active() 488 { 489 } 490 491 // Clock control. 492 493 int 494 Clock_active::have_clock(Cpm_regs ®s) 495 { 496 return _get_control().have_clock(regs); 497 } 498 499 void 500 Clock_active::start_clock(Cpm_regs ®s) 501 { 502 _get_control().start_clock(regs); 503 } 504 505 void 506 Clock_active::stop_clock(Cpm_regs ®s) 507 { 508 _get_control().stop_clock(regs); 509 } 510 511 // Clock sources. 512 513 uint8_t 514 Clock_active::get_source(Cpm_regs ®s) 515 { 516 return _source.get_source(regs); 517 } 518 519 void 520 Clock_active::set_source(Cpm_regs ®s, uint8_t source) 521 { 522 _get_control().change_enable(regs); 523 _source.set_source(regs, source); 524 _get_control().wait_busy(regs); 525 _get_control().change_disable(regs); 526 } 527 528 // Clock source frequencies. 529 530 uint32_t 531 Clock_active::get_source_frequency(Cpm_regs ®s) 532 { 533 return _source.get_frequency(regs); 534 } 535 536 // Output clock frequencies. 537 538 uint32_t 539 Clock_active::get_frequency(Cpm_regs ®s) 540 { 541 return get_source_frequency(regs); 542 } 543 544 545 546 // Divided clock interface. 547 548 Clock_divided::~Clock_divided() 549 { 550 } 551 552 // Output clock frequencies. 553 554 uint32_t 555 Clock_divided::get_frequency(Cpm_regs ®s) 556 { 557 return _get_divider().get_frequency(regs, get_source_frequency(regs)); 558 } 559 560 561 562 // PLL boilerplate. 563 564 Pll::~Pll() 565 { 566 } 567 568 // Feedback (13-bit) multiplier. 569 570 uint32_t 571 Pll::get_multiplier(Cpm_regs ®s) 572 { 573 return _divider.get_multiplier(regs); 574 } 575 576 void 577 Pll::set_multiplier(Cpm_regs ®s, uint32_t multiplier) 578 { 579 _divider.set_multiplier(regs, multiplier); 580 } 581 582 // Input (6-bit) divider. 583 584 uint32_t 585 Pll::get_input_divider(Cpm_regs ®s) 586 { 587 return _divider.get_input_divider(regs); 588 } 589 590 void 591 Pll::set_input_divider(Cpm_regs ®s, uint32_t divider) 592 { 593 _divider.set_input_divider(regs, divider); 594 } 595 596 // Output (dual 3-bit) dividers. 597 598 uint32_t 599 Pll::get_output_divider(Cpm_regs ®s) 600 { 601 return _divider.get_output_divider(regs); 602 } 603 604 void 605 Pll::set_output_divider(Cpm_regs ®s, uint32_t divider) 606 { 607 _divider.set_output_divider(regs, divider); 608 } 609 610 uint32_t 611 Pll::get_frequency(Cpm_regs ®s) 612 { 613 if (have_clock(regs)) 614 { 615 if (!_control.pll_bypassed(regs)) 616 return _divider.get_frequency(regs, get_source_frequency(regs)); 617 else 618 return get_source_frequency(regs); 619 } 620 else 621 return 0; 622 } 623 624 void 625 Pll::set_parameters(Cpm_regs ®s, uint32_t multiplier, 626 uint32_t in_divider, uint32_t out_divider) 627 { 628 _divider.set_parameters(regs, multiplier, in_divider, out_divider); 629 _control.wait_busy(regs); 630 } 631 632 633 634 // Clock dividers. 635 636 uint32_t 637 Clock::get_divider(Cpm_regs ®s) 638 { 639 return _divider.get_divider(regs); 640 } 641 642 void 643 Clock::set_divider(Cpm_regs ®s, uint32_t divider) 644 { 645 _control.change_enable(regs); 646 _divider.set_divider(regs, divider); 647 _control.wait_busy(regs); 648 _control.change_disable(regs); 649 }