1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/cpm/include/cpm-common.h Sat Sep 16 16:53:06 2023 +0200
1.3 @@ -0,0 +1,290 @@
1.4 +/*
1.5 + * Common clock functionality.
1.6 + *
1.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#pragma once
1.26 +
1.27 +#ifdef __cplusplus
1.28 +
1.29 +#include <l4/devices/hw_register_block.h>
1.30 +#include <l4/devices/cpm.h>
1.31 +#include <l4/sys/types.h>
1.32 +#include <stdint.h>
1.33 +
1.34 +/* Forward declaration. */
1.35 +
1.36 +class Clock_base;
1.37 +
1.38 +
1.39 +
1.40 +/* Register access type. */
1.41 +
1.42 +class Cpm_regs
1.43 +{
1.44 + Hw::Register_block<32> _regs;
1.45 +
1.46 +protected:
1.47 + Clock_base **_clocks;
1.48 +
1.49 +public:
1.50 + uint32_t exclk_freq;
1.51 +
1.52 + explicit Cpm_regs(l4_addr_t addr, Clock_base *clocks[],
1.53 + uint32_t exclk_freq);
1.54 +
1.55 + // Utility methods.
1.56 +
1.57 + uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift);
1.58 + void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value);
1.59 +
1.60 + Clock_base *get_clock(int num);
1.61 +};
1.62 +
1.63 +
1.64 +
1.65 +// Register field abstraction.
1.66 +
1.67 +class Field
1.68 +{
1.69 + uint32_t reg;
1.70 + uint32_t mask;
1.71 + uint8_t bit;
1.72 + bool defined;
1.73 +
1.74 +public:
1.75 + explicit Field()
1.76 + : defined(false)
1.77 + {
1.78 + }
1.79 +
1.80 + explicit Field(uint32_t reg, uint32_t mask, uint32_t bit)
1.81 + : reg(reg), mask(mask), bit(bit), defined(true)
1.82 + {
1.83 + }
1.84 +
1.85 + uint32_t get_field(Cpm_regs ®s);
1.86 + void set_field(Cpm_regs ®s, uint32_t value);
1.87 + bool is_defined() { return defined; }
1.88 +
1.89 + // Undefined field object.
1.90 +
1.91 + static Field undefined;
1.92 +};
1.93 +
1.94 +
1.95 +
1.96 +// Clock sources.
1.97 +
1.98 +class Mux
1.99 +{
1.100 + int _num_inputs;
1.101 + enum Clock_identifiers *_inputs, _input;
1.102 +
1.103 +public:
1.104 + explicit Mux(int num_inputs, enum Clock_identifiers inputs[])
1.105 + : _num_inputs(num_inputs), _inputs(inputs)
1.106 + {
1.107 + }
1.108 +
1.109 + explicit Mux(enum Clock_identifiers input)
1.110 + : _num_inputs(1), _inputs(&_input)
1.111 + {
1.112 + _input = input;
1.113 + }
1.114 +
1.115 + explicit Mux()
1.116 + : _num_inputs(0), _inputs(NULL)
1.117 + {
1.118 + }
1.119 +
1.120 + int get_number() { return _num_inputs; }
1.121 + enum Clock_identifiers get_input(int num);
1.122 +};
1.123 +
1.124 +class Source
1.125 +{
1.126 + Mux _inputs;
1.127 + Field _source;
1.128 +
1.129 +public:
1.130 + explicit Source(Mux inputs, Field source)
1.131 + : _inputs(inputs), _source(source)
1.132 + {
1.133 + }
1.134 +
1.135 + explicit Source(Mux inputs)
1.136 + : _inputs(inputs)
1.137 + {
1.138 + }
1.139 +
1.140 + explicit Source()
1.141 + {
1.142 + }
1.143 +
1.144 + int get_number() { return _inputs.get_number(); }
1.145 + enum Clock_identifiers get_input(int num) { return _inputs.get_input(num); }
1.146 +
1.147 + // Clock source.
1.148 +
1.149 + uint8_t get_source(Cpm_regs ®s);
1.150 + void set_source(Cpm_regs ®s, uint8_t source);
1.151 +
1.152 + // Clock source frequency.
1.153 +
1.154 + uint32_t get_frequency(Cpm_regs ®s);
1.155 +
1.156 + // Undefined source object.
1.157 +
1.158 + static Source undefined;
1.159 +};
1.160 +
1.161 +
1.162 +
1.163 +// Common clock abstraction.
1.164 +
1.165 +class Clock_base
1.166 +{
1.167 + Source _source;
1.168 +
1.169 +public:
1.170 + explicit Clock_base(Source source)
1.171 + : _source(source)
1.172 + {
1.173 + }
1.174 +
1.175 + // Clock control.
1.176 +
1.177 + virtual int have_clock(Cpm_regs ®s);
1.178 + virtual void start_clock(Cpm_regs ®s);
1.179 + virtual void stop_clock(Cpm_regs ®s);
1.180 +
1.181 + // Clock divider.
1.182 +
1.183 + virtual uint32_t get_divider(Cpm_regs ®s);
1.184 + virtual void set_divider(Cpm_regs ®s, uint32_t division);
1.185 +
1.186 + // Clock source.
1.187 +
1.188 + virtual uint8_t get_source(Cpm_regs ®s);
1.189 + virtual void set_source(Cpm_regs ®s, uint8_t source);
1.190 +
1.191 + // Clock source frequency.
1.192 +
1.193 + virtual uint32_t get_source_frequency(Cpm_regs ®s);
1.194 +
1.195 + // Output frequency.
1.196 +
1.197 + virtual uint32_t get_frequency(Cpm_regs ®s);
1.198 +};
1.199 +
1.200 +
1.201 +
1.202 +// PLL descriptions.
1.203 +
1.204 +class Pll : public Clock_base
1.205 +{
1.206 + Field _enable, _stable, _bypass;
1.207 + Field _multiplier, _input_division, _output_division0, _output_division1;
1.208 +
1.209 +public:
1.210 + explicit Pll(Source source,
1.211 + Field enable, Field stable, Field bypass,
1.212 + Field multiplier, Field input_division,
1.213 + Field output_division0, Field output_division1)
1.214 + : Clock_base(source),
1.215 + _enable(enable), _stable(stable), _bypass(bypass),
1.216 + _multiplier(multiplier), _input_division(input_division),
1.217 + _output_division0(output_division0), _output_division1(output_division1)
1.218 + {
1.219 + }
1.220 +
1.221 + // PLL_specific control.
1.222 +
1.223 + int have_pll(Cpm_regs ®s);
1.224 + int pll_enabled(Cpm_regs ®s);
1.225 + int pll_bypassed(Cpm_regs ®s);
1.226 +
1.227 + // Clock control.
1.228 +
1.229 + int have_clock(Cpm_regs ®s);
1.230 + void start_clock(Cpm_regs ®s);
1.231 + void stop_clock(Cpm_regs ®s);
1.232 +
1.233 + // General frequency modifiers.
1.234 +
1.235 + uint16_t get_multiplier(Cpm_regs ®s);
1.236 + void set_multiplier(Cpm_regs ®s, uint16_t multiplier);
1.237 + uint8_t get_input_division(Cpm_regs ®s);
1.238 + void set_input_division(Cpm_regs ®s, uint8_t divider);
1.239 + uint8_t get_output_division(Cpm_regs ®s);
1.240 + void set_output_division(Cpm_regs ®s, uint8_t divider);
1.241 +
1.242 + // PLL output frequency.
1.243 +
1.244 + uint32_t get_frequency(Cpm_regs ®s);
1.245 +
1.246 + // Other operations.
1.247 +
1.248 + void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier,
1.249 + uint8_t in_divider, uint8_t out_divider);
1.250 +};
1.251 +
1.252 +
1.253 +
1.254 +// Clock descriptions.
1.255 +
1.256 +class Clock : public Clock_base
1.257 +{
1.258 + Field _gate, _change_enable, _busy, _divider;
1.259 +
1.260 + // Clock control.
1.261 +
1.262 + void change_disable(Cpm_regs ®s);
1.263 + void change_enable(Cpm_regs ®s);
1.264 + void wait_busy(Cpm_regs ®s);
1.265 +
1.266 +public:
1.267 + explicit Clock(Source source = Source::undefined,
1.268 + Field gate = Field::undefined,
1.269 + Field change_enable = Field::undefined,
1.270 + Field busy = Field::undefined,
1.271 + Field divider = Field::undefined)
1.272 + : Clock_base(source),
1.273 + _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider)
1.274 + {
1.275 + }
1.276 +
1.277 + // Clock control.
1.278 +
1.279 + int have_clock(Cpm_regs ®s);
1.280 + void start_clock(Cpm_regs ®s);
1.281 + void stop_clock(Cpm_regs ®s);
1.282 +
1.283 + // Clock divider.
1.284 +
1.285 + uint32_t get_divider(Cpm_regs ®s);
1.286 + void set_divider(Cpm_regs ®s, uint32_t division);
1.287 +
1.288 + // Clock source.
1.289 +
1.290 + void set_source(Cpm_regs ®s, uint8_t source);
1.291 +};
1.292 +
1.293 +#endif /* __cplusplus */