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_lcd = 28, // LCD (in CLKGR0) 118 Clock_gate_tve = 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, // SMB2 (in CLKGR0) 124 Clock_gate_smb0 = 5, // SMB2 (in CLKGR0) 125 }; 126 127 enum Clock_gate_regs : unsigned 128 { 129 Clock_gate_reg_smb4 = Clock_gate1, 130 Clock_gate_reg_smb3 = Clock_gate1, 131 Clock_gate_reg_smb2 = Clock_gate0, 132 Clock_gate_reg_smb1 = Clock_gate0, 133 Clock_gate_reg_smb0 = Clock_gate0, 134 }; 135 136 enum Divider_bits : unsigned 137 { 138 Ddr_divider_value = 0, // DDRCDR 139 Hdmi_divider_value = 0, // HDMICDR 140 Lcd_divider_value = 0, // LPCDR 141 }; 142 143 enum Lcd_clock_values : unsigned 144 { 145 Lcd_change_enable = 0x10000000, // CE_LCD 146 Lcd_change_busy = 0x08000000, // LCD_BUSY 147 Lcd_clock_stop = 0x04000000, // LCD_STOP 148 }; 149 150 enum Hdmi_divider_values : unsigned 151 { 152 Hdmi_select_mask = 0xc0000000, // HPCS 153 Hdmi_change_enable = 0x20000000, // CE_HDMI 154 Hdmi_change_busy = 0x10000000, // HDMI_BUSY 155 Hdmi_clock_stop = 0x08000000, // HDMI_STOP 156 }; 157 158 159 160 // If implemented as a Hw::Device, various properties would be 161 // initialised in the constructor and obtained from the device tree 162 // definitions. 163 164 Cpm_jz4780_chip::Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq) 165 : _exclk_freq(exclk_freq), _rtclk_freq(rtclk_freq) 166 { 167 _regs = new Hw::Mmio_register_block<32>(addr); 168 169 // add_cid("cpm"); 170 // add_cid("cpm-jz4780"); 171 // register_property("exclk_freq", &_exclk_freq); 172 } 173 174 // Clock/timer control. 175 // NOTE: For the time being, assume that the system is configured. 176 177 int 178 Cpm_jz4780_chip::have_clock() 179 { 180 // return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); 181 return 1; 182 } 183 184 void 185 Cpm_jz4780_chip::start_clock() 186 { 187 // _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); 188 } 189 190 191 192 // Utility methods. 193 194 uint32_t 195 Cpm_jz4780_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 196 { 197 return (_regs[reg] & (mask << shift)) >> shift; 198 } 199 200 void 201 Cpm_jz4780_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 202 { 203 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 204 } 205 206 // General clock divider access. 207 208 uint8_t 209 Cpm_jz4780_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) 210 { 211 uint8_t d = get_field(reg, mask, shift); 212 213 // NOTE: Value 14 stops the clock, 15 presumably resumes the clock. 214 215 return (d < 14) ? d + 1 : 1; 216 } 217 218 219 220 // PLL control. 221 222 // Return whether the PLL is stable. 223 224 int 225 Cpm_jz4780_chip::have_pll(uint32_t pll_reg) 226 { 227 return _regs[pll_reg] & (1 << Pll_stable); 228 } 229 230 int 231 Cpm_jz4780_chip::pll_enabled(uint32_t pll_reg) 232 { 233 return _regs[pll_reg] & (1 << Pll_enabled); 234 } 235 236 int 237 Cpm_jz4780_chip::pll_bypassed(uint32_t pll_reg) 238 { 239 return _regs[pll_reg] & (1 << Pll_bypassed); 240 } 241 242 // Feedback (13-bit) multiplier. 243 244 uint16_t 245 Cpm_jz4780_chip::get_multiplier(uint32_t pll_reg) 246 { 247 return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; 248 } 249 250 void 251 Cpm_jz4780_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) 252 { 253 set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); 254 } 255 256 // Input (6-bit) divider. 257 258 uint8_t 259 Cpm_jz4780_chip::get_input_division(uint32_t pll_reg) 260 { 261 return get_field(pll_reg, 0x3f, Pll_input_division) + 1; 262 } 263 264 void 265 Cpm_jz4780_chip::set_input_division(uint32_t pll_reg, uint8_t divider) 266 { 267 set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); 268 } 269 270 // Output divider. 271 272 uint8_t 273 Cpm_jz4780_chip::get_output_division(uint32_t pll_reg) 274 { 275 uint8_t d = get_field(pll_reg, 0x0f, Pll_output_division); 276 277 // Zero yields a division of one. Otherwise enforce even results. 278 279 return d == 0 ? 1 : (d + 1) & 0x0e; 280 } 281 282 void 283 Cpm_jz4780_chip::set_output_division(uint32_t pll_reg, uint8_t divider) 284 { 285 uint8_t d = divider <= 1 ? 0 : (divider & 0x0e) - 1; 286 287 set_field(pll_reg, 0x0f, Pll_output_division, d); 288 } 289 290 uint32_t 291 Cpm_jz4780_chip::get_pll_frequency(uint32_t pll_reg) 292 { 293 // Test for PLL enable and not PLL bypass. 294 295 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 296 return (_exclk_freq * get_multiplier(pll_reg)) / 297 (get_input_division(pll_reg) * get_output_division(pll_reg)); 298 else 299 return _exclk_freq; 300 } 301 302 void 303 Cpm_jz4780_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 304 { 305 set_multiplier(pll_reg, multiplier); 306 set_input_division(pll_reg, in_divider); 307 set_output_division(pll_reg, out_divider); 308 309 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 310 while (!have_pll(pll_reg)); 311 } 312 313 314 315 // CPU clock (CCLK) divider. 316 317 uint8_t 318 Cpm_jz4780_chip::get_cpu_divider() 319 { 320 return _get_divider(Clock_control, 0xf, Clock_cpu_divider); 321 } 322 323 // Fast peripheral clock (H0CLK) divider. 324 325 uint8_t 326 Cpm_jz4780_chip::get_hclock0_divider() 327 { 328 return _get_divider(Clock_control, 0xf, Clock_hclock0_divider); 329 } 330 331 // Fast peripheral clock (H2CLK) divider. 332 333 uint8_t 334 Cpm_jz4780_chip::get_hclock2_divider() 335 { 336 return _get_divider(Clock_control, 0xf, Clock_hclock2_divider); 337 } 338 339 // Slow peripheral clock (PCLK) divider. 340 341 uint8_t 342 Cpm_jz4780_chip::get_pclock_divider() 343 { 344 return _get_divider(Clock_control, 0xf, Clock_pclock_divider); 345 } 346 347 // HDMI clock divider. 348 349 uint8_t 350 Cpm_jz4780_chip::get_hdmi_divider() 351 { 352 return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1; 353 } 354 355 // LCD clock (LPCLK) divider for LCD0 pixel clock. 356 357 uint8_t 358 Cpm_jz4780_chip::get_lcd_pixel_divider() 359 { 360 return get_field(Lcd_divider0, 0xff, Lcd_divider_value) + 1; 361 } 362 363 // Memory clock (DDR_CLK) divider. 364 365 uint8_t 366 Cpm_jz4780_chip::get_memory_divider() 367 { 368 return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); 369 } 370 371 // HDMI clock divider. 372 373 void 374 Cpm_jz4780_chip::set_hdmi_divider(uint16_t division) 375 { 376 if ((division < 1) || (division > 256)) 377 return; 378 379 // Enable change. 380 381 _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable; 382 383 // Set the divider. 384 385 set_field(Hdmi_divider, 0xff, Hdmi_divider_value, division - 1); 386 387 // Restart clock and disable change. 388 389 while (_regs[Hdmi_divider] & Hdmi_change_busy); 390 _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~Hdmi_change_enable; 391 } 392 393 // LCD pixel clock divider. 394 // NOTE: This only supports the first LCD peripheral. 395 396 void 397 Cpm_jz4780_chip::set_lcd_pixel_divider(uint16_t division) 398 { 399 if ((division < 1) || (division > 256)) 400 return; 401 402 // Enable change. 403 404 _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable; 405 406 // Set the divider. 407 408 set_field(Lcd_divider0, 0xff, Lcd_divider_value, division - 1); 409 410 // Restart clock and disable change. 411 412 while (_regs[Lcd_divider0] & Lcd_change_busy); 413 _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~Lcd_change_enable; 414 } 415 416 417 418 // Clock gating control. 419 420 void 421 Cpm_jz4780_chip::start_hdmi() 422 { 423 _regs[Clock_gate1] = _regs[Clock_gate1] & ~(1 << Clock_gate_hdmi); 424 } 425 426 void 427 Cpm_jz4780_chip::stop_hdmi() 428 { 429 _regs[Clock_gate1] = _regs[Clock_gate1] | (1 << Clock_gate_hdmi); 430 } 431 432 void 433 Cpm_jz4780_chip::start_lcd() 434 { 435 _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd); 436 } 437 438 void 439 Cpm_jz4780_chip::stop_lcd() 440 { 441 _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd); 442 } 443 444 void 445 Cpm_jz4780_chip::_update_i2c(uint8_t channel, int enable) 446 { 447 uint8_t bit; 448 uint32_t reg; 449 switch (channel) 450 { 451 case 0: bit = Clock_gate_smb0; reg = Clock_gate_reg_smb0; break; 452 case 1: bit = Clock_gate_smb1; reg = Clock_gate_reg_smb1; break; 453 case 2: bit = Clock_gate_smb2; reg = Clock_gate_reg_smb2; break; 454 case 3: bit = Clock_gate_smb3; reg = Clock_gate_reg_smb3; break; 455 case 4: bit = Clock_gate_smb4; reg = Clock_gate_reg_smb4; break; 456 default: return; 457 } 458 if (enable) 459 _regs[reg] = _regs[reg] & ~(1 << bit); 460 else 461 _regs[reg] = _regs[reg] | (1 << bit); 462 } 463 464 void 465 Cpm_jz4780_chip::start_i2c(uint8_t channel) 466 { 467 _update_i2c(channel, 1); 468 } 469 470 void 471 Cpm_jz4780_chip::stop_i2c(uint8_t channel) 472 { 473 _update_i2c(channel, 0); 474 } 475 476 477 478 // Clock sources. 479 480 uint8_t 481 Cpm_jz4780_chip::get_memory_source() 482 { 483 return get_field(Ddr_divider, 0x3, Clock_source_ddr); 484 } 485 486 uint32_t 487 Cpm_jz4780_chip::get_memory_source_frequency() 488 { 489 switch (get_memory_source()) 490 { 491 case Source_mux_main: 492 return get_main_frequency(); 493 case Source_mux_pll_M: 494 return get_pll_frequency(Pll_control_M); 495 default: 496 return 0; 497 } 498 } 499 500 uint8_t 501 Cpm_jz4780_chip::get_cpu_source() 502 { 503 return get_field(Clock_control, 0x3, Clock_source_cpu); 504 } 505 506 uint32_t 507 Cpm_jz4780_chip::get_cpu_source_frequency() 508 { 509 switch (get_cpu_source()) 510 { 511 case Source_mux_main: 512 return get_main_frequency(); 513 case Source_mux_pll_M: 514 return get_pll_frequency(Pll_control_M); 515 case Source_mux_pll_E: 516 return get_pll_frequency(Pll_control_E); 517 default: 518 return 0; 519 } 520 } 521 522 uint8_t 523 Cpm_jz4780_chip::get_hclock0_source() 524 { 525 return get_field(Clock_control, 0x3, Clock_source_hclock0); 526 } 527 528 uint32_t 529 Cpm_jz4780_chip::get_hclock0_source_frequency() 530 { 531 switch (get_hclock0_source()) 532 { 533 case Source_mux_main: 534 return get_main_frequency(); 535 case Source_mux_pll_M: 536 return get_pll_frequency(Pll_control_M); 537 case Source_mux_pll_E: 538 return get_pll_frequency(Pll_control_E); 539 default: 540 return 0; 541 } 542 } 543 544 uint8_t 545 Cpm_jz4780_chip::get_hclock2_source() 546 { 547 return get_field(Clock_control, 0x3, Clock_source_hclock2); 548 } 549 550 uint32_t 551 Cpm_jz4780_chip::get_hclock2_source_frequency() 552 { 553 switch (get_hclock2_source()) 554 { 555 case Source_mux_main: 556 return get_main_frequency(); 557 case Source_mux_pll_M: 558 return get_pll_frequency(Pll_control_M); 559 case Source_mux_realtime: 560 return _rtclk_freq; // "TCK" in the manual, RTCLK in Linux driver code 561 default: 562 return 0; 563 } 564 } 565 566 void 567 Cpm_jz4780_chip::set_hclock2_source(uint8_t source) 568 { 569 set_field(Clock_control, 0x3, Clock_source_hclock2, source); 570 } 571 572 uint8_t 573 Cpm_jz4780_chip::get_hdmi_source() 574 { 575 return get_field(Hdmi_divider, 0x3, Clock_source_hdmi); 576 } 577 578 uint32_t 579 Cpm_jz4780_chip::get_hdmi_source_frequency() 580 { 581 switch (get_hdmi_source()) 582 { 583 case Source_main: 584 return get_main_frequency(); 585 case Source_pll_M: 586 return get_pll_frequency(Pll_control_M); 587 case Source_pll_V: 588 return get_pll_frequency(Pll_control_V); 589 default: 590 return 0; 591 } 592 } 593 594 void 595 Cpm_jz4780_chip::set_hdmi_source(uint8_t source) 596 { 597 // Stop clock and enable change. 598 599 _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable | Hdmi_clock_stop; 600 601 // Set the source. 602 603 set_field(Hdmi_divider, 0x03, Clock_source_hdmi, source); 604 605 // Restart clock and disable change. 606 607 while (_regs[Hdmi_divider] & Hdmi_change_busy); 608 _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~(Hdmi_change_enable | Hdmi_clock_stop); 609 } 610 611 uint8_t 612 Cpm_jz4780_chip::get_lcd_source() 613 { 614 return get_field(Lcd_divider0, 0x3, Clock_source_lcd); 615 } 616 617 uint32_t 618 Cpm_jz4780_chip::get_lcd_source_frequency() 619 { 620 switch (get_lcd_source()) 621 { 622 case Source_main: 623 return get_main_frequency(); 624 case Source_pll_M: 625 return get_pll_frequency(Pll_control_M); 626 case Source_pll_V: 627 return get_pll_frequency(Pll_control_V); 628 default: 629 return 0; 630 } 631 } 632 633 void 634 Cpm_jz4780_chip::set_lcd_source(uint8_t source) 635 { 636 // Stop clock and enable change. 637 638 _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable | Lcd_clock_stop; 639 640 // Set the source. 641 642 set_field(Lcd_divider0, 0x03, Clock_source_lcd, source); 643 644 // Restart clock and disable change. 645 646 while (_regs[Lcd_divider0] & Lcd_change_busy); 647 _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~(Lcd_change_enable | Lcd_clock_stop); 648 } 649 650 uint8_t 651 Cpm_jz4780_chip::get_pclock_source() 652 { 653 return get_hclock2_source(); 654 } 655 656 uint32_t 657 Cpm_jz4780_chip::get_pclock_source_frequency() 658 { 659 return get_hclock2_source_frequency(); 660 } 661 662 void 663 Cpm_jz4780_chip::set_pclock_source(uint8_t source) 664 { 665 set_hclock2_source(source); 666 } 667 668 669 670 // Source frequency, used by various clock sources. 671 672 uint8_t 673 Cpm_jz4780_chip::get_main_source() 674 { 675 return get_field(Clock_control, 0x3, Clock_source_main); 676 } 677 678 uint32_t 679 Cpm_jz4780_chip::get_main_frequency() 680 { 681 switch (get_main_source()) 682 { 683 case Source_pll_A: 684 return get_pll_frequency(Pll_control_A); 685 case Source_external: 686 return _exclk_freq; 687 case Source_realtime: 688 return _rtclk_freq; 689 default: 690 return 0; 691 } 692 } 693 694 // Clock frequency for the CPU. 695 696 uint32_t 697 Cpm_jz4780_chip::get_cpu_frequency() 698 { 699 return get_cpu_source_frequency() / get_cpu_divider(); 700 } 701 702 // Clock frequency for fast peripherals. 703 704 uint32_t 705 Cpm_jz4780_chip::get_hclock0_frequency() 706 { 707 return get_hclock0_source_frequency() / get_hclock0_divider(); 708 } 709 710 // Clock frequency for fast peripherals. 711 712 uint32_t 713 Cpm_jz4780_chip::get_hclock2_frequency() 714 { 715 return get_hclock2_source_frequency() / get_hclock2_divider(); 716 } 717 718 // Clock frequency for slow peripherals. 719 720 uint32_t 721 Cpm_jz4780_chip::get_pclock_frequency() 722 { 723 return get_pclock_source_frequency() / get_pclock_divider(); 724 } 725 726 // Clock frequency for the HDMI peripheral. 727 728 uint32_t 729 Cpm_jz4780_chip::get_hdmi_frequency() 730 { 731 return get_hdmi_source_frequency() / get_hdmi_divider(); 732 } 733 734 // Clock frequency for the LCD0 controller. 735 736 uint32_t 737 Cpm_jz4780_chip::get_lcd_pixel_frequency() 738 { 739 return get_lcd_source_frequency() / get_lcd_pixel_divider(); 740 } 741 742 // Clock frequency for the memory. 743 744 uint32_t 745 Cpm_jz4780_chip::get_memory_frequency() 746 { 747 return get_memory_source_frequency() / get_memory_divider(); 748 } 749 750 uint32_t 751 Cpm_jz4780_chip::get_apll_frequency() 752 { 753 return get_pll_frequency(Pll_control_A); 754 } 755 756 uint32_t 757 Cpm_jz4780_chip::get_epll_frequency() 758 { 759 return get_pll_frequency(Pll_control_E); 760 } 761 762 uint32_t 763 Cpm_jz4780_chip::get_mpll_frequency() 764 { 765 return get_pll_frequency(Pll_control_M); 766 } 767 768 uint32_t 769 Cpm_jz4780_chip::get_vpll_frequency() 770 { 771 return get_pll_frequency(Pll_control_V); 772 } 773 774 775 776 void 777 Cpm_jz4780_chip::set_hdmi_frequency(uint32_t pclk) 778 { 779 // Switch to the video PLL and attempt to set the divider. 780 781 set_hdmi_source(Source_pll_V); 782 set_hdmi_divider(get_hdmi_source_frequency() / pclk); 783 } 784 785 // Set the pixel frequency. 786 // Unlike the jz4740, HCLK/AHB0 is used as the device frequency, with the pixel 787 // frequency being based on the selected clock source (SCLK_A, MPLL or VPLL). 788 789 void 790 Cpm_jz4780_chip::set_lcd_pixel_frequency(uint32_t pclk) 791 { 792 // Switch to the video PLL and attempt to set the divider. 793 794 set_lcd_source(Source_pll_V); 795 set_lcd_pixel_divider(get_lcd_source_frequency() / pclk); 796 } 797 798 // NOTE: Compatibility method. Probably needs reviewing. 799 800 void 801 Cpm_jz4780_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) 802 { 803 (void) ratio; 804 set_lcd_pixel_frequency(pclk); 805 } 806 807 // NOTE: Empty method for compatibility. 808 809 void 810 Cpm_jz4780_chip::update_output_frequency() 811 { 812 } 813 814 815 816 // C language interface functions. 817 818 void 819 *jz4780_cpm_init(l4_addr_t cpm_base) 820 { 821 /* Initialise the clock and power management peripheral with the 822 register memory region and a 48MHz EXCLK frequency. */ 823 824 return (void *) new Cpm_jz4780_chip(cpm_base, 48000000, 32768); 825 } 826 827 int 828 jz4780_cpm_have_clock(void *cpm) 829 { 830 return static_cast<Cpm_jz4780_chip *>(cpm)->have_clock(); 831 } 832 833 void 834 jz4780_cpm_start_clock(void *cpm) 835 { 836 static_cast<Cpm_jz4780_chip *>(cpm)->start_clock(); 837 } 838 839 840 841 void 842 jz4780_cpm_start_hdmi(void *cpm) 843 { 844 static_cast<Cpm_jz4780_chip *>(cpm)->start_hdmi(); 845 } 846 847 void 848 jz4780_cpm_stop_hdmi(void *cpm) 849 { 850 static_cast<Cpm_jz4780_chip *>(cpm)->stop_hdmi(); 851 } 852 853 void 854 jz4780_cpm_start_lcd(void *cpm) 855 { 856 static_cast<Cpm_jz4780_chip *>(cpm)->start_lcd(); 857 } 858 859 void 860 jz4780_cpm_stop_lcd(void *cpm) 861 { 862 static_cast<Cpm_jz4780_chip *>(cpm)->stop_lcd(); 863 } 864 865 866 867 uint8_t 868 jz4780_cpm_get_cpu_divider(void *cpm) 869 { 870 return static_cast<Cpm_jz4780_chip *>(cpm)->get_cpu_divider(); 871 } 872 873 uint8_t 874 jz4780_cpm_get_hclock0_divider(void *cpm) 875 { 876 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_divider(); 877 } 878 879 uint8_t 880 jz4780_cpm_get_hclock2_divider(void *cpm) 881 { 882 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_divider(); 883 } 884 885 uint8_t 886 jz4780_cpm_get_hdmi_divider(void *cpm) 887 { 888 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_divider(); 889 } 890 891 uint8_t 892 jz4780_cpm_get_lcd_pixel_divider(void *cpm) 893 { 894 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_divider(); 895 } 896 897 uint8_t 898 jz4780_cpm_get_memory_divider(void *cpm) 899 { 900 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_divider(); 901 } 902 903 uint8_t 904 jz4780_cpm_get_pclock_divider(void *cpm) 905 { 906 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_divider(); 907 } 908 909 910 911 uint8_t 912 jz4780_cpm_get_hclock0_source(void *cpm) 913 { 914 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_source(); 915 } 916 917 uint8_t 918 jz4780_cpm_get_hclock2_source(void *cpm) 919 { 920 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_source(); 921 } 922 923 uint8_t 924 jz4780_cpm_get_hdmi_source(void *cpm) 925 { 926 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source(); 927 } 928 929 uint8_t 930 jz4780_cpm_get_lcd_source(void *cpm) 931 { 932 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source(); 933 } 934 935 uint8_t 936 jz4780_cpm_get_memory_source(void *cpm) 937 { 938 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_source(); 939 } 940 941 uint8_t 942 jz4780_cpm_get_pclock_source(void *cpm) 943 { 944 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_source(); 945 } 946 947 void 948 jz4780_cpm_set_pclock_source(void *cpm, uint8_t source) 949 { 950 static_cast<Cpm_jz4780_chip *>(cpm)->set_pclock_source(source); 951 } 952 953 954 955 uint32_t 956 jz4780_cpm_get_hclock0_source_frequency(void *cpm) 957 { 958 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_source_frequency(); 959 } 960 961 uint32_t 962 jz4780_cpm_get_hclock2_source_frequency(void *cpm) 963 { 964 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_source_frequency(); 965 } 966 967 uint32_t 968 jz4780_cpm_get_hdmi_source_frequency(void *cpm) 969 { 970 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source_frequency(); 971 } 972 973 uint32_t 974 jz4780_cpm_get_lcd_source_frequency(void *cpm) 975 { 976 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source_frequency(); 977 } 978 979 uint32_t 980 jz4780_cpm_get_memory_source_frequency(void *cpm) 981 { 982 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_source_frequency(); 983 } 984 985 uint32_t 986 jz4780_cpm_get_pclock_source_frequency(void *cpm) 987 { 988 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_source_frequency(); 989 } 990 991 992 993 uint8_t 994 jz4780_cpm_get_main_source(void *cpm) 995 { 996 return static_cast<Cpm_jz4780_chip *>(cpm)->get_main_source(); 997 } 998 999 uint32_t 1000 jz4780_cpm_get_main_frequency(void *cpm) 1001 { 1002 return static_cast<Cpm_jz4780_chip *>(cpm)->get_main_frequency(); 1003 } 1004 1005 uint32_t 1006 jz4780_cpm_get_cpu_frequency(void *cpm) 1007 { 1008 return static_cast<Cpm_jz4780_chip *>(cpm)->get_cpu_frequency(); 1009 } 1010 1011 uint32_t 1012 jz4780_cpm_get_hclock0_frequency(void *cpm) 1013 { 1014 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_frequency(); 1015 } 1016 1017 uint32_t 1018 jz4780_cpm_get_hclock2_frequency(void *cpm) 1019 { 1020 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_frequency(); 1021 } 1022 1023 uint32_t 1024 jz4780_cpm_get_hdmi_frequency(void *cpm) 1025 { 1026 return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_frequency(); 1027 } 1028 1029 uint32_t 1030 jz4780_cpm_get_lcd_pixel_frequency(void *cpm) 1031 { 1032 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_frequency(); 1033 } 1034 1035 uint32_t 1036 jz4780_cpm_get_memory_frequency(void *cpm) 1037 { 1038 return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_frequency(); 1039 } 1040 1041 uint32_t 1042 jz4780_cpm_get_pclock_frequency(void *cpm) 1043 { 1044 return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_frequency(); 1045 } 1046 1047 uint32_t 1048 jz4780_cpm_get_apll_frequency(void *cpm) 1049 { 1050 return static_cast<Cpm_jz4780_chip *>(cpm)->get_apll_frequency(); 1051 } 1052 1053 uint32_t 1054 jz4780_cpm_get_epll_frequency(void *cpm) 1055 { 1056 return static_cast<Cpm_jz4780_chip *>(cpm)->get_epll_frequency(); 1057 } 1058 1059 uint32_t 1060 jz4780_cpm_get_mpll_frequency(void *cpm) 1061 { 1062 return static_cast<Cpm_jz4780_chip *>(cpm)->get_mpll_frequency(); 1063 } 1064 1065 uint32_t 1066 jz4780_cpm_get_vpll_frequency(void *cpm) 1067 { 1068 return static_cast<Cpm_jz4780_chip *>(cpm)->get_vpll_frequency(); 1069 } 1070 1071 1072 1073 void 1074 jz4780_cpm_set_hdmi_frequency(void *cpm, uint32_t pclk) 1075 { 1076 static_cast<Cpm_jz4780_chip *>(cpm)->set_hdmi_frequency(pclk); 1077 } 1078 1079 void 1080 jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk) 1081 { 1082 static_cast<Cpm_jz4780_chip *>(cpm)->set_lcd_pixel_frequency(pclk); 1083 } 1084 1085 void 1086 jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 1087 { 1088 static_cast<Cpm_jz4780_chip *>(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); 1089 }