1 /* 2 * CPM (clock and power management) support for the JZ4780. 3 * 4 * Copyright (C) 2017, 2018, 2020, 2021 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #pragma once 23 24 #include <l4/devices/cpm.h> 25 26 #include <l4/sys/types.h> 27 #include <stdint.h> 28 29 30 31 #ifdef __cplusplus 32 33 #include <l4/devices/hw_register_block.h> 34 35 /* A simple abstraction for accessing the CPM registers. 36 * A proper device could inherit from Hw::Device and use an 37 * Int_property for _exclk_freq and _rtclk_freq. */ 38 39 class Cpm_jz4780_chip : public Cpm_chip 40 { 41 private: 42 Hw::Register_block<32> _regs; 43 uint32_t _exclk_freq, _rtclk_freq; 44 45 // Utility methods. 46 47 uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); 48 void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); 49 uint8_t _get_divider(uint32_t reg, uint32_t mask, uint8_t shift); 50 51 // PLL control. 52 53 int have_pll(uint32_t pll_reg); 54 int pll_enabled(uint32_t pll_reg); 55 int pll_bypassed(uint32_t pll_reg); 56 void pll_disable(uint32_t pll_reg); 57 void pll_enable(uint32_t pll_reg); 58 59 // General frequency modifiers. 60 61 uint16_t get_multiplier(uint32_t pll_reg); 62 void set_multiplier(uint32_t pll_reg, uint16_t multiplier); 63 uint8_t get_input_division(uint32_t pll_reg); 64 void set_input_division(uint32_t pll_reg, uint8_t divider); 65 uint8_t get_output_division(uint32_t pll_reg); 66 void set_output_division(uint32_t pll_reg, uint8_t divider); 67 68 // Clock dividers. 69 70 void set_hdmi_divider(uint16_t division); 71 void set_lcd_pixel_divider(uint8_t controller, uint16_t division); 72 73 // Input frequencies. 74 75 uint32_t get_pll_frequency(uint32_t pll_reg); 76 77 // Clock sources. 78 79 void set_hclock2_source(uint8_t source); 80 void set_hdmi_source(uint8_t source); 81 void set_lcd_source(uint8_t controller, uint8_t source); 82 83 // Clock control. 84 85 uint32_t get_clock_gate_register(enum Clock_identifiers clock); 86 uint32_t get_clock_gate_value(enum Clock_identifiers clock); 87 88 public: 89 void set_pclock_source(uint8_t source); 90 Cpm_jz4780_chip(l4_addr_t addr, uint32_t exclk_freq, uint32_t rtclk_freq); 91 92 int have_clock(enum Clock_identifiers clock); 93 void start_clock(enum Clock_identifiers clock); 94 void stop_clock(enum Clock_identifiers clock); 95 96 // Clock divider values. 97 98 uint8_t get_cpu_divider(); 99 uint8_t get_hclock0_divider(); 100 uint8_t get_hclock2_divider(); 101 uint8_t get_pclock_divider(); 102 uint8_t get_hdmi_divider(); 103 uint8_t get_lcd_pixel_divider(uint8_t controller = 0); 104 uint8_t get_memory_divider(); 105 106 // Input frequencies. 107 108 uint8_t get_main_source(); 109 uint32_t get_main_frequency(); 110 111 // Clock sources, providing the input frequency. 112 113 uint8_t get_cpu_source(); 114 uint8_t get_hclock0_source(); 115 uint8_t get_hclock2_source(); 116 uint8_t get_hdmi_source(); 117 uint8_t get_lcd_source(uint8_t controller); 118 uint8_t get_lcd_source() { return get_lcd_source(0); } 119 uint8_t get_memory_source(); 120 uint8_t get_pclock_source(); 121 122 uint32_t get_cpu_source_frequency(); 123 uint32_t get_hclock0_source_frequency(); 124 uint32_t get_hclock2_source_frequency(); 125 uint32_t get_hdmi_source_frequency(); 126 uint32_t get_lcd_source_frequency(uint8_t controller); 127 uint32_t get_lcd_source_frequency() { return get_lcd_source_frequency(0); } 128 uint32_t get_memory_source_frequency(); 129 uint32_t get_pclock_source_frequency(); 130 131 // Final, calculated frequencies. 132 133 uint32_t get_cpu_frequency(); 134 uint32_t get_hclock0_frequency(); 135 uint32_t get_hclock2_frequency(); 136 uint32_t get_memory_frequency(); 137 uint32_t get_pclock_frequency(); 138 139 uint32_t get_apll_frequency(); 140 uint32_t get_epll_frequency(); 141 uint32_t get_mpll_frequency(); 142 uint32_t get_vpll_frequency(); 143 144 void set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); 145 146 uint32_t get_frequency(enum Clock_frequency_identifiers clock); 147 void set_frequency(enum Clock_frequency_identifiers clock, uint32_t frequency); 148 149 void update_output_frequency(); 150 }; 151 152 #endif /* __cplusplus */ 153 154 155 156 /* C language interface. */ 157 158 EXTERN_C_BEGIN 159 160 void *jz4780_cpm_init(l4_addr_t cpm_base); 161 162 int jz4780_cpm_have_clock(void *cpm, enum Clock_identifiers clock); 163 void jz4780_cpm_start_clock(void *cpm, enum Clock_identifiers clock); 164 void jz4780_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); 165 166 uint8_t jz4780_cpm_get_cpu_divider(void *cpm); 167 uint8_t jz4780_cpm_get_hclock0_divider(void *cpm); 168 uint8_t jz4780_cpm_get_hclock2_divider(void *cpm); 169 uint8_t jz4780_cpm_get_hdmi_divider(void *cpm); 170 uint8_t jz4780_cpm_get_lcd_pixel_divider(void *cpm); 171 uint8_t jz4780_cpm_get_memory_divider(void *cpm); 172 uint8_t jz4780_cpm_get_pclock_divider(void *cpm); 173 174 uint8_t jz4780_cpm_get_hclock0_source(void *cpm); 175 uint8_t jz4780_cpm_get_hclock2_source(void *cpm); 176 uint8_t jz4780_cpm_get_hdmi_source(void *cpm); 177 uint8_t jz4780_cpm_get_lcd_source(void *cpm); 178 uint8_t jz4780_cpm_get_memory_source(void *cpm); 179 uint8_t jz4780_cpm_get_pclock_source(void *cpm); 180 181 uint32_t jz4780_cpm_get_hclock0_source_frequency(void *cpm); 182 uint32_t jz4780_cpm_get_hclock2_source_frequency(void *cpm); 183 uint32_t jz4780_cpm_get_hdmi_source_frequency(void *cpm); 184 uint32_t jz4780_cpm_get_lcd_source_frequency(void *cpm); 185 uint32_t jz4780_cpm_get_memory_source_frequency(void *cpm); 186 uint32_t jz4780_cpm_get_pclock_source_frequency(void *cpm); 187 188 void jz4780_cpm_set_pclock_source(void *cpm, uint8_t source); 189 190 uint8_t jz4780_cpm_get_main_source(void *cpm); 191 uint32_t jz4780_cpm_get_main_frequency(void *cpm); 192 193 uint32_t jz4780_cpm_get_cpu_frequency(void *cpm); 194 uint32_t jz4780_cpm_get_hclock0_frequency(void *cpm); 195 uint32_t jz4780_cpm_get_hclock2_frequency(void *cpm); 196 uint32_t jz4780_cpm_get_memory_frequency(void *cpm); 197 uint32_t jz4780_cpm_get_pclock_frequency(void *cpm); 198 199 uint32_t jz4780_cpm_get_apll_frequency(void *cpm); 200 uint32_t jz4780_cpm_get_epll_frequency(void *cpm); 201 uint32_t jz4780_cpm_get_mpll_frequency(void *cpm); 202 uint32_t jz4780_cpm_get_vpll_frequency(void *cpm); 203 204 uint32_t jz4780_cpm_get_frequency(void *cpm, enum Clock_frequency_identifiers clock); 205 void jz4780_cpm_set_frequency(void *cpm, enum Clock_frequency_identifiers clock, uint32_t frequency); 206 207 void jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); 208 209 EXTERN_C_END