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