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