1 /* 2 * Clock and power management. This exposes the combined functionality 3 * provided by the X1600 and related SoCs. The power management 4 * functionality could be exposed using a separate driver. 5 * 6 * Copyright (C) 2017, 2018, 2020, 2021, 2023 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-x1600.h" 26 #include <math.h> 27 28 29 30 enum Regs : unsigned 31 { 32 Clock_control = 0x000, // CPCCR 33 Low_power_control = 0x004, // LCR 34 Clock_gate0 = 0x020, // CLKGR0 35 Clock_gate1 = 0x028, // CLKGR1 36 Sleep_control = 0x024, // OPCR (oscillator and power control) 37 Clock_status = 0x0d4, // CPCSR 38 Ddr_divider = 0x02c, // DDRCDR 39 Mac_divider = 0x054, // MACCDR 40 I2s_divider0 = 0x060, // I2SCDR 41 I2s_divider1 = 0x070, // I2S1CDR 42 Lcd_divider = 0x064, // LPCDR 43 Msc_divider0 = 0x068, // MSC0CDR 44 Msc_divider1 = 0x0a4, // MSC1CDR 45 Sfc_divider = 0x074, // SFCCDR 46 Ssi_divider = 0x05c, // SSICDR 47 Cim_divider = 0x078, // CIMCDR 48 Pwm_divider = 0x06c, // PWMCDR 49 Can_divider0 = 0x0a0, // CAN0CDR 50 Can_divider1 = 0x0a8, // CAN1CDR 51 Cdbus_divider = 0x0ac, // CDBUSCDR 52 Macphy0_divider = 0x0e4, // MPHY0C 53 Cpm_interrupt = 0x0b0, // CPM_INTR 54 Cpm_interrupt_en = 0x0b4, // CPM_INTRE 55 Cpm_swi = 0x0bc, // CPM_SFTINT 56 Ddr_gate = 0x0d0, // DRCG 57 Cpm_scratch_prot = 0x038, // CPSPPR 58 Cpm_scratch = 0x034, // CPSPR 59 Usb_param_control0 = 0x03c, // USBPCR 60 Usb_reset_detect = 0x040, // USBRDT 61 Usb_vbus_jitter = 0x044, // USBVBFIL 62 Usb_param_control1 = 0x048, // USBPCR1 63 Pll_control = 0x00c, // CPPCR 64 Pll_control_A = 0x010, // CPAPCR 65 Pll_control_M = 0x014, // CPMPCR 66 Pll_control_E = 0x018, // CPEPCR 67 Pll_fraction_A = 0x084, // CPAPACR 68 Pll_fraction_M = 0x088, // CPMPACR 69 Pll_fraction_E = 0x08c, // CPEPACR 70 }; 71 72 enum Clock_bits : unsigned 73 { 74 // Clock_control 75 76 Clock_gate_A = 23, // GATE_SCLKA 77 Clock_cpu_change_enable = 22, // CE_CPU 78 Clock_ahb0_change_enable = 21, // CE_AHB0 79 Clock_ahb2_change_enable = 20, // CE_AHB2 80 Clock_pclock_divider = 16, // PDIV (slow APB peripherals) 81 Clock_hclock2_divider = 12, // H2DIV (fast AHB peripherals) 82 Clock_hclock0_divider = 8, // H0DIV (fast AHB peripherals) 83 Clock_l2cache_divider = 4, // L2CDIV 84 Clock_cpu_divider = 0, // CDIV 85 }; 86 87 enum Clock_source_bits : unsigned 88 { 89 // Clock_control 90 91 Clock_source_main = 30, // SEL_SRC (output to SCLK_A) 92 Clock_source_cpu = 28, // SEL_CPLL (output to CCLK) 93 Clock_source_hclock0 = 26, // SEL_H0PLL (output to AHB0) 94 Clock_source_hclock2 = 24, // SEL_H2PLL (output to AHB2) 95 96 // Ddr_divider 97 98 Clock_source_ddr = 30, // DCS 99 100 // I2s_divider0 101 102 Clock_source_i2s = 31, // I2PCS 103 104 // Lcd_divider 105 106 Clock_source_lcd = 30, // LPCS 107 108 // Mac_divider 109 110 Clock_source_mac = 30, // MACPCS 111 112 // Msc_divider0, Msc_divider1 113 114 Clock_source_msc0 = 30, // MPCS 115 Clock_source_msc1 = 30, // MPCS 116 117 // Sfc_divider 118 119 Clock_source_sfc = 30, // SFCS 120 121 // Ssi_divider 122 123 Clock_source_ssi = 30, // SPCS 124 125 // Cim_divider 126 127 Clock_source_cim = 30, // CIMPCS 128 129 // Pwm_divider 130 131 Clock_source_pwm = 30, // PWMPCS 132 133 // Can_divider0, Can_divider1 134 135 Clock_source_can0 = 30, // CA0CS 136 Clock_source_can1 = 30, // CA1CS 137 138 // Cdbus_divider 139 140 Clock_source_cdbus = 30, // CDCS 141 }; 142 143 enum Clock_sources : unsigned 144 { 145 // Clock_source_main 146 147 Source_external = 1, // EXCLK 148 Source_pll_A = 2, // APLL 149 150 // Stoppable clock sources: 151 // Clock_source_cpu, Clock_source_hclock0, Clock_source_hclock2, 152 // Clock_source_ddr 153 154 Source_mux_stopped = 0, 155 Source_mux_main = 1, // SCLK_A 156 Source_mux_pll_M = 2, // MPLL 157 158 // Unstoppable clock sources: 159 // Clock_source_mac, Clock_source_i2s, Clock_source_lcd, Clock_source_msc0, 160 // Clock_source_msc1, Clock_source_sfc, Clock_source_ssi, Clock_source_cim, 161 // Clock_source_pwm, Clock_source_can0, Clock_source_can1, Clock_source_cdbus 162 163 Source_main = 0, // SCLK_A 164 Source_pll_M = 1, // MPLL 165 Source_pll_E = 2, // EPLL 166 167 Source_i2s_pll_E = 1, // EPLL 168 169 Source_can_external = 3, // EXCLK 170 }; 171 172 enum Clock_gate_bits : unsigned 173 { 174 // Clock_gate0 175 176 Clock_gate_ddr = 31, // DDR 177 Clock_gate_ahb0 = 29, // AHB0 178 Clock_gate_apb0 = 28, // APB0 179 Clock_gate_rtc = 27, // RTC 180 Clock_gate_aes = 24, // AES 181 Clock_gate_lcd_pixel = 23, // LCD 182 Clock_gate_cim = 22, // CIM 183 Clock_gate_dma = 21, // PDMA 184 Clock_gate_ost = 20, // OST 185 Clock_gate_ssi0 = 19, // SSI0 186 Clock_gate_timer = 18, // TCU 187 Clock_gate_dtrng = 17, // DTRNG 188 Clock_gate_uart2 = 16, // UART2 189 Clock_gate_uart1 = 15, // UART1 190 Clock_gate_uart0 = 14, // UART0 191 Clock_gate_sadc = 13, // SADC 192 Clock_gate_audio = 11, // AUDIO 193 Clock_gate_ssi_slv = 10, // SSI_SLV 194 Clock_gate_i2c1 = 8, // I2C1 195 Clock_gate_i2c0 = 7, // I2C0 196 Clock_gate_msc1 = 5, // MSC1 197 Clock_gate_msc0 = 4, // MSC0 198 Clock_gate_otg = 3, // OTG 199 Clock_gate_sfc = 2, // SFC 200 Clock_gate_efuse = 1, // EFUSE 201 Clock_gate_nemc = 0, // NEMC 202 203 // Clock_gate1 204 205 Clock_gate_arb = 30, // ARB 206 Clock_gate_mipi_csi = 28, // MIPI_CSI 207 Clock_gate_intc = 26, // INTC 208 Clock_gate_gmac0 = 23, // GMAC0 209 Clock_gate_uart3 = 16, // UART3 210 Clock_gate_i2s0_tx = 9, // I2S0_dev_tclk 211 Clock_gate_i2s0_rx = 8, // I2S0_dev_rclk 212 Clock_gate_hash = 6, // HASH 213 Clock_gate_pwm = 5, // PWM 214 Clock_gate_cdbus = 2, // CDBUS 215 Clock_gate_can1 = 1, // CAN1 216 Clock_gate_can0 = 0, // CAN0 217 218 // Special value 219 220 Clock_gate_undefined = 32, 221 }; 222 223 // Clock gate register correspondences. 224 225 static uint32_t clock_gate_reg[Clock_identifier_count] = { 226 /* Clock_aic_bitclk */ 0, 227 /* Clock_aic_pclk */ 0, 228 /* Clock_can0 */ Clock_gate1, 229 /* Clock_can1 */ Clock_gate1, 230 /* Clock_cdbus */ Clock_gate1, 231 /* Clock_cim */ Clock_gate0, 232 /* Clock_ddr */ Clock_gate0, 233 /* Clock_dma */ Clock_gate0, 234 /* Clock_emac */ 0, 235 /* Clock_hdmi */ 0, 236 /* Clock_i2c */ Clock_gate0, 237 /* Clock_i2c0 */ Clock_gate0, 238 /* Clock_i2c1 */ Clock_gate0, 239 /* Clock_i2s */ 0, 240 /* Clock_i2s0_rx */ Clock_gate1, 241 /* Clock_i2s0_tx */ Clock_gate1, 242 /* Clock_kbc */ 0, 243 /* Clock_lcd */ 0, 244 /* Clock_lcd_pixel */ Clock_gate0, 245 /* Clock_mac */ Clock_gate1, 246 /* Clock_msc */ Clock_gate0, 247 /* Clock_msc0 */ Clock_gate0, 248 /* Clock_msc1 */ Clock_gate0, 249 /* Clock_pwm */ Clock_gate1, 250 /* Clock_pwm0 */ Clock_gate1, 251 /* Clock_pwm1 */ 0, 252 /* Clock_scc */ 0, 253 /* Clock_sfc */ Clock_gate0, 254 /* Clock_smb0 */ 0, 255 /* Clock_smb1 */ 0, 256 /* Clock_smb2 */ 0, 257 /* Clock_smb3 */ 0, 258 /* Clock_smb4 */ 0, 259 /* Clock_ssi */ Clock_gate0, 260 /* Clock_timer */ Clock_gate0, 261 /* Clock_uart0 */ Clock_gate0, 262 /* Clock_uart1 */ Clock_gate0, 263 /* Clock_uart2 */ Clock_gate0, 264 /* Clock_uart3 */ Clock_gate1, 265 /* Clock_udc */ 0, 266 /* Clock_uhc */ 0, 267 /* Clock_uprt */ 0, 268 }; 269 270 // Clock gate register bit correspondences. 271 272 static enum Clock_gate_bits clock_gate_bit[Clock_identifier_count] = { 273 /* Clock_aic_bitclk */ Clock_gate_undefined, 274 /* Clock_aic_pclk */ Clock_gate_undefined, 275 /* Clock_can0 */ Clock_gate_can0, 276 /* Clock_can1 */ Clock_gate_can1, 277 /* Clock_cdbus */ Clock_gate_cdbus, 278 /* Clock_cim */ Clock_gate_cim, 279 /* Clock_ddr */ Clock_gate_ddr, 280 /* Clock_dma */ Clock_gate_dma, 281 /* Clock_emac */ Clock_gate_undefined, 282 /* Clock_hdmi */ Clock_gate_undefined, 283 /* Clock_i2c */ Clock_gate_i2c0, 284 /* Clock_i2c0 */ Clock_gate_i2c0, 285 /* Clock_i2c1 */ Clock_gate_i2c1, 286 /* Clock_i2s */ Clock_gate_undefined, 287 /* Clock_i2s0_rx */ Clock_gate_i2s0_rx, 288 /* Clock_i2s0_tx */ Clock_gate_i2s0_tx, 289 /* Clock_kbc */ Clock_gate_undefined, 290 /* Clock_lcd */ Clock_gate_undefined, 291 /* Clock_lcd_pixel */ Clock_gate_lcd_pixel, 292 /* Clock_mac */ Clock_gate_gmac0, 293 /* Clock_msc */ Clock_gate_msc0, 294 /* Clock_msc0 */ Clock_gate_msc0, 295 /* Clock_msc1 */ Clock_gate_msc1, 296 /* Clock_pwm */ Clock_gate_pwm, 297 /* Clock_pwm0 */ Clock_gate_pwm, 298 /* Clock_pwm1 */ Clock_gate_undefined, 299 /* Clock_scc */ Clock_gate_undefined, 300 /* Clock_sfc */ Clock_gate_sfc, 301 /* Clock_smb0 */ Clock_gate_undefined, 302 /* Clock_smb1 */ Clock_gate_undefined, 303 /* Clock_smb2 */ Clock_gate_undefined, 304 /* Clock_smb3 */ Clock_gate_undefined, 305 /* Clock_smb4 */ Clock_gate_undefined, 306 /* Clock_ssi */ Clock_gate_ssi0, 307 /* Clock_timer */ Clock_gate_timer, 308 /* Clock_uart0 */ Clock_gate_uart0, 309 /* Clock_uart1 */ Clock_gate_uart1, 310 /* Clock_uart2 */ Clock_gate_uart2, 311 /* Clock_uart3 */ Clock_gate_uart3, 312 /* Clock_udc */ Clock_gate_undefined, 313 /* Clock_uhc */ Clock_gate_undefined, 314 /* Clock_uprt */ Clock_gate_undefined, 315 }; 316 317 enum Divider_bits : unsigned 318 { 319 Ddr_divider_value = 0, // DDRCDR 320 Lcd_divider_value = 0, // LPCDR 321 }; 322 323 enum Clock_status_values : unsigned 324 { 325 Lcd_change_enable = 0x20000000, // CE_LCD 326 Lcd_change_busy = 0x10000000, // LCD_BUSY 327 Lcd_clock_stop = 0x08000000, // LCD_STOP 328 }; 329 330 enum Pll_bits : unsigned 331 { 332 // Pll_control_A, Pll_control_M, Pll_control_E 333 334 Pll_multiplier = 20, // xPLLM 335 Pll_input_division = 14, // xPLLN 336 Pll_output_division1 = 11, // xPLLOD1 337 Pll_output_division0 = 8, // xPLLOD0 338 Pll_stable = 3, // xPLL_ON 339 Pll_enabled = 0, // xPLLEN 340 }; 341 342 enum Pll_bypass_bits : unsigned 343 { 344 Pll_bypass_A = 30, // APLL_BP 345 Pll_bypass_M = 28, // MPLL_BP 346 Pll_bypass_E = 26, // EPLL_BP 347 }; 348 349 350 351 // If implemented as a Hw::Device, various properties would be 352 // initialised in the constructor and obtained from the device tree 353 // definitions. 354 355 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq) 356 : _exclk_freq(exclk_freq) 357 { 358 _regs = new Hw::Mmio_register_block<32>(addr); 359 360 // add_cid("cpm"); 361 // add_cid("cpm-x1600"); 362 // register_property("exclk_freq", &_exclk_freq); 363 } 364 365 // Clock/timer control. 366 367 uint32_t 368 Cpm_x1600_chip::get_clock_gate_register(enum Clock_identifiers clock) 369 { 370 return clock_gate_reg[clock]; 371 } 372 373 uint32_t 374 Cpm_x1600_chip::get_clock_gate_value(enum Clock_identifiers clock) 375 { 376 return 1 << clock_gate_bit[clock]; 377 } 378 379 int 380 Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) 381 { 382 return !(_regs[get_clock_gate_register(clock)] & get_clock_gate_value(clock)); 383 } 384 385 void 386 Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) 387 { 388 uint32_t gate = get_clock_gate_register(clock); 389 390 _regs[gate] = _regs[gate] & ~get_clock_gate_value(clock); 391 } 392 393 void 394 Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) 395 { 396 uint32_t gate = get_clock_gate_register(clock); 397 398 _regs[gate] = _regs[gate] | get_clock_gate_value(clock); 399 } 400 401 402 403 // Utility methods. 404 405 uint32_t 406 Cpm_x1600_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 407 { 408 return (_regs[reg] & (mask << shift)) >> shift; 409 } 410 411 void 412 Cpm_x1600_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 413 { 414 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 415 } 416 417 // General clock divider access. 418 419 uint8_t 420 Cpm_x1600_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) 421 { 422 return get_field(reg, mask, shift) + 1; 423 } 424 425 426 427 // PLL control. 428 429 // Return whether the PLL is stable. 430 431 int 432 Cpm_x1600_chip::have_pll(uint32_t pll_reg) 433 { 434 return _regs[pll_reg] & (1 << Pll_stable); 435 } 436 437 int 438 Cpm_x1600_chip::pll_enabled(uint32_t pll_reg) 439 { 440 return _regs[pll_reg] & (1 << Pll_enabled); 441 } 442 443 int 444 Cpm_x1600_chip::pll_bypassed(uint32_t pll_reg) 445 { 446 uint32_t mask; 447 448 switch (pll_reg) 449 { 450 case Pll_control_A: mask = (1 << Pll_bypass_A); break; 451 case Pll_control_M: mask = (1 << Pll_bypass_M); break; 452 case Pll_control_E: mask = (1 << Pll_bypass_E); break; 453 default: mask = 0; break; 454 } 455 456 return _regs[Pll_control] & mask; 457 } 458 459 void 460 Cpm_x1600_chip::pll_enable(uint32_t pll_reg) 461 { 462 _regs[pll_reg] = _regs[pll_reg] | (1 << Pll_enabled); 463 while (!(_regs[pll_reg] & (1 << Pll_stable))); 464 } 465 466 void 467 Cpm_x1600_chip::pll_disable(uint32_t pll_reg) 468 { 469 _regs[pll_reg] = _regs[pll_reg] & ~(1 << Pll_enabled); 470 while (_regs[pll_reg] & (1 << Pll_stable)); 471 } 472 473 // Feedback (13-bit) multiplier. 474 475 uint16_t 476 Cpm_x1600_chip::get_multiplier(uint32_t pll_reg) 477 { 478 return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; 479 } 480 481 void 482 Cpm_x1600_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) 483 { 484 set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); 485 } 486 487 // Input (6-bit) divider. 488 489 uint8_t 490 Cpm_x1600_chip::get_input_division(uint32_t pll_reg) 491 { 492 return get_field(pll_reg, 0x3f, Pll_input_division) + 1; 493 } 494 495 void 496 Cpm_x1600_chip::set_input_division(uint32_t pll_reg, uint8_t divider) 497 { 498 set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); 499 } 500 501 // Output (dual 3-bit) dividers. 502 503 uint8_t 504 Cpm_x1600_chip::get_output_division(uint32_t pll_reg) 505 { 506 uint8_t d0 = get_field(pll_reg, 0x07, Pll_output_division0); 507 uint8_t d1 = get_field(pll_reg, 0x07, Pll_output_division1); 508 509 return d0 * d1; 510 } 511 512 void 513 Cpm_x1600_chip::set_output_division(uint32_t pll_reg, uint8_t divider) 514 { 515 // Assert 1 as a minimum. 516 // Divider 0 must be less than or equal to divider 1. 517 518 uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1)); 519 uint8_t d1 = divider / d0; 520 521 set_field(pll_reg, 0x07, Pll_output_division0, d0); 522 set_field(pll_reg, 0x07, Pll_output_division1, d1); 523 } 524 525 uint32_t 526 Cpm_x1600_chip::get_pll_frequency(uint32_t pll_reg) 527 { 528 // Test for PLL enable and not PLL bypass. 529 530 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 531 return (_exclk_freq * get_multiplier(pll_reg)) / 532 (get_input_division(pll_reg) * get_output_division(pll_reg)); 533 else 534 return _exclk_freq; 535 } 536 537 void 538 Cpm_x1600_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 539 { 540 set_multiplier(pll_reg, multiplier); 541 set_input_division(pll_reg, in_divider); 542 set_output_division(pll_reg, out_divider); 543 544 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 545 while (!have_pll(pll_reg)); 546 } 547 548 549 550 // CPU clock (CCLK) divider. 551 552 uint8_t 553 Cpm_x1600_chip::get_cpu_divider() 554 { 555 return _get_divider(Clock_control, 0xf, Clock_cpu_divider); 556 } 557 558 // Fast peripheral clock (H0CLK) divider. 559 560 uint8_t 561 Cpm_x1600_chip::get_hclock0_divider() 562 { 563 return _get_divider(Clock_control, 0xf, Clock_hclock0_divider); 564 } 565 566 // Fast peripheral clock (H2CLK) divider. 567 568 uint8_t 569 Cpm_x1600_chip::get_hclock2_divider() 570 { 571 return _get_divider(Clock_control, 0xf, Clock_hclock2_divider); 572 } 573 574 // Slow peripheral clock (PCLK) divider. 575 576 uint8_t 577 Cpm_x1600_chip::get_pclock_divider() 578 { 579 return _get_divider(Clock_control, 0xf, Clock_pclock_divider); 580 } 581 582 // LCD clock (LPCLK) divider for LCD pixel clock. 583 584 uint8_t 585 Cpm_x1600_chip::get_lcd_pixel_divider(uint8_t controller) 586 { 587 (void) controller; 588 return _get_divider(Lcd_divider, 0xff, Lcd_divider_value); 589 } 590 591 // Memory clock (DDR_CLK) divider. 592 593 uint8_t 594 Cpm_x1600_chip::get_memory_divider() 595 { 596 return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); 597 } 598 599 // LCD pixel clock divider. 600 601 void 602 Cpm_x1600_chip::set_lcd_pixel_divider(uint8_t controller, uint16_t division) 603 { 604 if (controller > 0) 605 return; 606 607 if ((division < 1) || (division > 256)) 608 return; 609 610 // Enable change. 611 612 _regs[Lcd_divider] = _regs[Lcd_divider] | Lcd_change_enable; 613 614 // Set the divider. 615 616 set_field(Lcd_divider, 0xff, Lcd_divider_value, division - 1); 617 618 // Restart clock and disable change. 619 620 while (_regs[Lcd_divider] & Lcd_change_busy); 621 _regs[Lcd_divider] = _regs[Lcd_divider] & ~Lcd_change_enable; 622 } 623 624 625 626 // Clock sources. 627 628 uint8_t 629 Cpm_x1600_chip::get_memory_source() 630 { 631 return get_field(Ddr_divider, 0x3, Clock_source_ddr); 632 } 633 634 uint32_t 635 Cpm_x1600_chip::get_memory_source_frequency() 636 { 637 switch (get_memory_source()) 638 { 639 case Source_mux_main: 640 return get_main_frequency(); 641 case Source_mux_pll_M: 642 return get_pll_frequency(Pll_control_M); 643 default: 644 return 0; 645 } 646 } 647 648 uint8_t 649 Cpm_x1600_chip::get_cpu_source() 650 { 651 return get_field(Clock_control, 0x3, Clock_source_cpu); 652 } 653 654 uint32_t 655 Cpm_x1600_chip::get_cpu_source_frequency() 656 { 657 switch (get_cpu_source()) 658 { 659 case Source_mux_main: 660 return get_main_frequency(); 661 case Source_mux_pll_M: 662 return get_pll_frequency(Pll_control_M); 663 default: 664 return 0; 665 } 666 } 667 668 uint8_t 669 Cpm_x1600_chip::get_hclock0_source() 670 { 671 return get_field(Clock_control, 0x3, Clock_source_hclock0); 672 } 673 674 uint32_t 675 Cpm_x1600_chip::get_hclock0_source_frequency() 676 { 677 switch (get_hclock0_source()) 678 { 679 case Source_mux_main: 680 return get_main_frequency(); 681 case Source_mux_pll_M: 682 return get_pll_frequency(Pll_control_M); 683 default: 684 return 0; 685 } 686 } 687 688 uint8_t 689 Cpm_x1600_chip::get_hclock2_source() 690 { 691 return get_field(Clock_control, 0x3, Clock_source_hclock2); 692 } 693 694 uint32_t 695 Cpm_x1600_chip::get_hclock2_source_frequency() 696 { 697 switch (get_hclock2_source()) 698 { 699 case Source_mux_main: 700 return get_main_frequency(); 701 case Source_mux_pll_M: 702 return get_pll_frequency(Pll_control_M); 703 default: 704 return 0; 705 } 706 } 707 708 void 709 Cpm_x1600_chip::set_hclock2_source(uint8_t source) 710 { 711 set_field(Clock_control, 0x3, Clock_source_hclock2, source); 712 } 713 714 uint8_t 715 Cpm_x1600_chip::get_lcd_source(uint8_t controller) 716 { 717 (void) controller; 718 return get_field(Lcd_divider, 0x3, Clock_source_lcd); 719 } 720 721 uint32_t 722 Cpm_x1600_chip::get_lcd_source_frequency(uint8_t controller) 723 { 724 switch (get_lcd_source(controller)) 725 { 726 case Source_main: 727 return get_main_frequency(); 728 case Source_pll_M: 729 return get_pll_frequency(Pll_control_M); 730 case Source_pll_E: 731 return get_pll_frequency(Pll_control_E); 732 default: 733 return 0; 734 } 735 } 736 737 void 738 Cpm_x1600_chip::set_lcd_source(uint8_t controller, uint8_t source) 739 { 740 if (controller > 0) 741 return; 742 743 // Stop clock and enable change. 744 745 _regs[Lcd_divider] = _regs[Lcd_divider] | Lcd_change_enable | Lcd_clock_stop; 746 747 // Set the source. 748 749 set_field(Lcd_divider, 0x03, Clock_source_lcd, source); 750 751 // Restart clock and disable change. 752 753 while (_regs[Lcd_divider] & Lcd_change_busy); 754 _regs[Lcd_divider] = _regs[Lcd_divider] & ~(Lcd_change_enable | Lcd_clock_stop); 755 } 756 757 uint8_t 758 Cpm_x1600_chip::get_pclock_source() 759 { 760 return get_hclock2_source(); 761 } 762 763 uint32_t 764 Cpm_x1600_chip::get_pclock_source_frequency() 765 { 766 return get_hclock2_source_frequency(); 767 } 768 769 void 770 Cpm_x1600_chip::set_pclock_source(uint8_t source) 771 { 772 set_hclock2_source(source); 773 } 774 775 776 777 // Source frequency, used by various clock sources. 778 779 uint8_t 780 Cpm_x1600_chip::get_main_source() 781 { 782 return get_field(Clock_control, 0x3, Clock_source_main); 783 } 784 785 uint32_t 786 Cpm_x1600_chip::get_main_frequency() 787 { 788 switch (get_main_source()) 789 { 790 case Source_pll_A: 791 return get_pll_frequency(Pll_control_A); 792 case Source_external: 793 return _exclk_freq; 794 default: 795 return 0; 796 } 797 } 798 799 // Clock frequency for the CPU. 800 801 uint32_t 802 Cpm_x1600_chip::get_cpu_frequency() 803 { 804 return get_cpu_source_frequency() / get_cpu_divider(); 805 } 806 807 // Clock frequency for fast peripherals. 808 809 uint32_t 810 Cpm_x1600_chip::get_hclock0_frequency() 811 { 812 return get_hclock0_source_frequency() / get_hclock0_divider(); 813 } 814 815 // Clock frequency for fast peripherals. 816 817 uint32_t 818 Cpm_x1600_chip::get_hclock2_frequency() 819 { 820 return get_hclock2_source_frequency() / get_hclock2_divider(); 821 } 822 823 // Clock frequency for slow peripherals. 824 825 uint32_t 826 Cpm_x1600_chip::get_pclock_frequency() 827 { 828 return get_pclock_source_frequency() / get_pclock_divider(); 829 } 830 831 // Clock frequency for the memory. 832 833 uint32_t 834 Cpm_x1600_chip::get_memory_frequency() 835 { 836 return get_memory_source_frequency() / get_memory_divider(); 837 } 838 839 uint32_t 840 Cpm_x1600_chip::get_apll_frequency() 841 { 842 return get_pll_frequency(Pll_control_A); 843 } 844 845 uint32_t 846 Cpm_x1600_chip::get_epll_frequency() 847 { 848 return get_pll_frequency(Pll_control_E); 849 } 850 851 uint32_t 852 Cpm_x1600_chip::get_mpll_frequency() 853 { 854 return get_pll_frequency(Pll_control_M); 855 } 856 857 858 859 uint32_t 860 Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) 861 { 862 switch (clock) 863 { 864 // NOTE: Returning only the frequency for controller 0. 865 866 case Clock_lcd_pixel: 867 return get_lcd_source_frequency(0) / get_lcd_pixel_divider(0); 868 869 // NOTE: Consider a better error result. 870 871 default: 872 return 0; 873 } 874 } 875 876 void 877 Cpm_x1600_chip::set_frequency(enum Clock_identifiers clock, uint32_t frequency) 878 { 879 switch (clock) 880 { 881 // The pixel frequency is based on the selected clock source (SCLK_A, MPLL or 882 // EPLL). 883 884 case Clock_lcd_pixel: 885 886 // Switch to the MPLL and attempt to set the divider. 887 888 set_lcd_source(0, Source_pll_M); 889 pll_enable(Pll_control_M); 890 set_lcd_pixel_divider(0, get_lcd_source_frequency() / frequency); 891 break; 892 893 default: 894 break; 895 } 896 } 897 898 899 900 // C language interface functions. 901 902 void 903 *x1600_cpm_init(l4_addr_t cpm_base) 904 { 905 /* Initialise the clock and power management peripheral with the 906 register memory region and a 24MHz EXCLK frequency. */ 907 908 return (void *) new Cpm_x1600_chip(cpm_base, 24000000); 909 } 910 911 int 912 x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 913 { 914 return static_cast<Cpm_x1600_chip *>(cpm)->have_clock(clock); 915 } 916 917 void 918 x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 919 { 920 static_cast<Cpm_x1600_chip *>(cpm)->start_clock(clock); 921 } 922 923 void 924 x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 925 { 926 static_cast<Cpm_x1600_chip *>(cpm)->stop_clock(clock); 927 } 928 929 930 931 uint8_t 932 x1600_cpm_get_cpu_divider(void *cpm) 933 { 934 return static_cast<Cpm_x1600_chip *>(cpm)->get_cpu_divider(); 935 } 936 937 uint8_t 938 x1600_cpm_get_hclock0_divider(void *cpm) 939 { 940 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock0_divider(); 941 } 942 943 uint8_t 944 x1600_cpm_get_hclock2_divider(void *cpm) 945 { 946 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock2_divider(); 947 } 948 949 uint8_t 950 x1600_cpm_get_lcd_pixel_divider(void *cpm) 951 { 952 return static_cast<Cpm_x1600_chip *>(cpm)->get_lcd_pixel_divider(); 953 } 954 955 uint8_t 956 x1600_cpm_get_memory_divider(void *cpm) 957 { 958 return static_cast<Cpm_x1600_chip *>(cpm)->get_memory_divider(); 959 } 960 961 uint8_t 962 x1600_cpm_get_pclock_divider(void *cpm) 963 { 964 return static_cast<Cpm_x1600_chip *>(cpm)->get_pclock_divider(); 965 } 966 967 968 969 uint8_t 970 x1600_cpm_get_hclock0_source(void *cpm) 971 { 972 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock0_source(); 973 } 974 975 uint8_t 976 x1600_cpm_get_hclock2_source(void *cpm) 977 { 978 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock2_source(); 979 } 980 981 uint8_t 982 x1600_cpm_get_lcd_source(void *cpm) 983 { 984 return static_cast<Cpm_x1600_chip *>(cpm)->get_lcd_source(); 985 } 986 987 uint8_t 988 x1600_cpm_get_memory_source(void *cpm) 989 { 990 return static_cast<Cpm_x1600_chip *>(cpm)->get_memory_source(); 991 } 992 993 uint8_t 994 x1600_cpm_get_pclock_source(void *cpm) 995 { 996 return static_cast<Cpm_x1600_chip *>(cpm)->get_pclock_source(); 997 } 998 999 void 1000 x1600_cpm_set_pclock_source(void *cpm, uint8_t source) 1001 { 1002 static_cast<Cpm_x1600_chip *>(cpm)->set_pclock_source(source); 1003 } 1004 1005 1006 1007 uint32_t 1008 x1600_cpm_get_hclock0_source_frequency(void *cpm) 1009 { 1010 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock0_source_frequency(); 1011 } 1012 1013 uint32_t 1014 x1600_cpm_get_hclock2_source_frequency(void *cpm) 1015 { 1016 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock2_source_frequency(); 1017 } 1018 1019 uint32_t 1020 x1600_cpm_get_lcd_source_frequency(void *cpm) 1021 { 1022 return static_cast<Cpm_x1600_chip *>(cpm)->get_lcd_source_frequency(); 1023 } 1024 1025 uint32_t 1026 x1600_cpm_get_memory_source_frequency(void *cpm) 1027 { 1028 return static_cast<Cpm_x1600_chip *>(cpm)->get_memory_source_frequency(); 1029 } 1030 1031 uint32_t 1032 x1600_cpm_get_pclock_source_frequency(void *cpm) 1033 { 1034 return static_cast<Cpm_x1600_chip *>(cpm)->get_pclock_source_frequency(); 1035 } 1036 1037 1038 1039 uint8_t 1040 x1600_cpm_get_main_source(void *cpm) 1041 { 1042 return static_cast<Cpm_x1600_chip *>(cpm)->get_main_source(); 1043 } 1044 1045 uint32_t 1046 x1600_cpm_get_main_frequency(void *cpm) 1047 { 1048 return static_cast<Cpm_x1600_chip *>(cpm)->get_main_frequency(); 1049 } 1050 1051 uint32_t 1052 x1600_cpm_get_cpu_frequency(void *cpm) 1053 { 1054 return static_cast<Cpm_x1600_chip *>(cpm)->get_cpu_frequency(); 1055 } 1056 1057 uint32_t 1058 x1600_cpm_get_hclock0_frequency(void *cpm) 1059 { 1060 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock0_frequency(); 1061 } 1062 1063 uint32_t 1064 x1600_cpm_get_hclock2_frequency(void *cpm) 1065 { 1066 return static_cast<Cpm_x1600_chip *>(cpm)->get_hclock2_frequency(); 1067 } 1068 1069 uint32_t 1070 x1600_cpm_get_memory_frequency(void *cpm) 1071 { 1072 return static_cast<Cpm_x1600_chip *>(cpm)->get_memory_frequency(); 1073 } 1074 1075 uint32_t 1076 x1600_cpm_get_pclock_frequency(void *cpm) 1077 { 1078 return static_cast<Cpm_x1600_chip *>(cpm)->get_pclock_frequency(); 1079 } 1080 1081 uint32_t 1082 x1600_cpm_get_apll_frequency(void *cpm) 1083 { 1084 return static_cast<Cpm_x1600_chip *>(cpm)->get_apll_frequency(); 1085 } 1086 1087 uint32_t 1088 x1600_cpm_get_epll_frequency(void *cpm) 1089 { 1090 return static_cast<Cpm_x1600_chip *>(cpm)->get_epll_frequency(); 1091 } 1092 1093 uint32_t 1094 x1600_cpm_get_mpll_frequency(void *cpm) 1095 { 1096 return static_cast<Cpm_x1600_chip *>(cpm)->get_mpll_frequency(); 1097 } 1098 1099 1100 1101 uint32_t 1102 x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) 1103 { 1104 return static_cast<Cpm_x1600_chip *>(cpm)->get_frequency(clock); 1105 } 1106 1107 void 1108 x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency) 1109 { 1110 static_cast<Cpm_x1600_chip *>(cpm)->set_frequency(clock, frequency); 1111 } 1112 1113 void 1114 x1600_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 1115 { 1116 static_cast<Cpm_x1600_chip *>(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); 1117 }