1 /* 2 * Clock and power management. This exposes the combined functionality 3 * provided by the X1600 and related SoCs. The power management 4 * functionality could be exposed using a separate driver. 5 * 6 * Copyright (C) 2017, 2018, 2020, 2021, 2023 Paul Boddie <paul@boddie.org.uk> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA 22 */ 23 24 #include <l4/devices/hw_mmio_register_block.h> 25 #include "cpm-x1600.h" 26 #include <math.h> 27 #include <stdio.h> 28 29 30 31 // Register locations. 32 33 enum Regs : unsigned 34 { 35 Clock_control = 0x000, // CPCCR 36 Low_power_control = 0x004, // LCR 37 Clock_gate0 = 0x020, // CLKGR0 38 Clock_gate1 = 0x028, // CLKGR1 39 Sleep_control = 0x024, // OPCR (oscillator and power control) 40 Clock_status = 0x0d4, // CPCSR 41 Divider_ddr = 0x02c, // DDRCDR 42 Divider_mac = 0x054, // MACCDR 43 Divider0_i2s0 = 0x060, // I2SCDR 44 Divider1_i2s0 = 0x070, // I2S1CDR 45 Divider_lcd = 0x064, // LPCDR 46 Divider_msc0 = 0x068, // MSC0CDR 47 Divider_msc1 = 0x0a4, // MSC1CDR 48 Divider_sfc = 0x074, // SFCCDR 49 Divider_ssi = 0x05c, // SSICDR 50 Divider_cim = 0x078, // CIMCDR 51 Divider_pwm = 0x06c, // PWMCDR 52 Divider_can0 = 0x0a0, // CAN0CDR 53 Divider_can1 = 0x0a8, // CAN1CDR 54 Divider_cdbus = 0x0ac, // CDBUSCDR 55 Divider_macphy0 = 0x0e4, // MPHY0C 56 Cpm_interrupt = 0x0b0, // CPM_INTR 57 Cpm_interrupt_en = 0x0b4, // CPM_INTRE 58 Cpm_swi = 0x0bc, // CPM_SFTINT 59 Ddr_gate = 0x0d0, // DRCG 60 Cpm_scratch_prot = 0x038, // CPSPPR 61 Cpm_scratch = 0x034, // CPSPR 62 Usb_param_control0 = 0x03c, // USBPCR 63 Usb_reset_detect = 0x040, // USBRDT 64 Usb_vbus_jitter = 0x044, // USBVBFIL 65 Usb_param_control1 = 0x048, // USBPCR1 66 Pll_control = 0x00c, // CPPCR 67 Pll_control_A = 0x010, // CPAPCR 68 Pll_control_M = 0x014, // CPMPCR 69 Pll_control_E = 0x018, // CPEPCR 70 Pll_fraction_A = 0x084, // CPAPACR 71 Pll_fraction_M = 0x088, // CPMPACR 72 Pll_fraction_E = 0x08c, // CPEPACR 73 }; 74 75 enum Clock_source_values : unsigned 76 { 77 Source_mME_main = 0, 78 Source_mME_pll_M = 1, 79 Source_mME_pll_E = 2, 80 81 // Special value 82 83 Source_mask = 0x3, 84 }; 85 86 87 88 // Register field abstraction. 89 90 class Field 91 { 92 uint32_t reg; 93 uint32_t mask; 94 uint8_t bit; 95 bool defined; 96 97 public: 98 explicit Field() 99 : defined(false) 100 { 101 } 102 103 explicit Field(uint32_t reg, uint32_t mask, uint32_t bit) 104 : reg(reg), mask(mask), bit(bit), defined(true) 105 { 106 } 107 108 uint32_t get_field(Cpm_regs ®s); 109 void set_field(Cpm_regs ®s, uint32_t value); 110 bool is_defined() { return defined; } 111 }; 112 113 // Undefined fields. 114 115 Field Source_undefined, Gate_undefined, Change_enable_undefined, Busy_undefined, Divider_undefined; 116 117 118 119 // Clock sources. 120 121 class Mux 122 { 123 int _num_inputs; 124 enum Clock_identifiers *_inputs; 125 126 public: 127 explicit Mux(int num_inputs = 0, enum Clock_identifiers inputs[] = NULL) 128 : _num_inputs(num_inputs), _inputs(inputs) 129 { 130 } 131 132 int get_number() { return _num_inputs; } 133 enum Clock_identifiers get_input(int num); 134 }; 135 136 // Undefined sources. 137 138 Mux Mux_undefined; 139 140 141 142 // Common clock abstraction. 143 144 class Clock_base 145 { 146 Mux _inputs; 147 Field _source; 148 149 public: 150 explicit Clock_base(Mux inputs, 151 Field source = Source_undefined) 152 : _inputs(inputs), _source(source) 153 { 154 } 155 156 // Clock control. 157 158 virtual int have_clock(Cpm_regs ®s); 159 virtual void start_clock(Cpm_regs ®s); 160 virtual void stop_clock(Cpm_regs ®s); 161 162 // Clock divider. 163 164 virtual uint32_t get_divider(Cpm_regs ®s); 165 virtual void set_divider(Cpm_regs ®s, uint32_t division); 166 167 // Clock source. 168 169 virtual uint8_t get_source(Cpm_regs ®s); 170 virtual void set_source(Cpm_regs ®s, uint8_t source); 171 172 // Clock source frequency. 173 174 virtual uint32_t get_source_frequency(Cpm_regs ®s); 175 176 // Output frequency. 177 178 virtual uint32_t get_frequency(Cpm_regs ®s); 179 }; 180 181 182 183 // PLL descriptions. 184 185 class Pll : public Clock_base 186 { 187 Field _enable, _stable, _bypass; 188 Field _multiplier, _input_division, _output_division0, _output_division1; 189 190 public: 191 explicit Pll(Mux inputs, 192 Field enable, Field stable, Field bypass, 193 Field multiplier, Field input_division, 194 Field output_division0, Field output_division1) 195 : Clock_base(inputs), 196 _enable(enable), _stable(stable), _bypass(bypass), 197 _multiplier(multiplier), _input_division(input_division), 198 _output_division0(output_division0), _output_division1(output_division1) 199 { 200 } 201 202 // PLL_specific control. 203 204 int have_pll(Cpm_regs ®s); 205 int pll_enabled(Cpm_regs ®s); 206 int pll_bypassed(Cpm_regs ®s); 207 208 // Clock control. 209 210 int have_clock(Cpm_regs ®s); 211 void start_clock(Cpm_regs ®s); 212 void stop_clock(Cpm_regs ®s); 213 214 // General frequency modifiers. 215 216 uint16_t get_multiplier(Cpm_regs ®s); 217 void set_multiplier(Cpm_regs ®s, uint16_t multiplier); 218 uint8_t get_input_division(Cpm_regs ®s); 219 void set_input_division(Cpm_regs ®s, uint8_t divider); 220 uint8_t get_output_division(Cpm_regs ®s); 221 void set_output_division(Cpm_regs ®s, uint8_t divider); 222 223 // PLL output frequency. 224 225 uint32_t get_frequency(Cpm_regs ®s); 226 227 // Other operations. 228 229 void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, 230 uint8_t in_divider, uint8_t out_divider); 231 }; 232 233 234 235 // Clock descriptions. 236 237 class Clock : public Clock_base 238 { 239 Field _gate, _change_enable, _busy, _divider; 240 241 // Clock control. 242 243 void change_disable(Cpm_regs ®s); 244 void change_enable(Cpm_regs ®s); 245 void wait_busy(Cpm_regs ®s); 246 247 public: 248 explicit Clock(Mux inputs = Mux_undefined, 249 Field source = Source_undefined, 250 Field gate = Gate_undefined, 251 Field change_enable = Change_enable_undefined, 252 Field busy = Busy_undefined, 253 Field divider = Divider_undefined) 254 : Clock_base(inputs, source), 255 _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider) 256 { 257 } 258 259 // Clock control. 260 261 int have_clock(Cpm_regs ®s); 262 void start_clock(Cpm_regs ®s); 263 void stop_clock(Cpm_regs ®s); 264 265 // Clock divider. 266 267 uint32_t get_divider(Cpm_regs ®s); 268 void set_divider(Cpm_regs ®s, uint32_t division); 269 270 // Clock source. 271 272 void set_source(Cpm_regs ®s, uint8_t source); 273 }; 274 275 276 277 // Register field definitions. 278 279 Field Clock_source_main (Clock_control, 3, 30); // SEL_SRC (output to SCLK_A) 280 Field Clock_source_cpu (Clock_control, 3, 28); // SEL_CPLL (output to CCLK) 281 Field Clock_source_hclock0 (Clock_control, 3, 26); // SEL_H0PLL (output to AHB0) 282 Field Clock_source_hclock2 (Clock_control, 3, 24); // SEL_H2PLL (output to AHB2) 283 Field Clock_source_can0 (Divider_can0, 3, 30); // CA0CS 284 Field Clock_source_can1 (Divider_can1, 3, 30); // CA1CS 285 Field Clock_source_cdbus (Divider_cdbus, 3, 30); // CDCS 286 Field Clock_source_cim (Divider_cim, 3, 30); // CIMPCS 287 Field Clock_source_ddr (Divider_ddr, 3, 30); // DCS 288 Field Clock_source_i2s (Divider0_i2s0, 1, 31); // I2PCS 289 Field Clock_source_lcd (Divider_lcd, 3, 30); // LPCS 290 Field Clock_source_mac (Divider_mac, 3, 30); // MACPCS 291 Field Clock_source_msc0 (Divider_msc0, 3, 30); // MPCS 292 Field Clock_source_msc1 (Divider_msc1, 3, 30); // MPCS 293 Field Clock_source_pwm (Divider_pwm, 3, 30); // PWMPCS 294 Field Clock_source_sfc (Divider_sfc, 3, 30); // SFCS 295 Field Clock_source_ssi (Divider_ssi, 3, 30); // SPCS 296 297 Field Clock_busy_cpu (Clock_status, 1, 0); 298 Field Clock_busy_ddr (Divider_ddr, 1, 28); 299 Field Clock_busy_mac (Divider_mac, 1, 28); 300 Field Clock_busy_lcd (Divider_lcd, 1, 28); 301 Field Clock_busy_msc0 (Divider_msc0, 1, 28); 302 Field Clock_busy_msc1 (Divider_msc1, 1, 28); 303 Field Clock_busy_sfc (Divider_sfc, 1, 28); 304 Field Clock_busy_ssi (Divider_ssi, 1, 28); 305 Field Clock_busy_cim (Divider_cim, 1, 28); 306 Field Clock_busy_pwm (Divider_pwm, 1, 28); 307 Field Clock_busy_can0 (Divider_can0, 1, 28); 308 Field Clock_busy_can1 (Divider_can1, 1, 28); 309 Field Clock_busy_cdbus (Divider_cdbus, 1, 28); 310 311 Field Clock_change_enable_cpu (Clock_control, 1, 22); 312 Field Clock_change_enable_ahb0 (Clock_control, 1, 21); 313 Field Clock_change_enable_ahb2 (Clock_control, 1, 20); 314 Field Clock_change_enable_ddr (Divider_ddr, 1, 29); 315 Field Clock_change_enable_mac (Divider_mac, 1, 29); 316 Field Clock_change_enable_i2s (Divider0_i2s0, 1, 29); 317 Field Clock_change_enable_lcd (Divider_lcd, 1, 29); 318 Field Clock_change_enable_msc0 (Divider_msc0, 1, 29); 319 Field Clock_change_enable_msc1 (Divider_msc1, 1, 29); 320 Field Clock_change_enable_sfc (Divider_sfc, 1, 29); 321 Field Clock_change_enable_ssi (Divider_ssi, 1, 29); 322 Field Clock_change_enable_cim (Divider_cim, 1, 29); 323 Field Clock_change_enable_pwm (Divider_pwm, 1, 29); 324 Field Clock_change_enable_can0 (Divider_can0, 1, 29); 325 Field Clock_change_enable_can1 (Divider_can1, 1, 29); 326 Field Clock_change_enable_cdbus (Divider_cdbus, 1, 29); 327 328 Field Clock_divider_can0 (Divider_can0, 0xff, 0); // CAN0CDR 329 Field Clock_divider_can1 (Divider_can1, 0xff, 0); // CAN1CDR 330 Field Clock_divider_cdbus (Divider_cdbus, 0xff, 0); // CDBUSCDR 331 Field Clock_divider_cim (Divider_cim, 0xff, 0); // CIMCDR 332 Field Clock_divider_cpu (Clock_control, 0x0f, 0); // CDIV 333 Field Clock_divider_ddr (Divider_ddr, 0x0f, 0); // DDRCDR 334 Field Clock_divider_hclock0 (Clock_control, 0x0f, 8); // H0DIV (fast AHB peripherals) 335 Field Clock_divider_hclock2 (Clock_control, 0x0f, 12); // H2DIV (fast AHB peripherals) 336 Field Clock_divider_l2cache (Clock_control, 0x0f, 4); // L2CDIV 337 Field Clock_divider_lcd (Divider_lcd, 0xff, 0); // LPCDR 338 Field Clock_divider_mac (Divider_mac, 0xff, 0); // MACCDR 339 Field Clock_divider_msc0 (Divider_msc0, 0xff, 0); // MSC0CDR 340 Field Clock_divider_msc1 (Divider_msc1, 0xff, 0); // MSC1CDR 341 Field Clock_divider_pclock (Clock_control, 0x0f, 16); // PDIV (slow APB peripherals) 342 Field Clock_divider_pwm (Divider_pwm, 0x0f, 0); // PWMCDR 343 Field Clock_divider_sfc (Divider_sfc, 0xff, 0); // SFCCDR 344 Field Clock_divider_ssi (Divider_ssi, 0xff, 0); // SSICDR 345 346 Field Clock_gate_main (Clock_control, 1, 23); // GATE_SCLKA 347 Field Clock_gate_ddr (Clock_gate0, 1, 31); // DDR 348 Field Clock_gate_ahb0 (Clock_gate0, 1, 29); // AHB0 349 Field Clock_gate_apb0 (Clock_gate0, 1, 28); // APB0 350 Field Clock_gate_rtc (Clock_gate0, 1, 27); // RTC 351 Field Clock_gate_aes (Clock_gate0, 1, 24); // AES 352 Field Clock_gate_lcd_pixel (Clock_gate0, 1, 23); // LCD 353 Field Clock_gate_cim (Clock_gate0, 1, 22); // CIM 354 Field Clock_gate_dma (Clock_gate0, 1, 21); // PDMA 355 Field Clock_gate_ost (Clock_gate0, 1, 20); // OST 356 Field Clock_gate_ssi0 (Clock_gate0, 1, 19); // SSI0 357 Field Clock_gate_timer (Clock_gate0, 1, 18); // TCU 358 Field Clock_gate_dtrng (Clock_gate0, 1, 17); // DTRNG 359 Field Clock_gate_uart2 (Clock_gate0, 1, 16); // UART2 360 Field Clock_gate_uart1 (Clock_gate0, 1, 15); // UART1 361 Field Clock_gate_uart0 (Clock_gate0, 1, 14); // UART0 362 Field Clock_gate_sadc (Clock_gate0, 1, 13); // SADC 363 Field Clock_gate_audio (Clock_gate0, 1, 11); // AUDIO 364 Field Clock_gate_ssi_slv (Clock_gate0, 1, 10); // SSI_SLV 365 Field Clock_gate_i2c1 (Clock_gate0, 1, 8); // I2C1 366 Field Clock_gate_i2c0 (Clock_gate0, 1, 7); // I2C0 367 Field Clock_gate_msc1 (Clock_gate0, 1, 5); // MSC1 368 Field Clock_gate_msc0 (Clock_gate0, 1, 4); // MSC0 369 Field Clock_gate_otg (Clock_gate0, 1, 3); // OTG 370 Field Clock_gate_sfc (Clock_gate0, 1, 2); // SFC 371 Field Clock_gate_efuse (Clock_gate0, 1, 1); // EFUSE 372 Field Clock_gate_nemc (Clock_gate0, 1, 0); // NEMC 373 Field Clock_gate_arb (Clock_gate1, 1, 30); // ARB 374 Field Clock_gate_mipi_csi (Clock_gate1, 1, 28); // MIPI_CSI 375 Field Clock_gate_intc (Clock_gate1, 1, 26); // INTC 376 Field Clock_gate_gmac0 (Clock_gate1, 1, 23); // GMAC0 377 Field Clock_gate_uart3 (Clock_gate1, 1, 16); // UART3 378 Field Clock_gate_i2s0_tx (Clock_gate1, 1, 9); // I2S0_dev_tclk 379 Field Clock_gate_i2s0_rx (Clock_gate1, 1, 8); // I2S0_dev_rclk 380 Field Clock_gate_hash (Clock_gate1, 1, 6); // HASH 381 Field Clock_gate_pwm (Clock_gate1, 1, 5); // PWM 382 Field Clock_gate_cdbus (Clock_gate1, 1, 2); // CDBUS 383 Field Clock_gate_can1 (Clock_gate1, 1, 1); // CAN1 384 Field Clock_gate_can0 (Clock_gate1, 1, 0); // CAN0 385 386 Field Pll_enable_A (Pll_control_A, 1, 0); // APLLEN 387 Field Pll_enable_E (Pll_control_E, 1, 0); // EPLLEN 388 Field Pll_enable_M (Pll_control_M, 1, 0); // MPLLEN 389 390 Field Pll_stable_A (Pll_control_A, 1, 3); // APLL_ON 391 Field Pll_stable_E (Pll_control_E, 1, 3); // EPLL_ON 392 Field Pll_stable_M (Pll_control_M, 1, 3); // MPLL_ON 393 394 Field Pll_bypass_A (Pll_control_A, 1, 30); // APLL_BP 395 Field Pll_bypass_E (Pll_control_E, 1, 26); // EPLL_BP 396 Field Pll_bypass_M (Pll_control_M, 1, 28); // MPLL_BP 397 398 Field Pll_multiplier_A (Pll_control_A, 0x1fff, 20); // APLLM 399 Field Pll_multiplier_E (Pll_control_E, 0x1fff, 20); // EPLLM 400 Field Pll_multiplier_M (Pll_control_M, 0x1fff, 20); // MPLLM 401 402 Field Pll_input_division_A (Pll_control_A, 0x3f, 14); // APLLN 403 Field Pll_input_division_E (Pll_control_E, 0x3f, 14); // EPLLN 404 Field Pll_input_division_M (Pll_control_M, 0x3f, 14); // MPLLN 405 406 Field Pll_output_division1_A (Pll_control_A, 0x07, 11); // APLLOD1 407 Field Pll_output_division1_E (Pll_control_E, 0x07, 11); // EPLLOD1 408 Field Pll_output_division1_M (Pll_control_M, 0x07, 11); // MPLLOD1 409 410 Field Pll_output_division0_A (Pll_control_A, 0x07, 8); // APLLOD0 411 Field Pll_output_division0_E (Pll_control_E, 0x07, 8); // EPLLOD0 412 Field Pll_output_division0_M (Pll_control_M, 0x07, 8); // MPLLOD0 413 414 415 416 // Multiplexer instances. 417 418 #define Clocks(...) ((enum Clock_identifiers []) {__VA_ARGS__}) 419 420 Mux mux_external(1, Clocks(Clock_external)); 421 422 Mux mux_core(3, Clocks(Clock_none, Clock_main, Clock_pll_M)); 423 424 Mux mux_bus(4, Clocks(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external)); 425 426 Mux mux_dev(3, Clocks(Clock_main, Clock_pll_M, Clock_pll_E)); 427 428 Mux mux_pclock(1, Clocks(Clock_pclock)); 429 430 Mux mux_ahb2_apb(1, Clocks(Clock_ahb2_apb)); 431 432 Mux mux_i2s(2, Clocks(Clock_main, Clock_pll_E)); 433 434 435 436 // Clock instances. 437 438 Clock clock_ahb2_apb(mux_core, Clock_source_hclock2); 439 440 Clock clock_aic_bitclk; 441 442 Clock clock_aic_pclk; 443 444 Clock clock_can0(mux_bus, 445 Clock_source_can0, 446 Clock_gate_can0, 447 Clock_change_enable_can0, 448 Clock_busy_can0, 449 Clock_divider_can0); 450 451 Clock clock_can1(mux_bus, 452 Clock_source_can1, 453 Clock_gate_can1, 454 Clock_change_enable_can1, 455 Clock_busy_can1, 456 Clock_divider_can1); 457 458 Clock clock_cdbus(mux_dev, 459 Clock_source_cdbus, 460 Clock_gate_cdbus, 461 Clock_change_enable_cdbus, 462 Clock_busy_cdbus, 463 Clock_divider_cdbus); 464 465 Clock clock_cim(mux_dev, 466 Clock_source_cim, 467 Clock_gate_cim, 468 Clock_change_enable_cim, 469 Clock_busy_cim, 470 Clock_divider_cim); 471 472 Clock clock_cpu(mux_core, 473 Clock_source_cpu, 474 Gate_undefined, 475 Clock_change_enable_cpu, 476 Clock_busy_cpu, 477 Clock_divider_cpu); 478 479 Clock clock_ddr(mux_core, 480 Clock_source_ddr, 481 Clock_gate_ddr, 482 Clock_change_enable_ddr, 483 Clock_busy_ddr, 484 Clock_divider_ddr); 485 486 Clock clock_dma(mux_pclock, Source_undefined, Clock_gate_dma); 487 488 Clock clock_emac; 489 490 Clock clock_external; 491 492 Clock clock_hclock0(mux_core, 493 Clock_source_hclock0, 494 Clock_gate_ahb0, 495 Clock_change_enable_ahb0, 496 Busy_undefined, 497 Clock_divider_hclock0); 498 499 Clock clock_hclock2(mux_ahb2_apb, 500 Source_undefined, 501 Clock_gate_apb0, 502 Clock_change_enable_ahb2, 503 Busy_undefined, 504 Clock_divider_hclock2); 505 506 Clock clock_hdmi; 507 508 Clock clock_i2c(mux_pclock, 509 Source_undefined, 510 Clock_gate_i2c0); 511 512 Clock clock_i2c0(mux_pclock, 513 Source_undefined, 514 Clock_gate_i2c0); 515 516 Clock clock_i2c1(mux_pclock, 517 Source_undefined, 518 Clock_gate_i2c1); 519 520 Clock clock_i2s; 521 522 Clock clock_i2s0_rx(mux_i2s, 523 Clock_source_i2s, 524 Clock_gate_i2s0_rx, 525 Clock_change_enable_i2s); 526 527 Clock clock_i2s0_tx(mux_i2s, 528 Clock_source_i2s, 529 Clock_gate_i2s0_tx, 530 Clock_change_enable_i2s); 531 532 Clock clock_kbc; 533 534 Clock clock_lcd; 535 536 Clock clock_lcd_pixel(mux_dev, 537 Clock_source_lcd, 538 Clock_gate_lcd_pixel, 539 Clock_change_enable_lcd, 540 Clock_busy_lcd, 541 Clock_divider_lcd); 542 543 Clock clock_mac(mux_dev, 544 Clock_source_mac, 545 Clock_gate_gmac0, 546 Clock_change_enable_mac, 547 Clock_busy_mac, 548 Clock_divider_mac); 549 550 Clock clock_main(mux_core, 551 Clock_source_main, 552 Clock_gate_main); 553 554 Clock clock_msc(mux_dev, 555 Clock_source_msc0, 556 Clock_gate_msc0, 557 Clock_change_enable_msc0, 558 Clock_busy_msc0, 559 Clock_divider_msc0); 560 561 Clock clock_msc0(mux_dev, 562 Clock_source_msc0, 563 Clock_gate_msc0, 564 Clock_change_enable_msc0, 565 Clock_busy_msc0, 566 Clock_divider_msc0); 567 568 Clock clock_msc1(mux_dev, 569 Clock_source_msc1, 570 Clock_gate_msc1, 571 Clock_change_enable_msc1, 572 Clock_busy_msc1, 573 Clock_divider_msc1); 574 575 Clock clock_none; 576 577 Clock clock_pclock(mux_ahb2_apb, 578 Source_undefined, 579 Clock_gate_apb0, 580 Change_enable_undefined, 581 Busy_undefined, 582 Clock_divider_pclock); 583 584 Pll clock_pll_A(mux_external, 585 Pll_enable_A, Pll_stable_A, Pll_bypass_A, 586 Pll_multiplier_A, Pll_input_division_A, 587 Pll_output_division0_A, Pll_output_division1_A); 588 589 Pll clock_pll_E(mux_external, 590 Pll_enable_E, Pll_stable_E, Pll_bypass_E, 591 Pll_multiplier_E, Pll_input_division_E, 592 Pll_output_division0_E, Pll_output_division1_E); 593 594 Pll clock_pll_M(mux_external, 595 Pll_enable_M, Pll_stable_M, Pll_bypass_M, 596 Pll_multiplier_M, Pll_input_division_M, 597 Pll_output_division0_M, Pll_output_division1_M); 598 599 Clock clock_pwm(mux_dev, 600 Clock_source_pwm, 601 Clock_gate_pwm, 602 Clock_change_enable_pwm, 603 Clock_busy_pwm, 604 Clock_divider_pwm); 605 606 Clock clock_pwm0(mux_dev, 607 Clock_source_pwm, 608 Clock_gate_pwm, 609 Clock_change_enable_pwm, 610 Clock_busy_pwm, 611 Clock_divider_pwm); 612 613 Clock clock_pwm1; 614 615 Clock clock_scc; 616 617 Clock clock_sfc(mux_dev, 618 Clock_source_sfc, 619 Clock_gate_sfc, 620 Clock_change_enable_sfc, 621 Clock_busy_sfc, 622 Clock_divider_sfc); 623 624 Clock clock_smb0; 625 626 Clock clock_smb1; 627 628 Clock clock_smb2; 629 630 Clock clock_smb3; 631 632 Clock clock_smb4; 633 634 Clock clock_ssi(mux_dev, 635 Clock_source_ssi, 636 Clock_gate_ssi0, 637 Clock_change_enable_ssi, 638 Clock_busy_ssi, 639 Clock_divider_ssi); 640 641 Clock clock_timer(mux_pclock, Source_undefined, Clock_gate_timer); 642 643 Clock clock_uart0(mux_external, Source_undefined, Clock_gate_uart0); 644 645 Clock clock_uart1(mux_external, Source_undefined, Clock_gate_uart1); 646 647 Clock clock_uart2(mux_external, Source_undefined, Clock_gate_uart2); 648 649 Clock clock_uart3(mux_external, Source_undefined, Clock_gate_uart3); 650 651 Clock clock_udc; 652 653 Clock clock_uhc; 654 655 Clock clock_uprt; 656 657 658 659 // Clock register. 660 661 static Clock_base *clocks[Clock_identifier_count] = { 662 &clock_ahb2_apb, 663 &clock_aic_bitclk, 664 &clock_aic_pclk, 665 &clock_can0, 666 &clock_can1, 667 &clock_cdbus, 668 &clock_cim, 669 &clock_cpu, 670 &clock_ddr, 671 &clock_dma, 672 &clock_emac, 673 &clock_external, 674 &clock_hclock0, 675 &clock_hclock2, 676 &clock_hdmi, 677 &clock_i2c, 678 &clock_i2c0, 679 &clock_i2c1, 680 &clock_i2s, 681 &clock_i2s0_rx, 682 &clock_i2s0_tx, 683 &clock_kbc, 684 &clock_lcd, 685 &clock_lcd_pixel, 686 &clock_mac, 687 &clock_main, 688 &clock_msc, 689 &clock_msc0, 690 &clock_msc1, 691 &clock_none, 692 &clock_pclock, 693 &clock_pll_A, 694 &clock_pll_E, 695 &clock_pll_M, 696 &clock_pwm, 697 &clock_pwm0, 698 &clock_pwm1, 699 &clock_scc, 700 &clock_sfc, 701 &clock_smb0, 702 &clock_smb1, 703 &clock_smb2, 704 &clock_smb3, 705 &clock_smb4, 706 &clock_ssi, 707 &clock_timer, 708 &clock_uart0, 709 &clock_uart1, 710 &clock_uart2, 711 &clock_uart3, 712 &clock_udc, 713 &clock_uhc, 714 &clock_uprt, 715 }; 716 717 718 719 // Register access. 720 721 Cpm_regs::Cpm_regs(l4_addr_t addr, uint32_t exclk_freq) 722 : exclk_freq(exclk_freq) 723 { 724 _regs = new Hw::Mmio_register_block<32>(addr); 725 } 726 727 // Utility methods. 728 729 uint32_t 730 Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift) 731 { 732 return (_regs[reg] & (mask << shift)) >> shift; 733 } 734 735 void 736 Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) 737 { 738 _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); 739 } 740 741 742 743 // Field methods. 744 745 uint32_t 746 Field::get_field(Cpm_regs ®s) 747 { 748 if (defined) 749 return regs.get_field(reg, mask, bit); 750 else 751 return 0; 752 } 753 754 void 755 Field::set_field(Cpm_regs ®s, uint32_t value) 756 { 757 if (defined) 758 regs.set_field(reg, mask, bit, value); 759 } 760 761 762 763 // Clock sources. 764 765 enum Clock_identifiers 766 Mux::get_input(int num) 767 { 768 if (num < _num_inputs) 769 return _inputs[num]; 770 else 771 return Clock_undefined; 772 } 773 774 775 776 // Clock control. 777 778 int 779 Clock_base::have_clock(Cpm_regs ®s) 780 { 781 (void) regs; 782 return true; 783 } 784 785 void 786 Clock_base::start_clock(Cpm_regs ®s) 787 { 788 (void) regs; 789 } 790 791 void 792 Clock_base::stop_clock(Cpm_regs ®s) 793 { 794 (void) regs; 795 } 796 797 // Default divider. 798 799 uint32_t 800 Clock_base::get_divider(Cpm_regs ®s) 801 { 802 (void) regs; 803 return 1; 804 } 805 806 void 807 Clock_base::set_divider(Cpm_regs ®s, uint32_t division) 808 { 809 (void) regs; 810 (void) division; 811 } 812 813 // Clock sources. 814 815 uint8_t 816 Clock_base::get_source(Cpm_regs ®s) 817 { 818 if (_source.is_defined()) 819 return _source.get_field(regs); 820 else 821 return 0; 822 } 823 824 void 825 Clock_base::set_source(Cpm_regs ®s, uint8_t source) 826 { 827 if (_source.is_defined()) 828 return; 829 830 _source.set_field(regs, source); 831 } 832 833 // Clock source frequencies. 834 835 uint32_t 836 Clock_base::get_source_frequency(Cpm_regs ®s) 837 { 838 // Return the external clock frequency without any input clock. 839 840 if (_inputs.get_number() == 0) 841 return regs.exclk_freq; 842 843 // Clocks with one source yield that input frequency. 844 845 else if (_inputs.get_number() == 1) 846 return clocks[_inputs.get_input(0)]->get_frequency(regs); 847 848 // With multiple sources, obtain the selected source for the clock. 849 850 uint8_t source = get_source(regs); 851 enum Clock_identifiers input = _inputs.get_input(source); 852 853 // Return the frequency of the source. 854 855 if (input != Clock_undefined) 856 return clocks[input]->get_frequency(regs); 857 else 858 return 0; 859 } 860 861 // Output clock frequencies. 862 863 uint32_t 864 Clock_base::get_frequency(Cpm_regs ®s) 865 { 866 return get_source_frequency(regs) / get_divider(regs); 867 } 868 869 870 871 // PLL-specific control. 872 873 int 874 Pll::have_pll(Cpm_regs ®s) 875 { 876 return _stable.get_field(regs); 877 } 878 879 int 880 Pll::pll_enabled(Cpm_regs ®s) 881 { 882 return _enable.get_field(regs); 883 } 884 885 int 886 Pll::pll_bypassed(Cpm_regs ®s) 887 { 888 return _bypass.get_field(regs); 889 } 890 891 // Clock control. 892 893 int 894 Pll::have_clock(Cpm_regs ®s) 895 { 896 return have_pll(regs) && pll_enabled(regs); 897 } 898 899 void 900 Pll::start_clock(Cpm_regs ®s) 901 { 902 _enable.set_field(regs, 1); 903 while (!have_pll(regs)); 904 } 905 906 void 907 Pll::stop_clock(Cpm_regs ®s) 908 { 909 _enable.set_field(regs, 0); 910 while (have_pll(regs)); 911 } 912 913 // Feedback (13-bit) multiplier. 914 915 uint16_t 916 Pll::get_multiplier(Cpm_regs ®s) 917 { 918 return _multiplier.get_field(regs) + 1; 919 } 920 921 void 922 Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier) 923 { 924 _multiplier.set_field(regs, multiplier - 1); 925 } 926 927 // Input (6-bit) divider. 928 929 uint8_t 930 Pll::get_input_division(Cpm_regs ®s) 931 { 932 return _input_division.get_field(regs) + 1; 933 } 934 935 void 936 Pll::set_input_division(Cpm_regs ®s, uint8_t divider) 937 { 938 _input_division.set_field(regs, divider - 1); 939 } 940 941 // Output (dual 3-bit) dividers. 942 943 uint8_t 944 Pll::get_output_division(Cpm_regs ®s) 945 { 946 uint8_t d0 = _output_division0.get_field(regs); 947 uint8_t d1 = _output_division1.get_field(regs); 948 949 return d0 * d1; 950 } 951 952 void 953 Pll::set_output_division(Cpm_regs ®s, uint8_t divider) 954 { 955 // Assert 1 as a minimum. 956 // Divider 0 must be less than or equal to divider 1. 957 958 uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1)); 959 uint8_t d1 = divider / d0; 960 961 _output_division0.set_field(regs, d0); 962 _output_division1.set_field(regs, d1); 963 } 964 965 uint32_t 966 Pll::get_frequency(Cpm_regs ®s) 967 { 968 // Test for PLL enable and not PLL bypass. 969 970 if (pll_enabled(regs)) 971 { 972 if (!pll_bypassed(regs)) 973 return (get_source_frequency(regs) * get_multiplier(regs)) / 974 (get_input_division(regs) * get_output_division(regs)); 975 else 976 return get_source_frequency(regs); 977 } 978 else 979 return 0; 980 } 981 982 void 983 Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 984 { 985 set_multiplier(regs, multiplier); 986 set_input_division(regs, in_divider); 987 set_output_division(regs, out_divider); 988 989 if (pll_enabled(regs) && !pll_bypassed(regs)) 990 while (!have_pll(regs)); 991 } 992 993 994 995 // Clock control. 996 997 void 998 Clock::change_disable(Cpm_regs ®s) 999 { 1000 if (_change_enable.is_defined()) 1001 _change_enable.set_field(regs, 0); 1002 } 1003 1004 void 1005 Clock::change_enable(Cpm_regs ®s) 1006 { 1007 if (_change_enable.is_defined()) 1008 _change_enable.set_field(regs, 1); 1009 } 1010 1011 int 1012 Clock::have_clock(Cpm_regs ®s) 1013 { 1014 if (_gate.is_defined()) 1015 return !_gate.get_field(regs); 1016 else 1017 return true; 1018 } 1019 1020 void 1021 Clock::start_clock(Cpm_regs ®s) 1022 { 1023 if (_gate.is_defined()) 1024 _gate.set_field(regs, 0); 1025 } 1026 1027 void 1028 Clock::stop_clock(Cpm_regs ®s) 1029 { 1030 if (_gate.is_defined()) 1031 _gate.set_field(regs, 1); 1032 } 1033 1034 void 1035 Clock::wait_busy(Cpm_regs ®s) 1036 { 1037 if (_busy.is_defined()) 1038 while (_busy.get_field(regs)); 1039 } 1040 1041 1042 1043 // Clock dividers. 1044 1045 uint32_t 1046 Clock::get_divider(Cpm_regs ®s) 1047 { 1048 if (_divider.is_defined()) 1049 return _divider.get_field(regs) + 1; 1050 else 1051 return 1; 1052 } 1053 1054 void 1055 Clock::set_divider(Cpm_regs ®s, uint32_t division) 1056 { 1057 if (_divider.is_defined()) 1058 return; 1059 1060 change_enable(regs); 1061 _divider.set_field(regs, division - 1); 1062 wait_busy(regs); 1063 change_disable(regs); 1064 } 1065 1066 void 1067 Clock::set_source(Cpm_regs ®s, uint8_t source) 1068 { 1069 change_enable(regs); 1070 Clock_base::set_source(regs, source); 1071 wait_busy(regs); 1072 change_disable(regs); 1073 } 1074 1075 1076 1077 // If implemented as a Hw::Device, various properties would be 1078 // initialised in the constructor and obtained from the device tree 1079 // definitions. 1080 1081 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq) 1082 : _cpm_regs(addr, exclk_freq) 1083 { 1084 // add_cid("cpm"); 1085 // add_cid("cpm-x1600"); 1086 // register_property("exclk_freq", &exclk_freq); 1087 } 1088 1089 int 1090 Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) 1091 { 1092 return clocks[clock]->have_clock(_cpm_regs); 1093 } 1094 1095 void 1096 Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) 1097 { 1098 clocks[clock]->start_clock(_cpm_regs); 1099 } 1100 1101 void 1102 Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) 1103 { 1104 clocks[clock]->stop_clock(_cpm_regs); 1105 } 1106 1107 uint32_t 1108 Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) 1109 { 1110 return clocks[clock]->get_divider(_cpm_regs); 1111 } 1112 1113 void 1114 Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) 1115 { 1116 clocks[clock]->set_divider(_cpm_regs, division); 1117 } 1118 1119 uint8_t 1120 Cpm_x1600_chip::get_source(enum Clock_identifiers clock) 1121 { 1122 return clocks[clock]->get_source(_cpm_regs); 1123 } 1124 1125 void 1126 Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) 1127 { 1128 clocks[clock]->set_source(_cpm_regs, source); 1129 } 1130 1131 uint32_t 1132 Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) 1133 { 1134 return clocks[clock]->get_source_frequency(_cpm_regs); 1135 } 1136 1137 uint32_t 1138 Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) 1139 { 1140 return clocks[clock]->get_frequency(_cpm_regs); 1141 } 1142 1143 void 1144 Cpm_x1600_chip::set_frequency(enum Clock_identifiers clock, uint32_t frequency) 1145 { 1146 switch (clock) 1147 { 1148 // The pixel frequency is based on the selected clock source (SCLK_A, MPLL or 1149 // EPLL). 1150 1151 case Clock_lcd_pixel: 1152 { 1153 1154 // Switch to the MPLL and attempt to set the divider. 1155 1156 Clock_base *lcd = clocks[Clock_lcd_pixel]; 1157 Clock_base *pll = clocks[Clock_pll_M]; 1158 1159 lcd->set_source(_cpm_regs, Source_mME_pll_M); 1160 pll->start_clock(_cpm_regs); 1161 lcd->set_divider(_cpm_regs, lcd->get_source_frequency(_cpm_regs) / frequency); 1162 break; 1163 } 1164 1165 default: 1166 break; 1167 } 1168 } 1169 1170 void 1171 Cpm_x1600_chip::set_pll_parameters(enum Clock_identifiers clock, uint16_t multiplier, 1172 uint8_t in_divider, uint8_t out_divider) 1173 { 1174 Pll *pll = dynamic_cast<Pll *>(clocks[clock]); 1175 1176 pll->set_pll_parameters(_cpm_regs, multiplier, in_divider, out_divider); 1177 } 1178 1179 1180 1181 // C language interface functions. 1182 1183 void 1184 *x1600_cpm_init(l4_addr_t cpm_base) 1185 { 1186 /* Initialise the clock and power management peripheral with the 1187 register memory region and a 24MHz EXCLK frequency. */ 1188 1189 return (void *) new Cpm_x1600_chip(cpm_base, 24000000); 1190 } 1191 1192 int 1193 x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 1194 { 1195 return static_cast<Cpm_x1600_chip *>(cpm)->have_clock(clock); 1196 } 1197 1198 void 1199 x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 1200 { 1201 static_cast<Cpm_x1600_chip *>(cpm)->start_clock(clock); 1202 } 1203 1204 void 1205 x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 1206 { 1207 static_cast<Cpm_x1600_chip *>(cpm)->stop_clock(clock); 1208 } 1209 1210 uint32_t 1211 x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock) 1212 { 1213 return static_cast<Cpm_x1600_chip *>(cpm)->get_divider(clock); 1214 } 1215 1216 void 1217 x1600_cpm_set_divider(void *cpm, enum Clock_identifiers clock, uint32_t divider) 1218 { 1219 return static_cast<Cpm_x1600_chip *>(cpm)->set_divider(clock, divider); 1220 } 1221 1222 uint8_t 1223 x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) 1224 { 1225 return static_cast<Cpm_x1600_chip *>(cpm)->get_source(clock); 1226 } 1227 1228 void 1229 x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) 1230 { 1231 static_cast<Cpm_x1600_chip *>(cpm)->set_source(clock, source); 1232 } 1233 1234 uint32_t 1235 x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) 1236 { 1237 return static_cast<Cpm_x1600_chip *>(cpm)->get_source_frequency(clock); 1238 } 1239 1240 uint32_t 1241 x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) 1242 { 1243 return static_cast<Cpm_x1600_chip *>(cpm)->get_frequency(clock); 1244 } 1245 1246 void 1247 x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency) 1248 { 1249 static_cast<Cpm_x1600_chip *>(cpm)->set_frequency(clock, frequency); 1250 } 1251 1252 void 1253 x1600_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) 1254 { 1255 static_cast<Cpm_x1600_chip *>(cpm)->set_pll_parameters(Clock_pll_M, multiplier, in_divider, out_divider); 1256 }