1 /* 2 * Clock and power management. This exposes the combined functionality 3 * provided by the jz4780 and related SoCs. The power management 4 * functionality could be exposed using a separate driver. 5 * 6 * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA 22 */ 23 24 #include <l4/devices/hw_mmio_register_block.h> 25 #include "cpm-jz4780.h" 26 27 28 29 enum Regs : unsigned 30 { 31 Clock_control = 0x000, // CPCCR 32 Low_power_control = 0x004, // LCR 33 Pll_control = 0x00c, // CPPCR 34 Pll_control_A = 0x010, // CPAPCR 35 Pll_control_M = 0x014, // CPMPCR 36 Pll_control_E = 0x018, // CPEPCR 37 Pll_control_V = 0x01c, // CPVPCR 38 Clock_gate0 = 0x020, // CLKGR0 39 Clock_gate1 = 0x028, // CLKGR1 40 Sleep_control = 0x024, // OPCR (oscillator and power control) 41 Ddr_divider = 0x02c, // DDRCDR 42 I2s_divider0 = 0x060, // I2SCDR 43 I2s_divider1 = 0x0a0, // I2S1CDR 44 Lcd_divider0 = 0x054, // LP0CDR 45 Lcd_divider1 = 0x064, // LP1CDR 46 Msc_divider0 = 0x068, // MSC0CDR 47 Msc_divider1 = 0x0a4, // MSC1CDR 48 Msc_divider2 = 0x0a8, // MSC2CDR 49 Uhc_divider = 0x06c, // UHCCDR 50 Ssi_divider = 0x074, // SSICDR 51 52 // ... 53 54 Hdmi_divider = 0x08c, // HDMICDR 55 56 // ... 57 }; 58 59 enum Clock_bits : unsigned 60 { 61 Clock_enable = 22, // CE_CPU 62 Clock_pclock_divider = 16, // PDIV (slow APB peripherals) 63 Clock_hclock2_divider = 12, // H2DIV (fast AHB peripherals) 64 Clock_hclock0_divider = 8, // H0DIV (fast AHB peripherals) 65 Clock_cpu_divider = 0, // CDIV 66 }; 67 68 enum Pll_bits : unsigned 69 { 70 Pll_multiplier = 19, // xPLLM 71 Pll_input_division = 13, // xPLLN 72 Pll_output_division = 9, // xPLLOD 73 Pll_stable = 4, // xPLL_ON 74 Pll_bypassed = 1, // xPLLBP 75 Pll_enabled = 0, // xPLLEN 76 }; 77 78 enum Clock_source_bits : unsigned 79 { 80 Clock_source_main = 30, // SEL_SRC (output to SCLK_A) 81 Clock_source_cpu = 28, // SEL_CPLL (output to CCLK) 82 Clock_source_hclock0 = 26, // SEL_H0PLL (output to AHB0) 83 Clock_source_hclock2 = 24, // SEL_H2PLL (output to AHB2) 84 Clock_source_ddr = 30, // DCS 85 Clock_source_i2s = 31, // I2CS 86 Clock_source_lcd = 30, // LPCS 87 Clock_source_hdmi = 30, // HPCS 88 }; 89 90 enum Clock_sources : unsigned 91 { 92 // Main clock sources. 93 94 Source_pll_A = 1, // APLL 95 Source_external = 2, // EXCLK 96 Source_realtime = 3, // RTCLK 97 98 // Stoppable clock sources. 99 100 Source_mux_stopped = 0, 101 Source_mux_main = 1, // SCLK_A 102 Source_mux_pll_M = 2, // MPLL 103 Source_mux_pll_E = 3, // EPLL 104 Source_mux_realtime = 3, // RTCLK (TCK) 105 106 // Unstoppable clock sources. 107 108 Source_main = 0, // SCLK_A 109 Source_pll_M = 1, // MPLL 110 Source_pll_E = 2, // EPLL 111 Source_pll_V = 2, // VPLL 112 Source_otg_phy = 3, // OTG_PHY 113 }; 114 115 enum Clock_gate_bits : unsigned 116 { 117 Clock_gate_lcd1 = 28, // LCD (in CLKGR0) 118 Clock_gate_lcd0 = 27, // TVE (in CLKGR0) 119 Clock_gate_hdmi = 9, // HDMI (in CLKGR1) 120 Clock_gate_smb4 = 12, // SMB4 (in CLKGR1) 121 Clock_gate_smb3 = 0, // SMB3 (in CLKGR1) 122 Clock_gate_smb2 = 25, // SMB2 (in CLKGR0) 123 Clock_gate_smb1 = 6, // SMB1 (in CLKGR0) 124 Clock_gate_smb0 = 5, // SMB0 (in CLKGR0) 125 }; 126 127 enum Divider_bits : unsigned 128 { 129 Ddr_divider_value = 0, // DDRCDR 130 Hdmi_divider_value = 0, // HDMICDR 131 Lcd_divider_value = 0, // LPCDR 132 }; 133 134 enum Lcd_clock_values : unsigned 135 { 136 Lcd_change_enable = 0x10000000, // CE_LCD 137 Lcd_change_busy = 0x08000000, // LCD_BUSY 138 Lcd_clock_stop = 0x04000000, // LCD_STOP 139 }; 140 141 enum Hdmi_divider_values : unsigned 142 { 143 Hdmi_select_mask = 0xc0000000, // HPCS 144 Hdmi_change_enable = 0x20000000, // CE_HDMI 145 Hdmi_change_busy = 0x10000000, // HDMI_BUSY 146 Hdmi_clock_stop = 0x08000000, // HDMI_STOP 147 }; 148 149 150 151 // If implemented as a Hw::Device, various properties would be 152 // initialised in the constructor and obtained from the device tree 153 // definitions. 154 155 Cpm_jz4780_chip::Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq) 156 : _exclk_freq(exclk_freq), _rtclk_freq(rtclk_freq) 157 { 158 _regs = new Hw::Mmio_register_block<32>(addr); 159 160 // add_cid("cpm"); 161 // add_cid("cpm-jz4780"); 162 // register_property("exclk_freq", &_exclk_freq); 163 } 164 165 // Clock/timer control. 166 167 uint32_t 168 Cpm_jz4780_chip::get_clock_gate_register(enum Clock_identifiers clock) 169 { 170 switch (clock) 171 { 172 case Clock_hdmi: return Clock_gate1; 173 case Clock_smb4: return Clock_gate1; 174 case Clock_smb3: return Clock_gate1; 175 default: return Clock_gate0; 176 } 177 } 178 179 uint32_t 180 Cpm_jz4780_chip::get_clock_gate_value(enum Clock_identifiers clock) 181 { 182 switch (clock) 183 { 184 case Clock_lcd: return (1 << Clock_gate_lcd1) | (1 << Clock_gate_lcd0); 185 case Clock_hdmi: return (1 << Clock_gate_hdmi); 186 case Clock_smb4: return (1 << Clock_gate_smb4); 187 case Clock_smb3: return (1 << Clock_gate_smb3); 188 case Clock_smb2: return (1 << Clock_gate_smb2); 189 case Clock_smb1: return (1 << Clock_gate_smb1); 190 case Clock_smb0: return (1 << Clock_gate_smb0); 191 default: return 0; 192 } 193 } 194 195 int 196 Cpm_jz4780_chip::have_clock(enum Clock_identifiers clock) 197 { 198 return !(_regs[get_clock_gate_register(clock)] & get_clock_gate_value(clock)); 199 } 200 201 void 202 Cpm_jz4780_chip::start_clock(enum Clock_identifiers clock) 203 { 204 uint32_t gate = get_clock_gate_register(clock); 205 206 _regs[gate] = _regs[gate] & ~get_clock_gate_value(clock); 207 } 208 209 void 210 Cpm_jz4780_chip::stop_clock(enum Clock_identifiers clock) 211 { 212 uint32_t gate = get_clock_gate_register(clock); 213 214 _regs[gate] = _regs[gate] | get_clock_gate_value(clock); 215 } 216 217 218 219 // Utility methods. 220 221 uint32_t 222 Cpm_jz4780_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 223 { 224 return (_regs[reg] & (mask << shift)) >> shift; 225 } 226 227 void 228 Cpm_jz4780_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 229 { 230 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 231 } 232 233 // General clock divider access. 234 235 uint8_t 236 Cpm_jz4780_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) 237 { 238 uint8_t d = get_field(reg, mask, shift); 239 240 // NOTE: Value 15 stops the clock, 14 presumably resumes the clock. 241 242 return (d < 14) ? d + 1 : 1; 243 } 244 245 246 247 // PLL control. 248 249 // Return whether the PLL is stable. 250 251 int 252 Cpm_jz4780_chip::have_pll(uint32_t pll_reg) 253 { 254 return _regs[pll_reg] & (1 << Pll_stable); 255 } 256 257 int 258 Cpm_jz4780_chip::pll_enabled(uint32_t pll_reg) 259 { 260 return _regs[pll_reg] & (1 << Pll_enabled); 261 } 262 263 int 264 Cpm_jz4780_chip::pll_bypassed(uint32_t pll_reg) 265 { 266 return _regs[pll_reg] & (1 << Pll_bypassed); 267 } 268 269 void 270 Cpm_jz4780_chip::pll_enable(uint32_t pll_reg) 271 { 272 _regs[pll_reg] = _regs[pll_reg] | (1 << Pll_enabled); 273 while (!(_regs[pll_reg] & (1 << Pll_stable))); 274 } 275 276 void 277 Cpm_jz4780_chip::pll_disable(uint32_t pll_reg) 278 { 279 _regs[pll_reg] = _regs[pll_reg] & ~(1 << Pll_enabled); 280 while (_regs[pll_reg] & (1 << Pll_stable)); 281 } 282 283 // Feedback (13-bit) multiplier. 284 285 uint16_t 286 Cpm_jz4780_chip::get_multiplier(uint32_t pll_reg) 287 { 288 return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; 289 } 290 291 void 292 Cpm_jz4780_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) 293 { 294 set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); 295 } 296 297 // Input (6-bit) divider. 298 299 uint8_t 300 Cpm_jz4780_chip::get_input_division(uint32_t pll_reg) 301 { 302 return get_field(pll_reg, 0x3f, Pll_input_division) + 1; 303 } 304 305 void 306 Cpm_jz4780_chip::set_input_division(uint32_t pll_reg, uint8_t divider) 307 { 308 set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); 309 } 310 311 // Output divider. 312 313 uint8_t 314 Cpm_jz4780_chip::get_output_division(uint32_t pll_reg) 315 { 316 uint8_t d = get_field(pll_reg, 0x0f, Pll_output_division); 317 318 // Zero yields a division of one. Otherwise enforce even results. 319 320 return d == 0 ? 1 : (d + 1) & 0x0e; 321 } 322 323 void 324 Cpm_jz4780_chip::set_output_division(uint32_t pll_reg, uint8_t divider) 325 { 326 uint8_t d = divider <= 1 ? 0 : (divider & 0x0e) - 1; 327 328 set_field(pll_reg, 0x0f, Pll_output_division, d); 329 } 330 331 uint32_t 332 Cpm_jz4780_chip::get_pll_frequency(uint32_t pll_reg) 333 { 334 // Test for PLL enable and not PLL bypass. 335 336 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 337 return (_exclk_freq * get_multiplier(pll_reg)) / 338 (get_input_division(pll_reg) * get_output_division(pll_reg)); 339 else 340 return _exclk_freq; 341 } 342 343 void 344 Cpm_jz4780_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 345 { 346 set_multiplier(pll_reg, multiplier); 347 set_input_division(pll_reg, in_divider); 348 set_output_division(pll_reg, out_divider); 349 350 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 351 while (!have_pll(pll_reg)); 352 } 353 354 355 356 // CPU clock (CCLK) divider. 357 358 uint8_t 359 Cpm_jz4780_chip::get_cpu_divider() 360 { 361 return _get_divider(Clock_control, 0xf, Clock_cpu_divider); 362 } 363 364 // Fast peripheral clock (H0CLK) divider. 365 366 uint8_t 367 Cpm_jz4780_chip::get_hclock0_divider() 368 { 369 return _get_divider(Clock_control, 0xf, Clock_hclock0_divider); 370 } 371 372 // Fast peripheral clock (H2CLK) divider. 373 374 uint8_t 375 Cpm_jz4780_chip::get_hclock2_divider() 376 { 377 return _get_divider(Clock_control, 0xf, Clock_hclock2_divider); 378 } 379 380 // Slow peripheral clock (PCLK) divider. 381 382 uint8_t 383 Cpm_jz4780_chip::get_pclock_divider() 384 { 385 return _get_divider(Clock_control, 0xf, Clock_pclock_divider); 386 } 387 388 // HDMI clock divider. 389 390 uint8_t 391 Cpm_jz4780_chip::get_hdmi_divider() 392 { 393 return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1; 394 } 395 396 // LCD clock (LPCLK) divider for LCD0 or LCD1 pixel clock. 397 398 uint8_t 399 Cpm_jz4780_chip::get_lcd_pixel_divider(uint8_t controller) 400 { 401 return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0xff, Lcd_divider_value) + 1; 402 } 403 404 // Memory clock (DDR_CLK) divider. 405 406 uint8_t 407 Cpm_jz4780_chip::get_memory_divider() 408 { 409 return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); 410 } 411 412 // HDMI clock divider. 413 414 void 415 Cpm_jz4780_chip::set_hdmi_divider(uint16_t division) 416 { 417 if ((division < 1) || (division > 256)) 418 return; 419 420 // Enable change. 421 422 _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable; 423 424 // Set the divider. 425 426 set_field(Hdmi_divider, 0xff, Hdmi_divider_value, division - 1); 427 428 // Restart clock and disable change. 429 430 while (_regs[Hdmi_divider] & Hdmi_change_busy); 431 _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~Hdmi_change_enable; 432 } 433 434 // LCD pixel clock divider. 435 // NOTE: This only supports the first LCD peripheral. 436 437 void 438 Cpm_jz4780_chip::set_lcd_pixel_divider(uint8_t controller, uint16_t division) 439 { 440 uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0; 441 442 if ((division < 1) || (division > 256)) 443 return; 444 445 // Enable change. 446 447 _regs[divider] = _regs[divider] | Lcd_change_enable; 448 449 // Set the divider. 450 451 set_field(divider, 0xff, Lcd_divider_value, division - 1); 452 453 // Restart clock and disable change. 454 455 while (_regs[divider] & Lcd_change_busy); 456 _regs[divider] = _regs[divider] & ~Lcd_change_enable; 457 } 458 459 460 461 // Clock sources. 462 463 uint8_t 464 Cpm_jz4780_chip::get_memory_source() 465 { 466 return get_field(Ddr_divider, 0x3, Clock_source_ddr); 467 } 468 469 uint32_t 470 Cpm_jz4780_chip::get_memory_source_frequency() 471 { 472 switch (get_memory_source()) 473 { 474 case Source_mux_main: 475 return get_main_frequency(); 476 case Source_mux_pll_M: 477 return get_pll_frequency(Pll_control_M); 478 default: 479 return 0; 480 } 481 } 482 483 uint8_t 484 Cpm_jz4780_chip::get_cpu_source() 485 { 486 return get_field(Clock_control, 0x3, Clock_source_cpu); 487 } 488 489 uint32_t 490 Cpm_jz4780_chip::get_cpu_source_frequency() 491 { 492 switch (get_cpu_source()) 493 { 494 case Source_mux_main: 495 return get_main_frequency(); 496 case Source_mux_pll_M: 497 return get_pll_frequency(Pll_control_M); 498 case Source_mux_pll_E: 499 return get_pll_frequency(Pll_control_E); 500 default: 501 return 0; 502 } 503 } 504 505 uint8_t 506 Cpm_jz4780_chip::get_hclock0_source() 507 { 508 return get_field(Clock_control, 0x3, Clock_source_hclock0); 509 } 510 511 uint32_t 512 Cpm_jz4780_chip::get_hclock0_source_frequency() 513 { 514 switch (get_hclock0_source()) 515 { 516 case Source_mux_main: 517 return get_main_frequency(); 518 case Source_mux_pll_M: 519 return get_pll_frequency(Pll_control_M); 520 case Source_mux_pll_E: 521 return get_pll_frequency(Pll_control_E); 522 default: 523 return 0; 524 } 525 } 526 527 uint8_t 528 Cpm_jz4780_chip::get_hclock2_source() 529 { 530 return get_field(Clock_control, 0x3, Clock_source_hclock2); 531 } 532 533 uint32_t 534 Cpm_jz4780_chip::get_hclock2_source_frequency() 535 { 536 switch (get_hclock2_source()) 537 { 538 case Source_mux_main: 539 return get_main_frequency(); 540 case Source_mux_pll_M: 541 return get_pll_frequency(Pll_control_M); 542 case Source_mux_realtime: 543 return _rtclk_freq; // "TCK" in the manual, RTCLK in Linux driver code 544 default: 545 return 0; 546 } 547 } 548 549 void 550 Cpm_jz4780_chip::set_hclock2_source(uint8_t source) 551 { 552 set_field(Clock_control, 0x3, Clock_source_hclock2, source); 553 } 554 555 uint8_t 556 Cpm_jz4780_chip::get_hdmi_source() 557 { 558 return get_field(Hdmi_divider, 0x3, Clock_source_hdmi); 559 } 560 561 uint32_t 562 Cpm_jz4780_chip::get_hdmi_source_frequency() 563 { 564 switch (get_hdmi_source()) 565 { 566 case Source_main: 567 return get_main_frequency(); 568 case Source_pll_M: 569 return get_pll_frequency(Pll_control_M); 570 case Source_pll_V: 571 return get_pll_frequency(Pll_control_V); 572 default: 573 return 0; 574 } 575 } 576 577 void 578 Cpm_jz4780_chip::set_hdmi_source(uint8_t source) 579 { 580 // Stop clock and enable change. 581 582 _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable | Hdmi_clock_stop; 583 584 // Set the source. 585 586 set_field(Hdmi_divider, 0x03, Clock_source_hdmi, source); 587 588 // Restart clock and disable change. 589 590 while (_regs[Hdmi_divider] & Hdmi_change_busy); 591 _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~(Hdmi_change_enable | Hdmi_clock_stop); 592 } 593 594 uint8_t 595 Cpm_jz4780_chip::get_lcd_source(uint8_t controller) 596 { 597 return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0x3, Clock_source_lcd); 598 } 599 600 uint32_t 601 Cpm_jz4780_chip::get_lcd_source_frequency(uint8_t controller) 602 { 603 switch (get_lcd_source(controller)) 604 { 605 case Source_main: 606 return get_main_frequency(); 607 case Source_pll_M: 608 return get_pll_frequency(Pll_control_M); 609 case Source_pll_V: 610 return get_pll_frequency(Pll_control_V); 611 default: 612 return 0; 613 } 614 } 615 616 void 617 Cpm_jz4780_chip::set_lcd_source(uint8_t controller, uint8_t source) 618 { 619 uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0; 620 621 // Stop clock and enable change. 622 623 _regs[divider] = _regs[divider] | Lcd_change_enable | Lcd_clock_stop; 624 625 // Set the source. 626 627 set_field(divider, 0x03, Clock_source_lcd, source); 628 629 // Restart clock and disable change. 630 631 while (_regs[divider] & Lcd_change_busy); 632 _regs[divider] = _regs[divider] & ~(Lcd_change_enable | Lcd_clock_stop); 633 } 634 635 uint8_t 636 Cpm_jz4780_chip::get_pclock_source() 637 { 638 return get_hclock2_source(); 639 } 640 641 uint32_t 642 Cpm_jz4780_chip::get_pclock_source_frequency() 643 { 644 return get_hclock2_source_frequency(); 645 } 646 647 void 648 Cpm_jz4780_chip::set_pclock_source(uint8_t source) 649 { 650 set_hclock2_source(source); 651 } 652 653 654 655 // Source frequency, used by various clock sources. 656 657 uint8_t 658 Cpm_jz4780_chip::get_main_source() 659 { 660 return get_field(Clock_control, 0x3, Clock_source_main); 661 } 662 663 uint32_t 664 Cpm_jz4780_chip::get_main_frequency() 665 { 666 switch (get_main_source()) 667 { 668 case Source_pll_A: 669 return get_pll_frequency(Pll_control_A); 670 case Source_external: 671 return _exclk_freq; 672 case Source_realtime: 673 return _rtclk_freq; 674 default: 675 return 0; 676 } 677 } 678 679 // Clock frequency for the CPU. 680 681 uint32_t 682 Cpm_jz4780_chip::get_cpu_frequency() 683 { 684 return get_cpu_source_frequency() / get_cpu_divider(); 685 } 686 687 // Clock frequency for fast peripherals. 688 689 uint32_t 690 Cpm_jz4780_chip::get_hclock0_frequency() 691 { 692 return get_hclock0_source_frequency() / get_hclock0_divider(); 693 } 694 695 // Clock frequency for fast peripherals. 696 697 uint32_t 698 Cpm_jz4780_chip::get_hclock2_frequency() 699 { 700 return get_hclock2_source_frequency() / get_hclock2_divider(); 701 } 702 703 // Clock frequency for slow peripherals. 704 705 uint32_t 706 Cpm_jz4780_chip::get_pclock_frequency() 707 { 708 return get_pclock_source_frequency() / get_pclock_divider(); 709 } 710 711 // Clock frequency for the HDMI peripheral. 712 713 uint32_t 714 Cpm_jz4780_chip::get_hdmi_frequency() 715 { 716 return get_hdmi_source_frequency() / get_hdmi_divider(); 717 } 718 719 // Clock frequency for the LCD0 or LCD1 controller. 720 721 uint32_t 722 Cpm_jz4780_chip::get_lcd_pixel_frequency(uint8_t controller) 723 { 724 return get_lcd_source_frequency(controller) / get_lcd_pixel_divider(controller); 725 } 726 727 // Clock frequency for the memory. 728 729 uint32_t 730 Cpm_jz4780_chip::get_memory_frequency() 731 { 732 return get_memory_source_frequency() / get_memory_divider(); 733 } 734 735 uint32_t 736 Cpm_jz4780_chip::get_apll_frequency() 737 { 738 return get_pll_frequency(Pll_control_A); 739 } 740 741 uint32_t 742 Cpm_jz4780_chip::get_epll_frequency() 743 { 744 return get_pll_frequency(Pll_control_E); 745 } 746 747 uint32_t 748 Cpm_jz4780_chip::get_mpll_frequency() 749 { 750 return get_pll_frequency(Pll_control_M); 751 } 752 753 uint32_t 754 Cpm_jz4780_chip::get_vpll_frequency() 755 { 756 return get_pll_frequency(Pll_control_V); 757 } 758 759 760 761 void 762 Cpm_jz4780_chip::set_hdmi_frequency(uint32_t pclk) 763 { 764 // Switch to the video PLL and attempt to set the divider. 765 766 set_hdmi_source(Source_pll_V); 767 pll_enable(Pll_control_V); 768 set_hdmi_divider(get_hdmi_source_frequency() / pclk); 769 } 770 771 // Set the pixel frequency. 772 // Unlike the jz4740, HCLK/AHB0 is used as the device frequency, with the pixel 773 // frequency being based on the selected clock source (SCLK_A, MPLL or VPLL). 774 775 void 776 Cpm_jz4780_chip::set_lcd_pixel_frequency(uint32_t pclk) 777 { 778 // Switch to the video PLL and attempt to set the divider. 779 780 set_lcd_source(0, Source_pll_V); 781 set_lcd_source(1, Source_pll_V); 782 pll_enable(Pll_control_V); 783 set_lcd_pixel_divider(0, get_lcd_source_frequency() / pclk); 784 set_lcd_pixel_divider(1, get_lcd_source_frequency() / pclk); 785 } 786 787 // NOTE: Compatibility method. Probably needs reviewing. 788 // NOTE: HCLK/AHB0 must be 1.5 (for TFT) or 3 (for STN) times the pixel clock. 789 790 void 791 Cpm_jz4780_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) 792 { 793 (void) ratio; 794 set_lcd_pixel_frequency(pclk); 795 } 796 797 // NOTE: Empty method for compatibility. 798 // NOTE: It could potentially be combined with start_lcd. 799 800 void 801 Cpm_jz4780_chip::update_output_frequency() 802 { 803 } 804 805 806 807 // C language interface functions. 808 809 void 810 *jz4780_cpm_init(l4_addr_t cpm_base) 811 { 812 /* Initialise the clock and power management peripheral with the 813 register memory region and a 48MHz EXCLK frequency. */ 814 815 return (void *) new Cpm_jz4780_chip(cpm_base, 48000000, 32768); 816 } 817 818 int 819 jz4780_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 820 { 821 return static_cast<Cpm_jz4780_chip *>(cpm)->have_clock(clock); 822 } 823 824 void 825 jz4780_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 826 { 827 static_cast<Cpm_jz4780_chip *>(cpm)->start_clock(clock); 828 } 829 830 void 831 jz4780_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 832 { 833 static_cast<Cpm_jz4780_chip *>(cpm)->stop_clock(clock); 834 } 835 836 837 838 uint8_t 839 jz4780_cpm_get_cpu_divider(void *cpm) 840 { 841 return static_cast<Cpm_jz4780_chip *>(cpm)->get_cpu_divider(); 842 } 843 844 uint8_t 845 jz4780_cpm_get_hclock0_divider(void *cpm) 846 { 847 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_divider(); 848 } 849 850 uint8_t 851 jz4780_cpm_get_hclock2_divider(void *cpm) 852 { 853 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_divider(); 854 } 855 856 uint8_t 857 jz4780_cpm_get_hdmi_divider(void *cpm) 858 { 859 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_divider(); 860 } 861 862 uint8_t 863 jz4780_cpm_get_lcd_pixel_divider(void *cpm) 864 { 865 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_divider(); 866 } 867 868 uint8_t 869 jz4780_cpm_get_memory_divider(void *cpm) 870 { 871 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_divider(); 872 } 873 874 uint8_t 875 jz4780_cpm_get_pclock_divider(void *cpm) 876 { 877 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_divider(); 878 } 879 880 881 882 uint8_t 883 jz4780_cpm_get_hclock0_source(void *cpm) 884 { 885 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_source(); 886 } 887 888 uint8_t 889 jz4780_cpm_get_hclock2_source(void *cpm) 890 { 891 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_source(); 892 } 893 894 uint8_t 895 jz4780_cpm_get_hdmi_source(void *cpm) 896 { 897 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source(); 898 } 899 900 uint8_t 901 jz4780_cpm_get_lcd_source(void *cpm) 902 { 903 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source(); 904 } 905 906 uint8_t 907 jz4780_cpm_get_memory_source(void *cpm) 908 { 909 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_source(); 910 } 911 912 uint8_t 913 jz4780_cpm_get_pclock_source(void *cpm) 914 { 915 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_source(); 916 } 917 918 void 919 jz4780_cpm_set_pclock_source(void *cpm, uint8_t source) 920 { 921 static_cast<Cpm_jz4780_chip *>(cpm)->set_pclock_source(source); 922 } 923 924 925 926 uint32_t 927 jz4780_cpm_get_hclock0_source_frequency(void *cpm) 928 { 929 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_source_frequency(); 930 } 931 932 uint32_t 933 jz4780_cpm_get_hclock2_source_frequency(void *cpm) 934 { 935 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_source_frequency(); 936 } 937 938 uint32_t 939 jz4780_cpm_get_hdmi_source_frequency(void *cpm) 940 { 941 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source_frequency(); 942 } 943 944 uint32_t 945 jz4780_cpm_get_lcd_source_frequency(void *cpm) 946 { 947 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source_frequency(); 948 } 949 950 uint32_t 951 jz4780_cpm_get_memory_source_frequency(void *cpm) 952 { 953 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_source_frequency(); 954 } 955 956 uint32_t 957 jz4780_cpm_get_pclock_source_frequency(void *cpm) 958 { 959 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_source_frequency(); 960 } 961 962 963 964 uint8_t 965 jz4780_cpm_get_main_source(void *cpm) 966 { 967 return static_cast<Cpm_jz4780_chip *>(cpm)->get_main_source(); 968 } 969 970 uint32_t 971 jz4780_cpm_get_main_frequency(void *cpm) 972 { 973 return static_cast<Cpm_jz4780_chip *>(cpm)->get_main_frequency(); 974 } 975 976 uint32_t 977 jz4780_cpm_get_cpu_frequency(void *cpm) 978 { 979 return static_cast<Cpm_jz4780_chip *>(cpm)->get_cpu_frequency(); 980 } 981 982 uint32_t 983 jz4780_cpm_get_hclock0_frequency(void *cpm) 984 { 985 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_frequency(); 986 } 987 988 uint32_t 989 jz4780_cpm_get_hclock2_frequency(void *cpm) 990 { 991 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_frequency(); 992 } 993 994 uint32_t 995 jz4780_cpm_get_hdmi_frequency(void *cpm) 996 { 997 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_frequency(); 998 } 999 1000 uint32_t 1001 jz4780_cpm_get_lcd_pixel_frequency(void *cpm) 1002 { 1003 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_frequency(); 1004 } 1005 1006 uint32_t 1007 jz4780_cpm_get_memory_frequency(void *cpm) 1008 { 1009 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_frequency(); 1010 } 1011 1012 uint32_t 1013 jz4780_cpm_get_pclock_frequency(void *cpm) 1014 { 1015 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_frequency(); 1016 } 1017 1018 uint32_t 1019 jz4780_cpm_get_apll_frequency(void *cpm) 1020 { 1021 return static_cast<Cpm_jz4780_chip *>(cpm)->get_apll_frequency(); 1022 } 1023 1024 uint32_t 1025 jz4780_cpm_get_epll_frequency(void *cpm) 1026 { 1027 return static_cast<Cpm_jz4780_chip *>(cpm)->get_epll_frequency(); 1028 } 1029 1030 uint32_t 1031 jz4780_cpm_get_mpll_frequency(void *cpm) 1032 { 1033 return static_cast<Cpm_jz4780_chip *>(cpm)->get_mpll_frequency(); 1034 } 1035 1036 uint32_t 1037 jz4780_cpm_get_vpll_frequency(void *cpm) 1038 { 1039 return static_cast<Cpm_jz4780_chip *>(cpm)->get_vpll_frequency(); 1040 } 1041 1042 1043 1044 void 1045 jz4780_cpm_set_hdmi_frequency(void *cpm, uint32_t pclk) 1046 { 1047 static_cast<Cpm_jz4780_chip *>(cpm)->set_hdmi_frequency(pclk); 1048 } 1049 1050 void 1051 jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk) 1052 { 1053 static_cast<Cpm_jz4780_chip *>(cpm)->set_lcd_pixel_frequency(pclk); 1054 } 1055 1056 void 1057 jz4780_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio) 1058 { 1059 static_cast<Cpm_jz4780_chip *>(cpm)->set_lcd_frequencies(pclk, ratio); 1060 } 1061 1062 void 1063 jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 1064 { 1065 static_cast<Cpm_jz4780_chip *>(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); 1066 }