1 /* 2 * Clock and power management. This exposes the combined functionality 3 * provided by the jz4730. The power management functionality could be exposed 4 * using a separate driver. 5 * 6 * Copyright (C) 2017, 2018, 2020 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-jz4730.h" 26 27 28 29 enum Regs : unsigned 30 { 31 Clock_control = 0x000, // CFCR (CPCCR in JZ4740) 32 Pll_control = 0x010, // PLCR1 (CPPCR in JZ4740) 33 Clock_gate = 0x020, // MSCR (CLKGR in JZ4740) 34 Sleep_control = 0x024, // SCR 35 Lcd_divider = 0x060, // CFCR2 36 }; 37 38 enum Clock_bits : unsigned 39 { 40 Clock_enable = 20, // UPE 41 Clock_memory_divider = 16, // MFR 42 Clock_lcd_divider = 12, // LFR 43 Clock_pclock_divider = 8, // PFR (slow APB peripherals) 44 Clock_hclock_divider = 4, // SFR (fast AHB peripherals) 45 Clock_cpu_divider = 0, // IFR 46 }; 47 48 enum Pll_bits : unsigned 49 { 50 Pll_multiplier = 23, // PLL1FD 51 Pll_input_division = 18, // PLL1RD 52 Pll_output_division = 16, // PLL1OD 53 Pll_stable = 10, // PLL1S 54 Pll_bypassed = 9, // PLL1BP 55 Pll_enabled = 8, // PLL1EN 56 }; 57 58 enum Clock_gate_bits : unsigned 59 { 60 Clock_gate_uprt = 25, 61 Clock_gate_udc = 24, 62 Clock_gate_cim = 23, 63 Clock_gate_kbc = 22, 64 Clock_gate_emac = 21, 65 Clock_gate_uart3 = 20, 66 Clock_gate_aic_bitclk = 18, 67 Clock_gate_scc = 14, 68 Clock_gate_msc = 13, 69 Clock_gate_ssi = 12, 70 Clock_gate_pwm1 = 11, 71 Clock_gate_pmw0 = 10, 72 Clock_gate_aic_pclk = 9, 73 Clock_gate_i2c = 8, 74 Clock_gate_lcd = 7, 75 Clock_gate_uhc = 6, 76 Clock_gate_dmac = 5, 77 Clock_gate_timer = 3, 78 Clock_gate_uart2 = 2, 79 Clock_gate_uart1 = 1, 80 Clock_gate_uart0 = 0, 81 }; 82 83 enum Lcd_divider_bits : unsigned 84 { 85 Lcd_divider_value = 0, // PIXFR (in CFCR2) 86 }; 87 88 89 90 // If implemented as a Hw::Device, various properties would be 91 // initialised in the constructor and obtained from the device tree 92 // definitions. 93 94 Cpm_jz4730_chip::Cpm_jz4730_chip(l4_addr_t addr, uint32_t exclk_freq) 95 : _exclk_freq(exclk_freq) 96 { 97 _regs = new Hw::Mmio_register_block<32>(addr); 98 99 // add_cid("cpm"); 100 // add_cid("cpm-jz4730"); 101 // register_property("exclk_freq", &_exclk_freq); 102 } 103 104 // Clock/timer control. 105 106 int 107 Cpm_jz4730_chip::have_clock() 108 { 109 return !(_regs[Clock_gate] & (1 << Clock_gate_timer)); 110 } 111 112 void 113 Cpm_jz4730_chip::start_clock() 114 { 115 _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_timer); 116 } 117 118 // PLL control. 119 120 // Return whether the PLL is stable. 121 122 int 123 Cpm_jz4730_chip::have_pll() 124 { 125 return _regs[Pll_control] & (1 << Pll_stable); 126 } 127 128 int 129 Cpm_jz4730_chip::pll_enabled() 130 { 131 return _regs[Pll_control] & (1 << Pll_enabled); 132 } 133 134 int 135 Cpm_jz4730_chip::pll_bypassed() 136 { 137 return _regs[Pll_control] & (1 << Pll_bypassed); 138 } 139 140 // Feedback (9-bit) multiplier. 141 142 uint16_t 143 Cpm_jz4730_chip::get_multiplier() 144 { 145 return ((_regs[Pll_control] & (0x1ff << Pll_multiplier)) >> Pll_multiplier) + 2; 146 } 147 148 // Input (5-bit) divider. 149 150 uint8_t 151 Cpm_jz4730_chip::get_input_division() 152 { 153 return ((_regs[Pll_control] & (0x1f << Pll_input_division)) >> Pll_input_division) + 2; 154 } 155 156 // Output divider. 157 158 static uint8_t od[4] = {1, 2, 2, 4}; 159 160 uint8_t 161 Cpm_jz4730_chip::get_output_division() 162 { 163 return od[(_regs[Pll_control] & (0x03 << Pll_output_division)) >> Pll_output_division]; 164 } 165 166 // General clock divider. 167 168 static uint8_t cd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; 169 170 uint8_t 171 Cpm_jz4730_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) 172 { 173 uint8_t d = (_regs[reg] & mask) >> shift; 174 return (d < 10) ? cd[d] : 1; 175 } 176 177 // CPU clock (CCLK) divider. 178 179 uint8_t 180 Cpm_jz4730_chip::get_cpu_divider() 181 { 182 return _get_divider(Clock_control, 0xf << Clock_cpu_divider, Clock_cpu_divider); 183 } 184 185 // Fast peripheral clock (HCLK) divider. 186 187 uint8_t 188 Cpm_jz4730_chip::get_hclock_divider() 189 { 190 return _get_divider(Clock_control, 0xf << Clock_hclock_divider, Clock_hclock_divider); 191 } 192 193 // Slow peripheral clock (PCLK) divider. 194 195 uint8_t 196 Cpm_jz4730_chip::get_pclock_divider() 197 { 198 return _get_divider(Clock_control, 0xf << Clock_pclock_divider, Clock_pclock_divider); 199 } 200 201 // Memory clock (MCLK) divider. 202 203 uint8_t 204 Cpm_jz4730_chip::get_memory_divider() 205 { 206 return _get_divider(Clock_control, 0xf << Clock_memory_divider, Clock_memory_divider); 207 } 208 209 // Clock source divider for MSC, I2S, LCD and USB. 210 211 uint8_t 212 Cpm_jz4730_chip::get_source_divider() 213 { 214 return 1; 215 } 216 217 // LCD device clock divider. 218 219 void 220 Cpm_jz4730_chip::set_lcd_device_divider(uint8_t division) 221 { 222 if (division == 0) 223 division = 1; 224 225 // NOTE: The vendor code (clock.c) bounds the divider at 16, but maybe this is 226 // NOTE: confused with the width of the bitfield which actually contains an 227 // NOTE: index for the clock divider value array (cd). 228 229 else if (division > 16) 230 division = 16; 231 232 // Obtain the divider or closest higher divider. 233 234 int i; 235 236 for (i = 0; i < 10; i++) 237 if (cd[i] >= division) break; 238 239 _regs[Clock_control] = (_regs[Clock_control] & ~(0xf << Clock_lcd_divider)) | 240 (cd[i] << Clock_lcd_divider); 241 } 242 243 // LCD pixel clock divider. 244 245 uint16_t 246 Cpm_jz4730_chip::get_lcd_pixel_divider() 247 { 248 return (_regs[Lcd_divider] >> Lcd_divider_value) + 1; 249 } 250 251 void 252 Cpm_jz4730_chip::set_lcd_pixel_divider(uint16_t division) 253 { 254 if (division == 0) 255 division = 1; 256 else if (division > 512) 257 division = 512; 258 259 _regs[Lcd_divider] = (_regs[Lcd_divider] & ~(0x1ff << Lcd_divider_value)) | 260 ((division - 1) << Lcd_divider_value); 261 } 262 263 264 265 uint32_t 266 Cpm_jz4730_chip::get_lcd_pixel_frequency() 267 { 268 return get_output_frequency() / get_lcd_pixel_divider(); 269 } 270 271 // Set the device and pixel frequencies, indicating the latter and 272 // providing the device:pixel frequency ratio. 273 274 void 275 Cpm_jz4730_chip::set_lcd_frequencies(uint32_t pclk, uint8_t ratio) 276 { 277 uint32_t out = get_output_frequency(), 278 lcd = pclk * ratio; 279 280 set_lcd_pixel_divider(out / pclk); 281 282 // Limit the device frequency to 150MHz. 283 284 if (lcd > 150000000) lcd = 150000000; 285 286 set_lcd_device_divider(out / lcd); 287 } 288 289 290 291 // I2C clock control. 292 293 void 294 Cpm_jz4730_chip::start_i2c() 295 { 296 _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_i2c); 297 } 298 299 void 300 Cpm_jz4730_chip::stop_i2c() 301 { 302 _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_i2c); 303 } 304 305 306 307 // LCD clock control. 308 309 void 310 Cpm_jz4730_chip::start_lcd() 311 { 312 _regs[Clock_gate] = _regs[Clock_gate] & ~(1 << Clock_gate_lcd); 313 } 314 315 void 316 Cpm_jz4730_chip::stop_lcd() 317 { 318 _regs[Clock_gate] = _regs[Clock_gate] | (1 << Clock_gate_lcd); 319 } 320 321 322 323 uint32_t 324 Cpm_jz4730_chip::get_pll_frequency() 325 { 326 // Test for PLL enable and not PLL bypass. 327 328 if (pll_enabled() && !pll_bypassed()) 329 return (_exclk_freq * get_multiplier()) / 330 (get_input_division() * get_output_division()); 331 else 332 return _exclk_freq; 333 } 334 335 // Clock frequency for MSC, I2S, LCD and USB. 336 337 uint32_t 338 Cpm_jz4730_chip::get_output_frequency() 339 { 340 return get_pll_frequency() / get_source_divider(); 341 } 342 343 void 344 Cpm_jz4730_chip::update_output_frequency() 345 { 346 _regs[Clock_control] = _regs[Clock_control] | (1 << Clock_enable); 347 } 348 349 // Clock frequency for the CPU. 350 351 uint32_t Cpm_jz4730_chip::get_cpu_frequency() 352 { 353 if (pll_enabled()) 354 return get_pll_frequency() / get_cpu_divider(); 355 else 356 return _exclk_freq; 357 } 358 359 // Clock frequency for fast peripherals. 360 361 uint32_t 362 Cpm_jz4730_chip::get_hclock_frequency() 363 { 364 if (pll_enabled()) 365 return get_pll_frequency() / get_hclock_divider(); 366 else 367 return _exclk_freq; 368 } 369 370 // Clock frequency for slow peripherals. 371 372 uint32_t 373 Cpm_jz4730_chip::get_pclock_frequency() 374 { 375 if (pll_enabled()) 376 return get_pll_frequency() / get_pclock_divider(); 377 else 378 return _exclk_freq; 379 } 380 381 // Clock frequency for the memory. 382 383 uint32_t 384 Cpm_jz4730_chip::get_memory_frequency() 385 { 386 if (pll_enabled()) 387 return get_pll_frequency() / get_memory_divider(); 388 else 389 return _exclk_freq; 390 } 391 392 393 394 // C language interface functions. 395 396 void 397 *jz4730_cpm_init(l4_addr_t cpm_base) 398 { 399 /* Initialise the clock and power management peripheral with the 400 register memory region and a 3.6864 MHz EXCLK frequency. */ 401 402 return (void *) new Cpm_jz4730_chip(cpm_base, 3686400); 403 } 404 405 int 406 jz4730_cpm_have_clock(void *cpm) 407 { 408 return static_cast<Cpm_jz4730_chip *>(cpm)->have_clock(); 409 } 410 411 void 412 jz4730_cpm_start_clock(void *cpm) 413 { 414 static_cast<Cpm_jz4730_chip *>(cpm)->start_clock(); 415 } 416 417 void 418 jz4730_cpm_start_i2c(void *cpm) 419 { 420 static_cast<Cpm_jz4730_chip *>(cpm)->start_i2c(); 421 } 422 423 void 424 jz4730_cpm_stop_i2c(void *cpm) 425 { 426 static_cast<Cpm_jz4730_chip *>(cpm)->stop_i2c(); 427 } 428 429 void 430 jz4730_cpm_start_lcd(void *cpm) 431 { 432 static_cast<Cpm_jz4730_chip *>(cpm)->start_lcd(); 433 } 434 435 void 436 jz4730_cpm_stop_lcd(void *cpm) 437 { 438 static_cast<Cpm_jz4730_chip *>(cpm)->stop_lcd(); 439 } 440 441 uint32_t 442 jz4730_cpm_get_cpu_frequency(void *cpm) 443 { 444 return static_cast<Cpm_jz4730_chip *>(cpm)->get_cpu_frequency(); 445 } 446 447 uint32_t 448 jz4730_cpm_get_hclock_frequency(void *cpm) 449 { 450 return static_cast<Cpm_jz4730_chip *>(cpm)->get_hclock_frequency(); 451 } 452 453 uint32_t 454 jz4730_cpm_get_output_frequency(void *cpm) 455 { 456 return static_cast<Cpm_jz4730_chip *>(cpm)->get_output_frequency(); 457 } 458 459 uint32_t 460 jz4730_cpm_get_pclock_frequency(void *cpm) 461 { 462 return static_cast<Cpm_jz4730_chip *>(cpm)->get_pclock_frequency(); 463 } 464 465 uint32_t 466 jz4730_cpm_get_memory_frequency(void *cpm) 467 { 468 return static_cast<Cpm_jz4730_chip *>(cpm)->get_memory_frequency(); 469 } 470 471 uint16_t 472 jz4730_cpm_get_lcd_pixel_divider(void *cpm) 473 { 474 return static_cast<Cpm_jz4730_chip *>(cpm)->get_lcd_pixel_divider(); 475 } 476 477 uint32_t 478 jz4730_cpm_get_lcd_pixel_frequency(void *cpm) 479 { 480 return static_cast<Cpm_jz4730_chip *>(cpm)->get_lcd_pixel_frequency(); 481 } 482 483 void 484 jz4730_cpm_set_lcd_frequencies(void *cpm, uint32_t pclk, uint8_t ratio) 485 { 486 static_cast<Cpm_jz4730_chip *>(cpm)->set_lcd_frequencies(pclk, ratio); 487 } 488 489 void 490 jz4730_cpm_update_output_frequency(void *cpm) 491 { 492 static_cast<Cpm_jz4730_chip *>(cpm)->update_output_frequency(); 493 }