paul@0 | 1 | /* |
paul@0 | 2 | * Clock and power management. This exposes the combined functionality |
paul@0 | 3 | * provided by the jz4780 and related SoCs. The power management |
paul@0 | 4 | * functionality could be exposed using a separate driver. |
paul@0 | 5 | * |
paul@133 | 6 | * Copyright (C) 2017, 2018, 2020, 2021 Paul Boddie <paul@boddie.org.uk> |
paul@0 | 7 | * |
paul@0 | 8 | * This program is free software; you can redistribute it and/or |
paul@0 | 9 | * modify it under the terms of the GNU General Public License as |
paul@0 | 10 | * published by the Free Software Foundation; either version 2 of |
paul@0 | 11 | * the License, or (at your option) any later version. |
paul@0 | 12 | * |
paul@0 | 13 | * This program is distributed in the hope that it will be useful, |
paul@0 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@0 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@0 | 16 | * GNU General Public License for more details. |
paul@0 | 17 | * |
paul@0 | 18 | * You should have received a copy of the GNU General Public License |
paul@0 | 19 | * along with this program; if not, write to the Free Software |
paul@0 | 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@0 | 21 | * Boston, MA 02110-1301, USA |
paul@0 | 22 | */ |
paul@0 | 23 | |
paul@0 | 24 | #include <l4/devices/hw_mmio_register_block.h> |
paul@0 | 25 | #include "cpm-jz4780.h" |
paul@0 | 26 | |
paul@0 | 27 | |
paul@0 | 28 | |
paul@0 | 29 | enum Regs : unsigned |
paul@0 | 30 | { |
paul@0 | 31 | Clock_control = 0x000, // CPCCR |
paul@0 | 32 | Low_power_control = 0x004, // LCR |
paul@0 | 33 | Pll_control = 0x00c, // CPPCR |
paul@0 | 34 | Pll_control_A = 0x010, // CPAPCR |
paul@0 | 35 | Pll_control_M = 0x014, // CPMPCR |
paul@0 | 36 | Pll_control_E = 0x018, // CPEPCR |
paul@0 | 37 | Pll_control_V = 0x01c, // CPVPCR |
paul@0 | 38 | Clock_gate0 = 0x020, // CLKGR0 |
paul@0 | 39 | Clock_gate1 = 0x028, // CLKGR1 |
paul@0 | 40 | Sleep_control = 0x024, // OPCR (oscillator and power control) |
paul@0 | 41 | Ddr_divider = 0x02c, // DDRCDR |
paul@0 | 42 | I2s_divider0 = 0x060, // I2SCDR |
paul@0 | 43 | I2s_divider1 = 0x0a0, // I2S1CDR |
paul@0 | 44 | Lcd_divider0 = 0x054, // LP0CDR |
paul@0 | 45 | Lcd_divider1 = 0x064, // LP1CDR |
paul@0 | 46 | Msc_divider0 = 0x068, // MSC0CDR |
paul@0 | 47 | Msc_divider1 = 0x0a4, // MSC1CDR |
paul@0 | 48 | Msc_divider2 = 0x0a8, // MSC2CDR |
paul@0 | 49 | Uhc_divider = 0x06c, // UHCCDR |
paul@0 | 50 | Ssi_divider = 0x074, // SSICDR |
paul@62 | 51 | |
paul@62 | 52 | // ... |
paul@62 | 53 | |
paul@62 | 54 | Hdmi_divider = 0x08c, // HDMICDR |
paul@62 | 55 | |
paul@62 | 56 | // ... |
paul@0 | 57 | }; |
paul@0 | 58 | |
paul@0 | 59 | enum Clock_bits : unsigned |
paul@0 | 60 | { |
paul@0 | 61 | Clock_enable = 22, // CE_CPU |
paul@0 | 62 | Clock_pclock_divider = 16, // PDIV (slow APB peripherals) |
paul@0 | 63 | Clock_hclock2_divider = 12, // H2DIV (fast AHB peripherals) |
paul@0 | 64 | Clock_hclock0_divider = 8, // H0DIV (fast AHB peripherals) |
paul@0 | 65 | Clock_cpu_divider = 0, // CDIV |
paul@0 | 66 | }; |
paul@0 | 67 | |
paul@0 | 68 | enum Pll_bits : unsigned |
paul@0 | 69 | { |
paul@0 | 70 | Pll_multiplier = 19, // xPLLM |
paul@0 | 71 | Pll_input_division = 13, // xPLLN |
paul@0 | 72 | Pll_output_division = 9, // xPLLOD |
paul@0 | 73 | Pll_stable = 4, // xPLL_ON |
paul@0 | 74 | Pll_bypassed = 1, // xPLLBP |
paul@0 | 75 | Pll_enabled = 0, // xPLLEN |
paul@0 | 76 | }; |
paul@0 | 77 | |
paul@0 | 78 | enum Clock_source_bits : unsigned |
paul@0 | 79 | { |
paul@0 | 80 | Clock_source_main = 30, // SEL_SRC (output to SCLK_A) |
paul@0 | 81 | Clock_source_cpu = 28, // SEL_CPLL (output to CCLK) |
paul@0 | 82 | Clock_source_hclock0 = 26, // SEL_H0PLL (output to AHB0) |
paul@0 | 83 | Clock_source_hclock2 = 24, // SEL_H2PLL (output to AHB2) |
paul@0 | 84 | Clock_source_ddr = 30, // DCS |
paul@0 | 85 | Clock_source_i2s = 31, // I2CS |
paul@0 | 86 | Clock_source_lcd = 30, // LPCS |
paul@62 | 87 | Clock_source_hdmi = 30, // HPCS |
paul@0 | 88 | }; |
paul@0 | 89 | |
paul@0 | 90 | enum Clock_sources : unsigned |
paul@0 | 91 | { |
paul@62 | 92 | // Main clock sources. |
paul@62 | 93 | |
paul@0 | 94 | Source_pll_A = 1, // APLL |
paul@0 | 95 | Source_external = 2, // EXCLK |
paul@0 | 96 | Source_realtime = 3, // RTCLK |
paul@62 | 97 | |
paul@62 | 98 | // Stoppable clock sources. |
paul@62 | 99 | |
paul@62 | 100 | Source_mux_stopped = 0, |
paul@62 | 101 | Source_mux_main = 1, // SCLK_A |
paul@62 | 102 | Source_mux_pll_M = 2, // MPLL |
paul@62 | 103 | Source_mux_pll_E = 3, // EPLL |
paul@62 | 104 | Source_mux_realtime = 3, // RTCLK (TCK) |
paul@62 | 105 | |
paul@62 | 106 | // Unstoppable clock sources. |
paul@62 | 107 | |
paul@62 | 108 | Source_main = 0, // SCLK_A |
paul@62 | 109 | Source_pll_M = 1, // MPLL |
paul@62 | 110 | Source_pll_E = 2, // EPLL |
paul@62 | 111 | Source_pll_V = 2, // VPLL |
paul@62 | 112 | Source_otg_phy = 3, // OTG_PHY |
paul@0 | 113 | }; |
paul@0 | 114 | |
paul@0 | 115 | enum Clock_gate_bits : unsigned |
paul@0 | 116 | { |
paul@67 | 117 | Clock_gate_lcd1 = 28, // LCD (in CLKGR0) |
paul@67 | 118 | Clock_gate_lcd0 = 27, // TVE (in CLKGR0) |
paul@62 | 119 | Clock_gate_hdmi = 9, // HDMI (in CLKGR1) |
paul@0 | 120 | Clock_gate_smb4 = 12, // SMB4 (in CLKGR1) |
paul@0 | 121 | Clock_gate_smb3 = 0, // SMB3 (in CLKGR1) |
paul@0 | 122 | Clock_gate_smb2 = 25, // SMB2 (in CLKGR0) |
paul@128 | 123 | Clock_gate_smb1 = 6, // SMB1 (in CLKGR0) |
paul@128 | 124 | Clock_gate_smb0 = 5, // SMB0 (in CLKGR0) |
paul@0 | 125 | }; |
paul@0 | 126 | |
paul@0 | 127 | enum Divider_bits : unsigned |
paul@0 | 128 | { |
paul@0 | 129 | Ddr_divider_value = 0, // DDRCDR |
paul@62 | 130 | Hdmi_divider_value = 0, // HDMICDR |
paul@0 | 131 | Lcd_divider_value = 0, // LPCDR |
paul@0 | 132 | }; |
paul@0 | 133 | |
paul@62 | 134 | enum Lcd_clock_values : unsigned |
paul@0 | 135 | { |
paul@62 | 136 | Lcd_change_enable = 0x10000000, // CE_LCD |
paul@62 | 137 | Lcd_change_busy = 0x08000000, // LCD_BUSY |
paul@62 | 138 | Lcd_clock_stop = 0x04000000, // LCD_STOP |
paul@62 | 139 | }; |
paul@62 | 140 | |
paul@62 | 141 | enum Hdmi_divider_values : unsigned |
paul@62 | 142 | { |
paul@62 | 143 | Hdmi_select_mask = 0xc0000000, // HPCS |
paul@62 | 144 | Hdmi_change_enable = 0x20000000, // CE_HDMI |
paul@62 | 145 | Hdmi_change_busy = 0x10000000, // HDMI_BUSY |
paul@62 | 146 | Hdmi_clock_stop = 0x08000000, // HDMI_STOP |
paul@0 | 147 | }; |
paul@0 | 148 | |
paul@0 | 149 | |
paul@0 | 150 | |
paul@0 | 151 | // If implemented as a Hw::Device, various properties would be |
paul@0 | 152 | // initialised in the constructor and obtained from the device tree |
paul@0 | 153 | // definitions. |
paul@0 | 154 | |
paul@0 | 155 | Cpm_jz4780_chip::Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq) |
paul@0 | 156 | : _exclk_freq(exclk_freq), _rtclk_freq(rtclk_freq) |
paul@0 | 157 | { |
paul@0 | 158 | _regs = new Hw::Mmio_register_block<32>(addr); |
paul@0 | 159 | |
paul@0 | 160 | // add_cid("cpm"); |
paul@0 | 161 | // add_cid("cpm-jz4780"); |
paul@0 | 162 | // register_property("exclk_freq", &_exclk_freq); |
paul@0 | 163 | } |
paul@0 | 164 | |
paul@0 | 165 | // Clock/timer control. |
paul@128 | 166 | |
paul@128 | 167 | uint32_t |
paul@128 | 168 | Cpm_jz4780_chip::get_clock_gate_register(enum Clock_identifiers clock) |
paul@128 | 169 | { |
paul@128 | 170 | switch (clock) |
paul@128 | 171 | { |
paul@128 | 172 | case Clock_hdmi: return Clock_gate1; |
paul@128 | 173 | case Clock_smb4: return Clock_gate1; |
paul@128 | 174 | case Clock_smb3: return Clock_gate1; |
paul@128 | 175 | default: return Clock_gate0; |
paul@128 | 176 | } |
paul@128 | 177 | } |
paul@128 | 178 | |
paul@128 | 179 | uint32_t |
paul@128 | 180 | Cpm_jz4780_chip::get_clock_gate_value(enum Clock_identifiers clock) |
paul@128 | 181 | { |
paul@128 | 182 | switch (clock) |
paul@128 | 183 | { |
paul@128 | 184 | case Clock_lcd: return (1 << Clock_gate_lcd1) | (1 << Clock_gate_lcd0); |
paul@128 | 185 | case Clock_hdmi: return (1 << Clock_gate_hdmi); |
paul@128 | 186 | case Clock_smb4: return (1 << Clock_gate_smb4); |
paul@128 | 187 | case Clock_smb3: return (1 << Clock_gate_smb3); |
paul@128 | 188 | case Clock_smb2: return (1 << Clock_gate_smb2); |
paul@128 | 189 | case Clock_smb1: return (1 << Clock_gate_smb1); |
paul@128 | 190 | case Clock_smb0: return (1 << Clock_gate_smb0); |
paul@128 | 191 | default: return 0; |
paul@128 | 192 | } |
paul@128 | 193 | } |
paul@0 | 194 | |
paul@0 | 195 | int |
paul@128 | 196 | Cpm_jz4780_chip::have_clock(enum Clock_identifiers clock) |
paul@0 | 197 | { |
paul@128 | 198 | return !(_regs[get_clock_gate_register(clock)] & get_clock_gate_value(clock)); |
paul@0 | 199 | } |
paul@0 | 200 | |
paul@0 | 201 | void |
paul@128 | 202 | Cpm_jz4780_chip::start_clock(enum Clock_identifiers clock) |
paul@0 | 203 | { |
paul@128 | 204 | uint32_t gate = get_clock_gate_register(clock); |
paul@128 | 205 | |
paul@128 | 206 | _regs[gate] = _regs[gate] & ~get_clock_gate_value(clock); |
paul@128 | 207 | } |
paul@128 | 208 | |
paul@128 | 209 | void |
paul@128 | 210 | Cpm_jz4780_chip::stop_clock(enum Clock_identifiers clock) |
paul@128 | 211 | { |
paul@128 | 212 | uint32_t gate = get_clock_gate_register(clock); |
paul@128 | 213 | |
paul@128 | 214 | _regs[gate] = _regs[gate] | get_clock_gate_value(clock); |
paul@0 | 215 | } |
paul@0 | 216 | |
paul@0 | 217 | |
paul@0 | 218 | |
paul@0 | 219 | // Utility methods. |
paul@0 | 220 | |
paul@0 | 221 | uint32_t |
paul@0 | 222 | Cpm_jz4780_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) |
paul@0 | 223 | { |
paul@0 | 224 | return (_regs[reg] & (mask << shift)) >> shift; |
paul@0 | 225 | } |
paul@0 | 226 | |
paul@0 | 227 | void |
paul@0 | 228 | Cpm_jz4780_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) |
paul@0 | 229 | { |
paul@0 | 230 | _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); |
paul@0 | 231 | } |
paul@0 | 232 | |
paul@0 | 233 | // General clock divider access. |
paul@0 | 234 | |
paul@0 | 235 | uint8_t |
paul@0 | 236 | Cpm_jz4780_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) |
paul@0 | 237 | { |
paul@0 | 238 | uint8_t d = get_field(reg, mask, shift); |
paul@0 | 239 | |
paul@67 | 240 | // NOTE: Value 15 stops the clock, 14 presumably resumes the clock. |
paul@0 | 241 | |
paul@0 | 242 | return (d < 14) ? d + 1 : 1; |
paul@0 | 243 | } |
paul@0 | 244 | |
paul@0 | 245 | |
paul@0 | 246 | |
paul@0 | 247 | // PLL control. |
paul@0 | 248 | |
paul@0 | 249 | // Return whether the PLL is stable. |
paul@0 | 250 | |
paul@0 | 251 | int |
paul@0 | 252 | Cpm_jz4780_chip::have_pll(uint32_t pll_reg) |
paul@0 | 253 | { |
paul@0 | 254 | return _regs[pll_reg] & (1 << Pll_stable); |
paul@0 | 255 | } |
paul@0 | 256 | |
paul@0 | 257 | int |
paul@0 | 258 | Cpm_jz4780_chip::pll_enabled(uint32_t pll_reg) |
paul@0 | 259 | { |
paul@0 | 260 | return _regs[pll_reg] & (1 << Pll_enabled); |
paul@0 | 261 | } |
paul@0 | 262 | |
paul@0 | 263 | int |
paul@0 | 264 | Cpm_jz4780_chip::pll_bypassed(uint32_t pll_reg) |
paul@0 | 265 | { |
paul@0 | 266 | return _regs[pll_reg] & (1 << Pll_bypassed); |
paul@0 | 267 | } |
paul@0 | 268 | |
paul@67 | 269 | void |
paul@67 | 270 | Cpm_jz4780_chip::pll_enable(uint32_t pll_reg) |
paul@67 | 271 | { |
paul@67 | 272 | _regs[pll_reg] = _regs[pll_reg] | (1 << Pll_enabled); |
paul@67 | 273 | while (!(_regs[pll_reg] & (1 << Pll_stable))); |
paul@67 | 274 | } |
paul@67 | 275 | |
paul@67 | 276 | void |
paul@67 | 277 | Cpm_jz4780_chip::pll_disable(uint32_t pll_reg) |
paul@67 | 278 | { |
paul@67 | 279 | _regs[pll_reg] = _regs[pll_reg] & ~(1 << Pll_enabled); |
paul@67 | 280 | while (_regs[pll_reg] & (1 << Pll_stable)); |
paul@67 | 281 | } |
paul@67 | 282 | |
paul@0 | 283 | // Feedback (13-bit) multiplier. |
paul@0 | 284 | |
paul@0 | 285 | uint16_t |
paul@0 | 286 | Cpm_jz4780_chip::get_multiplier(uint32_t pll_reg) |
paul@0 | 287 | { |
paul@0 | 288 | return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; |
paul@0 | 289 | } |
paul@0 | 290 | |
paul@0 | 291 | void |
paul@0 | 292 | Cpm_jz4780_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) |
paul@0 | 293 | { |
paul@0 | 294 | set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); |
paul@0 | 295 | } |
paul@0 | 296 | |
paul@0 | 297 | // Input (6-bit) divider. |
paul@0 | 298 | |
paul@0 | 299 | uint8_t |
paul@0 | 300 | Cpm_jz4780_chip::get_input_division(uint32_t pll_reg) |
paul@0 | 301 | { |
paul@0 | 302 | return get_field(pll_reg, 0x3f, Pll_input_division) + 1; |
paul@0 | 303 | } |
paul@0 | 304 | |
paul@0 | 305 | void |
paul@0 | 306 | Cpm_jz4780_chip::set_input_division(uint32_t pll_reg, uint8_t divider) |
paul@0 | 307 | { |
paul@0 | 308 | set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); |
paul@0 | 309 | } |
paul@0 | 310 | |
paul@0 | 311 | // Output divider. |
paul@0 | 312 | |
paul@0 | 313 | uint8_t |
paul@0 | 314 | Cpm_jz4780_chip::get_output_division(uint32_t pll_reg) |
paul@0 | 315 | { |
paul@0 | 316 | uint8_t d = get_field(pll_reg, 0x0f, Pll_output_division); |
paul@0 | 317 | |
paul@0 | 318 | // Zero yields a division of one. Otherwise enforce even results. |
paul@0 | 319 | |
paul@0 | 320 | return d == 0 ? 1 : (d + 1) & 0x0e; |
paul@0 | 321 | } |
paul@0 | 322 | |
paul@0 | 323 | void |
paul@0 | 324 | Cpm_jz4780_chip::set_output_division(uint32_t pll_reg, uint8_t divider) |
paul@0 | 325 | { |
paul@0 | 326 | uint8_t d = divider <= 1 ? 0 : (divider & 0x0e) - 1; |
paul@0 | 327 | |
paul@0 | 328 | set_field(pll_reg, 0x0f, Pll_output_division, d); |
paul@0 | 329 | } |
paul@0 | 330 | |
paul@0 | 331 | uint32_t |
paul@0 | 332 | Cpm_jz4780_chip::get_pll_frequency(uint32_t pll_reg) |
paul@0 | 333 | { |
paul@0 | 334 | // Test for PLL enable and not PLL bypass. |
paul@0 | 335 | |
paul@0 | 336 | if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) |
paul@0 | 337 | return (_exclk_freq * get_multiplier(pll_reg)) / |
paul@0 | 338 | (get_input_division(pll_reg) * get_output_division(pll_reg)); |
paul@0 | 339 | else |
paul@0 | 340 | return _exclk_freq; |
paul@0 | 341 | } |
paul@0 | 342 | |
paul@0 | 343 | void |
paul@0 | 344 | Cpm_jz4780_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) |
paul@0 | 345 | { |
paul@0 | 346 | set_multiplier(pll_reg, multiplier); |
paul@0 | 347 | set_input_division(pll_reg, in_divider); |
paul@0 | 348 | set_output_division(pll_reg, out_divider); |
paul@0 | 349 | |
paul@0 | 350 | if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) |
paul@0 | 351 | while (!have_pll(pll_reg)); |
paul@0 | 352 | } |
paul@0 | 353 | |
paul@0 | 354 | |
paul@0 | 355 | |
paul@0 | 356 | // CPU clock (CCLK) divider. |
paul@0 | 357 | |
paul@0 | 358 | uint8_t |
paul@0 | 359 | Cpm_jz4780_chip::get_cpu_divider() |
paul@0 | 360 | { |
paul@0 | 361 | return _get_divider(Clock_control, 0xf, Clock_cpu_divider); |
paul@0 | 362 | } |
paul@0 | 363 | |
paul@0 | 364 | // Fast peripheral clock (H0CLK) divider. |
paul@0 | 365 | |
paul@0 | 366 | uint8_t |
paul@0 | 367 | Cpm_jz4780_chip::get_hclock0_divider() |
paul@0 | 368 | { |
paul@0 | 369 | return _get_divider(Clock_control, 0xf, Clock_hclock0_divider); |
paul@0 | 370 | } |
paul@0 | 371 | |
paul@0 | 372 | // Fast peripheral clock (H2CLK) divider. |
paul@0 | 373 | |
paul@0 | 374 | uint8_t |
paul@0 | 375 | Cpm_jz4780_chip::get_hclock2_divider() |
paul@0 | 376 | { |
paul@0 | 377 | return _get_divider(Clock_control, 0xf, Clock_hclock2_divider); |
paul@0 | 378 | } |
paul@0 | 379 | |
paul@0 | 380 | // Slow peripheral clock (PCLK) divider. |
paul@0 | 381 | |
paul@0 | 382 | uint8_t |
paul@0 | 383 | Cpm_jz4780_chip::get_pclock_divider() |
paul@0 | 384 | { |
paul@0 | 385 | return _get_divider(Clock_control, 0xf, Clock_pclock_divider); |
paul@0 | 386 | } |
paul@0 | 387 | |
paul@62 | 388 | // HDMI clock divider. |
paul@62 | 389 | |
paul@62 | 390 | uint8_t |
paul@62 | 391 | Cpm_jz4780_chip::get_hdmi_divider() |
paul@62 | 392 | { |
paul@62 | 393 | return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1; |
paul@62 | 394 | } |
paul@62 | 395 | |
paul@67 | 396 | // LCD clock (LPCLK) divider for LCD0 or LCD1 pixel clock. |
paul@0 | 397 | |
paul@0 | 398 | uint8_t |
paul@67 | 399 | Cpm_jz4780_chip::get_lcd_pixel_divider(uint8_t controller) |
paul@0 | 400 | { |
paul@67 | 401 | return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0xff, Lcd_divider_value) + 1; |
paul@0 | 402 | } |
paul@0 | 403 | |
paul@0 | 404 | // Memory clock (DDR_CLK) divider. |
paul@0 | 405 | |
paul@0 | 406 | uint8_t |
paul@0 | 407 | Cpm_jz4780_chip::get_memory_divider() |
paul@0 | 408 | { |
paul@0 | 409 | return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); |
paul@0 | 410 | } |
paul@0 | 411 | |
paul@62 | 412 | // HDMI clock divider. |
paul@62 | 413 | |
paul@62 | 414 | void |
paul@62 | 415 | Cpm_jz4780_chip::set_hdmi_divider(uint16_t division) |
paul@62 | 416 | { |
paul@62 | 417 | if ((division < 1) || (division > 256)) |
paul@62 | 418 | return; |
paul@62 | 419 | |
paul@62 | 420 | // Enable change. |
paul@62 | 421 | |
paul@62 | 422 | _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable; |
paul@62 | 423 | |
paul@62 | 424 | // Set the divider. |
paul@62 | 425 | |
paul@62 | 426 | set_field(Hdmi_divider, 0xff, Hdmi_divider_value, division - 1); |
paul@62 | 427 | |
paul@62 | 428 | // Restart clock and disable change. |
paul@62 | 429 | |
paul@62 | 430 | while (_regs[Hdmi_divider] & Hdmi_change_busy); |
paul@62 | 431 | _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~Hdmi_change_enable; |
paul@62 | 432 | } |
paul@62 | 433 | |
paul@0 | 434 | // LCD pixel clock divider. |
paul@0 | 435 | // NOTE: This only supports the first LCD peripheral. |
paul@0 | 436 | |
paul@0 | 437 | void |
paul@67 | 438 | Cpm_jz4780_chip::set_lcd_pixel_divider(uint8_t controller, uint16_t division) |
paul@0 | 439 | { |
paul@67 | 440 | uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0; |
paul@67 | 441 | |
paul@0 | 442 | if ((division < 1) || (division > 256)) |
paul@0 | 443 | return; |
paul@0 | 444 | |
paul@0 | 445 | // Enable change. |
paul@0 | 446 | |
paul@67 | 447 | _regs[divider] = _regs[divider] | Lcd_change_enable; |
paul@0 | 448 | |
paul@0 | 449 | // Set the divider. |
paul@0 | 450 | |
paul@67 | 451 | set_field(divider, 0xff, Lcd_divider_value, division - 1); |
paul@0 | 452 | |
paul@0 | 453 | // Restart clock and disable change. |
paul@0 | 454 | |
paul@67 | 455 | while (_regs[divider] & Lcd_change_busy); |
paul@67 | 456 | _regs[divider] = _regs[divider] & ~Lcd_change_enable; |
paul@0 | 457 | } |
paul@0 | 458 | |
paul@0 | 459 | |
paul@0 | 460 | |
paul@0 | 461 | // Clock sources. |
paul@0 | 462 | |
paul@0 | 463 | uint8_t |
paul@0 | 464 | Cpm_jz4780_chip::get_memory_source() |
paul@0 | 465 | { |
paul@0 | 466 | return get_field(Ddr_divider, 0x3, Clock_source_ddr); |
paul@0 | 467 | } |
paul@0 | 468 | |
paul@0 | 469 | uint32_t |
paul@0 | 470 | Cpm_jz4780_chip::get_memory_source_frequency() |
paul@0 | 471 | { |
paul@0 | 472 | switch (get_memory_source()) |
paul@0 | 473 | { |
paul@62 | 474 | case Source_mux_main: |
paul@133 | 475 | return get_main_frequency(); |
paul@62 | 476 | case Source_mux_pll_M: |
paul@133 | 477 | return get_pll_frequency(Pll_control_M); |
paul@0 | 478 | default: |
paul@133 | 479 | return 0; |
paul@0 | 480 | } |
paul@0 | 481 | } |
paul@0 | 482 | |
paul@0 | 483 | uint8_t |
paul@0 | 484 | Cpm_jz4780_chip::get_cpu_source() |
paul@0 | 485 | { |
paul@0 | 486 | return get_field(Clock_control, 0x3, Clock_source_cpu); |
paul@0 | 487 | } |
paul@0 | 488 | |
paul@0 | 489 | uint32_t |
paul@0 | 490 | Cpm_jz4780_chip::get_cpu_source_frequency() |
paul@0 | 491 | { |
paul@0 | 492 | switch (get_cpu_source()) |
paul@0 | 493 | { |
paul@62 | 494 | case Source_mux_main: |
paul@133 | 495 | return get_main_frequency(); |
paul@62 | 496 | case Source_mux_pll_M: |
paul@133 | 497 | return get_pll_frequency(Pll_control_M); |
paul@62 | 498 | case Source_mux_pll_E: |
paul@133 | 499 | return get_pll_frequency(Pll_control_E); |
paul@0 | 500 | default: |
paul@133 | 501 | return 0; |
paul@0 | 502 | } |
paul@0 | 503 | } |
paul@0 | 504 | |
paul@0 | 505 | uint8_t |
paul@0 | 506 | Cpm_jz4780_chip::get_hclock0_source() |
paul@0 | 507 | { |
paul@0 | 508 | return get_field(Clock_control, 0x3, Clock_source_hclock0); |
paul@0 | 509 | } |
paul@0 | 510 | |
paul@0 | 511 | uint32_t |
paul@0 | 512 | Cpm_jz4780_chip::get_hclock0_source_frequency() |
paul@0 | 513 | { |
paul@0 | 514 | switch (get_hclock0_source()) |
paul@0 | 515 | { |
paul@62 | 516 | case Source_mux_main: |
paul@133 | 517 | return get_main_frequency(); |
paul@62 | 518 | case Source_mux_pll_M: |
paul@133 | 519 | return get_pll_frequency(Pll_control_M); |
paul@62 | 520 | case Source_mux_pll_E: |
paul@133 | 521 | return get_pll_frequency(Pll_control_E); |
paul@0 | 522 | default: |
paul@133 | 523 | return 0; |
paul@0 | 524 | } |
paul@0 | 525 | } |
paul@0 | 526 | |
paul@0 | 527 | uint8_t |
paul@0 | 528 | Cpm_jz4780_chip::get_hclock2_source() |
paul@0 | 529 | { |
paul@0 | 530 | return get_field(Clock_control, 0x3, Clock_source_hclock2); |
paul@0 | 531 | } |
paul@0 | 532 | |
paul@0 | 533 | uint32_t |
paul@0 | 534 | Cpm_jz4780_chip::get_hclock2_source_frequency() |
paul@0 | 535 | { |
paul@0 | 536 | switch (get_hclock2_source()) |
paul@0 | 537 | { |
paul@62 | 538 | case Source_mux_main: |
paul@133 | 539 | return get_main_frequency(); |
paul@62 | 540 | case Source_mux_pll_M: |
paul@133 | 541 | return get_pll_frequency(Pll_control_M); |
paul@62 | 542 | case Source_mux_realtime: |
paul@133 | 543 | return _rtclk_freq; // "TCK" in the manual, RTCLK in Linux driver code |
paul@0 | 544 | default: |
paul@133 | 545 | return 0; |
paul@0 | 546 | } |
paul@0 | 547 | } |
paul@0 | 548 | |
paul@0 | 549 | void |
paul@0 | 550 | Cpm_jz4780_chip::set_hclock2_source(uint8_t source) |
paul@0 | 551 | { |
paul@0 | 552 | set_field(Clock_control, 0x3, Clock_source_hclock2, source); |
paul@0 | 553 | } |
paul@0 | 554 | |
paul@0 | 555 | uint8_t |
paul@62 | 556 | Cpm_jz4780_chip::get_hdmi_source() |
paul@62 | 557 | { |
paul@62 | 558 | return get_field(Hdmi_divider, 0x3, Clock_source_hdmi); |
paul@62 | 559 | } |
paul@62 | 560 | |
paul@62 | 561 | uint32_t |
paul@62 | 562 | Cpm_jz4780_chip::get_hdmi_source_frequency() |
paul@62 | 563 | { |
paul@62 | 564 | switch (get_hdmi_source()) |
paul@62 | 565 | { |
paul@62 | 566 | case Source_main: |
paul@133 | 567 | return get_main_frequency(); |
paul@62 | 568 | case Source_pll_M: |
paul@133 | 569 | return get_pll_frequency(Pll_control_M); |
paul@62 | 570 | case Source_pll_V: |
paul@133 | 571 | return get_pll_frequency(Pll_control_V); |
paul@62 | 572 | default: |
paul@133 | 573 | return 0; |
paul@62 | 574 | } |
paul@62 | 575 | } |
paul@62 | 576 | |
paul@62 | 577 | void |
paul@62 | 578 | Cpm_jz4780_chip::set_hdmi_source(uint8_t source) |
paul@62 | 579 | { |
paul@62 | 580 | // Stop clock and enable change. |
paul@62 | 581 | |
paul@62 | 582 | _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable | Hdmi_clock_stop; |
paul@62 | 583 | |
paul@62 | 584 | // Set the source. |
paul@62 | 585 | |
paul@62 | 586 | set_field(Hdmi_divider, 0x03, Clock_source_hdmi, source); |
paul@62 | 587 | |
paul@62 | 588 | // Restart clock and disable change. |
paul@62 | 589 | |
paul@62 | 590 | while (_regs[Hdmi_divider] & Hdmi_change_busy); |
paul@62 | 591 | _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~(Hdmi_change_enable | Hdmi_clock_stop); |
paul@62 | 592 | } |
paul@62 | 593 | |
paul@62 | 594 | uint8_t |
paul@67 | 595 | Cpm_jz4780_chip::get_lcd_source(uint8_t controller) |
paul@0 | 596 | { |
paul@67 | 597 | return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0x3, Clock_source_lcd); |
paul@0 | 598 | } |
paul@0 | 599 | |
paul@0 | 600 | uint32_t |
paul@67 | 601 | Cpm_jz4780_chip::get_lcd_source_frequency(uint8_t controller) |
paul@0 | 602 | { |
paul@67 | 603 | switch (get_lcd_source(controller)) |
paul@0 | 604 | { |
paul@62 | 605 | case Source_main: |
paul@133 | 606 | return get_main_frequency(); |
paul@0 | 607 | case Source_pll_M: |
paul@133 | 608 | return get_pll_frequency(Pll_control_M); |
paul@0 | 609 | case Source_pll_V: |
paul@133 | 610 | return get_pll_frequency(Pll_control_V); |
paul@0 | 611 | default: |
paul@133 | 612 | return 0; |
paul@0 | 613 | } |
paul@0 | 614 | } |
paul@0 | 615 | |
paul@0 | 616 | void |
paul@67 | 617 | Cpm_jz4780_chip::set_lcd_source(uint8_t controller, uint8_t source) |
paul@0 | 618 | { |
paul@67 | 619 | uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0; |
paul@67 | 620 | |
paul@0 | 621 | // Stop clock and enable change. |
paul@0 | 622 | |
paul@67 | 623 | _regs[divider] = _regs[divider] | Lcd_change_enable | Lcd_clock_stop; |
paul@0 | 624 | |
paul@0 | 625 | // Set the source. |
paul@0 | 626 | |
paul@67 | 627 | set_field(divider, 0x03, Clock_source_lcd, source); |
paul@0 | 628 | |
paul@0 | 629 | // Restart clock and disable change. |
paul@0 | 630 | |
paul@67 | 631 | while (_regs[divider] & Lcd_change_busy); |
paul@67 | 632 | _regs[divider] = _regs[divider] & ~(Lcd_change_enable | Lcd_clock_stop); |
paul@0 | 633 | } |
paul@0 | 634 | |
paul@0 | 635 | uint8_t |
paul@0 | 636 | Cpm_jz4780_chip::get_pclock_source() |
paul@0 | 637 | { |
paul@0 | 638 | return get_hclock2_source(); |
paul@0 | 639 | } |
paul@0 | 640 | |
paul@0 | 641 | uint32_t |
paul@0 | 642 | Cpm_jz4780_chip::get_pclock_source_frequency() |
paul@0 | 643 | { |
paul@0 | 644 | return get_hclock2_source_frequency(); |
paul@0 | 645 | } |
paul@0 | 646 | |
paul@0 | 647 | void |
paul@0 | 648 | Cpm_jz4780_chip::set_pclock_source(uint8_t source) |
paul@0 | 649 | { |
paul@0 | 650 | set_hclock2_source(source); |
paul@0 | 651 | } |
paul@0 | 652 | |
paul@0 | 653 | |
paul@0 | 654 | |
paul@0 | 655 | // Source frequency, used by various clock sources. |
paul@0 | 656 | |
paul@0 | 657 | uint8_t |
paul@0 | 658 | Cpm_jz4780_chip::get_main_source() |
paul@0 | 659 | { |
paul@0 | 660 | return get_field(Clock_control, 0x3, Clock_source_main); |
paul@0 | 661 | } |
paul@0 | 662 | |
paul@0 | 663 | uint32_t |
paul@0 | 664 | Cpm_jz4780_chip::get_main_frequency() |
paul@0 | 665 | { |
paul@0 | 666 | switch (get_main_source()) |
paul@0 | 667 | { |
paul@0 | 668 | case Source_pll_A: |
paul@133 | 669 | return get_pll_frequency(Pll_control_A); |
paul@0 | 670 | case Source_external: |
paul@133 | 671 | return _exclk_freq; |
paul@0 | 672 | case Source_realtime: |
paul@133 | 673 | return _rtclk_freq; |
paul@0 | 674 | default: |
paul@133 | 675 | return 0; |
paul@0 | 676 | } |
paul@0 | 677 | } |
paul@0 | 678 | |
paul@0 | 679 | // Clock frequency for the CPU. |
paul@0 | 680 | |
paul@0 | 681 | uint32_t |
paul@0 | 682 | Cpm_jz4780_chip::get_cpu_frequency() |
paul@0 | 683 | { |
paul@0 | 684 | return get_cpu_source_frequency() / get_cpu_divider(); |
paul@0 | 685 | } |
paul@0 | 686 | |
paul@0 | 687 | // Clock frequency for fast peripherals. |
paul@0 | 688 | |
paul@0 | 689 | uint32_t |
paul@0 | 690 | Cpm_jz4780_chip::get_hclock0_frequency() |
paul@0 | 691 | { |
paul@0 | 692 | return get_hclock0_source_frequency() / get_hclock0_divider(); |
paul@0 | 693 | } |
paul@0 | 694 | |
paul@0 | 695 | // Clock frequency for fast peripherals. |
paul@0 | 696 | |
paul@0 | 697 | uint32_t |
paul@0 | 698 | Cpm_jz4780_chip::get_hclock2_frequency() |
paul@0 | 699 | { |
paul@0 | 700 | return get_hclock2_source_frequency() / get_hclock2_divider(); |
paul@0 | 701 | } |
paul@0 | 702 | |
paul@0 | 703 | // Clock frequency for slow peripherals. |
paul@0 | 704 | |
paul@0 | 705 | uint32_t |
paul@0 | 706 | Cpm_jz4780_chip::get_pclock_frequency() |
paul@0 | 707 | { |
paul@0 | 708 | return get_pclock_source_frequency() / get_pclock_divider(); |
paul@0 | 709 | } |
paul@0 | 710 | |
paul@0 | 711 | // Clock frequency for the memory. |
paul@0 | 712 | |
paul@0 | 713 | uint32_t |
paul@0 | 714 | Cpm_jz4780_chip::get_memory_frequency() |
paul@0 | 715 | { |
paul@0 | 716 | return get_memory_source_frequency() / get_memory_divider(); |
paul@0 | 717 | } |
paul@0 | 718 | |
paul@0 | 719 | uint32_t |
paul@0 | 720 | Cpm_jz4780_chip::get_apll_frequency() |
paul@0 | 721 | { |
paul@0 | 722 | return get_pll_frequency(Pll_control_A); |
paul@0 | 723 | } |
paul@0 | 724 | |
paul@0 | 725 | uint32_t |
paul@0 | 726 | Cpm_jz4780_chip::get_epll_frequency() |
paul@0 | 727 | { |
paul@0 | 728 | return get_pll_frequency(Pll_control_E); |
paul@0 | 729 | } |
paul@0 | 730 | |
paul@0 | 731 | uint32_t |
paul@0 | 732 | Cpm_jz4780_chip::get_mpll_frequency() |
paul@0 | 733 | { |
paul@0 | 734 | return get_pll_frequency(Pll_control_M); |
paul@0 | 735 | } |
paul@0 | 736 | |
paul@0 | 737 | uint32_t |
paul@0 | 738 | Cpm_jz4780_chip::get_vpll_frequency() |
paul@0 | 739 | { |
paul@0 | 740 | return get_pll_frequency(Pll_control_V); |
paul@0 | 741 | } |
paul@0 | 742 | |
paul@0 | 743 | |
paul@0 | 744 | |
paul@133 | 745 | uint32_t |
paul@133 | 746 | Cpm_jz4780_chip::get_frequency(enum Clock_frequency_identifiers clock) |
paul@62 | 747 | { |
paul@133 | 748 | switch (clock) |
paul@133 | 749 | { |
paul@133 | 750 | // NOTE: Returning only the frequency for controller 0. |
paul@133 | 751 | |
paul@133 | 752 | case Clock_frequency_lcd_pixel: |
paul@133 | 753 | return get_lcd_source_frequency(0) / get_lcd_pixel_divider(0); |
paul@62 | 754 | |
paul@133 | 755 | case Clock_frequency_hdmi: |
paul@133 | 756 | return get_hdmi_source_frequency() / get_hdmi_divider(); |
paul@133 | 757 | |
paul@133 | 758 | // NOTE: Consider a better error result. |
paul@133 | 759 | |
paul@133 | 760 | default: |
paul@133 | 761 | return 0; |
paul@133 | 762 | } |
paul@62 | 763 | } |
paul@62 | 764 | |
paul@0 | 765 | void |
paul@133 | 766 | Cpm_jz4780_chip::set_frequency(enum Clock_frequency_identifiers clock, uint32_t frequency) |
paul@0 | 767 | { |
paul@133 | 768 | switch (clock) |
paul@133 | 769 | { |
paul@133 | 770 | // NOTE: HCLK/AHB0 must be 1.5 (for TFT) or 3 (for STN) times the pixel clock. |
paul@133 | 771 | // NOTE: Here, the actual frequency value is ignored, but should at least be |
paul@133 | 772 | // NOTE: tested. |
paul@133 | 773 | |
paul@133 | 774 | case Clock_frequency_lcd: |
paul@133 | 775 | set_lcd_source(0, Source_pll_V); |
paul@133 | 776 | set_lcd_source(1, Source_pll_V); |
paul@133 | 777 | pll_enable(Pll_control_V); |
paul@133 | 778 | break; |
paul@133 | 779 | |
paul@133 | 780 | // Unlike the JZ4740, HCLK/AHB0 is used as the device frequency, with the pixel |
paul@133 | 781 | // frequency being based on the selected clock source (SCLK_A, MPLL or VPLL). |
paul@133 | 782 | |
paul@133 | 783 | case Clock_frequency_lcd_pixel: |
paul@0 | 784 | |
paul@133 | 785 | // Switch to the video PLL and attempt to set the divider. |
paul@133 | 786 | |
paul@133 | 787 | set_lcd_pixel_divider(0, get_lcd_source_frequency() / frequency); |
paul@133 | 788 | set_lcd_pixel_divider(1, get_lcd_source_frequency() / frequency); |
paul@133 | 789 | break; |
paul@133 | 790 | |
paul@133 | 791 | case Clock_frequency_hdmi: |
paul@0 | 792 | |
paul@133 | 793 | // Switch to the video PLL and attempt to set the divider. |
paul@0 | 794 | |
paul@133 | 795 | set_hdmi_source(Source_pll_V); |
paul@133 | 796 | pll_enable(Pll_control_V); |
paul@133 | 797 | set_hdmi_divider(get_hdmi_source_frequency() / frequency); |
paul@133 | 798 | break; |
paul@133 | 799 | |
paul@133 | 800 | default: |
paul@133 | 801 | break; |
paul@133 | 802 | } |
paul@0 | 803 | } |
paul@0 | 804 | |
paul@0 | 805 | // NOTE: Empty method for compatibility. |
paul@0 | 806 | |
paul@0 | 807 | void |
paul@0 | 808 | Cpm_jz4780_chip::update_output_frequency() |
paul@0 | 809 | { |
paul@0 | 810 | } |
paul@0 | 811 | |
paul@0 | 812 | |
paul@0 | 813 | |
paul@0 | 814 | // C language interface functions. |
paul@0 | 815 | |
paul@0 | 816 | void |
paul@0 | 817 | *jz4780_cpm_init(l4_addr_t cpm_base) |
paul@0 | 818 | { |
paul@0 | 819 | /* Initialise the clock and power management peripheral with the |
paul@0 | 820 | register memory region and a 48MHz EXCLK frequency. */ |
paul@0 | 821 | |
paul@0 | 822 | return (void *) new Cpm_jz4780_chip(cpm_base, 48000000, 32768); |
paul@0 | 823 | } |
paul@0 | 824 | |
paul@0 | 825 | int |
paul@128 | 826 | jz4780_cpm_have_clock(void *cpm, enum Clock_identifiers clock) |
paul@0 | 827 | { |
paul@128 | 828 | return static_cast<Cpm_jz4780_chip *>(cpm)->have_clock(clock); |
paul@0 | 829 | } |
paul@0 | 830 | |
paul@0 | 831 | void |
paul@128 | 832 | jz4780_cpm_start_clock(void *cpm, enum Clock_identifiers clock) |
paul@0 | 833 | { |
paul@128 | 834 | static_cast<Cpm_jz4780_chip *>(cpm)->start_clock(clock); |
paul@62 | 835 | } |
paul@62 | 836 | |
paul@62 | 837 | void |
paul@128 | 838 | jz4780_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) |
paul@0 | 839 | { |
paul@128 | 840 | static_cast<Cpm_jz4780_chip *>(cpm)->stop_clock(clock); |
paul@0 | 841 | } |
paul@0 | 842 | |
paul@0 | 843 | |
paul@0 | 844 | |
paul@0 | 845 | uint8_t |
paul@0 | 846 | jz4780_cpm_get_cpu_divider(void *cpm) |
paul@0 | 847 | { |
paul@0 | 848 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_cpu_divider(); |
paul@0 | 849 | } |
paul@0 | 850 | |
paul@0 | 851 | uint8_t |
paul@0 | 852 | jz4780_cpm_get_hclock0_divider(void *cpm) |
paul@0 | 853 | { |
paul@0 | 854 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_divider(); |
paul@0 | 855 | } |
paul@0 | 856 | |
paul@0 | 857 | uint8_t |
paul@0 | 858 | jz4780_cpm_get_hclock2_divider(void *cpm) |
paul@0 | 859 | { |
paul@0 | 860 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_divider(); |
paul@0 | 861 | } |
paul@0 | 862 | |
paul@0 | 863 | uint8_t |
paul@62 | 864 | jz4780_cpm_get_hdmi_divider(void *cpm) |
paul@62 | 865 | { |
paul@62 | 866 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_divider(); |
paul@62 | 867 | } |
paul@62 | 868 | |
paul@62 | 869 | uint8_t |
paul@0 | 870 | jz4780_cpm_get_lcd_pixel_divider(void *cpm) |
paul@0 | 871 | { |
paul@0 | 872 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_divider(); |
paul@0 | 873 | } |
paul@0 | 874 | |
paul@0 | 875 | uint8_t |
paul@0 | 876 | jz4780_cpm_get_memory_divider(void *cpm) |
paul@0 | 877 | { |
paul@0 | 878 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_divider(); |
paul@0 | 879 | } |
paul@0 | 880 | |
paul@0 | 881 | uint8_t |
paul@0 | 882 | jz4780_cpm_get_pclock_divider(void *cpm) |
paul@0 | 883 | { |
paul@0 | 884 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_divider(); |
paul@0 | 885 | } |
paul@0 | 886 | |
paul@0 | 887 | |
paul@0 | 888 | |
paul@0 | 889 | uint8_t |
paul@0 | 890 | jz4780_cpm_get_hclock0_source(void *cpm) |
paul@0 | 891 | { |
paul@0 | 892 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_source(); |
paul@0 | 893 | } |
paul@0 | 894 | |
paul@0 | 895 | uint8_t |
paul@0 | 896 | jz4780_cpm_get_hclock2_source(void *cpm) |
paul@0 | 897 | { |
paul@0 | 898 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_source(); |
paul@0 | 899 | } |
paul@0 | 900 | |
paul@0 | 901 | uint8_t |
paul@62 | 902 | jz4780_cpm_get_hdmi_source(void *cpm) |
paul@62 | 903 | { |
paul@62 | 904 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source(); |
paul@62 | 905 | } |
paul@62 | 906 | |
paul@62 | 907 | uint8_t |
paul@0 | 908 | jz4780_cpm_get_lcd_source(void *cpm) |
paul@0 | 909 | { |
paul@0 | 910 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source(); |
paul@0 | 911 | } |
paul@0 | 912 | |
paul@0 | 913 | uint8_t |
paul@0 | 914 | jz4780_cpm_get_memory_source(void *cpm) |
paul@0 | 915 | { |
paul@0 | 916 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_source(); |
paul@0 | 917 | } |
paul@0 | 918 | |
paul@0 | 919 | uint8_t |
paul@0 | 920 | jz4780_cpm_get_pclock_source(void *cpm) |
paul@0 | 921 | { |
paul@0 | 922 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_source(); |
paul@0 | 923 | } |
paul@0 | 924 | |
paul@0 | 925 | void |
paul@0 | 926 | jz4780_cpm_set_pclock_source(void *cpm, uint8_t source) |
paul@0 | 927 | { |
paul@0 | 928 | static_cast<Cpm_jz4780_chip *>(cpm)->set_pclock_source(source); |
paul@0 | 929 | } |
paul@0 | 930 | |
paul@0 | 931 | |
paul@0 | 932 | |
paul@0 | 933 | uint32_t |
paul@0 | 934 | jz4780_cpm_get_hclock0_source_frequency(void *cpm) |
paul@0 | 935 | { |
paul@0 | 936 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_source_frequency(); |
paul@0 | 937 | } |
paul@0 | 938 | |
paul@0 | 939 | uint32_t |
paul@0 | 940 | jz4780_cpm_get_hclock2_source_frequency(void *cpm) |
paul@0 | 941 | { |
paul@0 | 942 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_source_frequency(); |
paul@0 | 943 | } |
paul@0 | 944 | |
paul@0 | 945 | uint32_t |
paul@62 | 946 | jz4780_cpm_get_hdmi_source_frequency(void *cpm) |
paul@62 | 947 | { |
paul@62 | 948 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source_frequency(); |
paul@62 | 949 | } |
paul@62 | 950 | |
paul@62 | 951 | uint32_t |
paul@0 | 952 | jz4780_cpm_get_lcd_source_frequency(void *cpm) |
paul@0 | 953 | { |
paul@0 | 954 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source_frequency(); |
paul@0 | 955 | } |
paul@0 | 956 | |
paul@0 | 957 | uint32_t |
paul@0 | 958 | jz4780_cpm_get_memory_source_frequency(void *cpm) |
paul@0 | 959 | { |
paul@0 | 960 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_source_frequency(); |
paul@0 | 961 | } |
paul@0 | 962 | |
paul@0 | 963 | uint32_t |
paul@0 | 964 | jz4780_cpm_get_pclock_source_frequency(void *cpm) |
paul@0 | 965 | { |
paul@0 | 966 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_source_frequency(); |
paul@0 | 967 | } |
paul@0 | 968 | |
paul@0 | 969 | |
paul@0 | 970 | |
paul@0 | 971 | uint8_t |
paul@0 | 972 | jz4780_cpm_get_main_source(void *cpm) |
paul@0 | 973 | { |
paul@0 | 974 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_main_source(); |
paul@0 | 975 | } |
paul@0 | 976 | |
paul@0 | 977 | uint32_t |
paul@0 | 978 | jz4780_cpm_get_main_frequency(void *cpm) |
paul@0 | 979 | { |
paul@0 | 980 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_main_frequency(); |
paul@0 | 981 | } |
paul@0 | 982 | |
paul@0 | 983 | uint32_t |
paul@0 | 984 | jz4780_cpm_get_cpu_frequency(void *cpm) |
paul@0 | 985 | { |
paul@0 | 986 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_cpu_frequency(); |
paul@0 | 987 | } |
paul@0 | 988 | |
paul@0 | 989 | uint32_t |
paul@0 | 990 | jz4780_cpm_get_hclock0_frequency(void *cpm) |
paul@0 | 991 | { |
paul@0 | 992 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock0_frequency(); |
paul@0 | 993 | } |
paul@0 | 994 | |
paul@0 | 995 | uint32_t |
paul@0 | 996 | jz4780_cpm_get_hclock2_frequency(void *cpm) |
paul@0 | 997 | { |
paul@0 | 998 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_hclock2_frequency(); |
paul@0 | 999 | } |
paul@0 | 1000 | |
paul@0 | 1001 | uint32_t |
paul@0 | 1002 | jz4780_cpm_get_memory_frequency(void *cpm) |
paul@0 | 1003 | { |
paul@0 | 1004 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_memory_frequency(); |
paul@0 | 1005 | } |
paul@0 | 1006 | |
paul@0 | 1007 | uint32_t |
paul@0 | 1008 | jz4780_cpm_get_pclock_frequency(void *cpm) |
paul@0 | 1009 | { |
paul@0 | 1010 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_pclock_frequency(); |
paul@0 | 1011 | } |
paul@0 | 1012 | |
paul@0 | 1013 | uint32_t |
paul@0 | 1014 | jz4780_cpm_get_apll_frequency(void *cpm) |
paul@0 | 1015 | { |
paul@0 | 1016 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_apll_frequency(); |
paul@0 | 1017 | } |
paul@0 | 1018 | |
paul@0 | 1019 | uint32_t |
paul@0 | 1020 | jz4780_cpm_get_epll_frequency(void *cpm) |
paul@0 | 1021 | { |
paul@0 | 1022 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_epll_frequency(); |
paul@0 | 1023 | } |
paul@0 | 1024 | |
paul@0 | 1025 | uint32_t |
paul@0 | 1026 | jz4780_cpm_get_mpll_frequency(void *cpm) |
paul@0 | 1027 | { |
paul@0 | 1028 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_mpll_frequency(); |
paul@0 | 1029 | } |
paul@0 | 1030 | |
paul@0 | 1031 | uint32_t |
paul@0 | 1032 | jz4780_cpm_get_vpll_frequency(void *cpm) |
paul@0 | 1033 | { |
paul@0 | 1034 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_vpll_frequency(); |
paul@0 | 1035 | } |
paul@0 | 1036 | |
paul@0 | 1037 | |
paul@0 | 1038 | |
paul@133 | 1039 | uint32_t |
paul@133 | 1040 | jz4780_cpm_get_frequency(void *cpm, enum Clock_frequency_identifiers clock) |
paul@62 | 1041 | { |
paul@133 | 1042 | return static_cast<Cpm_jz4780_chip *>(cpm)->get_frequency(clock); |
paul@62 | 1043 | } |
paul@62 | 1044 | |
paul@62 | 1045 | void |
paul@133 | 1046 | jz4780_cpm_set_frequency(void *cpm, enum Clock_frequency_identifiers clock, uint32_t frequency) |
paul@0 | 1047 | { |
paul@133 | 1048 | static_cast<Cpm_jz4780_chip *>(cpm)->set_frequency(clock, frequency); |
paul@64 | 1049 | } |
paul@64 | 1050 | |
paul@64 | 1051 | void |
paul@0 | 1052 | jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) |
paul@0 | 1053 | { |
paul@0 | 1054 | static_cast<Cpm_jz4780_chip *>(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); |
paul@0 | 1055 | } |