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 Ddr_divider = 0x02c, // DDRCDR 42 Mac_divider = 0x054, // MACCDR 43 I2s_divider0 = 0x060, // I2SCDR 44 I2s_divider1 = 0x070, // I2S1CDR 45 Lcd_divider = 0x064, // LPCDR 46 Msc_divider0 = 0x068, // MSC0CDR 47 Msc_divider1 = 0x0a4, // MSC1CDR 48 Sfc_divider = 0x074, // SFCCDR 49 Ssi_divider = 0x05c, // SSICDR 50 Cim_divider = 0x078, // CIMCDR 51 Pwm_divider = 0x06c, // PWMCDR 52 Can_divider0 = 0x0a0, // CAN0CDR 53 Can_divider1 = 0x0a8, // CAN1CDR 54 Cdbus_divider = 0x0ac, // CDBUSCDR 55 Macphy0_divider = 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 // Special value 75 76 Reg_undefined = 0xfff, 77 }; 78 79 enum Clock_source_bits : unsigned 80 { 81 // Clock_control 82 83 Clock_source_main = 30, // SEL_SRC (output to SCLK_A) 84 Clock_source_cpu = 28, // SEL_CPLL (output to CCLK) 85 Clock_source_hclock0 = 26, // SEL_H0PLL (output to AHB0) 86 Clock_source_hclock2 = 24, // SEL_H2PLL (output to AHB2) 87 88 // Divider registers 89 90 Clock_source_can0 = 30, // CA0CS 91 Clock_source_can1 = 30, // CA1CS 92 Clock_source_cdbus = 30, // CDCS 93 Clock_source_cim = 30, // CIMPCS 94 Clock_source_ddr = 30, // DCS 95 Clock_source_i2s = 31, // I2PCS 96 Clock_source_lcd = 30, // LPCS 97 Clock_source_mac = 30, // MACPCS 98 Clock_source_msc0 = 30, // MPCS 99 Clock_source_msc1 = 30, // MPCS 100 Clock_source_pwm = 30, // PWMPCS 101 Clock_source_sfc = 30, // SFCS 102 Clock_source_ssi = 30, // SPCS 103 104 // Special value 105 106 Clock_source_undefined = 32, 107 }; 108 109 enum Clock_source_values : unsigned 110 { 111 Source_mME_main = 0, 112 Source_mME_pll_M = 1, 113 Source_mME_pll_E = 2, 114 115 // Special value 116 117 Source_mask = 0x3, 118 }; 119 120 enum Clock_gate_bits : unsigned 121 { 122 // Clock_control 123 124 Clock_gate_main = 23, // GATE_SCLKA 125 126 // Clock_gate0 127 128 Clock_gate_ddr = 31, // DDR 129 Clock_gate_ahb0 = 29, // AHB0 130 Clock_gate_apb0 = 28, // APB0 131 Clock_gate_rtc = 27, // RTC 132 Clock_gate_aes = 24, // AES 133 Clock_gate_lcd_pixel = 23, // LCD 134 Clock_gate_cim = 22, // CIM 135 Clock_gate_dma = 21, // PDMA 136 Clock_gate_ost = 20, // OST 137 Clock_gate_ssi0 = 19, // SSI0 138 Clock_gate_timer = 18, // TCU 139 Clock_gate_dtrng = 17, // DTRNG 140 Clock_gate_uart2 = 16, // UART2 141 Clock_gate_uart1 = 15, // UART1 142 Clock_gate_uart0 = 14, // UART0 143 Clock_gate_sadc = 13, // SADC 144 Clock_gate_audio = 11, // AUDIO 145 Clock_gate_ssi_slv = 10, // SSI_SLV 146 Clock_gate_i2c1 = 8, // I2C1 147 Clock_gate_i2c0 = 7, // I2C0 148 Clock_gate_msc1 = 5, // MSC1 149 Clock_gate_msc0 = 4, // MSC0 150 Clock_gate_otg = 3, // OTG 151 Clock_gate_sfc = 2, // SFC 152 Clock_gate_efuse = 1, // EFUSE 153 Clock_gate_nemc = 0, // NEMC 154 155 // Clock_gate1 156 157 Clock_gate_arb = 30, // ARB 158 Clock_gate_mipi_csi = 28, // MIPI_CSI 159 Clock_gate_intc = 26, // INTC 160 Clock_gate_gmac0 = 23, // GMAC0 161 Clock_gate_uart3 = 16, // UART3 162 Clock_gate_i2s0_tx = 9, // I2S0_dev_tclk 163 Clock_gate_i2s0_rx = 8, // I2S0_dev_rclk 164 Clock_gate_hash = 6, // HASH 165 Clock_gate_pwm = 5, // PWM 166 Clock_gate_cdbus = 2, // CDBUS 167 Clock_gate_can1 = 1, // CAN1 168 Clock_gate_can0 = 0, // CAN0 169 170 // Special value 171 172 Clock_gate_undefined = 32, 173 }; 174 175 enum Clock_change_enable_bits : unsigned 176 { 177 Clock_change_enable_cpu = 22, 178 Clock_change_enable_ahb0 = 21, 179 Clock_change_enable_ahb2 = 20, 180 Clock_change_enable_ddr = 29, 181 Clock_change_enable_mac = 29, 182 Clock_change_enable_i2s = 29, 183 Clock_change_enable_lcd = 29, 184 Clock_change_enable_msc0 = 29, 185 Clock_change_enable_msc1 = 29, 186 Clock_change_enable_sfc = 29, 187 Clock_change_enable_ssi = 29, 188 Clock_change_enable_cim = 29, 189 Clock_change_enable_pwm = 29, 190 Clock_change_enable_can0 = 29, 191 Clock_change_enable_can1 = 29, 192 Clock_change_enable_cdbus = 29, 193 194 // Special value 195 196 Clock_change_enable_undefined = 32, 197 }; 198 199 enum Clock_busy_bits : unsigned 200 { 201 Clock_busy_cpu = 0, 202 Clock_busy_ddr = 28, 203 Clock_busy_mac = 28, 204 Clock_busy_lcd = 28, 205 Clock_busy_msc0 = 28, 206 Clock_busy_msc1 = 28, 207 Clock_busy_sfc = 28, 208 Clock_busy_ssi = 28, 209 Clock_busy_cim = 28, 210 Clock_busy_pwm = 28, 211 Clock_busy_can0 = 28, 212 Clock_busy_can1 = 28, 213 Clock_busy_cdbus = 28, 214 215 // Special value 216 217 Clock_busy_undefined = 32, 218 }; 219 220 enum Clock_divider_bits : unsigned 221 { 222 Clock_divider_can0 = 0, // CAN0CDR 223 Clock_divider_can1 = 0, // CAN1CDR 224 Clock_divider_cdbus = 0, // CDBUSCDR 225 Clock_divider_cim = 0, // CIMCDR 226 Clock_divider_cpu = 0, // CDIV 227 Clock_divider_ddr = 0, // DDRCDR 228 Clock_divider_hclock0 = 8, // H0DIV (fast AHB peripherals) 229 Clock_divider_hclock2 = 12, // H2DIV (fast AHB peripherals) 230 Clock_divider_l2cache = 4, // L2CDIV 231 Clock_divider_lcd = 0, // LPCDR 232 Clock_divider_mac = 0, // MACCDR 233 Clock_divider_msc0 = 0, // MSC0CDR 234 Clock_divider_msc1 = 0, // MSC1CDR 235 Clock_divider_pclock = 16, // PDIV (slow APB peripherals) 236 Clock_divider_pwm = 0, // PWMCDR 237 Clock_divider_sfc = 0, // SFCCDR 238 Clock_divider_ssi = 0, // SSICDR 239 240 // Special value 241 242 Clock_divider_undefined = 32, 243 }; 244 245 enum Pll_bits : unsigned 246 { 247 // Pll_control_A, Pll_control_M, Pll_control_E 248 249 Pll_multiplier = 20, // xPLLM 250 Pll_input_division = 14, // xPLLN 251 Pll_output_division1 = 11, // xPLLOD1 252 Pll_output_division0 = 8, // xPLLOD0 253 Pll_stable = 3, // xPLL_ON 254 Pll_enabled = 0, // xPLLEN 255 }; 256 257 enum Pll_bypass_bits : unsigned 258 { 259 Pll_bypass_A = 30, // APLL_BP 260 Pll_bypass_M = 28, // MPLL_BP 261 Pll_bypass_E = 26, // EPLL_BP 262 }; 263 264 265 266 // Clock input descriptions. 267 268 struct Clock_input_desc 269 { 270 uint32_t source_reg; 271 enum Clock_source_bits source_bit; 272 int num_inputs; 273 enum Clock_input_identifiers inputs[3]; 274 }; 275 276 struct Clock_input_desc clock_input_desc[Clock_input_identifier_count] = { 277 278 /* Clock_input_ahb2_apb */ {Clock_control, Clock_source_hclock2, 279 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}}, 280 281 /* Clock_input_external */ {Reg_undefined, Clock_source_undefined, 282 0, {}}, 283 284 /* Clock_input_main */ {Clock_control, Clock_source_main, 285 3, {Clock_input_none, Clock_input_external, Clock_input_pll_A}}, 286 287 /* Clock_input_none */ {Reg_undefined, Clock_source_undefined, 288 0, {}}, 289 290 /* Clock_input_pll_A */ {Reg_undefined, Clock_source_undefined, 291 1, {Clock_input_external}}, 292 293 /* Clock_input_pll_E */ {Reg_undefined, Clock_source_undefined, 294 1, {Clock_input_external}}, 295 296 /* Clock_input_pll_M */ {Reg_undefined, Clock_source_undefined, 297 1, {Clock_input_external}}, 298 }; 299 300 301 302 // Clock descriptions. 303 304 struct Clock_desc 305 { 306 uint32_t source_reg; 307 enum Clock_source_bits source_bit; 308 uint32_t gate_reg; 309 enum Clock_gate_bits gate_bit; 310 uint32_t change_enable_reg; 311 enum Clock_change_enable_bits change_enable_bit; 312 uint32_t busy_reg; 313 enum Clock_busy_bits busy_bit; 314 uint32_t divider_reg; 315 enum Clock_divider_bits divider_bit; 316 uint32_t divider_mask; 317 int num_inputs; 318 enum Clock_input_identifiers inputs[4]; 319 enum Clock_identifiers clock_input; 320 }; 321 322 #define Clock_desc_undefined {Reg_undefined, Clock_source_undefined, \ 323 Reg_undefined, Clock_gate_undefined, \ 324 Reg_undefined, Clock_change_enable_undefined, \ 325 Reg_undefined, Clock_busy_undefined, \ 326 Reg_undefined, Clock_divider_undefined, 0, \ 327 0, {}, \ 328 Clock_undefined} 329 330 static struct Clock_desc clock_desc[Clock_identifier_count] = { 331 332 /* Clock_aic_bitclk */ Clock_desc_undefined, 333 334 /* Clock_aic_pclk */ Clock_desc_undefined, 335 336 /* Clock_can0 */ {Can_divider0, Clock_source_can0, 337 Clock_gate1, Clock_gate_can0, 338 Can_divider0, Clock_change_enable_can0, 339 Can_divider0, Clock_busy_can0, 340 Can_divider0, Clock_divider_can0, 0xff, 341 4, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E, Clock_input_external}, 342 Clock_undefined}, 343 344 /* Clock_can1 */ {Can_divider1, Clock_source_can1, 345 Clock_gate1, Clock_gate_can1, 346 Can_divider1, Clock_change_enable_can1, 347 Can_divider1, Clock_busy_can1, 348 Can_divider1, Clock_divider_can1, 0xff, 349 4, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E, Clock_input_external}, 350 Clock_undefined}, 351 352 /* Clock_cdbus */ {Cdbus_divider, Clock_source_cdbus, 353 Clock_gate1, Clock_gate_cdbus, 354 Cdbus_divider, Clock_change_enable_cdbus, 355 Cdbus_divider, Clock_busy_cdbus, 356 Cdbus_divider, Clock_divider_cdbus, 0xff, 357 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 358 Clock_undefined}, 359 360 /* Clock_cim */ {Cim_divider, Clock_source_cim, 361 Clock_gate0, Clock_gate_cim, 362 Cim_divider, Clock_change_enable_cim, 363 Cim_divider, Clock_busy_cim, 364 Cim_divider, Clock_divider_cim, 0xff, 365 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 366 Clock_undefined}, 367 368 /* Clock_cpu */ {Clock_control, Clock_source_cpu, 369 Reg_undefined, Clock_gate_undefined, 370 Clock_control, Clock_change_enable_cpu, 371 Clock_status, Clock_busy_cpu, 372 Clock_control, Clock_divider_cpu, 0x0f, 373 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}, 374 Clock_undefined}, 375 376 /* Clock_ddr */ {Ddr_divider, Clock_source_ddr, 377 Clock_gate0, Clock_gate_ddr, 378 Ddr_divider, Clock_change_enable_ddr, 379 Ddr_divider, Clock_busy_ddr, 380 Ddr_divider, Clock_divider_ddr, 0x0f, 381 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}, 382 Clock_undefined}, 383 384 /* Clock_dma */ {Reg_undefined, Clock_source_undefined, 385 Clock_gate0, Clock_gate_dma, 386 Reg_undefined, Clock_change_enable_undefined, 387 Reg_undefined, Clock_busy_undefined, 388 Reg_undefined, Clock_divider_undefined, 0, 389 0, {}, 390 Clock_pclock}, 391 392 /* Clock_emac */ Clock_desc_undefined, 393 394 /* Clock_hclock0 */ {Clock_control, Clock_source_hclock0, 395 Clock_gate0, Clock_gate_ahb0, 396 Clock_control, Clock_change_enable_ahb0, 397 Reg_undefined, Clock_busy_undefined, 398 Clock_control, Clock_divider_hclock0, 0x0f, 399 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}, 400 Clock_undefined}, 401 402 /* Clock_hclock2 */ {Reg_undefined, Clock_source_undefined, 403 Clock_gate0, Clock_gate_apb0, 404 Clock_control, Clock_change_enable_ahb2, 405 Reg_undefined, Clock_busy_undefined, 406 Clock_control, Clock_divider_hclock2, 0x0f, 407 1, {Clock_input_ahb2_apb}, 408 Clock_undefined}, 409 410 /* Clock_hdmi */ Clock_desc_undefined, 411 412 /* Clock_i2c */ {Reg_undefined, Clock_source_undefined, 413 Clock_gate0, Clock_gate_i2c0, 414 Reg_undefined, Clock_change_enable_undefined, 415 Reg_undefined, Clock_busy_undefined, 416 Reg_undefined, Clock_divider_undefined, 0, 417 0, {}, 418 Clock_pclock}, 419 420 /* Clock_i2c0 */ {Reg_undefined, Clock_source_undefined, 421 Clock_gate0, Clock_gate_i2c0, 422 Reg_undefined, Clock_change_enable_undefined, 423 Reg_undefined, Clock_busy_undefined, 424 Reg_undefined, Clock_divider_undefined, 0, 425 0, {}, 426 Clock_pclock}, 427 428 /* Clock_i2c1 */ {Reg_undefined, Clock_source_undefined, 429 Clock_gate0, Clock_gate_i2c1, 430 Reg_undefined, Clock_change_enable_undefined, 431 Reg_undefined, Clock_busy_undefined, 432 Reg_undefined, Clock_divider_undefined, 0, 433 0, {}, 434 Clock_pclock}, 435 436 /* Clock_i2s */ Clock_desc_undefined, 437 438 /* Clock_i2s0_rx */ {I2s_divider0, Clock_source_i2s, 439 Clock_gate1, Clock_gate_i2s0_rx, 440 I2s_divider0, Clock_change_enable_i2s, 441 Reg_undefined, Clock_busy_undefined, 442 Reg_undefined, Clock_divider_undefined, 0, // NOTE: To define. 443 2, {Clock_input_main, Clock_input_pll_E}, 444 Clock_undefined}, 445 446 /* Clock_i2s0_tx */ {I2s_divider0, Clock_source_i2s, 447 Clock_gate1, Clock_gate_i2s0_tx, 448 I2s_divider0, Clock_change_enable_i2s, 449 Reg_undefined, Clock_busy_undefined, 450 Reg_undefined, Clock_divider_undefined, 0, // NOTE: To define. 451 2, {Clock_input_main, Clock_input_pll_E}, 452 Clock_undefined}, 453 454 /* Clock_kbc */ Clock_desc_undefined, 455 456 /* Clock_lcd */ Clock_desc_undefined, 457 458 /* Clock_lcd_pixel */ {Lcd_divider, Clock_source_lcd, 459 Clock_gate0, Clock_gate_lcd_pixel, 460 Lcd_divider, Clock_change_enable_lcd, 461 Lcd_divider, Clock_busy_lcd, 462 Lcd_divider, Clock_divider_lcd, 0xff, 463 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 464 Clock_undefined}, 465 466 /* Clock_mac */ {Mac_divider, Clock_source_mac, 467 Clock_gate1, Clock_gate_gmac0, 468 Mac_divider, Clock_change_enable_mac, 469 Mac_divider, Clock_busy_mac, 470 Mac_divider, Clock_divider_mac, 0xff, 471 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 472 Clock_undefined}, 473 474 /* Clock_main */ {Reg_undefined, Clock_source_undefined, 475 Clock_control, Clock_gate_main, 476 Reg_undefined, Clock_change_enable_undefined, 477 Reg_undefined, Clock_busy_undefined, 478 Reg_undefined, Clock_divider_undefined, 0, 479 1, {Clock_input_main}, 480 Clock_undefined}, 481 482 /* Clock_msc */ {Msc_divider0, Clock_source_msc0, 483 Clock_gate0, Clock_gate_msc0, 484 Msc_divider0, Clock_change_enable_msc0, 485 Msc_divider0, Clock_busy_msc0, 486 Msc_divider0, Clock_divider_msc0, 0xff, 487 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 488 Clock_undefined}, 489 490 /* Clock_msc0 */ {Msc_divider0, Clock_source_msc0, 491 Clock_gate0, Clock_gate_msc0, 492 Msc_divider0, Clock_change_enable_msc0, 493 Msc_divider0, Clock_busy_msc0, 494 Msc_divider0, Clock_divider_msc0, 0xff, 495 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 496 Clock_undefined}, 497 498 /* Clock_msc1 */ {Msc_divider1, Clock_source_msc1, 499 Clock_gate0, Clock_gate_msc1, 500 Msc_divider1, Clock_change_enable_msc1, 501 Msc_divider1, Clock_busy_msc1, 502 Msc_divider1, Clock_divider_msc1, 0xff, 503 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 504 Clock_undefined}, 505 506 /* Clock_pclock */ {Reg_undefined, Clock_source_undefined, 507 Clock_gate0, Clock_gate_apb0, 508 Reg_undefined, Clock_change_enable_undefined, 509 Reg_undefined, Clock_busy_undefined, 510 Clock_control, Clock_divider_pclock, 0x0f, 511 1, {Clock_input_ahb2_apb}, 512 Clock_undefined}, 513 514 /* Clock_pwm */ {Pwm_divider, Clock_source_pwm, 515 Clock_gate1, Clock_gate_pwm, 516 Pwm_divider, Clock_change_enable_pwm, 517 Pwm_divider, Clock_busy_pwm, 518 Pwm_divider, Clock_divider_pwm, 0x0f, 519 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 520 Clock_undefined}, 521 522 /* Clock_pwm0 */ {Pwm_divider, Clock_source_pwm, 523 Clock_gate1, Clock_gate_pwm, 524 Pwm_divider, Clock_change_enable_pwm, 525 Pwm_divider, Clock_busy_pwm, 526 Pwm_divider, Clock_divider_pwm, 0x0f, 527 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 528 Clock_undefined}, 529 530 /* Clock_pwm1 */ Clock_desc_undefined, 531 532 /* Clock_scc */ Clock_desc_undefined, 533 534 /* Clock_sfc */ {Sfc_divider, Clock_source_sfc, 535 Clock_gate0, Clock_gate_sfc, 536 Sfc_divider, Clock_change_enable_sfc, 537 Sfc_divider, Clock_busy_sfc, 538 Sfc_divider, Clock_divider_sfc, 0xff, 539 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 540 Clock_undefined}, 541 542 /* Clock_smb0 */ Clock_desc_undefined, 543 544 /* Clock_smb1 */ Clock_desc_undefined, 545 546 /* Clock_smb2 */ Clock_desc_undefined, 547 548 /* Clock_smb3 */ Clock_desc_undefined, 549 550 /* Clock_smb4 */ Clock_desc_undefined, 551 552 /* Clock_ssi */ {Ssi_divider, Clock_source_ssi, 553 Clock_gate0, Clock_gate_ssi0, 554 Ssi_divider, Clock_change_enable_ssi, 555 Ssi_divider, Clock_busy_ssi, 556 Ssi_divider, Clock_divider_ssi, 0xff, 557 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}, 558 Clock_undefined}, 559 560 /* Clock_timer */ {Reg_undefined, Clock_source_undefined, 561 Clock_gate0, Clock_gate_timer, 562 Reg_undefined, Clock_change_enable_undefined, 563 Reg_undefined, Clock_busy_undefined, 564 Reg_undefined, Clock_divider_undefined, 0, 565 0, {}, 566 Clock_pclock}, 567 568 /* Clock_uart0 */ {Reg_undefined, Clock_source_undefined, 569 Clock_gate0, Clock_gate_uart0, 570 Reg_undefined, Clock_change_enable_undefined, 571 Reg_undefined, Clock_busy_undefined, 572 Reg_undefined, Clock_divider_undefined, 0, 573 1, {Clock_input_external}, 574 Clock_undefined}, 575 576 /* Clock_uart1 */ {Reg_undefined, Clock_source_undefined, 577 Clock_gate0, Clock_gate_uart1, 578 Reg_undefined, Clock_change_enable_undefined, 579 Reg_undefined, Clock_busy_undefined, 580 Reg_undefined, Clock_divider_undefined, 0, 581 1, {Clock_input_external}, 582 Clock_undefined}, 583 584 /* Clock_uart2 */ {Reg_undefined, Clock_source_undefined, 585 Clock_gate0, Clock_gate_uart2, 586 Reg_undefined, Clock_change_enable_undefined, 587 Reg_undefined, Clock_busy_undefined, 588 Reg_undefined, Clock_divider_undefined, 0, 589 1, {Clock_input_external}, 590 Clock_undefined}, 591 592 /* Clock_uart3 */ {Reg_undefined, Clock_source_undefined, 593 Clock_gate1, Clock_gate_uart3, 594 Reg_undefined, Clock_change_enable_undefined, 595 Reg_undefined, Clock_busy_undefined, 596 Reg_undefined, Clock_divider_undefined, 0, 597 1, {Clock_input_external}, 598 Clock_undefined}, 599 600 /* Clock_udc */ Clock_desc_undefined, 601 602 /* Clock_uhc */ Clock_desc_undefined, 603 604 /* Clock_uprt */ Clock_desc_undefined, 605 }; 606 607 608 609 // Convenience functions. 610 611 static uint8_t get_clock_gate_bit(enum Clock_identifiers clock) 612 { 613 enum Clock_gate_bits bit = clock_desc[clock].gate_bit; 614 615 return bit != Clock_gate_undefined ? (uint8_t) bit : 0; 616 } 617 618 static uint32_t get_clock_gate_mask(enum Clock_identifiers clock) 619 { 620 enum Clock_gate_bits bit = clock_desc[clock].gate_bit; 621 622 return bit != Clock_gate_undefined ? 1 : 0; 623 } 624 625 626 627 // If implemented as a Hw::Device, various properties would be 628 // initialised in the constructor and obtained from the device tree 629 // definitions. 630 631 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq) 632 : _exclk_freq(exclk_freq) 633 { 634 _regs = new Hw::Mmio_register_block<32>(addr); 635 636 // add_cid("cpm"); 637 // add_cid("cpm-x1600"); 638 // register_property("exclk_freq", &_exclk_freq); 639 } 640 641 642 643 // Utility methods. 644 645 uint32_t 646 Cpm_x1600_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 647 { 648 return (_regs[reg] & (mask << shift)) >> shift; 649 } 650 651 void 652 Cpm_x1600_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 653 { 654 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 655 } 656 657 658 659 // Clock/timer control. 660 661 void 662 Cpm_x1600_chip::change_disable(enum Clock_identifiers clock) 663 { 664 enum Clock_change_enable_bits bit = clock_desc[clock].change_enable_bit; 665 666 if (bit != Clock_change_enable_undefined) 667 set_field(clock_desc[clock].change_enable_reg, 1, bit, 0); 668 } 669 670 void 671 Cpm_x1600_chip::change_enable(enum Clock_identifiers clock) 672 { 673 enum Clock_change_enable_bits bit = clock_desc[clock].change_enable_bit; 674 675 if (bit != Clock_change_enable_undefined) 676 set_field(clock_desc[clock].change_enable_reg, 1, bit, 1); 677 } 678 679 int 680 Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) 681 { 682 if (clock_desc[clock].gate_bit != Clock_gate_undefined) 683 return !get_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), 684 get_clock_gate_bit(clock)); 685 else 686 return true; 687 } 688 689 void 690 Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) 691 { 692 if (clock_desc[clock].gate_bit != Clock_gate_undefined) 693 set_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), 694 get_clock_gate_bit(clock), 0); 695 } 696 697 void 698 Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) 699 { 700 if (clock_desc[clock].gate_bit != Clock_gate_undefined) 701 set_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), 702 get_clock_gate_bit(clock), 1); 703 } 704 705 void 706 Cpm_x1600_chip::wait_busy(enum Clock_identifiers clock) 707 { 708 enum Clock_busy_bits bit = clock_desc[clock].busy_bit; 709 710 if (bit != Clock_busy_undefined) 711 while (get_field(clock_desc[clock].busy_reg, 1, bit)); 712 } 713 714 715 716 // PLL control. 717 718 // Return whether the PLL is stable. 719 720 int 721 Cpm_x1600_chip::have_pll(uint32_t pll_reg) 722 { 723 return get_field(pll_reg, 1, Pll_stable); 724 } 725 726 int 727 Cpm_x1600_chip::pll_enabled(uint32_t pll_reg) 728 { 729 return get_field(pll_reg, 1, Pll_enabled); 730 } 731 732 int 733 Cpm_x1600_chip::pll_bypassed(uint32_t pll_reg) 734 { 735 uint8_t bit; 736 unsigned mask = 1; 737 738 switch (pll_reg) 739 { 740 case Pll_control_A: bit = Pll_bypass_A; break; 741 case Pll_control_M: bit = Pll_bypass_M; break; 742 case Pll_control_E: bit = Pll_bypass_E; break; 743 default: bit = 0; mask = 0; break; 744 } 745 746 return get_field(Pll_control, mask, bit); 747 } 748 749 void 750 Cpm_x1600_chip::pll_enable(uint32_t pll_reg) 751 { 752 set_field(pll_reg, 1, Pll_enabled, 1); 753 while (!have_pll(pll_reg)); 754 } 755 756 void 757 Cpm_x1600_chip::pll_disable(uint32_t pll_reg) 758 { 759 set_field(pll_reg, 1, Pll_enabled, 0); 760 while (have_pll(pll_reg)); 761 } 762 763 // Feedback (13-bit) multiplier. 764 765 uint16_t 766 Cpm_x1600_chip::get_multiplier(uint32_t pll_reg) 767 { 768 return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; 769 } 770 771 void 772 Cpm_x1600_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) 773 { 774 set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); 775 } 776 777 // Input (6-bit) divider. 778 779 uint8_t 780 Cpm_x1600_chip::get_input_division(uint32_t pll_reg) 781 { 782 return get_field(pll_reg, 0x3f, Pll_input_division) + 1; 783 } 784 785 void 786 Cpm_x1600_chip::set_input_division(uint32_t pll_reg, uint8_t divider) 787 { 788 set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); 789 } 790 791 // Output (dual 3-bit) dividers. 792 793 uint8_t 794 Cpm_x1600_chip::get_output_division(uint32_t pll_reg) 795 { 796 uint8_t d0 = get_field(pll_reg, 0x07, Pll_output_division0); 797 uint8_t d1 = get_field(pll_reg, 0x07, Pll_output_division1); 798 799 return d0 * d1; 800 } 801 802 void 803 Cpm_x1600_chip::set_output_division(uint32_t pll_reg, uint8_t divider) 804 { 805 // Assert 1 as a minimum. 806 // Divider 0 must be less than or equal to divider 1. 807 808 uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1)); 809 uint8_t d1 = divider / d0; 810 811 set_field(pll_reg, 0x07, Pll_output_division0, d0); 812 set_field(pll_reg, 0x07, Pll_output_division1, d1); 813 } 814 815 uint32_t 816 Cpm_x1600_chip::get_pll_frequency(uint32_t pll_reg) 817 { 818 // Test for PLL enable and not PLL bypass. 819 820 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 821 return (_exclk_freq * get_multiplier(pll_reg)) / 822 (get_input_division(pll_reg) * get_output_division(pll_reg)); 823 else 824 return _exclk_freq; 825 } 826 827 void 828 Cpm_x1600_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 829 { 830 set_multiplier(pll_reg, multiplier); 831 set_input_division(pll_reg, in_divider); 832 set_output_division(pll_reg, out_divider); 833 834 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 835 while (!have_pll(pll_reg)); 836 } 837 838 839 840 // Clock dividers. 841 842 uint32_t 843 Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) 844 { 845 if (clock_desc[clock].divider_bit != Clock_divider_undefined) 846 return get_field(clock_desc[clock].divider_reg, clock_desc[clock].divider_mask, 847 clock_desc[clock].divider_bit) + 1; 848 else 849 return 1; 850 } 851 852 void 853 Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) 854 { 855 if (clock_desc[clock].divider_bit == Clock_divider_undefined) 856 return; 857 858 change_enable(clock); 859 set_field(clock_desc[clock].divider_reg, clock_desc[clock].divider_mask, 860 clock_desc[clock].divider_bit, division - 1); 861 wait_busy(clock); 862 change_disable(clock); 863 } 864 865 866 867 // Clock sources. 868 869 uint8_t 870 Cpm_x1600_chip::get_source(enum Clock_identifiers clock) 871 { 872 if (clock_desc[clock].source_bit != Clock_source_undefined) 873 return get_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit); 874 else 875 return 0; 876 } 877 878 void 879 Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) 880 { 881 if (clock_desc[clock].source_bit == Clock_source_undefined) 882 return; 883 884 change_enable(clock); 885 set_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit, source); 886 wait_busy(clock); 887 change_disable(clock); 888 } 889 890 891 892 // Clock source frequencies. 893 894 uint32_t 895 Cpm_x1600_chip::get_input_frequency(enum Clock_input_identifiers clock) 896 { 897 struct Clock_input_desc desc = clock_input_desc[clock]; 898 899 // Clocks with no inputs provide a frequency. 900 901 if (desc.num_inputs == 0) 902 { 903 switch (clock) 904 { 905 case Clock_input_external: return _exclk_freq; 906 default: return 0; 907 } 908 } 909 910 // Of the input clocks, only PLLs have a single input. 911 912 else if (desc.num_inputs == 1) 913 { 914 switch (clock) 915 { 916 case Clock_input_pll_A: return get_pll_frequency(Pll_control_A); 917 case Clock_input_pll_E: return get_pll_frequency(Pll_control_E); 918 case Clock_input_pll_M: return get_pll_frequency(Pll_control_M); 919 default: return 0; 920 } 921 } 922 923 // With multiple sources, obtain the selected source for the clock. 924 925 uint8_t source = get_field(desc.source_reg, Source_mask, desc.source_bit); 926 927 // Return the frequency of the source. 928 929 if (source < desc.num_inputs) 930 return get_input_frequency(desc.inputs[source]); 931 else 932 return 0; 933 } 934 935 uint32_t 936 Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) 937 { 938 struct Clock_desc desc = clock_desc[clock]; 939 940 if (desc.num_inputs == 0) 941 { 942 // Clocks may reference other clocks. 943 944 if (desc.clock_input != Clock_undefined) 945 return get_frequency(desc.clock_input); 946 947 // Undefined clocks return zero. 948 949 else 950 return 0; 951 } 952 953 // Clocks with one source yield that input frequency. 954 955 else if (desc.num_inputs == 1) 956 return get_input_frequency(desc.inputs[0]); 957 958 // With multiple sources, obtain the selected source for the clock. 959 960 uint8_t source = get_source(clock); 961 962 // Return the frequency of the source. 963 964 if (source < desc.num_inputs) 965 return get_input_frequency(desc.inputs[source]); 966 else 967 return 0; 968 } 969 970 971 972 // Output clock frequencies. 973 974 uint32_t 975 Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) 976 { 977 return get_source_frequency(clock) / get_divider(clock); 978 } 979 980 void 981 Cpm_x1600_chip::set_frequency(enum Clock_identifiers clock, uint32_t frequency) 982 { 983 switch (clock) 984 { 985 // The pixel frequency is based on the selected clock source (SCLK_A, MPLL or 986 // EPLL). 987 988 case Clock_lcd_pixel: 989 990 // Switch to the MPLL and attempt to set the divider. 991 992 set_source(Clock_lcd_pixel, Source_mME_pll_M); 993 pll_enable(Pll_control_M); 994 set_divider(Clock_lcd_pixel, get_source_frequency(clock) / frequency); 995 break; 996 997 default: 998 break; 999 } 1000 } 1001 1002 1003 1004 // C language interface functions. 1005 1006 void 1007 *x1600_cpm_init(l4_addr_t cpm_base) 1008 { 1009 /* Initialise the clock and power management peripheral with the 1010 register memory region and a 24MHz EXCLK frequency. */ 1011 1012 return (void *) new Cpm_x1600_chip(cpm_base, 24000000); 1013 } 1014 1015 int 1016 x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 1017 { 1018 return static_cast<Cpm_x1600_chip *>(cpm)->have_clock(clock); 1019 } 1020 1021 void 1022 x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 1023 { 1024 static_cast<Cpm_x1600_chip *>(cpm)->start_clock(clock); 1025 } 1026 1027 void 1028 x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 1029 { 1030 static_cast<Cpm_x1600_chip *>(cpm)->stop_clock(clock); 1031 } 1032 1033 1034 1035 uint32_t 1036 x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock) 1037 { 1038 return static_cast<Cpm_x1600_chip *>(cpm)->get_divider(clock); 1039 } 1040 1041 void 1042 x1600_cpm_set_divider(void *cpm, enum Clock_identifiers clock, uint32_t divider) 1043 { 1044 return static_cast<Cpm_x1600_chip *>(cpm)->set_divider(clock, divider); 1045 } 1046 1047 1048 1049 uint8_t 1050 x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) 1051 { 1052 return static_cast<Cpm_x1600_chip *>(cpm)->get_source(clock); 1053 } 1054 1055 void 1056 x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) 1057 { 1058 static_cast<Cpm_x1600_chip *>(cpm)->set_source(clock, source); 1059 } 1060 1061 1062 1063 uint32_t 1064 x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) 1065 { 1066 return static_cast<Cpm_x1600_chip *>(cpm)->get_source_frequency(clock); 1067 } 1068 1069 1070 1071 uint32_t 1072 x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) 1073 { 1074 return static_cast<Cpm_x1600_chip *>(cpm)->get_frequency(clock); 1075 } 1076 1077 void 1078 x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency) 1079 { 1080 static_cast<Cpm_x1600_chip *>(cpm)->set_frequency(clock, frequency); 1081 } 1082 1083 1084 1085 void 1086 x1600_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 1087 { 1088 static_cast<Cpm_x1600_chip *>(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); 1089 }