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, 2021 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 uint32_t 107 Cpm_jz4730_chip::get_clock_gate_value(enum Clock_identifiers clock) 108 { 109 switch (clock) 110 { 111 case Clock_uprt: return (1 << Clock_gate_uprt); 112 case Clock_udc: return (1 << Clock_gate_udc); 113 case Clock_cim: return (1 << Clock_gate_cim); 114 case Clock_kbc: return (1 << Clock_gate_kbc); 115 case Clock_emac: return (1 << Clock_gate_emac); 116 case Clock_uart3: return (1 << Clock_gate_uart3); 117 case Clock_aic_bitclk: return (1 << Clock_gate_aic_bitclk); 118 case Clock_scc: return (1 << Clock_gate_scc); 119 case Clock_msc: return (1 << Clock_gate_msc); 120 case Clock_ssi: return (1 << Clock_gate_ssi); 121 case Clock_pwm1: return (1 << Clock_gate_pwm1); 122 case Clock_pmw0: return (1 << Clock_gate_pmw0); 123 case Clock_aic_pclk: return (1 << Clock_gate_aic_pclk); 124 case Clock_i2c: return (1 << Clock_gate_i2c); 125 case Clock_lcd: return (1 << Clock_gate_lcd); 126 case Clock_uhc: return (1 << Clock_gate_uhc); 127 case Clock_dma: return (1 << Clock_gate_dmac); 128 case Clock_timer: return (1 << Clock_gate_timer); 129 case Clock_uart2: return (1 << Clock_gate_uart2); 130 case Clock_uart1: return (1 << Clock_gate_uart1); 131 case Clock_uart0: return (1 << Clock_gate_uart0); 132 default: return 0; 133 } 134 } 135 136 int 137 Cpm_jz4730_chip::have_clock(enum Clock_identifiers clock) 138 { 139 return !(_regs[Clock_gate] & get_clock_gate_value(clock)); 140 } 141 142 void 143 Cpm_jz4730_chip::start_clock(enum Clock_identifiers clock) 144 { 145 _regs[Clock_gate] = _regs[Clock_gate] & ~get_clock_gate_value(clock); 146 } 147 148 void 149 Cpm_jz4730_chip::stop_clock(enum Clock_identifiers clock) 150 { 151 _regs[Clock_gate] = _regs[Clock_gate] | get_clock_gate_value(clock); 152 } 153 154 // PLL control. 155 156 // Return whether the PLL is stable. 157 158 int 159 Cpm_jz4730_chip::have_pll() 160 { 161 return _regs[Pll_control] & (1 << Pll_stable); 162 } 163 164 int 165 Cpm_jz4730_chip::pll_enabled() 166 { 167 return _regs[Pll_control] & (1 << Pll_enabled); 168 } 169 170 int 171 Cpm_jz4730_chip::pll_bypassed() 172 { 173 return _regs[Pll_control] & (1 << Pll_bypassed); 174 } 175 176 // Feedback (9-bit) multiplier. 177 178 uint16_t 179 Cpm_jz4730_chip::get_multiplier() 180 { 181 return ((_regs[Pll_control] & (0x1ff << Pll_multiplier)) >> Pll_multiplier) + 2; 182 } 183 184 // Input (5-bit) divider. 185 186 uint8_t 187 Cpm_jz4730_chip::get_input_division() 188 { 189 return ((_regs[Pll_control] & (0x1f << Pll_input_division)) >> Pll_input_division) + 2; 190 } 191 192 // Output divider. 193 194 static uint8_t od[4] = {1, 2, 2, 4}; 195 196 uint8_t 197 Cpm_jz4730_chip::get_output_division() 198 { 199 return od[(_regs[Pll_control] & (0x03 << Pll_output_division)) >> Pll_output_division]; 200 } 201 202 // General clock divider. 203 204 static uint8_t cd[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; 205 206 uint8_t 207 Cpm_jz4730_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) 208 { 209 uint8_t d = (_regs[reg] & mask) >> shift; 210 return (d < 10) ? cd[d] : 1; 211 } 212 213 // CPU clock (CCLK) divider. 214 215 uint8_t 216 Cpm_jz4730_chip::get_cpu_divider() 217 { 218 return _get_divider(Clock_control, 0xf << Clock_cpu_divider, Clock_cpu_divider); 219 } 220 221 // Fast peripheral clock (HCLK) divider. 222 223 uint8_t 224 Cpm_jz4730_chip::get_hclock_divider() 225 { 226 return _get_divider(Clock_control, 0xf << Clock_hclock_divider, Clock_hclock_divider); 227 } 228 229 // Slow peripheral clock (PCLK) divider. 230 231 uint8_t 232 Cpm_jz4730_chip::get_pclock_divider() 233 { 234 return _get_divider(Clock_control, 0xf << Clock_pclock_divider, Clock_pclock_divider); 235 } 236 237 // Memory clock (MCLK) divider. 238 239 uint8_t 240 Cpm_jz4730_chip::get_memory_divider() 241 { 242 return _get_divider(Clock_control, 0xf << Clock_memory_divider, Clock_memory_divider); 243 } 244 245 // Clock source divider for MSC, I2S, LCD and USB. 246 247 uint8_t 248 Cpm_jz4730_chip::get_source_divider() 249 { 250 return 1; 251 } 252 253 // LCD device clock divider. 254 255 void 256 Cpm_jz4730_chip::set_lcd_device_divider(uint8_t division) 257 { 258 if (division == 0) 259 division = 1; 260 261 // NOTE: The vendor code (clock.c) bounds the divider at 16, but maybe this is 262 // NOTE: confused with the width of the bitfield which actually contains an 263 // NOTE: index for the clock divider value array (cd). 264 265 else if (division > 16) 266 division = 16; 267 268 // Obtain the divider or closest higher divider. 269 270 int i; 271 272 for (i = 0; i < 10; i++) 273 if (cd[i] >= division) break; 274 275 _regs[Clock_control] = (_regs[Clock_control] & ~(0xf << Clock_lcd_divider)) | 276 (cd[i] << Clock_lcd_divider); 277 } 278 279 // LCD pixel clock divider. 280 281 uint16_t 282 Cpm_jz4730_chip::get_lcd_pixel_divider() 283 { 284 return (_regs[Lcd_divider] >> Lcd_divider_value) + 1; 285 } 286 287 void 288 Cpm_jz4730_chip::set_lcd_pixel_divider(uint16_t division) 289 { 290 if (division == 0) 291 division = 1; 292 else if (division > 512) 293 division = 512; 294 295 _regs[Lcd_divider] = (_regs[Lcd_divider] & ~(0x1ff << Lcd_divider_value)) | 296 ((division - 1) << Lcd_divider_value); 297 } 298 299 300 301 uint32_t 302 Cpm_jz4730_chip::get_frequency(enum Clock_frequency_identifiers clock) 303 { 304 if (clock == Clock_frequency_lcd_pixel) 305 return get_output_frequency() / get_lcd_pixel_divider(); 306 307 // NOTE: Consider a better error result. 308 return 0; 309 } 310 311 void 312 Cpm_jz4730_chip::set_frequency(enum Clock_frequency_identifiers clock, uint32_t frequency) 313 { 314 uint32_t out = get_output_frequency(); 315 316 switch (clock) 317 { 318 // Limit the device frequency to 150MHz. 319 320 case Clock_frequency_lcd: 321 if (frequency > 150000000) 322 frequency = 150000000; 323 set_lcd_device_divider(out / frequency); 324 break; 325 326 case Clock_frequency_lcd_pixel: 327 set_lcd_pixel_divider(out / frequency); 328 break; 329 330 default: 331 break; 332 } 333 } 334 335 336 337 uint32_t 338 Cpm_jz4730_chip::get_pll_frequency() 339 { 340 // Test for PLL enable and not PLL bypass. 341 342 if (pll_enabled() && !pll_bypassed()) 343 return (_exclk_freq * get_multiplier()) / 344 (get_input_division() * get_output_division()); 345 else 346 return _exclk_freq; 347 } 348 349 // Clock frequency for MSC, I2S, LCD and USB. 350 351 uint32_t 352 Cpm_jz4730_chip::get_output_frequency() 353 { 354 return get_pll_frequency() / get_source_divider(); 355 } 356 357 void 358 Cpm_jz4730_chip::update_output_frequency() 359 { 360 _regs[Clock_control] = _regs[Clock_control] | (1 << Clock_enable); 361 } 362 363 // Clock frequency for the CPU. 364 365 uint32_t Cpm_jz4730_chip::get_cpu_frequency() 366 { 367 if (pll_enabled()) 368 return get_pll_frequency() / get_cpu_divider(); 369 else 370 return _exclk_freq; 371 } 372 373 // Clock frequency for fast peripherals. 374 375 uint32_t 376 Cpm_jz4730_chip::get_hclock_frequency() 377 { 378 if (pll_enabled()) 379 return get_pll_frequency() / get_hclock_divider(); 380 else 381 return _exclk_freq; 382 } 383 384 // Clock frequency for slow peripherals. 385 386 uint32_t 387 Cpm_jz4730_chip::get_pclock_frequency() 388 { 389 if (pll_enabled()) 390 return get_pll_frequency() / get_pclock_divider(); 391 else 392 return _exclk_freq; 393 } 394 395 // Clock frequency for the memory. 396 397 uint32_t 398 Cpm_jz4730_chip::get_memory_frequency() 399 { 400 if (pll_enabled()) 401 return get_pll_frequency() / get_memory_divider(); 402 else 403 return _exclk_freq; 404 } 405 406 407 408 // C language interface functions. 409 410 void 411 *jz4730_cpm_init(l4_addr_t cpm_base) 412 { 413 /* Initialise the clock and power management peripheral with the 414 register memory region and a 3.6864 MHz EXCLK frequency. */ 415 416 return (void *) new Cpm_jz4730_chip(cpm_base, 3686400); 417 } 418 419 int 420 jz4730_cpm_have_clock(void *cpm, enum Clock_identifiers clock) 421 { 422 return static_cast<Cpm_jz4730_chip *>(cpm)->have_clock(clock); 423 } 424 425 void 426 jz4730_cpm_start_clock(void *cpm, enum Clock_identifiers clock) 427 { 428 static_cast<Cpm_jz4730_chip *>(cpm)->start_clock(clock); 429 } 430 431 void 432 jz4730_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) 433 { 434 static_cast<Cpm_jz4730_chip *>(cpm)->stop_clock(clock); 435 } 436 437 uint32_t 438 jz4730_cpm_get_cpu_frequency(void *cpm) 439 { 440 return static_cast<Cpm_jz4730_chip *>(cpm)->get_cpu_frequency(); 441 } 442 443 uint32_t 444 jz4730_cpm_get_hclock_frequency(void *cpm) 445 { 446 return static_cast<Cpm_jz4730_chip *>(cpm)->get_hclock_frequency(); 447 } 448 449 uint32_t 450 jz4730_cpm_get_output_frequency(void *cpm) 451 { 452 return static_cast<Cpm_jz4730_chip *>(cpm)->get_output_frequency(); 453 } 454 455 uint32_t 456 jz4730_cpm_get_pclock_frequency(void *cpm) 457 { 458 return static_cast<Cpm_jz4730_chip *>(cpm)->get_pclock_frequency(); 459 } 460 461 uint32_t 462 jz4730_cpm_get_memory_frequency(void *cpm) 463 { 464 return static_cast<Cpm_jz4730_chip *>(cpm)->get_memory_frequency(); 465 } 466 467 uint16_t 468 jz4730_cpm_get_lcd_pixel_divider(void *cpm) 469 { 470 return static_cast<Cpm_jz4730_chip *>(cpm)->get_lcd_pixel_divider(); 471 } 472 473 uint32_t 474 jz4730_cpm_get_frequency(void *cpm, enum Clock_frequency_identifiers clock) 475 { 476 return static_cast<Cpm_jz4730_chip *>(cpm)->get_frequency(clock); 477 } 478 479 void 480 jz4730_cpm_set_frequency(void *cpm, enum Clock_frequency_identifiers clock, uint32_t frequency) 481 { 482 static_cast<Cpm_jz4730_chip *>(cpm)->set_frequency(clock, frequency); 483 } 484 485 void 486 jz4730_cpm_update_output_frequency(void *cpm) 487 { 488 static_cast<Cpm_jz4730_chip *>(cpm)->update_output_frequency(); 489 }