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 #include <stdio.h> 28 29 30 31 // Register locations. 32 33 enum Regs : unsigned 34 { 35 Clock_control = 0x000, // CPCCR 36 Low_power_control = 0x004, // LCR 37 Clock_gate0 = 0x020, // CLKGR0 38 Clock_gate1 = 0x028, // CLKGR1 39 Sleep_control = 0x024, // OPCR (oscillator and power control) 40 Clock_status = 0x0d4, // CPCSR 41 Divider_ddr = 0x02c, // DDRCDR 42 Divider_mac = 0x054, // MACCDR 43 Divider0_i2s0 = 0x060, // I2SCDR 44 Divider1_i2s0 = 0x070, // I2S1CDR 45 Divider_lcd = 0x064, // LPCDR 46 Divider_msc0 = 0x068, // MSC0CDR 47 Divider_msc1 = 0x0a4, // MSC1CDR 48 Divider_sfc = 0x074, // SFCCDR 49 Divider_ssi = 0x05c, // SSICDR 50 Divider_cim = 0x078, // CIMCDR 51 Divider_pwm = 0x06c, // PWMCDR 52 Divider_can0 = 0x0a0, // CAN0CDR 53 Divider_can1 = 0x0a8, // CAN1CDR 54 Divider_cdbus = 0x0ac, // CDBUSCDR 55 Divider_macphy0 = 0x0e4, // MPHY0C 56 Cpm_interrupt = 0x0b0, // CPM_INTR 57 Cpm_interrupt_en = 0x0b4, // CPM_INTRE 58 Cpm_swi = 0x0bc, // CPM_SFTINT 59 Ddr_gate = 0x0d0, // DRCG 60 Cpm_scratch_prot = 0x038, // CPSPPR 61 Cpm_scratch = 0x034, // CPSPR 62 Usb_param_control0 = 0x03c, // USBPCR 63 Usb_reset_detect = 0x040, // USBRDT 64 Usb_vbus_jitter = 0x044, // USBVBFIL 65 Usb_param_control1 = 0x048, // USBPCR1 66 Pll_control = 0x00c, // CPPCR 67 Pll_control_A = 0x010, // CPAPCR 68 Pll_control_M = 0x014, // CPMPCR 69 Pll_control_E = 0x018, // CPEPCR 70 Pll_fraction_A = 0x084, // CPAPACR 71 Pll_fraction_M = 0x088, // CPMPACR 72 Pll_fraction_E = 0x08c, // CPEPACR 73 }; 74 75 enum Clock_source_values : unsigned 76 { 77 Source_mME_main = 0, 78 Source_mME_pll_M = 1, 79 Source_mME_pll_E = 2, 80 81 // Special value 82 83 Source_mask = 0x3, 84 }; 85 86 87 88 // Register field definitions. 89 90 Field Clock_source_main (Clock_control, 3, 30); // SEL_SRC (output to SCLK_A) 91 Field Clock_source_cpu (Clock_control, 3, 28); // SEL_CPLL (output to CCLK) 92 Field Clock_source_hclock0 (Clock_control, 3, 26); // SEL_H0PLL (output to AHB0) 93 Field Clock_source_hclock2 (Clock_control, 3, 24); // SEL_H2PLL (output to AHB2) 94 Field Clock_source_can0 (Divider_can0, 3, 30); // CA0CS 95 Field Clock_source_can1 (Divider_can1, 3, 30); // CA1CS 96 Field Clock_source_cdbus (Divider_cdbus, 3, 30); // CDCS 97 Field Clock_source_cim (Divider_cim, 3, 30); // CIMPCS 98 Field Clock_source_ddr (Divider_ddr, 3, 30); // DCS 99 Field Clock_source_i2s (Divider0_i2s0, 1, 31); // I2PCS 100 Field Clock_source_lcd (Divider_lcd, 3, 30); // LPCS 101 Field Clock_source_mac (Divider_mac, 3, 30); // MACPCS 102 Field Clock_source_msc0 (Divider_msc0, 3, 30); // MPCS 103 Field Clock_source_msc1 (Divider_msc1, 3, 30); // MPCS 104 Field Clock_source_pwm (Divider_pwm, 3, 30); // PWMPCS 105 Field Clock_source_sfc (Divider_sfc, 3, 30); // SFCS 106 Field Clock_source_ssi (Divider_ssi, 3, 30); // SPCS 107 108 Field Clock_busy_cpu (Clock_status, 1, 0); 109 Field Clock_busy_ddr (Divider_ddr, 1, 28); 110 Field Clock_busy_mac (Divider_mac, 1, 28); 111 Field Clock_busy_lcd (Divider_lcd, 1, 28); 112 Field Clock_busy_msc0 (Divider_msc0, 1, 28); 113 Field Clock_busy_msc1 (Divider_msc1, 1, 28); 114 Field Clock_busy_sfc (Divider_sfc, 1, 28); 115 Field Clock_busy_ssi (Divider_ssi, 1, 28); 116 Field Clock_busy_cim (Divider_cim, 1, 28); 117 Field Clock_busy_pwm (Divider_pwm, 1, 28); 118 Field Clock_busy_can0 (Divider_can0, 1, 28); 119 Field Clock_busy_can1 (Divider_can1, 1, 28); 120 Field Clock_busy_cdbus (Divider_cdbus, 1, 28); 121 122 Field Clock_change_enable_cpu (Clock_control, 1, 22); 123 Field Clock_change_enable_ahb0 (Clock_control, 1, 21); 124 Field Clock_change_enable_ahb2 (Clock_control, 1, 20); 125 Field Clock_change_enable_ddr (Divider_ddr, 1, 29); 126 Field Clock_change_enable_mac (Divider_mac, 1, 29); 127 Field Clock_change_enable_i2s (Divider0_i2s0, 1, 29); 128 Field Clock_change_enable_lcd (Divider_lcd, 1, 29); 129 Field Clock_change_enable_msc0 (Divider_msc0, 1, 29); 130 Field Clock_change_enable_msc1 (Divider_msc1, 1, 29); 131 Field Clock_change_enable_sfc (Divider_sfc, 1, 29); 132 Field Clock_change_enable_ssi (Divider_ssi, 1, 29); 133 Field Clock_change_enable_cim (Divider_cim, 1, 29); 134 Field Clock_change_enable_pwm (Divider_pwm, 1, 29); 135 Field Clock_change_enable_can0 (Divider_can0, 1, 29); 136 Field Clock_change_enable_can1 (Divider_can1, 1, 29); 137 Field Clock_change_enable_cdbus (Divider_cdbus, 1, 29); 138 139 Field Clock_divider_can0 (Divider_can0, 0xff, 0); // CAN0CDR 140 Field Clock_divider_can1 (Divider_can1, 0xff, 0); // CAN1CDR 141 Field Clock_divider_cdbus (Divider_cdbus, 0xff, 0); // CDBUSCDR 142 Field Clock_divider_cim (Divider_cim, 0xff, 0); // CIMCDR 143 Field Clock_divider_cpu (Clock_control, 0x0f, 0); // CDIV 144 Field Clock_divider_ddr (Divider_ddr, 0x0f, 0); // DDRCDR 145 Field Clock_divider_hclock0 (Clock_control, 0x0f, 8); // H0DIV (fast AHB peripherals) 146 Field Clock_divider_hclock2 (Clock_control, 0x0f, 12); // H2DIV (fast AHB peripherals) 147 Field Clock_divider_l2cache (Clock_control, 0x0f, 4); // L2CDIV 148 Field Clock_divider_lcd (Divider_lcd, 0xff, 0); // LPCDR 149 Field Clock_divider_mac (Divider_mac, 0xff, 0); // MACCDR 150 Field Clock_divider_msc0 (Divider_msc0, 0xff, 0); // MSC0CDR 151 Field Clock_divider_msc1 (Divider_msc1, 0xff, 0); // MSC1CDR 152 Field Clock_divider_pclock (Clock_control, 0x0f, 16); // PDIV (slow APB peripherals) 153 Field Clock_divider_pwm (Divider_pwm, 0x0f, 0); // PWMCDR 154 Field Clock_divider_sfc (Divider_sfc, 0xff, 0); // SFCCDR 155 Field Clock_divider_ssi (Divider_ssi, 0xff, 0); // SSICDR 156 157 Field Clock_gate_main (Clock_control, 1, 23); // GATE_SCLKA 158 Field Clock_gate_ddr (Clock_gate0, 1, 31); // DDR 159 Field Clock_gate_ahb0 (Clock_gate0, 1, 29); // AHB0 160 Field Clock_gate_apb0 (Clock_gate0, 1, 28); // APB0 161 Field Clock_gate_rtc (Clock_gate0, 1, 27); // RTC 162 Field Clock_gate_aes (Clock_gate0, 1, 24); // AES 163 Field Clock_gate_lcd_pixel (Clock_gate0, 1, 23); // LCD 164 Field Clock_gate_cim (Clock_gate0, 1, 22); // CIM 165 Field Clock_gate_dma (Clock_gate0, 1, 21); // PDMA 166 Field Clock_gate_ost (Clock_gate0, 1, 20); // OST 167 Field Clock_gate_ssi0 (Clock_gate0, 1, 19); // SSI0 168 Field Clock_gate_timer (Clock_gate0, 1, 18); // TCU 169 Field Clock_gate_dtrng (Clock_gate0, 1, 17); // DTRNG 170 Field Clock_gate_uart2 (Clock_gate0, 1, 16); // UART2 171 Field Clock_gate_uart1 (Clock_gate0, 1, 15); // UART1 172 Field Clock_gate_uart0 (Clock_gate0, 1, 14); // UART0 173 Field Clock_gate_sadc (Clock_gate0, 1, 13); // SADC 174 Field Clock_gate_audio (Clock_gate0, 1, 11); // AUDIO 175 Field Clock_gate_ssi_slv (Clock_gate0, 1, 10); // SSI_SLV 176 Field Clock_gate_i2c1 (Clock_gate0, 1, 8); // I2C1 177 Field Clock_gate_i2c0 (Clock_gate0, 1, 7); // I2C0 178 Field Clock_gate_msc1 (Clock_gate0, 1, 5); // MSC1 179 Field Clock_gate_msc0 (Clock_gate0, 1, 4); // MSC0 180 Field Clock_gate_otg (Clock_gate0, 1, 3); // OTG 181 Field Clock_gate_sfc (Clock_gate0, 1, 2); // SFC 182 Field Clock_gate_efuse (Clock_gate0, 1, 1); // EFUSE 183 Field Clock_gate_nemc (Clock_gate0, 1, 0); // NEMC 184 Field Clock_gate_arb (Clock_gate1, 1, 30); // ARB 185 Field Clock_gate_mipi_csi (Clock_gate1, 1, 28); // MIPI_CSI 186 Field Clock_gate_intc (Clock_gate1, 1, 26); // INTC 187 Field Clock_gate_gmac0 (Clock_gate1, 1, 23); // GMAC0 188 Field Clock_gate_uart3 (Clock_gate1, 1, 16); // UART3 189 Field Clock_gate_i2s0_tx (Clock_gate1, 1, 9); // I2S0_dev_tclk 190 Field Clock_gate_i2s0_rx (Clock_gate1, 1, 8); // I2S0_dev_rclk 191 Field Clock_gate_hash (Clock_gate1, 1, 6); // HASH 192 Field Clock_gate_pwm (Clock_gate1, 1, 5); // PWM 193 Field Clock_gate_cdbus (Clock_gate1, 1, 2); // CDBUS 194 Field Clock_gate_can1 (Clock_gate1, 1, 1); // CAN1 195 Field Clock_gate_can0 (Clock_gate1, 1, 0); // CAN0 196 197 Field Pll_enable_A (Pll_control_A, 1, 0); // APLLEN 198 Field Pll_enable_E (Pll_control_E, 1, 0); // EPLLEN 199 Field Pll_enable_M (Pll_control_M, 1, 0); // MPLLEN 200 201 Field Pll_stable_A (Pll_control_A, 1, 3); // APLL_ON 202 Field Pll_stable_E (Pll_control_E, 1, 3); // EPLL_ON 203 Field Pll_stable_M (Pll_control_M, 1, 3); // MPLL_ON 204 205 Field Pll_bypass_A (Pll_control_A, 1, 30); // APLL_BP 206 Field Pll_bypass_E (Pll_control_E, 1, 26); // EPLL_BP 207 Field Pll_bypass_M (Pll_control_M, 1, 28); // MPLL_BP 208 209 Field Pll_multiplier_A (Pll_control_A, 0x1fff, 20); // APLLM 210 Field Pll_multiplier_E (Pll_control_E, 0x1fff, 20); // EPLLM 211 Field Pll_multiplier_M (Pll_control_M, 0x1fff, 20); // MPLLM 212 213 Field Pll_input_division_A (Pll_control_A, 0x3f, 14); // APLLN 214 Field Pll_input_division_E (Pll_control_E, 0x3f, 14); // EPLLN 215 Field Pll_input_division_M (Pll_control_M, 0x3f, 14); // MPLLN 216 217 Field Pll_output_division1_A (Pll_control_A, 0x07, 11); // APLLOD1 218 Field Pll_output_division1_E (Pll_control_E, 0x07, 11); // EPLLOD1 219 Field Pll_output_division1_M (Pll_control_M, 0x07, 11); // MPLLOD1 220 221 Field Pll_output_division0_A (Pll_control_A, 0x07, 8); // APLLOD0 222 Field Pll_output_division0_E (Pll_control_E, 0x07, 8); // EPLLOD0 223 Field Pll_output_division0_M (Pll_control_M, 0x07, 8); // MPLLOD0 224 225 226 227 // Multiplexer instances. 228 229 #define Clocks(...) ((enum Clock_identifiers []) {__VA_ARGS__}) 230 231 Mux mux_external(Clock_external); 232 233 Mux mux_pclock(Clock_pclock); 234 235 Mux mux_ahb2_apb(Clock_ahb2_apb); 236 237 Mux mux_core(3, Clocks(Clock_none, Clock_main, Clock_pll_M)); 238 239 Mux mux_bus(4, Clocks(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external)); 240 241 Mux mux_dev(3, Clocks(Clock_main, Clock_pll_M, Clock_pll_E)); 242 243 Mux mux_i2s(2, Clocks(Clock_main, Clock_pll_E)); 244 245 246 247 // Clock instances. 248 249 Clock clock_ahb2_apb(Source(mux_core, Clock_source_hclock2)); 250 251 Clock clock_aic_bitclk; 252 253 Clock clock_aic_pclk; 254 255 Clock clock_can0(Source(mux_bus, Clock_source_can0), 256 Clock_gate_can0, 257 Clock_change_enable_can0, 258 Clock_busy_can0, 259 Clock_divider_can0); 260 261 Clock clock_can1(Source(mux_bus, Clock_source_can1), 262 Clock_gate_can1, 263 Clock_change_enable_can1, 264 Clock_busy_can1, 265 Clock_divider_can1); 266 267 Clock clock_cdbus(Source(mux_dev, Clock_source_cdbus), 268 Clock_gate_cdbus, 269 Clock_change_enable_cdbus, 270 Clock_busy_cdbus, 271 Clock_divider_cdbus); 272 273 Clock clock_cim(Source(mux_dev, Clock_source_cim), 274 Clock_gate_cim, 275 Clock_change_enable_cim, 276 Clock_busy_cim, 277 Clock_divider_cim); 278 279 Clock clock_cpu(Source(mux_core, Clock_source_cpu), 280 Field::undefined, 281 Clock_change_enable_cpu, 282 Clock_busy_cpu, 283 Clock_divider_cpu); 284 285 Clock clock_ddr(Source(mux_core, Clock_source_ddr), 286 Clock_gate_ddr, 287 Clock_change_enable_ddr, 288 Clock_busy_ddr, 289 Clock_divider_ddr); 290 291 Clock clock_dma(Source(mux_pclock), Clock_gate_dma); 292 293 Clock clock_emac; 294 295 Clock clock_external; 296 297 Clock clock_hclock0(Source(mux_core, Clock_source_hclock0), 298 Clock_gate_ahb0, 299 Clock_change_enable_ahb0, 300 Field::undefined, 301 Clock_divider_hclock0); 302 303 Clock clock_hclock2(Source(mux_ahb2_apb), 304 Clock_gate_apb0, 305 Clock_change_enable_ahb2, 306 Field::undefined, 307 Clock_divider_hclock2); 308 309 Clock clock_hdmi; 310 311 Clock clock_i2c(Source(mux_pclock), Clock_gate_i2c0); 312 313 Clock clock_i2c0(Source(mux_pclock), Clock_gate_i2c0); 314 315 Clock clock_i2c1(Source(mux_pclock), Clock_gate_i2c1); 316 317 Clock clock_i2s; 318 319 Clock clock_i2s0_rx(Source(mux_i2s, Clock_source_i2s), 320 Clock_gate_i2s0_rx, 321 Clock_change_enable_i2s); 322 323 Clock clock_i2s0_tx(Source(mux_i2s, Clock_source_i2s), 324 Clock_gate_i2s0_tx, 325 Clock_change_enable_i2s); 326 327 Clock clock_kbc; 328 329 Clock clock_lcd; 330 331 Clock clock_lcd_pixel(Source(mux_dev, Clock_source_lcd), 332 Clock_gate_lcd_pixel, 333 Clock_change_enable_lcd, 334 Clock_busy_lcd, 335 Clock_divider_lcd); 336 337 Clock clock_mac(Source(mux_dev, Clock_source_mac), 338 Clock_gate_gmac0, 339 Clock_change_enable_mac, 340 Clock_busy_mac, 341 Clock_divider_mac); 342 343 Clock clock_main(Source(mux_core, Clock_source_main), 344 Clock_gate_main); 345 346 Clock clock_msc(Source(mux_dev, Clock_source_msc0), 347 Clock_gate_msc0, 348 Clock_change_enable_msc0, 349 Clock_busy_msc0, 350 Clock_divider_msc0); 351 352 Clock clock_msc0(Source(mux_dev, Clock_source_msc0), 353 Clock_gate_msc0, 354 Clock_change_enable_msc0, 355 Clock_busy_msc0, 356 Clock_divider_msc0); 357 358 Clock clock_msc1(Source(mux_dev, Clock_source_msc1), 359 Clock_gate_msc1, 360 Clock_change_enable_msc1, 361 Clock_busy_msc1, 362 Clock_divider_msc1); 363 364 Clock clock_none; 365 366 Clock clock_pclock(Source(mux_ahb2_apb), 367 Clock_gate_apb0, 368 Field::undefined, 369 Field::undefined, 370 Clock_divider_pclock); 371 372 Pll clock_pll_A(Source(mux_external), 373 Pll_enable_A, Pll_stable_A, Pll_bypass_A, 374 Pll_multiplier_A, Pll_input_division_A, 375 Pll_output_division0_A, Pll_output_division1_A); 376 377 Pll clock_pll_E(Source(mux_external), 378 Pll_enable_E, Pll_stable_E, Pll_bypass_E, 379 Pll_multiplier_E, Pll_input_division_E, 380 Pll_output_division0_E, Pll_output_division1_E); 381 382 Pll clock_pll_M(Source(mux_external), 383 Pll_enable_M, Pll_stable_M, Pll_bypass_M, 384 Pll_multiplier_M, Pll_input_division_M, 385 Pll_output_division0_M, Pll_output_division1_M); 386 387 Clock clock_pwm(Source(mux_dev, Clock_source_pwm), 388 Clock_gate_pwm, 389 Clock_change_enable_pwm, 390 Clock_busy_pwm, 391 Clock_divider_pwm); 392 393 Clock clock_pwm0(Source(mux_dev, Clock_source_pwm), 394 Clock_gate_pwm, 395 Clock_change_enable_pwm, 396 Clock_busy_pwm, 397 Clock_divider_pwm); 398 399 Clock clock_pwm1; 400 401 Clock clock_scc; 402 403 Clock clock_sfc(Source(mux_dev, Clock_source_sfc), 404 Clock_gate_sfc, 405 Clock_change_enable_sfc, 406 Clock_busy_sfc, 407 Clock_divider_sfc); 408 409 Clock clock_smb0; 410 411 Clock clock_smb1; 412 413 Clock clock_smb2; 414 415 Clock clock_smb3; 416 417 Clock clock_smb4; 418 419 Clock clock_ssi(Source(mux_dev, Clock_source_ssi), 420 Clock_gate_ssi0, 421 Clock_change_enable_ssi, 422 Clock_busy_ssi, 423 Clock_divider_ssi); 424 425 Clock clock_timer(Source(mux_pclock), Clock_gate_timer); 426 427 Clock clock_uart0(Source(mux_external), Clock_gate_uart0); 428 429 Clock clock_uart1(Source(mux_external), Clock_gate_uart1); 430 431 Clock clock_uart2(Source(mux_external), Clock_gate_uart2); 432 433 Clock clock_uart3(Source(mux_external), Clock_gate_uart3); 434 435 Clock clock_udc; 436 437 Clock clock_uhc; 438 439 Clock clock_uprt; 440 441 442 443 // Clock register. 444 445 static Clock_base *clocks[Clock_identifier_count] = { 446 &clock_ahb2_apb, 447 &clock_aic_bitclk, 448 &clock_aic_pclk, 449 &clock_can0, 450 &clock_can1, 451 &clock_cdbus, 452 &clock_cim, 453 &clock_cpu, 454 &clock_ddr, 455 &clock_dma, 456 &clock_emac, 457 &clock_external, 458 &clock_hclock0, 459 &clock_hclock2, 460 &clock_hdmi, 461 &clock_i2c, 462 &clock_i2c0, 463 &clock_i2c1, 464 &clock_i2s, 465 &clock_i2s0_rx, 466 &clock_i2s0_tx, 467 &clock_kbc, 468 &clock_lcd, 469 &clock_lcd_pixel, 470 &clock_mac, 471 &clock_main, 472 &clock_msc, 473 &clock_msc0, 474 &clock_msc1, 475 &clock_none, 476 &clock_pclock, 477 &clock_pll_A, 478 &clock_pll_E, 479 &clock_pll_M, 480 &clock_pwm, 481 &clock_pwm0, 482 &clock_pwm1, 483 &clock_scc, 484 &clock_sfc, 485 &clock_smb0, 486 &clock_smb1, 487 &clock_smb2, 488 &clock_smb3, 489 &clock_smb4, 490 &clock_ssi, 491 &clock_timer, 492 &clock_uart0, 493 &clock_uart1, 494 &clock_uart2, 495 &clock_uart3, 496 &clock_udc, 497 &clock_uhc, 498 &clock_uprt, 499 }; 500 501 502 503 // If implemented as a Hw::Device, various properties would be 504 // initialised in the constructor and obtained from the device tree 505 // definitions. 506 507 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq) 508 : _cpm_regs(addr, clocks, exclk_freq) 509 { 510 // add_cid("cpm"); 511 // add_cid("cpm-x1600"); 512 // register_property("exclk_freq", &exclk_freq); 513 } 514 515 int 516 Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) 517 { 518 return clocks[clock]->have_clock(_cpm_regs); 519 } 520 521 void 522 Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) 523 { 524 clocks[clock]->start_clock(_cpm_regs); 525 } 526 527 void 528 Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) 529 { 530 clocks[clock]->stop_clock(_cpm_regs); 531 } 532 533 uint32_t 534 Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) 535 { 536 return clocks[clock]->get_divider(_cpm_regs); 537 } 538 539 void 540 Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) 541 { 542 clocks[clock]->set_divider(_cpm_regs, division); 543 } 544 545 uint8_t 546 Cpm_x1600_chip::get_source(enum Clock_identifiers clock) 547 { 548 return clocks[clock]->get_source(_cpm_regs); 549 } 550 551 void 552 Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) 553 { 554 clocks[clock]->set_source(_cpm_regs, source); 555 } 556 557 uint32_t 558 Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) 559 { 560 return clocks[clock]->get_source_frequency(_cpm_regs); 561 } 562 563 uint32_t 564 Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) 565 { 566 return clocks[clock]->get_frequency(_cpm_regs); 567 } 568 569 void 570 Cpm_x1600_chip::set_frequency(enum Clock_identifiers clock, uint32_t frequency) 571 { 572 switch (clock) 573 { 574 // The pixel frequency is based on the selected clock source (SCLK_A, MPLL or 575 // EPLL). 576 577 case Clock_lcd_pixel: 578 { 579 580 // Switch to the MPLL and attempt to set the divider. 581 582 Clock_base *lcd = clocks[Clock_lcd_pixel]; 583 Clock_base *pll = clocks[Clock_pll_M]; 584 585 lcd->set_source(_cpm_regs, Source_mME_pll_M); 586 pll->start_clock(_cpm_regs); 587 lcd->set_divider(_cpm_regs, lcd->get_source_frequency(_cpm_regs) / frequency); 588 break; 589 } 590 591 default: 592 break; 593 } 594 } 595 596 void 597 Cpm_x1600_chip::set_pll_parameters(enum Clock_identifiers clock, uint16_t multiplier, 598 uint8_t in_divider, uint8_t out_divider) 599 { 600 Pll *pll = dynamic_cast<Pll *>(clocks[clock]); 601 602 pll->set_pll_parameters(_cpm_regs, multiplier, in_divider, out_divider); 603 } 604 605 606 607 // C language interface functions. 608 609 void 610 *x1600_cpm_init(l4_addr_t cpm_base) 611 { 612 /* Initialise the clock and power management peripheral with the 613 register memory region and a 24MHz EXCLK frequency. */ 614 615 return (void *) new Cpm_x1600_chip(cpm_base, 24000000); 616 } 617 618 int 619 x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 620 { 621 return static_cast<Cpm_x1600_chip *>(cpm)->have_clock(clock); 622 } 623 624 void 625 x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 626 { 627 static_cast<Cpm_x1600_chip *>(cpm)->start_clock(clock); 628 } 629 630 void 631 x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 632 { 633 static_cast<Cpm_x1600_chip *>(cpm)->stop_clock(clock); 634 } 635 636 uint32_t 637 x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock) 638 { 639 return static_cast<Cpm_x1600_chip *>(cpm)->get_divider(clock); 640 } 641 642 void 643 x1600_cpm_set_divider(void *cpm, enum Clock_identifiers clock, uint32_t divider) 644 { 645 return static_cast<Cpm_x1600_chip *>(cpm)->set_divider(clock, divider); 646 } 647 648 uint8_t 649 x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) 650 { 651 return static_cast<Cpm_x1600_chip *>(cpm)->get_source(clock); 652 } 653 654 void 655 x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) 656 { 657 static_cast<Cpm_x1600_chip *>(cpm)->set_source(clock, source); 658 } 659 660 uint32_t 661 x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) 662 { 663 return static_cast<Cpm_x1600_chip *>(cpm)->get_source_frequency(clock); 664 } 665 666 uint32_t 667 x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) 668 { 669 return static_cast<Cpm_x1600_chip *>(cpm)->get_frequency(clock); 670 } 671 672 void 673 x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency) 674 { 675 static_cast<Cpm_x1600_chip *>(cpm)->set_frequency(clock, frequency); 676 } 677 678 void 679 x1600_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 680 { 681 static_cast<Cpm_x1600_chip *>(cpm)->set_pll_parameters(Clock_pll_M, multiplier, in_divider, out_divider); 682 }