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 }; 320 321 #define Clock_undefined {Reg_undefined, Clock_source_undefined, \ 322 Reg_undefined, Clock_gate_undefined, \ 323 Reg_undefined, Clock_change_enable_undefined, \ 324 Reg_undefined, Clock_busy_undefined, \ 325 Reg_undefined, Clock_divider_undefined, 0, \ 326 0, {}} 327 328 static struct Clock_desc clock_desc[Clock_identifier_count] = { 329 330 /* Clock_aic_bitclk */ Clock_undefined, 331 332 /* Clock_aic_pclk */ Clock_undefined, 333 334 /* Clock_can0 */ {Can_divider0, Clock_source_can0, 335 Clock_gate1, Clock_gate_can0, 336 Can_divider0, Clock_change_enable_can0, 337 Can_divider0, Clock_busy_can0, 338 Can_divider0, Clock_divider_can0, 0xff, 339 4, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E, Clock_input_external}}, 340 341 /* Clock_can1 */ {Can_divider1, Clock_source_can1, 342 Clock_gate1, Clock_gate_can1, 343 Can_divider1, Clock_change_enable_can1, 344 Can_divider1, Clock_busy_can1, 345 Can_divider1, Clock_divider_can1, 0xff, 346 4, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E, Clock_input_external}}, 347 348 /* Clock_cdbus */ {Cdbus_divider, Clock_source_cdbus, 349 Clock_gate1, Clock_gate_cdbus, 350 Cdbus_divider, Clock_change_enable_cdbus, 351 Cdbus_divider, Clock_busy_cdbus, 352 Cdbus_divider, Clock_divider_cdbus, 0xff, 353 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 354 355 /* Clock_cim */ {Cim_divider, Clock_source_cim, 356 Clock_gate0, Clock_gate_cim, 357 Cim_divider, Clock_change_enable_cim, 358 Cim_divider, Clock_busy_cim, 359 Cim_divider, Clock_divider_cim, 0xff, 360 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 361 362 /* Clock_cpu */ {Clock_control, Clock_source_cpu, 363 Reg_undefined, Clock_gate_undefined, 364 Clock_control, Clock_change_enable_cpu, 365 Clock_status, Clock_busy_cpu, 366 Clock_control, Clock_divider_cpu, 0x0f, 367 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}}, 368 369 /* Clock_ddr */ {Ddr_divider, Clock_source_ddr, 370 Clock_gate0, Clock_gate_ddr, 371 Ddr_divider, Clock_change_enable_ddr, 372 Ddr_divider, Clock_busy_ddr, 373 Ddr_divider, Clock_divider_ddr, 0x0f, 374 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}}, 375 376 /* Clock_dma */ {Reg_undefined, Clock_source_undefined, 377 Clock_gate0, Clock_gate_dma, 378 Reg_undefined, Clock_change_enable_undefined, 379 Reg_undefined, Clock_busy_undefined, 380 Reg_undefined, Clock_divider_undefined, 0, 381 1, {Clock_input_ahb2_apb}}, 382 383 /* Clock_emac */ Clock_undefined, 384 385 /* Clock_hclock0 */ {Clock_control, Clock_source_hclock0, 386 Clock_gate0, Clock_gate_ahb0, 387 Clock_control, Clock_change_enable_ahb0, 388 Reg_undefined, Clock_busy_undefined, 389 Clock_control, Clock_divider_hclock0, 0x0f, 390 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}}, 391 392 /* Clock_hclock2 */ {Reg_undefined, Clock_source_undefined, 393 Clock_gate0, Clock_gate_apb0, 394 Clock_control, Clock_change_enable_ahb2, 395 Reg_undefined, Clock_busy_undefined, 396 Clock_control, Clock_divider_hclock2, 0x0f, 397 1, {Clock_input_ahb2_apb}}, 398 399 /* Clock_hdmi */ Clock_undefined, 400 401 /* Clock_i2c */ {Reg_undefined, Clock_source_undefined, 402 Clock_gate0, Clock_gate_i2c0, 403 Reg_undefined, Clock_change_enable_undefined, 404 Reg_undefined, Clock_busy_undefined, 405 Reg_undefined, Clock_divider_undefined, 0, 406 1, {Clock_input_ahb2_apb}}, 407 408 /* Clock_i2c0 */ {Reg_undefined, Clock_source_undefined, 409 Clock_gate0, Clock_gate_i2c0, 410 Reg_undefined, Clock_change_enable_undefined, 411 Reg_undefined, Clock_busy_undefined, 412 Reg_undefined, Clock_divider_undefined, 0, 413 1, {Clock_input_ahb2_apb}}, 414 415 /* Clock_i2c1 */ {Reg_undefined, Clock_source_undefined, 416 Clock_gate0, Clock_gate_i2c1, 417 Reg_undefined, Clock_change_enable_undefined, 418 Reg_undefined, Clock_busy_undefined, 419 Reg_undefined, Clock_divider_undefined, 0, 420 1, {Clock_input_ahb2_apb}}, 421 422 /* Clock_i2s */ Clock_undefined, 423 424 /* Clock_i2s0_rx */ {I2s_divider0, Clock_source_i2s, 425 Clock_gate1, Clock_gate_i2s0_rx, 426 I2s_divider0, Clock_change_enable_i2s, 427 Reg_undefined, Clock_busy_undefined, 428 Reg_undefined, Clock_divider_undefined, 0, // NOTE: To define. 429 2, {Clock_input_main, Clock_input_pll_E}}, 430 431 /* Clock_i2s0_tx */ {I2s_divider0, Clock_source_i2s, 432 Clock_gate1, Clock_gate_i2s0_tx, 433 I2s_divider0, Clock_change_enable_i2s, 434 Reg_undefined, Clock_busy_undefined, 435 Reg_undefined, Clock_divider_undefined, 0, // NOTE: To define. 436 2, {Clock_input_main, Clock_input_pll_E}}, 437 438 /* Clock_kbc */ Clock_undefined, 439 440 /* Clock_lcd */ Clock_undefined, 441 442 /* Clock_lcd_pixel */ {Lcd_divider, Clock_source_lcd, 443 Clock_gate0, Clock_gate_lcd_pixel, 444 Lcd_divider, Clock_change_enable_lcd, 445 Lcd_divider, Clock_busy_lcd, 446 Lcd_divider, Clock_divider_lcd, 0xff, 447 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 448 449 /* Clock_mac */ {Mac_divider, Clock_source_mac, 450 Clock_gate1, Clock_gate_gmac0, 451 Mac_divider, Clock_change_enable_mac, 452 Mac_divider, Clock_busy_mac, 453 Mac_divider, Clock_divider_mac, 0xff, 454 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 455 456 /* Clock_main */ {Reg_undefined, Clock_source_undefined, 457 Clock_control, Clock_gate_main, 458 Reg_undefined, Clock_change_enable_undefined, 459 Reg_undefined, Clock_busy_undefined, 460 Reg_undefined, Clock_divider_undefined, 0, 461 1, {Clock_input_main}}, 462 463 /* Clock_msc */ {Msc_divider0, Clock_source_msc0, 464 Clock_gate0, Clock_gate_msc0, 465 Msc_divider0, Clock_change_enable_msc0, 466 Msc_divider0, Clock_busy_msc0, 467 Msc_divider0, Clock_divider_msc0, 0xff, 468 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 469 470 /* Clock_msc0 */ {Msc_divider0, Clock_source_msc0, 471 Clock_gate0, Clock_gate_msc0, 472 Msc_divider0, Clock_change_enable_msc0, 473 Msc_divider0, Clock_busy_msc0, 474 Msc_divider0, Clock_divider_msc0, 0xff, 475 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 476 477 /* Clock_msc1 */ {Msc_divider1, Clock_source_msc1, 478 Clock_gate0, Clock_gate_msc1, 479 Msc_divider1, Clock_change_enable_msc1, 480 Msc_divider1, Clock_busy_msc1, 481 Msc_divider1, Clock_divider_msc1, 0xff, 482 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 483 484 /* Clock_pclock */ {Reg_undefined, Clock_source_undefined, 485 Clock_gate0, Clock_gate_apb0, 486 Reg_undefined, Clock_change_enable_undefined, 487 Reg_undefined, Clock_busy_undefined, 488 Clock_control, Clock_divider_pclock, 0x0f, 489 1, {Clock_input_ahb2_apb}}, 490 491 /* Clock_pwm */ {Pwm_divider, Clock_source_pwm, 492 Clock_gate1, Clock_gate_pwm, 493 Pwm_divider, Clock_change_enable_pwm, 494 Pwm_divider, Clock_busy_pwm, 495 Pwm_divider, Clock_divider_pwm, 0x0f, 496 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 497 498 /* Clock_pwm0 */ {Pwm_divider, Clock_source_pwm, 499 Clock_gate1, Clock_gate_pwm, 500 Pwm_divider, Clock_change_enable_pwm, 501 Pwm_divider, Clock_busy_pwm, 502 Pwm_divider, Clock_divider_pwm, 0x0f, 503 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 504 505 /* Clock_pwm1 */ Clock_undefined, 506 507 /* Clock_scc */ Clock_undefined, 508 509 /* Clock_sfc */ {Sfc_divider, Clock_source_sfc, 510 Clock_gate0, Clock_gate_sfc, 511 Sfc_divider, Clock_change_enable_sfc, 512 Sfc_divider, Clock_busy_sfc, 513 Sfc_divider, Clock_divider_sfc, 0xff, 514 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 515 516 /* Clock_smb0 */ Clock_undefined, 517 518 /* Clock_smb1 */ Clock_undefined, 519 520 /* Clock_smb2 */ Clock_undefined, 521 522 /* Clock_smb3 */ Clock_undefined, 523 524 /* Clock_smb4 */ Clock_undefined, 525 526 /* Clock_ssi */ {Ssi_divider, Clock_source_ssi, 527 Clock_gate0, Clock_gate_ssi0, 528 Ssi_divider, Clock_change_enable_ssi, 529 Ssi_divider, Clock_busy_ssi, 530 Ssi_divider, Clock_divider_ssi, 0xff, 531 3, {Clock_input_main, Clock_input_pll_M, Clock_input_pll_E}}, 532 533 /* Clock_timer */ {Reg_undefined, Clock_source_undefined, 534 Clock_gate0, Clock_gate_timer, 535 Reg_undefined, Clock_change_enable_undefined, 536 Reg_undefined, Clock_busy_undefined, 537 Reg_undefined, Clock_divider_undefined, 0, 538 1, {Clock_input_ahb2_apb}}, 539 540 /* Clock_uart0 */ {Reg_undefined, Clock_source_undefined, 541 Clock_gate0, Clock_gate_uart0, 542 Reg_undefined, Clock_change_enable_undefined, 543 Reg_undefined, Clock_busy_undefined, 544 Reg_undefined, Clock_divider_undefined, 0, 545 1, {Clock_input_ahb2_apb}}, 546 547 /* Clock_uart1 */ {Reg_undefined, Clock_source_undefined, 548 Clock_gate0, Clock_gate_uart1, 549 Reg_undefined, Clock_change_enable_undefined, 550 Reg_undefined, Clock_busy_undefined, 551 Reg_undefined, Clock_divider_undefined, 0, 552 1, {Clock_input_ahb2_apb}}, 553 554 /* Clock_uart2 */ {Reg_undefined, Clock_source_undefined, 555 Clock_gate0, Clock_gate_uart2, 556 Reg_undefined, Clock_change_enable_undefined, 557 Reg_undefined, Clock_busy_undefined, 558 Reg_undefined, Clock_divider_undefined, 0, 559 1, {Clock_input_ahb2_apb}}, 560 561 /* Clock_uart3 */ {Reg_undefined, Clock_source_undefined, 562 Clock_gate1, Clock_gate_uart3, 563 Reg_undefined, Clock_change_enable_undefined, 564 Reg_undefined, Clock_busy_undefined, 565 Reg_undefined, Clock_divider_undefined, 0, 566 1, {Clock_input_ahb2_apb}}, 567 568 /* Clock_udc */ Clock_undefined, 569 570 /* Clock_uhc */ Clock_undefined, 571 572 /* Clock_uprt */ Clock_undefined, 573 }; 574 575 576 577 // Convenience functions. 578 579 static uint8_t get_clock_gate_bit(enum Clock_identifiers clock) 580 { 581 enum Clock_gate_bits bit = clock_desc[clock].gate_bit; 582 583 return bit != Clock_gate_undefined ? (uint8_t) bit : 0; 584 } 585 586 static uint32_t get_clock_gate_mask(enum Clock_identifiers clock) 587 { 588 enum Clock_gate_bits bit = clock_desc[clock].gate_bit; 589 590 return bit != Clock_gate_undefined ? 1 : 0; 591 } 592 593 594 595 // If implemented as a Hw::Device, various properties would be 596 // initialised in the constructor and obtained from the device tree 597 // definitions. 598 599 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq) 600 : _exclk_freq(exclk_freq) 601 { 602 _regs = new Hw::Mmio_register_block<32>(addr); 603 604 // add_cid("cpm"); 605 // add_cid("cpm-x1600"); 606 // register_property("exclk_freq", &_exclk_freq); 607 } 608 609 610 611 // Utility methods. 612 613 uint32_t 614 Cpm_x1600_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 615 { 616 return (_regs[reg] & (mask << shift)) >> shift; 617 } 618 619 void 620 Cpm_x1600_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 621 { 622 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 623 } 624 625 626 627 // Clock/timer control. 628 629 void 630 Cpm_x1600_chip::change_disable(enum Clock_identifiers clock) 631 { 632 enum Clock_change_enable_bits bit = clock_desc[clock].change_enable_bit; 633 634 if (bit != Clock_change_enable_undefined) 635 set_field(clock_desc[clock].change_enable_reg, 1, bit, 0); 636 } 637 638 void 639 Cpm_x1600_chip::change_enable(enum Clock_identifiers clock) 640 { 641 enum Clock_change_enable_bits bit = clock_desc[clock].change_enable_bit; 642 643 if (bit != Clock_change_enable_undefined) 644 set_field(clock_desc[clock].change_enable_reg, 1, bit, 1); 645 } 646 647 int 648 Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) 649 { 650 if (clock_desc[clock].gate_bit != Clock_gate_undefined) 651 return !get_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), 652 get_clock_gate_bit(clock)); 653 else 654 return true; 655 } 656 657 void 658 Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) 659 { 660 if (clock_desc[clock].gate_bit != Clock_gate_undefined) 661 set_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), 662 get_clock_gate_bit(clock), 0); 663 } 664 665 void 666 Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) 667 { 668 if (clock_desc[clock].gate_bit != Clock_gate_undefined) 669 set_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), 670 get_clock_gate_bit(clock), 1); 671 } 672 673 void 674 Cpm_x1600_chip::wait_busy(enum Clock_identifiers clock) 675 { 676 enum Clock_busy_bits bit = clock_desc[clock].busy_bit; 677 678 if (bit != Clock_busy_undefined) 679 while (get_field(clock_desc[clock].busy_reg, 1, bit)); 680 } 681 682 683 684 // PLL control. 685 686 // Return whether the PLL is stable. 687 688 int 689 Cpm_x1600_chip::have_pll(uint32_t pll_reg) 690 { 691 return get_field(pll_reg, 1, Pll_stable); 692 } 693 694 int 695 Cpm_x1600_chip::pll_enabled(uint32_t pll_reg) 696 { 697 return get_field(pll_reg, 1, Pll_enabled); 698 } 699 700 int 701 Cpm_x1600_chip::pll_bypassed(uint32_t pll_reg) 702 { 703 uint8_t bit; 704 unsigned mask = 1; 705 706 switch (pll_reg) 707 { 708 case Pll_control_A: bit = Pll_bypass_A; break; 709 case Pll_control_M: bit = Pll_bypass_M; break; 710 case Pll_control_E: bit = Pll_bypass_E; break; 711 default: bit = 0; mask = 0; break; 712 } 713 714 return get_field(Pll_control, mask, bit); 715 } 716 717 void 718 Cpm_x1600_chip::pll_enable(uint32_t pll_reg) 719 { 720 set_field(pll_reg, 1, Pll_enabled, 1); 721 while (!have_pll(pll_reg)); 722 } 723 724 void 725 Cpm_x1600_chip::pll_disable(uint32_t pll_reg) 726 { 727 set_field(pll_reg, 1, Pll_enabled, 0); 728 while (have_pll(pll_reg)); 729 } 730 731 // Feedback (13-bit) multiplier. 732 733 uint16_t 734 Cpm_x1600_chip::get_multiplier(uint32_t pll_reg) 735 { 736 return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; 737 } 738 739 void 740 Cpm_x1600_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) 741 { 742 set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); 743 } 744 745 // Input (6-bit) divider. 746 747 uint8_t 748 Cpm_x1600_chip::get_input_division(uint32_t pll_reg) 749 { 750 return get_field(pll_reg, 0x3f, Pll_input_division) + 1; 751 } 752 753 void 754 Cpm_x1600_chip::set_input_division(uint32_t pll_reg, uint8_t divider) 755 { 756 set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); 757 } 758 759 // Output (dual 3-bit) dividers. 760 761 uint8_t 762 Cpm_x1600_chip::get_output_division(uint32_t pll_reg) 763 { 764 uint8_t d0 = get_field(pll_reg, 0x07, Pll_output_division0); 765 uint8_t d1 = get_field(pll_reg, 0x07, Pll_output_division1); 766 767 return d0 * d1; 768 } 769 770 void 771 Cpm_x1600_chip::set_output_division(uint32_t pll_reg, uint8_t divider) 772 { 773 // Assert 1 as a minimum. 774 // Divider 0 must be less than or equal to divider 1. 775 776 uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1)); 777 uint8_t d1 = divider / d0; 778 779 set_field(pll_reg, 0x07, Pll_output_division0, d0); 780 set_field(pll_reg, 0x07, Pll_output_division1, d1); 781 } 782 783 uint32_t 784 Cpm_x1600_chip::get_pll_frequency(uint32_t pll_reg) 785 { 786 // Test for PLL enable and not PLL bypass. 787 788 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 789 return (_exclk_freq * get_multiplier(pll_reg)) / 790 (get_input_division(pll_reg) * get_output_division(pll_reg)); 791 else 792 return _exclk_freq; 793 } 794 795 void 796 Cpm_x1600_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 797 { 798 set_multiplier(pll_reg, multiplier); 799 set_input_division(pll_reg, in_divider); 800 set_output_division(pll_reg, out_divider); 801 802 if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) 803 while (!have_pll(pll_reg)); 804 } 805 806 807 808 // Clock dividers. 809 810 uint32_t 811 Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) 812 { 813 if (clock_desc[clock].divider_bit != Clock_divider_undefined) 814 return get_field(clock_desc[clock].divider_reg, clock_desc[clock].divider_mask, 815 clock_desc[clock].divider_bit) + 1; 816 else 817 return 1; 818 } 819 820 void 821 Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) 822 { 823 if (clock_desc[clock].divider_bit == Clock_divider_undefined) 824 return; 825 826 change_enable(clock); 827 set_field(clock_desc[clock].divider_reg, clock_desc[clock].divider_mask, 828 clock_desc[clock].divider_bit, division - 1); 829 wait_busy(clock); 830 change_disable(clock); 831 } 832 833 834 835 // Clock sources. 836 837 uint8_t 838 Cpm_x1600_chip::get_source(enum Clock_identifiers clock) 839 { 840 if (clock_desc[clock].source_bit != Clock_source_undefined) 841 return get_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit); 842 else 843 return 0; 844 } 845 846 void 847 Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) 848 { 849 if (clock_desc[clock].source_bit == Clock_source_undefined) 850 return; 851 852 change_enable(clock); 853 set_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit, source); 854 wait_busy(clock); 855 change_disable(clock); 856 } 857 858 859 860 // Clock source frequencies. 861 862 uint32_t 863 Cpm_x1600_chip::get_input_frequency(enum Clock_input_identifiers clock) 864 { 865 struct Clock_input_desc desc = clock_input_desc[clock]; 866 867 // Clocks with no inputs provide a frequency. 868 869 if (desc.num_inputs == 0) 870 { 871 switch (clock) 872 { 873 case Clock_input_external: return _exclk_freq; 874 default: return 0; 875 } 876 } 877 878 // Of the input clocks, only PLLs have a single input. 879 880 else if (desc.num_inputs == 1) 881 { 882 switch (clock) 883 { 884 case Clock_input_pll_A: return get_pll_frequency(Pll_control_A); 885 case Clock_input_pll_E: return get_pll_frequency(Pll_control_E); 886 case Clock_input_pll_M: return get_pll_frequency(Pll_control_M); 887 default: return 0; 888 } 889 } 890 891 // With multiple sources, obtain the selected source for the clock. 892 893 uint8_t source = get_field(desc.source_reg, Source_mask, desc.source_bit); 894 895 // Return the frequency of the source. 896 897 if (source < desc.num_inputs) 898 return get_input_frequency(desc.inputs[source]); 899 else 900 return 0; 901 } 902 903 uint32_t 904 Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) 905 { 906 struct Clock_desc desc = clock_desc[clock]; 907 908 // Undefined clocks return zero. 909 910 if (desc.num_inputs == 0) 911 return 0; 912 913 // Clocks with one source yield that input frequency. 914 915 else if (desc.num_inputs == 1) 916 return get_input_frequency(desc.inputs[0]); 917 918 // With multiple sources, obtain the selected source for the clock. 919 920 uint8_t source = get_source(clock); 921 922 // Return the frequency of the source. 923 924 if (source < desc.num_inputs) 925 return get_input_frequency(desc.inputs[source]); 926 else 927 return 0; 928 } 929 930 931 932 // Output clock frequencies. 933 934 uint32_t 935 Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) 936 { 937 return get_source_frequency(clock) / get_divider(clock); 938 } 939 940 void 941 Cpm_x1600_chip::set_frequency(enum Clock_identifiers clock, uint32_t frequency) 942 { 943 switch (clock) 944 { 945 // The pixel frequency is based on the selected clock source (SCLK_A, MPLL or 946 // EPLL). 947 948 case Clock_lcd_pixel: 949 950 // Switch to the MPLL and attempt to set the divider. 951 952 set_source(Clock_lcd_pixel, Source_mME_pll_M); 953 pll_enable(Pll_control_M); 954 set_divider(Clock_lcd_pixel, get_source_frequency(clock) / frequency); 955 break; 956 957 default: 958 break; 959 } 960 } 961 962 963 964 // C language interface functions. 965 966 void 967 *x1600_cpm_init(l4_addr_t cpm_base) 968 { 969 /* Initialise the clock and power management peripheral with the 970 register memory region and a 24MHz EXCLK frequency. */ 971 972 return (void *) new Cpm_x1600_chip(cpm_base, 24000000); 973 } 974 975 int 976 x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 977 { 978 return static_cast<Cpm_x1600_chip *>(cpm)->have_clock(clock); 979 } 980 981 void 982 x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 983 { 984 static_cast<Cpm_x1600_chip *>(cpm)->start_clock(clock); 985 } 986 987 void 988 x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 989 { 990 static_cast<Cpm_x1600_chip *>(cpm)->stop_clock(clock); 991 } 992 993 994 995 uint32_t 996 x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock) 997 { 998 return static_cast<Cpm_x1600_chip *>(cpm)->get_divider(clock); 999 } 1000 1001 void 1002 x1600_cpm_set_divider(void *cpm, enum Clock_identifiers clock, uint32_t divider) 1003 { 1004 return static_cast<Cpm_x1600_chip *>(cpm)->set_divider(clock, divider); 1005 } 1006 1007 1008 1009 uint8_t 1010 x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) 1011 { 1012 return static_cast<Cpm_x1600_chip *>(cpm)->get_source(clock); 1013 } 1014 1015 void 1016 x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) 1017 { 1018 static_cast<Cpm_x1600_chip *>(cpm)->set_source(clock, source); 1019 } 1020 1021 1022 1023 uint32_t 1024 x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) 1025 { 1026 return static_cast<Cpm_x1600_chip *>(cpm)->get_source_frequency(clock); 1027 } 1028 1029 1030 1031 uint32_t 1032 x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) 1033 { 1034 return static_cast<Cpm_x1600_chip *>(cpm)->get_frequency(clock); 1035 } 1036 1037 void 1038 x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency) 1039 { 1040 static_cast<Cpm_x1600_chip *>(cpm)->set_frequency(clock, frequency); 1041 } 1042 1043 1044 1045 void 1046 x1600_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 1047 { 1048 static_cast<Cpm_x1600_chip *>(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); 1049 }