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