1 /* 2 * Common clock functionality. 3 * 4 * Copyright (C) 2023 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 #ifdef __cplusplus 25 26 #include <l4/devices/hw_register_block.h> 27 #include <l4/devices/cpm.h> 28 #include <l4/sys/types.h> 29 #include <stdint.h> 30 31 /* Forward declaration. */ 32 33 class Clock_base; 34 35 36 37 /* Register access type. */ 38 39 class Cpm_regs 40 { 41 Hw::Register_block<32> _regs; 42 43 protected: 44 Clock_base **_clocks; 45 46 public: 47 uint32_t exclk_freq; 48 49 explicit Cpm_regs(l4_addr_t addr, Clock_base *clocks[], 50 uint32_t exclk_freq); 51 52 // Utility methods. 53 54 uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); 55 void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); 56 57 Clock_base *get_clock(int num); 58 }; 59 60 61 62 // Register field abstraction. 63 64 class Field 65 { 66 uint32_t reg; 67 uint32_t mask; 68 uint8_t bit; 69 bool defined; 70 71 public: 72 explicit Field() 73 : defined(false) 74 { 75 } 76 77 explicit Field(uint32_t reg, uint32_t mask, uint32_t bit) 78 : reg(reg), mask(mask), bit(bit), defined(true) 79 { 80 } 81 82 uint32_t get_field(Cpm_regs ®s); 83 void set_field(Cpm_regs ®s, uint32_t value); 84 bool is_defined() { return defined; } 85 86 // Undefined field object. 87 88 static Field undefined; 89 }; 90 91 92 93 // Clock sources. 94 95 class Mux 96 { 97 int _num_inputs; 98 enum Clock_identifiers *_inputs, _input; 99 100 public: 101 explicit Mux(int num_inputs, enum Clock_identifiers inputs[]) 102 : _num_inputs(num_inputs), _inputs(inputs) 103 { 104 } 105 106 explicit Mux(enum Clock_identifiers input) 107 : _num_inputs(1), _inputs(&_input) 108 { 109 _input = input; 110 } 111 112 explicit Mux() 113 : _num_inputs(0), _inputs(NULL) 114 { 115 } 116 117 int get_number() { return _num_inputs; } 118 enum Clock_identifiers get_input(int num); 119 }; 120 121 class Source 122 { 123 Mux _inputs; 124 Field _source; 125 126 public: 127 explicit Source(Mux inputs, Field source) 128 : _inputs(inputs), _source(source) 129 { 130 } 131 132 explicit Source(Mux inputs) 133 : _inputs(inputs) 134 { 135 } 136 137 explicit Source() 138 { 139 } 140 141 int get_number() { return _inputs.get_number(); } 142 enum Clock_identifiers get_input(int num) { return _inputs.get_input(num); } 143 144 // Clock source. 145 146 uint8_t get_source(Cpm_regs ®s); 147 void set_source(Cpm_regs ®s, uint8_t source); 148 149 // Clock source frequency. 150 151 uint32_t get_frequency(Cpm_regs ®s); 152 153 // Undefined source object. 154 155 static Source undefined; 156 }; 157 158 159 160 // Common clock abstraction. 161 162 class Clock_base 163 { 164 Source _source; 165 166 public: 167 explicit Clock_base(Source source) 168 : _source(source) 169 { 170 } 171 172 // Clock control. 173 174 virtual int have_clock(Cpm_regs ®s); 175 virtual void start_clock(Cpm_regs ®s); 176 virtual void stop_clock(Cpm_regs ®s); 177 178 // Clock divider. 179 180 virtual uint32_t get_divider(Cpm_regs ®s); 181 virtual void set_divider(Cpm_regs ®s, uint32_t division); 182 183 // Clock source. 184 185 virtual uint8_t get_source(Cpm_regs ®s); 186 virtual void set_source(Cpm_regs ®s, uint8_t source); 187 188 // Clock source frequency. 189 190 virtual uint32_t get_source_frequency(Cpm_regs ®s); 191 192 // Output frequency. 193 194 virtual uint32_t get_frequency(Cpm_regs ®s); 195 }; 196 197 198 199 // PLL descriptions. 200 201 class Pll : public Clock_base 202 { 203 Field _enable, _stable, _bypass; 204 Field _multiplier, _input_division, _output_division0, _output_division1; 205 206 public: 207 explicit Pll(Source source, 208 Field enable, Field stable, Field bypass, 209 Field multiplier, Field input_division, 210 Field output_division0, Field output_division1) 211 : Clock_base(source), 212 _enable(enable), _stable(stable), _bypass(bypass), 213 _multiplier(multiplier), _input_division(input_division), 214 _output_division0(output_division0), _output_division1(output_division1) 215 { 216 } 217 218 // PLL_specific control. 219 220 int have_pll(Cpm_regs ®s); 221 int pll_enabled(Cpm_regs ®s); 222 int pll_bypassed(Cpm_regs ®s); 223 224 // Clock control. 225 226 int have_clock(Cpm_regs ®s); 227 void start_clock(Cpm_regs ®s); 228 void stop_clock(Cpm_regs ®s); 229 230 // General frequency modifiers. 231 232 uint16_t get_multiplier(Cpm_regs ®s); 233 void set_multiplier(Cpm_regs ®s, uint16_t multiplier); 234 uint8_t get_input_division(Cpm_regs ®s); 235 void set_input_division(Cpm_regs ®s, uint8_t divider); 236 uint8_t get_output_division(Cpm_regs ®s); 237 void set_output_division(Cpm_regs ®s, uint8_t divider); 238 239 // PLL output frequency. 240 241 uint32_t get_frequency(Cpm_regs ®s); 242 243 // Other operations. 244 245 void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, 246 uint8_t in_divider, uint8_t out_divider); 247 }; 248 249 250 251 // Clock descriptions. 252 253 class Clock : public Clock_base 254 { 255 Field _gate, _change_enable, _busy, _divider; 256 257 // Clock control. 258 259 void change_disable(Cpm_regs ®s); 260 void change_enable(Cpm_regs ®s); 261 void wait_busy(Cpm_regs ®s); 262 263 public: 264 explicit Clock(Source source = Source::undefined, 265 Field gate = Field::undefined, 266 Field change_enable = Field::undefined, 267 Field busy = Field::undefined, 268 Field divider = Field::undefined) 269 : Clock_base(source), 270 _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider) 271 { 272 } 273 274 // Clock control. 275 276 int have_clock(Cpm_regs ®s); 277 void start_clock(Cpm_regs ®s); 278 void stop_clock(Cpm_regs ®s); 279 280 // Clock divider. 281 282 uint32_t get_divider(Cpm_regs ®s); 283 void set_divider(Cpm_regs ®s, uint32_t division); 284 285 // Clock source. 286 287 void set_source(Cpm_regs ®s, uint8_t source); 288 }; 289 290 #endif /* __cplusplus */