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 */
2.1 --- a/pkg/devices/lib/cpm/include/cpm-x1600.h Sat Sep 16 14:28:01 2023 +0200
2.2 +++ b/pkg/devices/lib/cpm/include/cpm-x1600.h Sat Sep 16 16:53:06 2023 +0200
2.3 @@ -22,7 +22,6 @@
2.4 #pragma once
2.5
2.6 #include <l4/devices/cpm.h>
2.7 -
2.8 #include <l4/sys/types.h>
2.9 #include <stdint.h>
2.10
2.11 @@ -31,23 +30,7 @@
2.12 #ifdef __cplusplus
2.13
2.14 #include <l4/devices/hw_register_block.h>
2.15 -
2.16 -/* Register access type. */
2.17 -
2.18 -class Cpm_regs
2.19 -{
2.20 - Hw::Register_block<32> _regs;
2.21 -
2.22 -public:
2.23 - uint32_t exclk_freq;
2.24 -
2.25 - explicit Cpm_regs(l4_addr_t addr, uint32_t exclk_freq);
2.26 -
2.27 - // Utility methods.
2.28 -
2.29 - uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift);
2.30 - void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value);
2.31 -};
2.32 +#include <l4/devices/cpm-common.h>
2.33
2.34 /* A simple abstraction for accessing the CPM registers.
2.35 * A proper device could inherit from Hw::Device and use an
3.1 --- a/pkg/devices/lib/cpm/src/Makefile Sat Sep 16 14:28:01 2023 +0200
3.2 +++ b/pkg/devices/lib/cpm/src/Makefile Sat Sep 16 16:53:06 2023 +0200
3.3 @@ -4,7 +4,7 @@
3.4 TARGET = libcpm.o.a libcpm.o.so
3.5 PC_FILENAME := libdrivers-cpm
3.6
3.7 -SRC_CC := jz4730.cc jz4740.cc jz4780.cc x1600.cc
3.8 +SRC_CC := common.cc jz4730.cc jz4740.cc jz4780.cc x1600.cc
3.9
3.10 PRIVATE_INCDIR += $(PKGDIR)/lib/cpm/include
3.11
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/pkg/devices/lib/cpm/src/common.cc Sat Sep 16 16:53:06 2023 +0200
4.3 @@ -0,0 +1,420 @@
4.4 +/*
4.5 + * Common clock functionality.
4.6 + *
4.7 + * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk>
4.8 + *
4.9 + * This program is free software; you can redistribute it and/or
4.10 + * modify it under the terms of the GNU General Public License as
4.11 + * published by the Free Software Foundation; either version 2 of
4.12 + * the License, or (at your option) any later version.
4.13 + *
4.14 + * This program is distributed in the hope that it will be useful,
4.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.17 + * GNU General Public License for more details.
4.18 + *
4.19 + * You should have received a copy of the GNU General Public License
4.20 + * along with this program; if not, write to the Free Software
4.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
4.22 + * Boston, MA 02110-1301, USA
4.23 + */
4.24 +
4.25 +#include <l4/devices/hw_mmio_register_block.h>
4.26 +
4.27 +#include "cpm-common.h"
4.28 +#include <math.h>
4.29 +
4.30 +
4.31 +
4.32 +// Register access.
4.33 +
4.34 +Cpm_regs::Cpm_regs(l4_addr_t addr, Clock_base *clocks[],
4.35 + uint32_t exclk_freq)
4.36 +: _clocks(clocks), exclk_freq(exclk_freq)
4.37 +{
4.38 + _regs = new Hw::Mmio_register_block<32>(addr);
4.39 +}
4.40 +
4.41 +// Utility methods.
4.42 +
4.43 +uint32_t
4.44 +Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift)
4.45 +{
4.46 + return (_regs[reg] & (mask << shift)) >> shift;
4.47 +}
4.48 +
4.49 +void
4.50 +Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value)
4.51 +{
4.52 + _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift);
4.53 +}
4.54 +
4.55 +Clock_base *
4.56 +Cpm_regs::get_clock(int num)
4.57 +{
4.58 + return _clocks[num];
4.59 +}
4.60 +
4.61 +
4.62 +
4.63 +// Field methods.
4.64 +
4.65 +uint32_t
4.66 +Field::get_field(Cpm_regs ®s)
4.67 +{
4.68 + if (defined)
4.69 + return regs.get_field(reg, mask, bit);
4.70 + else
4.71 + return 0;
4.72 +}
4.73 +
4.74 +void
4.75 +Field::set_field(Cpm_regs ®s, uint32_t value)
4.76 +{
4.77 + if (defined)
4.78 + regs.set_field(reg, mask, bit, value);
4.79 +}
4.80 +
4.81 +// Undefined field.
4.82 +
4.83 +Field Field::undefined;
4.84 +
4.85 +
4.86 +
4.87 +// Clock sources.
4.88 +
4.89 +enum Clock_identifiers
4.90 +Mux::get_input(int num)
4.91 +{
4.92 + if (num < _num_inputs)
4.93 + return _inputs[num];
4.94 + else
4.95 + return Clock_undefined;
4.96 +}
4.97 +
4.98 +// Clock sources.
4.99 +
4.100 +uint8_t
4.101 +Source::get_source(Cpm_regs ®s)
4.102 +{
4.103 + if (_source.is_defined())
4.104 + return _source.get_field(regs);
4.105 + else
4.106 + return 0;
4.107 +}
4.108 +
4.109 +void
4.110 +Source::set_source(Cpm_regs ®s, uint8_t source)
4.111 +{
4.112 + if (!_source.is_defined())
4.113 + return;
4.114 +
4.115 + _source.set_field(regs, source);
4.116 +}
4.117 +
4.118 +// Clock source frequencies.
4.119 +
4.120 +uint32_t
4.121 +Source::get_frequency(Cpm_regs ®s)
4.122 +{
4.123 + // Return the external clock frequency without any input clock.
4.124 +
4.125 + if (get_number() == 0)
4.126 + return regs.exclk_freq;
4.127 +
4.128 + // Clocks with one source yield that input frequency.
4.129 +
4.130 + else if (get_number() == 1)
4.131 + return regs.get_clock(get_input(0))->get_frequency(regs);
4.132 +
4.133 + // With multiple sources, obtain the selected source for the clock.
4.134 +
4.135 + uint8_t source = get_source(regs);
4.136 + enum Clock_identifiers input = get_input(source);
4.137 +
4.138 + // Return the frequency of the source.
4.139 +
4.140 + if (input != Clock_undefined)
4.141 + return regs.get_clock(input)->get_frequency(regs);
4.142 + else
4.143 + return 0;
4.144 +}
4.145 +
4.146 +// Undefined source.
4.147 +
4.148 +Source Source::undefined;
4.149 +
4.150 +
4.151 +
4.152 +// Clock control.
4.153 +
4.154 +int
4.155 +Clock_base::have_clock(Cpm_regs ®s)
4.156 +{
4.157 + (void) regs;
4.158 + return true;
4.159 +}
4.160 +
4.161 +void
4.162 +Clock_base::start_clock(Cpm_regs ®s)
4.163 +{
4.164 + (void) regs;
4.165 +}
4.166 +
4.167 +void
4.168 +Clock_base::stop_clock(Cpm_regs ®s)
4.169 +{
4.170 + (void) regs;
4.171 +}
4.172 +
4.173 +// Default divider.
4.174 +
4.175 +uint32_t
4.176 +Clock_base::get_divider(Cpm_regs ®s)
4.177 +{
4.178 + (void) regs;
4.179 + return 1;
4.180 +}
4.181 +
4.182 +void
4.183 +Clock_base::set_divider(Cpm_regs ®s, uint32_t division)
4.184 +{
4.185 + (void) regs;
4.186 + (void) division;
4.187 +}
4.188 +
4.189 +// Clock sources.
4.190 +
4.191 +uint8_t
4.192 +Clock_base::get_source(Cpm_regs ®s)
4.193 +{
4.194 + return _source.get_source(regs);
4.195 +}
4.196 +
4.197 +void
4.198 +Clock_base::set_source(Cpm_regs ®s, uint8_t source)
4.199 +{
4.200 + _source.set_source(regs, source);
4.201 +}
4.202 +
4.203 +// Clock source frequencies.
4.204 +
4.205 +uint32_t
4.206 +Clock_base::get_source_frequency(Cpm_regs ®s)
4.207 +{
4.208 + return _source.get_frequency(regs);
4.209 +}
4.210 +
4.211 +// Output clock frequencies.
4.212 +
4.213 +uint32_t
4.214 +Clock_base::get_frequency(Cpm_regs ®s)
4.215 +{
4.216 + return get_source_frequency(regs) / get_divider(regs);
4.217 +}
4.218 +
4.219 +
4.220 +
4.221 +// PLL-specific control.
4.222 +
4.223 +int
4.224 +Pll::have_pll(Cpm_regs ®s)
4.225 +{
4.226 + return _stable.get_field(regs);
4.227 +}
4.228 +
4.229 +int
4.230 +Pll::pll_enabled(Cpm_regs ®s)
4.231 +{
4.232 + return _enable.get_field(regs);
4.233 +}
4.234 +
4.235 +int
4.236 +Pll::pll_bypassed(Cpm_regs ®s)
4.237 +{
4.238 + return _bypass.get_field(regs);
4.239 +}
4.240 +
4.241 +// Clock control.
4.242 +
4.243 +int
4.244 +Pll::have_clock(Cpm_regs ®s)
4.245 +{
4.246 + return have_pll(regs) && pll_enabled(regs);
4.247 +}
4.248 +
4.249 +void
4.250 +Pll::start_clock(Cpm_regs ®s)
4.251 +{
4.252 + _enable.set_field(regs, 1);
4.253 + while (!have_pll(regs));
4.254 +}
4.255 +
4.256 +void
4.257 +Pll::stop_clock(Cpm_regs ®s)
4.258 +{
4.259 + _enable.set_field(regs, 0);
4.260 + while (have_pll(regs));
4.261 +}
4.262 +
4.263 +// Feedback (13-bit) multiplier.
4.264 +
4.265 +uint16_t
4.266 +Pll::get_multiplier(Cpm_regs ®s)
4.267 +{
4.268 + return _multiplier.get_field(regs) + 1;
4.269 +}
4.270 +
4.271 +void
4.272 +Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier)
4.273 +{
4.274 + _multiplier.set_field(regs, multiplier - 1);
4.275 +}
4.276 +
4.277 +// Input (6-bit) divider.
4.278 +
4.279 +uint8_t
4.280 +Pll::get_input_division(Cpm_regs ®s)
4.281 +{
4.282 + return _input_division.get_field(regs) + 1;
4.283 +}
4.284 +
4.285 +void
4.286 +Pll::set_input_division(Cpm_regs ®s, uint8_t divider)
4.287 +{
4.288 + _input_division.set_field(regs, divider - 1);
4.289 +}
4.290 +
4.291 +// Output (dual 3-bit) dividers.
4.292 +
4.293 +uint8_t
4.294 +Pll::get_output_division(Cpm_regs ®s)
4.295 +{
4.296 + uint8_t d0 = _output_division0.get_field(regs);
4.297 + uint8_t d1 = _output_division1.get_field(regs);
4.298 +
4.299 + return d0 * d1;
4.300 +}
4.301 +
4.302 +void
4.303 +Pll::set_output_division(Cpm_regs ®s, uint8_t divider)
4.304 +{
4.305 + // Assert 1 as a minimum.
4.306 + // Divider 0 must be less than or equal to divider 1.
4.307 +
4.308 + uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1));
4.309 + uint8_t d1 = divider / d0;
4.310 +
4.311 + _output_division0.set_field(regs, d0);
4.312 + _output_division1.set_field(regs, d1);
4.313 +}
4.314 +
4.315 +uint32_t
4.316 +Pll::get_frequency(Cpm_regs ®s)
4.317 +{
4.318 + // Test for PLL enable and not PLL bypass.
4.319 +
4.320 + if (pll_enabled(regs))
4.321 + {
4.322 + if (!pll_bypassed(regs))
4.323 + return (get_source_frequency(regs) * get_multiplier(regs)) /
4.324 + (get_input_division(regs) * get_output_division(regs));
4.325 + else
4.326 + return get_source_frequency(regs);
4.327 + }
4.328 + else
4.329 + return 0;
4.330 +}
4.331 +
4.332 +void
4.333 +Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider)
4.334 +{
4.335 + set_multiplier(regs, multiplier);
4.336 + set_input_division(regs, in_divider);
4.337 + set_output_division(regs, out_divider);
4.338 +
4.339 + if (pll_enabled(regs) && !pll_bypassed(regs))
4.340 + while (!have_pll(regs));
4.341 +}
4.342 +
4.343 +
4.344 +
4.345 +// Clock control.
4.346 +
4.347 +void
4.348 +Clock::change_disable(Cpm_regs ®s)
4.349 +{
4.350 + if (_change_enable.is_defined())
4.351 + _change_enable.set_field(regs, 0);
4.352 +}
4.353 +
4.354 +void
4.355 +Clock::change_enable(Cpm_regs ®s)
4.356 +{
4.357 + if (_change_enable.is_defined())
4.358 + _change_enable.set_field(regs, 1);
4.359 +}
4.360 +
4.361 +int
4.362 +Clock::have_clock(Cpm_regs ®s)
4.363 +{
4.364 + if (_gate.is_defined())
4.365 + return !_gate.get_field(regs);
4.366 + else
4.367 + return true;
4.368 +}
4.369 +
4.370 +void
4.371 +Clock::start_clock(Cpm_regs ®s)
4.372 +{
4.373 + if (_gate.is_defined())
4.374 + _gate.set_field(regs, 0);
4.375 +}
4.376 +
4.377 +void
4.378 +Clock::stop_clock(Cpm_regs ®s)
4.379 +{
4.380 + if (_gate.is_defined())
4.381 + _gate.set_field(regs, 1);
4.382 +}
4.383 +
4.384 +void
4.385 +Clock::wait_busy(Cpm_regs ®s)
4.386 +{
4.387 + if (_busy.is_defined())
4.388 + while (_busy.get_field(regs));
4.389 +}
4.390 +
4.391 +
4.392 +
4.393 +// Clock dividers.
4.394 +
4.395 +uint32_t
4.396 +Clock::get_divider(Cpm_regs ®s)
4.397 +{
4.398 + if (_divider.is_defined())
4.399 + return _divider.get_field(regs) + 1;
4.400 + else
4.401 + return 1;
4.402 +}
4.403 +
4.404 +void
4.405 +Clock::set_divider(Cpm_regs ®s, uint32_t division)
4.406 +{
4.407 + if (!_divider.is_defined())
4.408 + return;
4.409 +
4.410 + change_enable(regs);
4.411 + _divider.set_field(regs, division - 1);
4.412 + wait_busy(regs);
4.413 + change_disable(regs);
4.414 +}
4.415 +
4.416 +void
4.417 +Clock::set_source(Cpm_regs ®s, uint8_t source)
4.418 +{
4.419 + change_enable(regs);
4.420 + Clock_base::set_source(regs, source);
4.421 + wait_busy(regs);
4.422 + change_disable(regs);
4.423 +}
5.1 --- a/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 14:28:01 2023 +0200
5.2 +++ b/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 16:53:06 2023 +0200
5.3 @@ -85,236 +85,6 @@
5.4
5.5
5.6
5.7 -// Register field abstraction.
5.8 -
5.9 -class Field
5.10 -{
5.11 - uint32_t reg;
5.12 - uint32_t mask;
5.13 - uint8_t bit;
5.14 - bool defined;
5.15 -
5.16 -public:
5.17 - explicit Field()
5.18 - : defined(false)
5.19 - {
5.20 - }
5.21 -
5.22 - explicit Field(uint32_t reg, uint32_t mask, uint32_t bit)
5.23 - : reg(reg), mask(mask), bit(bit), defined(true)
5.24 - {
5.25 - }
5.26 -
5.27 - uint32_t get_field(Cpm_regs ®s);
5.28 - void set_field(Cpm_regs ®s, uint32_t value);
5.29 - bool is_defined() { return defined; }
5.30 -};
5.31 -
5.32 -// Undefined fields.
5.33 -
5.34 -Field Gate_undefined, Change_enable_undefined, Busy_undefined, Divider_undefined;
5.35 -
5.36 -
5.37 -
5.38 -// Clock sources.
5.39 -
5.40 -class Mux
5.41 -{
5.42 - int _num_inputs;
5.43 - enum Clock_identifiers *_inputs, _input;
5.44 -
5.45 -public:
5.46 - explicit Mux(int num_inputs, enum Clock_identifiers inputs[])
5.47 - : _num_inputs(num_inputs), _inputs(inputs)
5.48 - {
5.49 - }
5.50 -
5.51 - explicit Mux(enum Clock_identifiers input)
5.52 - : _num_inputs(1), _inputs(&_input)
5.53 - {
5.54 - _input = input;
5.55 - }
5.56 -
5.57 - explicit Mux()
5.58 - : _num_inputs(0), _inputs(NULL)
5.59 - {
5.60 - }
5.61 -
5.62 - int get_number() { return _num_inputs; }
5.63 - enum Clock_identifiers get_input(int num);
5.64 -};
5.65 -
5.66 -class Source
5.67 -{
5.68 - Mux _inputs;
5.69 - Field _source;
5.70 -
5.71 -public:
5.72 - explicit Source(Mux inputs, Field source)
5.73 - : _inputs(inputs), _source(source)
5.74 - {
5.75 - }
5.76 -
5.77 - explicit Source(Mux inputs)
5.78 - : _inputs(inputs)
5.79 - {
5.80 - }
5.81 -
5.82 - explicit Source()
5.83 - {
5.84 - }
5.85 -
5.86 - int get_number() { return _inputs.get_number(); }
5.87 - enum Clock_identifiers get_input(int num) { return _inputs.get_input(num); }
5.88 -
5.89 - // Clock source.
5.90 -
5.91 - uint8_t get_source(Cpm_regs ®s);
5.92 - void set_source(Cpm_regs ®s, uint8_t source);
5.93 -
5.94 - // Clock source frequency.
5.95 -
5.96 - uint32_t get_frequency(Cpm_regs ®s);
5.97 -};
5.98 -
5.99 -// Undefined sources.
5.100 -
5.101 -Source Source_undefined;
5.102 -
5.103 -
5.104 -
5.105 -// Common clock abstraction.
5.106 -
5.107 -class Clock_base
5.108 -{
5.109 - Source _source;
5.110 -
5.111 -public:
5.112 - explicit Clock_base(Source source)
5.113 - : _source(source)
5.114 - {
5.115 - }
5.116 -
5.117 - // Clock control.
5.118 -
5.119 - virtual int have_clock(Cpm_regs ®s);
5.120 - virtual void start_clock(Cpm_regs ®s);
5.121 - virtual void stop_clock(Cpm_regs ®s);
5.122 -
5.123 - // Clock divider.
5.124 -
5.125 - virtual uint32_t get_divider(Cpm_regs ®s);
5.126 - virtual void set_divider(Cpm_regs ®s, uint32_t division);
5.127 -
5.128 - // Clock source.
5.129 -
5.130 - virtual uint8_t get_source(Cpm_regs ®s);
5.131 - virtual void set_source(Cpm_regs ®s, uint8_t source);
5.132 -
5.133 - // Clock source frequency.
5.134 -
5.135 - virtual uint32_t get_source_frequency(Cpm_regs ®s);
5.136 -
5.137 - // Output frequency.
5.138 -
5.139 - virtual uint32_t get_frequency(Cpm_regs ®s);
5.140 -};
5.141 -
5.142 -
5.143 -
5.144 -// PLL descriptions.
5.145 -
5.146 -class Pll : public Clock_base
5.147 -{
5.148 - Field _enable, _stable, _bypass;
5.149 - Field _multiplier, _input_division, _output_division0, _output_division1;
5.150 -
5.151 -public:
5.152 - explicit Pll(Source source,
5.153 - Field enable, Field stable, Field bypass,
5.154 - Field multiplier, Field input_division,
5.155 - Field output_division0, Field output_division1)
5.156 - : Clock_base(source),
5.157 - _enable(enable), _stable(stable), _bypass(bypass),
5.158 - _multiplier(multiplier), _input_division(input_division),
5.159 - _output_division0(output_division0), _output_division1(output_division1)
5.160 - {
5.161 - }
5.162 -
5.163 - // PLL_specific control.
5.164 -
5.165 - int have_pll(Cpm_regs ®s);
5.166 - int pll_enabled(Cpm_regs ®s);
5.167 - int pll_bypassed(Cpm_regs ®s);
5.168 -
5.169 - // Clock control.
5.170 -
5.171 - int have_clock(Cpm_regs ®s);
5.172 - void start_clock(Cpm_regs ®s);
5.173 - void stop_clock(Cpm_regs ®s);
5.174 -
5.175 - // General frequency modifiers.
5.176 -
5.177 - uint16_t get_multiplier(Cpm_regs ®s);
5.178 - void set_multiplier(Cpm_regs ®s, uint16_t multiplier);
5.179 - uint8_t get_input_division(Cpm_regs ®s);
5.180 - void set_input_division(Cpm_regs ®s, uint8_t divider);
5.181 - uint8_t get_output_division(Cpm_regs ®s);
5.182 - void set_output_division(Cpm_regs ®s, uint8_t divider);
5.183 -
5.184 - // PLL output frequency.
5.185 -
5.186 - uint32_t get_frequency(Cpm_regs ®s);
5.187 -
5.188 - // Other operations.
5.189 -
5.190 - void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier,
5.191 - uint8_t in_divider, uint8_t out_divider);
5.192 -};
5.193 -
5.194 -
5.195 -
5.196 -// Clock descriptions.
5.197 -
5.198 -class Clock : public Clock_base
5.199 -{
5.200 - Field _gate, _change_enable, _busy, _divider;
5.201 -
5.202 - // Clock control.
5.203 -
5.204 - void change_disable(Cpm_regs ®s);
5.205 - void change_enable(Cpm_regs ®s);
5.206 - void wait_busy(Cpm_regs ®s);
5.207 -
5.208 -public:
5.209 - explicit Clock(Source source = Source_undefined,
5.210 - Field gate = Gate_undefined,
5.211 - Field change_enable = Change_enable_undefined,
5.212 - Field busy = Busy_undefined,
5.213 - Field divider = Divider_undefined)
5.214 - : Clock_base(source),
5.215 - _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider)
5.216 - {
5.217 - }
5.218 -
5.219 - // Clock control.
5.220 -
5.221 - int have_clock(Cpm_regs ®s);
5.222 - void start_clock(Cpm_regs ®s);
5.223 - void stop_clock(Cpm_regs ®s);
5.224 -
5.225 - // Clock divider.
5.226 -
5.227 - uint32_t get_divider(Cpm_regs ®s);
5.228 - void set_divider(Cpm_regs ®s, uint32_t division);
5.229 -
5.230 - // Clock source.
5.231 -
5.232 - void set_source(Cpm_regs ®s, uint8_t source);
5.233 -};
5.234 -
5.235 -
5.236 -
5.237 // Register field definitions.
5.238
5.239 Field Clock_source_main (Clock_control, 3, 30); // SEL_SRC (output to SCLK_A)
5.240 @@ -507,7 +277,7 @@
5.241 Clock_divider_cim);
5.242
5.243 Clock clock_cpu(Source(mux_core, Clock_source_cpu),
5.244 - Gate_undefined,
5.245 + Field::undefined,
5.246 Clock_change_enable_cpu,
5.247 Clock_busy_cpu,
5.248 Clock_divider_cpu);
5.249 @@ -527,13 +297,13 @@
5.250 Clock clock_hclock0(Source(mux_core, Clock_source_hclock0),
5.251 Clock_gate_ahb0,
5.252 Clock_change_enable_ahb0,
5.253 - Busy_undefined,
5.254 + Field::undefined,
5.255 Clock_divider_hclock0);
5.256
5.257 Clock clock_hclock2(Source(mux_ahb2_apb),
5.258 Clock_gate_apb0,
5.259 Clock_change_enable_ahb2,
5.260 - Busy_undefined,
5.261 + Field::undefined,
5.262 Clock_divider_hclock2);
5.263
5.264 Clock clock_hdmi;
5.265 @@ -595,8 +365,8 @@
5.266
5.267 Clock clock_pclock(Source(mux_ahb2_apb),
5.268 Clock_gate_apb0,
5.269 - Change_enable_undefined,
5.270 - Busy_undefined,
5.271 + Field::undefined,
5.272 + Field::undefined,
5.273 Clock_divider_pclock);
5.274
5.275 Pll clock_pll_A(Source(mux_external),
5.276 @@ -730,392 +500,12 @@
5.277
5.278
5.279
5.280 -// Register access.
5.281 -
5.282 -Cpm_regs::Cpm_regs(l4_addr_t addr, uint32_t exclk_freq)
5.283 -: exclk_freq(exclk_freq)
5.284 -{
5.285 - _regs = new Hw::Mmio_register_block<32>(addr);
5.286 -}
5.287 -
5.288 -// Utility methods.
5.289 -
5.290 -uint32_t
5.291 -Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift)
5.292 -{
5.293 - return (_regs[reg] & (mask << shift)) >> shift;
5.294 -}
5.295 -
5.296 -void
5.297 -Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value)
5.298 -{
5.299 - _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift);
5.300 -}
5.301 -
5.302 -
5.303 -
5.304 -// Field methods.
5.305 -
5.306 -uint32_t
5.307 -Field::get_field(Cpm_regs ®s)
5.308 -{
5.309 - if (defined)
5.310 - return regs.get_field(reg, mask, bit);
5.311 - else
5.312 - return 0;
5.313 -}
5.314 -
5.315 -void
5.316 -Field::set_field(Cpm_regs ®s, uint32_t value)
5.317 -{
5.318 - if (defined)
5.319 - regs.set_field(reg, mask, bit, value);
5.320 -}
5.321 -
5.322 -
5.323 -
5.324 -// Clock sources.
5.325 -
5.326 -enum Clock_identifiers
5.327 -Mux::get_input(int num)
5.328 -{
5.329 - if (num < _num_inputs)
5.330 - return _inputs[num];
5.331 - else
5.332 - return Clock_undefined;
5.333 -}
5.334 -
5.335 -// Clock sources.
5.336 -
5.337 -uint8_t
5.338 -Source::get_source(Cpm_regs ®s)
5.339 -{
5.340 - if (_source.is_defined())
5.341 - return _source.get_field(regs);
5.342 - else
5.343 - return 0;
5.344 -}
5.345 -
5.346 -void
5.347 -Source::set_source(Cpm_regs ®s, uint8_t source)
5.348 -{
5.349 - if (!_source.is_defined())
5.350 - return;
5.351 -
5.352 - _source.set_field(regs, source);
5.353 -}
5.354 -
5.355 -// Clock source frequencies.
5.356 -
5.357 -uint32_t
5.358 -Source::get_frequency(Cpm_regs ®s)
5.359 -{
5.360 - // Return the external clock frequency without any input clock.
5.361 -
5.362 - if (get_number() == 0)
5.363 - return regs.exclk_freq;
5.364 -
5.365 - // Clocks with one source yield that input frequency.
5.366 -
5.367 - else if (get_number() == 1)
5.368 - return clocks[get_input(0)]->get_frequency(regs);
5.369 -
5.370 - // With multiple sources, obtain the selected source for the clock.
5.371 -
5.372 - uint8_t source = get_source(regs);
5.373 - enum Clock_identifiers input = get_input(source);
5.374 -
5.375 - // Return the frequency of the source.
5.376 -
5.377 - if (input != Clock_undefined)
5.378 - return clocks[input]->get_frequency(regs);
5.379 - else
5.380 - return 0;
5.381 -}
5.382 -
5.383 -
5.384 -
5.385 -// Clock control.
5.386 -
5.387 -int
5.388 -Clock_base::have_clock(Cpm_regs ®s)
5.389 -{
5.390 - (void) regs;
5.391 - return true;
5.392 -}
5.393 -
5.394 -void
5.395 -Clock_base::start_clock(Cpm_regs ®s)
5.396 -{
5.397 - (void) regs;
5.398 -}
5.399 -
5.400 -void
5.401 -Clock_base::stop_clock(Cpm_regs ®s)
5.402 -{
5.403 - (void) regs;
5.404 -}
5.405 -
5.406 -// Default divider.
5.407 -
5.408 -uint32_t
5.409 -Clock_base::get_divider(Cpm_regs ®s)
5.410 -{
5.411 - (void) regs;
5.412 - return 1;
5.413 -}
5.414 -
5.415 -void
5.416 -Clock_base::set_divider(Cpm_regs ®s, uint32_t division)
5.417 -{
5.418 - (void) regs;
5.419 - (void) division;
5.420 -}
5.421 -
5.422 -// Clock sources.
5.423 -
5.424 -uint8_t
5.425 -Clock_base::get_source(Cpm_regs ®s)
5.426 -{
5.427 - return _source.get_source(regs);
5.428 -}
5.429 -
5.430 -void
5.431 -Clock_base::set_source(Cpm_regs ®s, uint8_t source)
5.432 -{
5.433 - _source.set_source(regs, source);
5.434 -}
5.435 -
5.436 -// Clock source frequencies.
5.437 -
5.438 -uint32_t
5.439 -Clock_base::get_source_frequency(Cpm_regs ®s)
5.440 -{
5.441 - return _source.get_frequency(regs);
5.442 -}
5.443 -
5.444 -// Output clock frequencies.
5.445 -
5.446 -uint32_t
5.447 -Clock_base::get_frequency(Cpm_regs ®s)
5.448 -{
5.449 - return get_source_frequency(regs) / get_divider(regs);
5.450 -}
5.451 -
5.452 -
5.453 -
5.454 -// PLL-specific control.
5.455 -
5.456 -int
5.457 -Pll::have_pll(Cpm_regs ®s)
5.458 -{
5.459 - return _stable.get_field(regs);
5.460 -}
5.461 -
5.462 -int
5.463 -Pll::pll_enabled(Cpm_regs ®s)
5.464 -{
5.465 - return _enable.get_field(regs);
5.466 -}
5.467 -
5.468 -int
5.469 -Pll::pll_bypassed(Cpm_regs ®s)
5.470 -{
5.471 - return _bypass.get_field(regs);
5.472 -}
5.473 -
5.474 -// Clock control.
5.475 -
5.476 -int
5.477 -Pll::have_clock(Cpm_regs ®s)
5.478 -{
5.479 - return have_pll(regs) && pll_enabled(regs);
5.480 -}
5.481 -
5.482 -void
5.483 -Pll::start_clock(Cpm_regs ®s)
5.484 -{
5.485 - _enable.set_field(regs, 1);
5.486 - while (!have_pll(regs));
5.487 -}
5.488 -
5.489 -void
5.490 -Pll::stop_clock(Cpm_regs ®s)
5.491 -{
5.492 - _enable.set_field(regs, 0);
5.493 - while (have_pll(regs));
5.494 -}
5.495 -
5.496 -// Feedback (13-bit) multiplier.
5.497 -
5.498 -uint16_t
5.499 -Pll::get_multiplier(Cpm_regs ®s)
5.500 -{
5.501 - return _multiplier.get_field(regs) + 1;
5.502 -}
5.503 -
5.504 -void
5.505 -Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier)
5.506 -{
5.507 - _multiplier.set_field(regs, multiplier - 1);
5.508 -}
5.509 -
5.510 -// Input (6-bit) divider.
5.511 -
5.512 -uint8_t
5.513 -Pll::get_input_division(Cpm_regs ®s)
5.514 -{
5.515 - return _input_division.get_field(regs) + 1;
5.516 -}
5.517 -
5.518 -void
5.519 -Pll::set_input_division(Cpm_regs ®s, uint8_t divider)
5.520 -{
5.521 - _input_division.set_field(regs, divider - 1);
5.522 -}
5.523 -
5.524 -// Output (dual 3-bit) dividers.
5.525 -
5.526 -uint8_t
5.527 -Pll::get_output_division(Cpm_regs ®s)
5.528 -{
5.529 - uint8_t d0 = _output_division0.get_field(regs);
5.530 - uint8_t d1 = _output_division1.get_field(regs);
5.531 -
5.532 - return d0 * d1;
5.533 -}
5.534 -
5.535 -void
5.536 -Pll::set_output_division(Cpm_regs ®s, uint8_t divider)
5.537 -{
5.538 - // Assert 1 as a minimum.
5.539 - // Divider 0 must be less than or equal to divider 1.
5.540 -
5.541 - uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1));
5.542 - uint8_t d1 = divider / d0;
5.543 -
5.544 - _output_division0.set_field(regs, d0);
5.545 - _output_division1.set_field(regs, d1);
5.546 -}
5.547 -
5.548 -uint32_t
5.549 -Pll::get_frequency(Cpm_regs ®s)
5.550 -{
5.551 - // Test for PLL enable and not PLL bypass.
5.552 -
5.553 - if (pll_enabled(regs))
5.554 - {
5.555 - if (!pll_bypassed(regs))
5.556 - return (get_source_frequency(regs) * get_multiplier(regs)) /
5.557 - (get_input_division(regs) * get_output_division(regs));
5.558 - else
5.559 - return get_source_frequency(regs);
5.560 - }
5.561 - else
5.562 - return 0;
5.563 -}
5.564 -
5.565 -void
5.566 -Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider)
5.567 -{
5.568 - set_multiplier(regs, multiplier);
5.569 - set_input_division(regs, in_divider);
5.570 - set_output_division(regs, out_divider);
5.571 -
5.572 - if (pll_enabled(regs) && !pll_bypassed(regs))
5.573 - while (!have_pll(regs));
5.574 -}
5.575 -
5.576 -
5.577 -
5.578 -// Clock control.
5.579 -
5.580 -void
5.581 -Clock::change_disable(Cpm_regs ®s)
5.582 -{
5.583 - if (_change_enable.is_defined())
5.584 - _change_enable.set_field(regs, 0);
5.585 -}
5.586 -
5.587 -void
5.588 -Clock::change_enable(Cpm_regs ®s)
5.589 -{
5.590 - if (_change_enable.is_defined())
5.591 - _change_enable.set_field(regs, 1);
5.592 -}
5.593 -
5.594 -int
5.595 -Clock::have_clock(Cpm_regs ®s)
5.596 -{
5.597 - if (_gate.is_defined())
5.598 - return !_gate.get_field(regs);
5.599 - else
5.600 - return true;
5.601 -}
5.602 -
5.603 -void
5.604 -Clock::start_clock(Cpm_regs ®s)
5.605 -{
5.606 - if (_gate.is_defined())
5.607 - _gate.set_field(regs, 0);
5.608 -}
5.609 -
5.610 -void
5.611 -Clock::stop_clock(Cpm_regs ®s)
5.612 -{
5.613 - if (_gate.is_defined())
5.614 - _gate.set_field(regs, 1);
5.615 -}
5.616 -
5.617 -void
5.618 -Clock::wait_busy(Cpm_regs ®s)
5.619 -{
5.620 - if (_busy.is_defined())
5.621 - while (_busy.get_field(regs));
5.622 -}
5.623 -
5.624 -
5.625 -
5.626 -// Clock dividers.
5.627 -
5.628 -uint32_t
5.629 -Clock::get_divider(Cpm_regs ®s)
5.630 -{
5.631 - if (_divider.is_defined())
5.632 - return _divider.get_field(regs) + 1;
5.633 - else
5.634 - return 1;
5.635 -}
5.636 -
5.637 -void
5.638 -Clock::set_divider(Cpm_regs ®s, uint32_t division)
5.639 -{
5.640 - if (!_divider.is_defined())
5.641 - return;
5.642 -
5.643 - change_enable(regs);
5.644 - _divider.set_field(regs, division - 1);
5.645 - wait_busy(regs);
5.646 - change_disable(regs);
5.647 -}
5.648 -
5.649 -void
5.650 -Clock::set_source(Cpm_regs ®s, uint8_t source)
5.651 -{
5.652 - change_enable(regs);
5.653 - Clock_base::set_source(regs, source);
5.654 - wait_busy(regs);
5.655 - change_disable(regs);
5.656 -}
5.657 -
5.658 -
5.659 -
5.660 // If implemented as a Hw::Device, various properties would be
5.661 // initialised in the constructor and obtained from the device tree
5.662 // definitions.
5.663
5.664 Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq)
5.665 -: _cpm_regs(addr, exclk_freq)
5.666 +: _cpm_regs(addr, clocks, exclk_freq)
5.667 {
5.668 // add_cid("cpm");
5.669 // add_cid("cpm-x1600");