# HG changeset patch # User Paul Boddie # Date 1694968901 -7200 # Node ID 85d8a7f95553af4f4031beb6172450db314ac8e2 # Parent 350ba4f76082a7394363fe690e2feafab2b6c9da Introduced various specialised control, divider and clock abstractions. diff -r 350ba4f76082 -r 85d8a7f95553 pkg/devices/lib/cpm/include/cpm-common.h --- a/pkg/devices/lib/cpm/include/cpm-common.h Sat Sep 16 17:56:49 2023 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-common.h Sun Sep 17 18:41:41 2023 +0200 @@ -120,6 +120,8 @@ +// Controllable clock source. + class Source { Mux _inputs; @@ -159,11 +161,96 @@ +// Common clock control. + +class Control_base +{ +public: + virtual ~Control_base(); + + virtual void change_disable(Cpm_regs ®s); + virtual void change_enable(Cpm_regs ®s); + + virtual void wait_busy(Cpm_regs ®s) = 0; + virtual int have_clock(Cpm_regs ®s) = 0; + virtual void start_clock(Cpm_regs ®s) = 0; + virtual void stop_clock(Cpm_regs ®s) = 0; +}; + + + +// Clock control. + +class Control : public Control_base +{ + Field _gate, _change_enable, _busy; + +public: + explicit Control(Field gate, + Field change_enable = Field::undefined, + Field busy = Field::undefined) + : _gate(gate), _change_enable(change_enable), _busy(busy) + { + } + + explicit Control() + : _gate(Field::undefined), _change_enable(Field::undefined), + _busy(Field::undefined) + { + } + + // Clock control. + + void change_disable(Cpm_regs ®s); + void change_enable(Cpm_regs ®s); + + void wait_busy(Cpm_regs ®s); + int have_clock(Cpm_regs ®s); + void start_clock(Cpm_regs ®s); + void stop_clock(Cpm_regs ®s); + + // Undefined control. + + static Control undefined; +}; + + + +// PLL control. + +class Control_pll : public Control_base +{ + Field _enable, _stable, _bypass; + + // PLL_specific control. + + int have_pll(Cpm_regs ®s); + int pll_enabled(Cpm_regs ®s); + +public: + explicit Control_pll(Field enable, Field stable, Field bypass) + : _enable(enable), _stable(stable), _bypass(bypass) + { + } + + // Clock control. + + int pll_bypassed(Cpm_regs ®s); + + void wait_busy(Cpm_regs ®s); + int have_clock(Cpm_regs ®s); + void start_clock(Cpm_regs ®s); + void stop_clock(Cpm_regs ®s); +}; + + + // Frequency transformation. -class Transform +class Divider_base { public: + virtual ~Divider_base(); // Output frequency. @@ -172,7 +259,9 @@ -class Divider : public Transform +// Simple divider for regular clocks. + +class Divider : public Divider_base { Field _divider; @@ -190,7 +279,7 @@ // Clock divider. uint32_t get_divider(Cpm_regs ®s); - void set_divider(Cpm_regs ®s, uint32_t division); + void set_divider(Cpm_regs ®s, uint32_t divider); // Output frequency. @@ -203,26 +292,28 @@ -class Divider_pll : public Transform +// Divider for PLLs. + +class Divider_pll : public Divider_base { - Field _multiplier, _input_division, _output_division0, _output_division1; + Field _multiplier, _input_divider, _output_divider0, _output_divider1; public: - explicit Divider_pll(Field multiplier, Field input_division, - Field output_division0, Field output_division1) - : _multiplier(multiplier), _input_division(input_division), - _output_division0(output_division0), _output_division1(output_division1) + explicit Divider_pll(Field multiplier, Field input_divider, + Field output_divider0, Field output_divider1) + : _multiplier(multiplier), _input_divider(input_divider), + _output_divider0(output_divider0), _output_divider1(output_divider1) { } // General frequency modifiers. - uint16_t get_multiplier(Cpm_regs ®s); - void set_multiplier(Cpm_regs ®s, uint16_t multiplier); - uint8_t get_input_division(Cpm_regs ®s); - void set_input_division(Cpm_regs ®s, uint8_t divider); - uint8_t get_output_division(Cpm_regs ®s); - void set_output_division(Cpm_regs ®s, uint8_t divider); + uint32_t get_multiplier(Cpm_regs ®s); + void set_multiplier(Cpm_regs ®s, uint32_t multiplier); + uint32_t get_input_divider(Cpm_regs ®s); + void set_input_divider(Cpm_regs ®s, uint32_t divider); + uint32_t get_output_divider(Cpm_regs ®s); + void set_output_divider(Cpm_regs ®s, uint32_t divider); // Output frequency. @@ -230,8 +321,40 @@ // Other operations. - void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, - uint8_t in_divider, uint8_t out_divider); + void set_parameters(Cpm_regs ®s, uint32_t multiplier, + uint32_t in_divider, uint32_t out_divider); +}; + + + +// Divider for I2S clocks. + +class Divider_i2s : public Divider_base +{ + Field _multiplier, _divider_N, _divider_D; + +public: + explicit Divider_i2s(Field multiplier, Field divider_N, + Field divider_D) + : _multiplier(multiplier), _divider_N(divider_N), + _divider_D(divider_D) + { + } + + // General frequency modifiers. + + uint32_t get_multiplier(Cpm_regs ®s); + uint32_t get_divider_N(Cpm_regs ®s); + uint32_t get_divider_D(Cpm_regs ®s); + + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency); + + // Other operations. + + void set_parameters(Cpm_regs ®s, uint32_t multiplier, + uint32_t divider_N, uint32_t divider_D); }; @@ -240,13 +363,46 @@ class Clock_base { - Source _source; - public: - explicit Clock_base(Source source) - : _source(source) - { - } + virtual ~Clock_base(); + + // Clock control. + + virtual int have_clock(Cpm_regs ®s) = 0; + virtual void start_clock(Cpm_regs ®s) = 0; + virtual void stop_clock(Cpm_regs ®s) = 0; + + // Output frequency. + + virtual uint32_t get_frequency(Cpm_regs ®s) = 0; +}; + + + +// Null (absent or undefined) clock abstraction. + +class Clock_null : public Clock_base +{ +public: + + // Clock control. + + int have_clock(Cpm_regs ®s); + void start_clock(Cpm_regs ®s); + void stop_clock(Cpm_regs ®s); + + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s); +}; + + + +// Passive (root or input) clock without any source of its own. + +class Clock_passive : public Clock_base +{ +public: // Clock control. @@ -254,10 +410,40 @@ virtual void start_clock(Cpm_regs ®s); virtual void stop_clock(Cpm_regs ®s); - // Clock divider. + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s); +}; + + + +// An actively managed clock with source. + +class Clock_active : public Clock_base +{ +protected: + Source _source; + + virtual Control_base &_get_control() = 0; - virtual uint32_t get_divider(Cpm_regs ®s); - virtual void set_divider(Cpm_regs ®s, uint32_t division); +public: + explicit Clock_active(Source source) + : _source(source) + { + } + + explicit Clock_active() + : _source(Source::undefined) + { + } + + virtual ~Clock_active(); + + // Clock control. + + virtual int have_clock(Cpm_regs ®s); + virtual void start_clock(Cpm_regs ®s); + virtual void stop_clock(Cpm_regs ®s); // Clock source. @@ -275,98 +461,114 @@ -// PLL descriptions. +// Divided clock interface. -class Pll : public Clock_base +class Clock_divided : public Clock_active { - Field _enable, _stable, _bypass; - Divider_pll _divider; +protected: + virtual Divider_base &_get_divider() = 0; public: - explicit Pll(Source source, - Field enable, Field stable, Field bypass, - Divider_pll divider) - : Clock_base(source), - _enable(enable), _stable(stable), _bypass(bypass), - _divider(divider) + explicit Clock_divided(Source source) + : Clock_active(source) { } - // PLL_specific control. - - int have_pll(Cpm_regs ®s); - int pll_enabled(Cpm_regs ®s); - int pll_bypassed(Cpm_regs ®s); - - // Clock control. - - int have_clock(Cpm_regs ®s); - void start_clock(Cpm_regs ®s); - void stop_clock(Cpm_regs ®s); - - // General frequency modifiers. - - uint16_t get_multiplier(Cpm_regs ®s); - void set_multiplier(Cpm_regs ®s, uint16_t multiplier); - uint8_t get_input_division(Cpm_regs ®s); - void set_input_division(Cpm_regs ®s, uint8_t divider); - uint8_t get_output_division(Cpm_regs ®s); - void set_output_division(Cpm_regs ®s, uint8_t divider); - - // PLL output frequency. - - uint32_t get_frequency(Cpm_regs ®s); - - // Other operations. - - void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, - uint8_t in_divider, uint8_t out_divider); -}; - - - -// Clock descriptions. - -class Clock : public Clock_base -{ - Field _gate, _change_enable, _busy; - Divider _divider; - - // Clock control. - - void change_disable(Cpm_regs ®s); - void change_enable(Cpm_regs ®s); - void wait_busy(Cpm_regs ®s); - -public: - explicit Clock(Source source = Source::undefined, - Field gate = Field::undefined, - Field change_enable = Field::undefined, - Field busy = Field::undefined, - Divider divider = Divider::undefined) - : Clock_base(source), - _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider) - { - } - - // Clock control. - - int have_clock(Cpm_regs ®s); - void start_clock(Cpm_regs ®s); - void stop_clock(Cpm_regs ®s); - - // Clock divider. - - uint32_t get_divider(Cpm_regs ®s); - void set_divider(Cpm_regs ®s, uint32_t division); - - // Clock source. - - void set_source(Cpm_regs ®s, uint8_t source); + virtual ~Clock_divided(); // Output frequency. uint32_t get_frequency(Cpm_regs ®s); }; + + +// PLL description. + +class Pll : public Clock_divided +{ + // Value storage. + + Control_pll _control; + Divider_pll _divider; + + virtual Control_base &_get_control() { return _control; } + virtual Divider_base &_get_divider() { return _divider; } + +public: + explicit Pll(Source source, Control_pll control, Divider_pll divider) + : Clock_divided(source), _control(control), _divider(divider) + { + } + + virtual ~Pll(); + + // General frequency modifiers. + + uint32_t get_multiplier(Cpm_regs ®s); + void set_multiplier(Cpm_regs ®s, uint32_t multiplier); + uint32_t get_input_divider(Cpm_regs ®s); + void set_input_divider(Cpm_regs ®s, uint32_t divider); + uint32_t get_output_divider(Cpm_regs ®s); + void set_output_divider(Cpm_regs ®s, uint32_t divider); + + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s); + + // Other operations. + + void set_parameters(Cpm_regs ®s, uint32_t multiplier, + uint32_t in_divider, uint32_t out_divider); +}; + + + +// Clock description. + +class Clock : public Clock_divided +{ + // Value storage. + + Control _control; + Divider _divider; + + virtual Control_base &_get_control() { return _control; } + virtual Divider_base &_get_divider() { return _divider; } + +public: + explicit Clock(Source source, + Control control = Control::undefined, + Divider divider = Divider::undefined) + : Clock_divided(source), _control(control), _divider(divider) + { + } + + // Clock divider. + + uint32_t get_divider(Cpm_regs ®s); + void set_divider(Cpm_regs ®s, uint32_t divider); +}; + + + +// I2S clock description. + +class Clock_divided_i2s : public Clock_divided +{ + // Value storage. + + Control _control; + Divider_i2s _divider; + + virtual Control_base &_get_control() { return _control; } + virtual Divider_base &_get_divider() { return _divider; } + +public: + explicit Clock_divided_i2s(Source source, Control control, Divider_i2s divider) + : Clock_divided(source), _control(control), _divider(divider) + { + } +}; + #endif /* __cplusplus */ diff -r 350ba4f76082 -r 85d8a7f95553 pkg/devices/lib/cpm/src/common.cc --- a/pkg/devices/lib/cpm/src/common.cc Sat Sep 16 17:56:49 2023 +0200 +++ b/pkg/devices/lib/cpm/src/common.cc Sun Sep 17 18:41:41 2023 +0200 @@ -117,14 +117,9 @@ uint32_t Source::get_frequency(Cpm_regs ®s) { - // Return the external clock frequency without any input clock. - - if (get_number() == 0) - return regs.exclk_freq; - // Clocks with one source yield that input frequency. - else if (get_number() == 1) + if (get_number() == 1) return regs.get_clock(get_input(0))->get_frequency(regs); // With multiple sources, obtain the selected source for the clock. @@ -146,8 +141,133 @@ +// Clock control. + +Control_base::~Control_base() +{ +} + +void +Control_base::change_disable(Cpm_regs ®s) +{ + (void) regs; +} + +void +Control_base::change_enable(Cpm_regs ®s) +{ + (void) regs; +} + +int +Control::have_clock(Cpm_regs ®s) +{ + if (_gate.is_defined()) + return !_gate.get_field(regs); + else + return true; +} + +void +Control::start_clock(Cpm_regs ®s) +{ + if (_gate.is_defined()) + _gate.set_field(regs, 0); +} + +void +Control::stop_clock(Cpm_regs ®s) +{ + if (_gate.is_defined()) + _gate.set_field(regs, 1); +} + +void +Control::wait_busy(Cpm_regs ®s) +{ + if (_busy.is_defined()) + while (_busy.get_field(regs)); +} + +void +Control::change_disable(Cpm_regs ®s) +{ + if (_change_enable.is_defined()) + _change_enable.set_field(regs, 0); +} + +void +Control::change_enable(Cpm_regs ®s) +{ + if (_change_enable.is_defined()) + _change_enable.set_field(regs, 1); +} + +// Undefined control. + +Control Control::undefined; + + + +// PLL-specific control. + +int +Control_pll::have_pll(Cpm_regs ®s) +{ + return _stable.get_field(regs); +} + +int +Control_pll::pll_enabled(Cpm_regs ®s) +{ + return _enable.get_field(regs); +} + +int +Control_pll::pll_bypassed(Cpm_regs ®s) +{ + return _bypass.get_field(regs); +} + +// Clock control. + +int +Control_pll::have_clock(Cpm_regs ®s) +{ + return have_pll(regs) && pll_enabled(regs); +} + +void +Control_pll::start_clock(Cpm_regs ®s) +{ + _enable.set_field(regs, 1); + while (!have_pll(regs)); +} + +void +Control_pll::stop_clock(Cpm_regs ®s) +{ + _enable.set_field(regs, 0); + while (have_pll(regs)); +} + +void +Control_pll::wait_busy(Cpm_regs ®s) +{ + if (pll_enabled(regs) && !pll_bypassed(regs)) + while (!have_pll(regs)); +} + + + // Clock dividers. +Divider_base::~Divider_base() +{ +} + + + uint32_t Divider::get_divider(Cpm_regs ®s) { @@ -158,10 +278,10 @@ } void -Divider::set_divider(Cpm_regs ®s, uint32_t division) +Divider::set_divider(Cpm_regs ®s, uint32_t divider) { if (_divider.is_defined()) - _divider.set_field(regs, division - 1); + _divider.set_field(regs, divider - 1); } // Output clock frequencies. @@ -180,129 +300,235 @@ // Feedback (13-bit) multiplier. -uint16_t +uint32_t Divider_pll::get_multiplier(Cpm_regs ®s) { return _multiplier.get_field(regs) + 1; } void -Divider_pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier) +Divider_pll::set_multiplier(Cpm_regs ®s, uint32_t multiplier) { _multiplier.set_field(regs, multiplier - 1); } // Input (6-bit) divider. -uint8_t -Divider_pll::get_input_division(Cpm_regs ®s) +uint32_t +Divider_pll::get_input_divider(Cpm_regs ®s) { - return _input_division.get_field(regs) + 1; + return _input_divider.get_field(regs) + 1; } void -Divider_pll::set_input_division(Cpm_regs ®s, uint8_t divider) +Divider_pll::set_input_divider(Cpm_regs ®s, uint32_t divider) { - _input_division.set_field(regs, divider - 1); + _input_divider.set_field(regs, divider - 1); } // Output (dual 3-bit) dividers. -uint8_t -Divider_pll::get_output_division(Cpm_regs ®s) +uint32_t +Divider_pll::get_output_divider(Cpm_regs ®s) { - uint8_t d0 = _output_division0.get_field(regs); - uint8_t d1 = _output_division1.get_field(regs); + uint32_t d0 = _output_divider0.get_field(regs); + uint32_t d1 = _output_divider1.get_field(regs); return d0 * d1; } void -Divider_pll::set_output_division(Cpm_regs ®s, uint8_t divider) +Divider_pll::set_output_divider(Cpm_regs ®s, uint32_t divider) { // Assert 1 as a minimum. // Divider 0 must be less than or equal to divider 1. - uint8_t d0 = (uint8_t) floor(sqrt(divider ? divider : 1)); - uint8_t d1 = divider / d0; + uint32_t d0 = (uint32_t) floor(sqrt(divider ? divider : 1)); + uint32_t d1 = divider / d0; - _output_division0.set_field(regs, d0); - _output_division1.set_field(regs, d1); + _output_divider0.set_field(regs, d0); + _output_divider1.set_field(regs, d1); } uint32_t Divider_pll::get_frequency(Cpm_regs ®s, uint32_t source_frequency) { return (source_frequency * get_multiplier(regs)) / - (get_input_division(regs) * get_output_division(regs)); + (get_input_divider(regs) * get_output_divider(regs)); } void -Divider_pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, - uint8_t in_divider, uint8_t out_divider) +Divider_pll::set_parameters(Cpm_regs ®s, uint32_t multiplier, + uint32_t in_divider, uint32_t out_divider) { set_multiplier(regs, multiplier); - set_input_division(regs, in_divider); - set_output_division(regs, out_divider); + set_input_divider(regs, in_divider); + set_output_divider(regs, out_divider); } -// Clock control. +// I2S clock divider. + +uint32_t +Divider_i2s::get_multiplier(Cpm_regs ®s) +{ + return _multiplier.get_field(regs); +} + +uint32_t +Divider_i2s::get_divider_D(Cpm_regs ®s) +{ + return _divider_D.get_field(regs); +} + +uint32_t +Divider_i2s::get_divider_N(Cpm_regs ®s) +{ + return _divider_N.get_field(regs); +} + +uint32_t +Divider_i2s::get_frequency(Cpm_regs ®s, uint32_t source_frequency) +{ + return (source_frequency * get_multiplier(regs)) / + (get_divider_N(regs) * get_divider_D(regs)); +} + +void +Divider_i2s::set_parameters(Cpm_regs ®s, uint32_t multiplier, + uint32_t divider_N, uint32_t divider_D) +{ + if (divider_N < 2 * multiplier) + return; + + _multiplier.set_field(regs, multiplier); + _divider_N.set_field(regs, divider_N); + _divider_D.set_field(regs, divider_D); +} + + + +// Clock interface. + +Clock_base::~Clock_base() +{ +} + + + +// Null clock. int -Clock_base::have_clock(Cpm_regs ®s) +Clock_null::have_clock(Cpm_regs ®s) +{ + (void) regs; + return false; +} + +void +Clock_null::start_clock(Cpm_regs ®s) +{ + (void) regs; +} + +void +Clock_null::stop_clock(Cpm_regs ®s) +{ + (void) regs; +} + +// Output clock frequencies. + +uint32_t +Clock_null::get_frequency(Cpm_regs ®s) +{ + (void) regs; + return 0; +} + + + +// Passive clock. + +int +Clock_passive::have_clock(Cpm_regs ®s) { (void) regs; return true; } void -Clock_base::start_clock(Cpm_regs ®s) +Clock_passive::start_clock(Cpm_regs ®s) { (void) regs; } void -Clock_base::stop_clock(Cpm_regs ®s) +Clock_passive::stop_clock(Cpm_regs ®s) { (void) regs; } -// Default divider. +// Output clock frequencies. uint32_t -Clock_base::get_divider(Cpm_regs ®s) +Clock_passive::get_frequency(Cpm_regs ®s) { - (void) regs; - return 1; + // NOTE: Return the external clock frequency. + + return regs.exclk_freq; +} + + + +// Active clock interface. + +Clock_active::~Clock_active() +{ +} + +// Clock control. + +int +Clock_active::have_clock(Cpm_regs ®s) +{ + return _get_control().have_clock(regs); } void -Clock_base::set_divider(Cpm_regs ®s, uint32_t division) +Clock_active::start_clock(Cpm_regs ®s) { - (void) regs; - (void) division; + _get_control().start_clock(regs); +} + +void +Clock_active::stop_clock(Cpm_regs ®s) +{ + _get_control().stop_clock(regs); } // Clock sources. uint8_t -Clock_base::get_source(Cpm_regs ®s) +Clock_active::get_source(Cpm_regs ®s) { return _source.get_source(regs); } void -Clock_base::set_source(Cpm_regs ®s, uint8_t source) +Clock_active::set_source(Cpm_regs ®s, uint8_t source) { + _get_control().change_enable(regs); _source.set_source(regs, source); + _get_control().wait_busy(regs); + _get_control().change_disable(regs); } // Clock source frequencies. uint32_t -Clock_base::get_source_frequency(Cpm_regs ®s) +Clock_active::get_source_frequency(Cpm_regs ®s) { return _source.get_frequency(regs); } @@ -310,105 +536,83 @@ // Output clock frequencies. uint32_t -Clock_base::get_frequency(Cpm_regs ®s) +Clock_active::get_frequency(Cpm_regs ®s) { return get_source_frequency(regs); } -// PLL-specific control. - -int -Pll::have_pll(Cpm_regs ®s) -{ - return _stable.get_field(regs); -} +// Divided clock interface. -int -Pll::pll_enabled(Cpm_regs ®s) +Clock_divided::~Clock_divided() { - return _enable.get_field(regs); -} - -int -Pll::pll_bypassed(Cpm_regs ®s) -{ - return _bypass.get_field(regs); } -// Clock control. +// Output clock frequencies. -int -Pll::have_clock(Cpm_regs ®s) +uint32_t +Clock_divided::get_frequency(Cpm_regs ®s) { - return have_pll(regs) && pll_enabled(regs); + return _get_divider().get_frequency(regs, get_source_frequency(regs)); } -void -Pll::start_clock(Cpm_regs ®s) + + +// PLL boilerplate. + +Pll::~Pll() { - _enable.set_field(regs, 1); - while (!have_pll(regs)); -} - -void -Pll::stop_clock(Cpm_regs ®s) -{ - _enable.set_field(regs, 0); - while (have_pll(regs)); } // Feedback (13-bit) multiplier. -uint16_t +uint32_t Pll::get_multiplier(Cpm_regs ®s) { return _divider.get_multiplier(regs); } void -Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier) +Pll::set_multiplier(Cpm_regs ®s, uint32_t multiplier) { _divider.set_multiplier(regs, multiplier); } // Input (6-bit) divider. -uint8_t -Pll::get_input_division(Cpm_regs ®s) +uint32_t +Pll::get_input_divider(Cpm_regs ®s) { - return _divider.get_input_division(regs); + return _divider.get_input_divider(regs); } void -Pll::set_input_division(Cpm_regs ®s, uint8_t divider) +Pll::set_input_divider(Cpm_regs ®s, uint32_t divider) { - _divider.set_input_division(regs, divider); + _divider.set_input_divider(regs, divider); } // Output (dual 3-bit) dividers. -uint8_t -Pll::get_output_division(Cpm_regs ®s) +uint32_t +Pll::get_output_divider(Cpm_regs ®s) { - return _divider.get_output_division(regs); + return _divider.get_output_divider(regs); } void -Pll::set_output_division(Cpm_regs ®s, uint8_t divider) +Pll::set_output_divider(Cpm_regs ®s, uint32_t divider) { - _divider.set_output_division(regs, divider); + _divider.set_output_divider(regs, divider); } uint32_t Pll::get_frequency(Cpm_regs ®s) { - // Test for PLL enable and not PLL bypass. - - if (pll_enabled(regs)) + if (have_clock(regs)) { - if (!pll_bypassed(regs)) + if (!_control.pll_bypassed(regs)) return _divider.get_frequency(regs, get_source_frequency(regs)); else return get_source_frequency(regs); @@ -418,63 +622,15 @@ } void -Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, - uint8_t in_divider, uint8_t out_divider) +Pll::set_parameters(Cpm_regs ®s, uint32_t multiplier, + uint32_t in_divider, uint32_t out_divider) { - set_pll_parameters(regs, multiplier, in_divider, out_divider); - - if (pll_enabled(regs) && !pll_bypassed(regs)) - while (!have_pll(regs)); + set_parameters(regs, multiplier, in_divider, out_divider); + _control.wait_busy(regs); } -// Clock control. - -void -Clock::change_disable(Cpm_regs ®s) -{ - if (_change_enable.is_defined()) - _change_enable.set_field(regs, 0); -} - -void -Clock::change_enable(Cpm_regs ®s) -{ - if (_change_enable.is_defined()) - _change_enable.set_field(regs, 1); -} - -int -Clock::have_clock(Cpm_regs ®s) -{ - if (_gate.is_defined()) - return !_gate.get_field(regs); - else - return true; -} - -void -Clock::start_clock(Cpm_regs ®s) -{ - if (_gate.is_defined()) - _gate.set_field(regs, 0); -} - -void -Clock::stop_clock(Cpm_regs ®s) -{ - if (_gate.is_defined()) - _gate.set_field(regs, 1); -} - -void -Clock::wait_busy(Cpm_regs ®s) -{ - if (_busy.is_defined()) - while (_busy.get_field(regs)); -} - // Clock dividers. uint32_t @@ -484,27 +640,10 @@ } void -Clock::set_divider(Cpm_regs ®s, uint32_t division) -{ - change_enable(regs); - _divider.set_divider(regs, division); - wait_busy(regs); - change_disable(regs); -} - -void -Clock::set_source(Cpm_regs ®s, uint8_t source) +Clock::set_divider(Cpm_regs ®s, uint32_t divider) { - change_enable(regs); - Clock_base::set_source(regs, source); - wait_busy(regs); - change_disable(regs); + _control.change_enable(regs); + _divider.set_divider(regs, divider); + _control.wait_busy(regs); + _control.change_disable(regs); } - -// Output clock frequencies. - -uint32_t -Clock::get_frequency(Cpm_regs ®s) -{ - return _divider.get_frequency(regs, get_source_frequency(regs)); -} diff -r 350ba4f76082 -r 85d8a7f95553 pkg/devices/lib/cpm/src/x1600.cc --- a/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 17:56:49 2023 +0200 +++ b/pkg/devices/lib/cpm/src/x1600.cc Sun Sep 17 18:41:41 2023 +0200 @@ -40,8 +40,10 @@ Clock_status = 0x0d4, // CPCSR Divider_ddr = 0x02c, // DDRCDR Divider_mac = 0x054, // MACCDR - Divider0_i2s0 = 0x060, // I2SCDR - Divider1_i2s0 = 0x070, // I2S1CDR + Divider0_i2s0 = 0x060, // I2S0CDR + Divider1_i2s0 = 0x070, // I2S0CDR1 + Divider0_i2s1 = 0x07c, // I2S1CDR (from X2000 manual) + Divider1_i2s1 = 0x080, // I2S1CDR1 (from X2000 manual) Divider_lcd = 0x064, // LPCDR Divider_msc0 = 0x068, // MSC0CDR Divider_msc1 = 0x0a4, // MSC1CDR @@ -87,140 +89,146 @@ // Register field definitions. -Field Clock_source_main (Clock_control, 3, 30); // SEL_SRC (output to SCLK_A) -Field Clock_source_cpu (Clock_control, 3, 28); // SEL_CPLL (output to CCLK) -Field Clock_source_hclock0 (Clock_control, 3, 26); // SEL_H0PLL (output to AHB0) -Field Clock_source_hclock2 (Clock_control, 3, 24); // SEL_H2PLL (output to AHB2) -Field Clock_source_can0 (Divider_can0, 3, 30); // CA0CS -Field Clock_source_can1 (Divider_can1, 3, 30); // CA1CS -Field Clock_source_cdbus (Divider_cdbus, 3, 30); // CDCS -Field Clock_source_cim (Divider_cim, 3, 30); // CIMPCS -Field Clock_source_ddr (Divider_ddr, 3, 30); // DCS -Field Clock_source_i2s (Divider0_i2s0, 1, 31); // I2PCS -Field Clock_source_lcd (Divider_lcd, 3, 30); // LPCS -Field Clock_source_mac (Divider_mac, 3, 30); // MACPCS -Field Clock_source_msc0 (Divider_msc0, 3, 30); // MPCS -Field Clock_source_msc1 (Divider_msc1, 3, 30); // MPCS -Field Clock_source_pwm (Divider_pwm, 3, 30); // PWMPCS -Field Clock_source_sfc (Divider_sfc, 3, 30); // SFCS -Field Clock_source_ssi (Divider_ssi, 3, 30); // SPCS - -Field Clock_busy_cpu (Clock_status, 1, 0); -Field Clock_busy_ddr (Divider_ddr, 1, 28); -Field Clock_busy_mac (Divider_mac, 1, 28); -Field Clock_busy_lcd (Divider_lcd, 1, 28); -Field Clock_busy_msc0 (Divider_msc0, 1, 28); -Field Clock_busy_msc1 (Divider_msc1, 1, 28); -Field Clock_busy_sfc (Divider_sfc, 1, 28); -Field Clock_busy_ssi (Divider_ssi, 1, 28); -Field Clock_busy_cim (Divider_cim, 1, 28); -Field Clock_busy_pwm (Divider_pwm, 1, 28); -Field Clock_busy_can0 (Divider_can0, 1, 28); -Field Clock_busy_can1 (Divider_can1, 1, 28); -Field Clock_busy_cdbus (Divider_cdbus, 1, 28); +static Field Clock_source_main (Clock_control, 3, 30), // SEL_SRC (output to SCLK_A) + Clock_source_cpu (Clock_control, 3, 28), // SEL_CPLL (output to CCLK) + Clock_source_hclock0 (Clock_control, 3, 26), // SEL_H0PLL (output to AHB0) + Clock_source_hclock2 (Clock_control, 3, 24), // SEL_H2PLL (output to AHB2) + Clock_source_can0 (Divider_can0, 3, 30), // CA0CS + Clock_source_can1 (Divider_can1, 3, 30), // CA1CS + Clock_source_cdbus (Divider_cdbus, 3, 30), // CDCS + Clock_source_cim (Divider_cim, 3, 30), // CIMPCS + Clock_source_ddr (Divider_ddr, 3, 30), // DCS + Clock_source_i2s (Divider0_i2s0, 1, 31), // I2PCS + Clock_source_lcd (Divider_lcd, 3, 30), // LPCS + Clock_source_mac (Divider_mac, 3, 30), // MACPCS + Clock_source_msc0 (Divider_msc0, 3, 30), // MPCS + Clock_source_msc1 (Divider_msc1, 3, 30), // MPCS + Clock_source_pwm (Divider_pwm, 3, 30), // PWMPCS + Clock_source_sfc (Divider_sfc, 3, 30), // SFCS + Clock_source_ssi (Divider_ssi, 3, 30), // SPCS -Field Clock_change_enable_cpu (Clock_control, 1, 22); -Field Clock_change_enable_ahb0 (Clock_control, 1, 21); -Field Clock_change_enable_ahb2 (Clock_control, 1, 20); -Field Clock_change_enable_ddr (Divider_ddr, 1, 29); -Field Clock_change_enable_mac (Divider_mac, 1, 29); -Field Clock_change_enable_i2s (Divider0_i2s0, 1, 29); -Field Clock_change_enable_lcd (Divider_lcd, 1, 29); -Field Clock_change_enable_msc0 (Divider_msc0, 1, 29); -Field Clock_change_enable_msc1 (Divider_msc1, 1, 29); -Field Clock_change_enable_sfc (Divider_sfc, 1, 29); -Field Clock_change_enable_ssi (Divider_ssi, 1, 29); -Field Clock_change_enable_cim (Divider_cim, 1, 29); -Field Clock_change_enable_pwm (Divider_pwm, 1, 29); -Field Clock_change_enable_can0 (Divider_can0, 1, 29); -Field Clock_change_enable_can1 (Divider_can1, 1, 29); -Field Clock_change_enable_cdbus (Divider_cdbus, 1, 29); + Clock_busy_cpu (Clock_status, 1, 0), + Clock_busy_ddr (Divider_ddr, 1, 28), + Clock_busy_mac (Divider_mac, 1, 28), + Clock_busy_lcd (Divider_lcd, 1, 28), + Clock_busy_msc0 (Divider_msc0, 1, 28), + Clock_busy_msc1 (Divider_msc1, 1, 28), + Clock_busy_sfc (Divider_sfc, 1, 28), + Clock_busy_ssi (Divider_ssi, 1, 28), + Clock_busy_cim (Divider_cim, 1, 28), + Clock_busy_pwm (Divider_pwm, 1, 28), + Clock_busy_can0 (Divider_can0, 1, 28), + Clock_busy_can1 (Divider_can1, 1, 28), + Clock_busy_cdbus (Divider_cdbus, 1, 28), -Field Clock_divider_can0 (Divider_can0, 0xff, 0); // CAN0CDR -Field Clock_divider_can1 (Divider_can1, 0xff, 0); // CAN1CDR -Field Clock_divider_cdbus (Divider_cdbus, 0xff, 0); // CDBUSCDR -Field Clock_divider_cim (Divider_cim, 0xff, 0); // CIMCDR -Field Clock_divider_cpu (Clock_control, 0x0f, 0); // CDIV -Field Clock_divider_ddr (Divider_ddr, 0x0f, 0); // DDRCDR -Field Clock_divider_hclock0 (Clock_control, 0x0f, 8); // H0DIV (fast AHB peripherals) -Field Clock_divider_hclock2 (Clock_control, 0x0f, 12); // H2DIV (fast AHB peripherals) -Field Clock_divider_l2cache (Clock_control, 0x0f, 4); // L2CDIV -Field Clock_divider_lcd (Divider_lcd, 0xff, 0); // LPCDR -Field Clock_divider_mac (Divider_mac, 0xff, 0); // MACCDR -Field Clock_divider_msc0 (Divider_msc0, 0xff, 0); // MSC0CDR -Field Clock_divider_msc1 (Divider_msc1, 0xff, 0); // MSC1CDR -Field Clock_divider_pclock (Clock_control, 0x0f, 16); // PDIV (slow APB peripherals) -Field Clock_divider_pwm (Divider_pwm, 0x0f, 0); // PWMCDR -Field Clock_divider_sfc (Divider_sfc, 0xff, 0); // SFCCDR -Field Clock_divider_ssi (Divider_ssi, 0xff, 0); // SSICDR + Clock_change_enable_cpu (Clock_control, 1, 22), + Clock_change_enable_ahb0 (Clock_control, 1, 21), + Clock_change_enable_ahb2 (Clock_control, 1, 20), + Clock_change_enable_ddr (Divider_ddr, 1, 29), + Clock_change_enable_mac (Divider_mac, 1, 29), + Clock_change_enable_i2s (Divider0_i2s0, 1, 29), + Clock_change_enable_lcd (Divider_lcd, 1, 29), + Clock_change_enable_msc0 (Divider_msc0, 1, 29), + Clock_change_enable_msc1 (Divider_msc1, 1, 29), + Clock_change_enable_sfc (Divider_sfc, 1, 29), + Clock_change_enable_ssi (Divider_ssi, 1, 29), + Clock_change_enable_cim (Divider_cim, 1, 29), + Clock_change_enable_pwm (Divider_pwm, 1, 29), + Clock_change_enable_can0 (Divider_can0, 1, 29), + Clock_change_enable_can1 (Divider_can1, 1, 29), + Clock_change_enable_cdbus (Divider_cdbus, 1, 29), -Field Clock_gate_main (Clock_control, 1, 23); // GATE_SCLKA -Field Clock_gate_ddr (Clock_gate0, 1, 31); // DDR -Field Clock_gate_ahb0 (Clock_gate0, 1, 29); // AHB0 -Field Clock_gate_apb0 (Clock_gate0, 1, 28); // APB0 -Field Clock_gate_rtc (Clock_gate0, 1, 27); // RTC -Field Clock_gate_aes (Clock_gate0, 1, 24); // AES -Field Clock_gate_lcd_pixel (Clock_gate0, 1, 23); // LCD -Field Clock_gate_cim (Clock_gate0, 1, 22); // CIM -Field Clock_gate_dma (Clock_gate0, 1, 21); // PDMA -Field Clock_gate_ost (Clock_gate0, 1, 20); // OST -Field Clock_gate_ssi0 (Clock_gate0, 1, 19); // SSI0 -Field Clock_gate_timer (Clock_gate0, 1, 18); // TCU -Field Clock_gate_dtrng (Clock_gate0, 1, 17); // DTRNG -Field Clock_gate_uart2 (Clock_gate0, 1, 16); // UART2 -Field Clock_gate_uart1 (Clock_gate0, 1, 15); // UART1 -Field Clock_gate_uart0 (Clock_gate0, 1, 14); // UART0 -Field Clock_gate_sadc (Clock_gate0, 1, 13); // SADC -Field Clock_gate_audio (Clock_gate0, 1, 11); // AUDIO -Field Clock_gate_ssi_slv (Clock_gate0, 1, 10); // SSI_SLV -Field Clock_gate_i2c1 (Clock_gate0, 1, 8); // I2C1 -Field Clock_gate_i2c0 (Clock_gate0, 1, 7); // I2C0 -Field Clock_gate_msc1 (Clock_gate0, 1, 5); // MSC1 -Field Clock_gate_msc0 (Clock_gate0, 1, 4); // MSC0 -Field Clock_gate_otg (Clock_gate0, 1, 3); // OTG -Field Clock_gate_sfc (Clock_gate0, 1, 2); // SFC -Field Clock_gate_efuse (Clock_gate0, 1, 1); // EFUSE -Field Clock_gate_nemc (Clock_gate0, 1, 0); // NEMC -Field Clock_gate_arb (Clock_gate1, 1, 30); // ARB -Field Clock_gate_mipi_csi (Clock_gate1, 1, 28); // MIPI_CSI -Field Clock_gate_intc (Clock_gate1, 1, 26); // INTC -Field Clock_gate_gmac0 (Clock_gate1, 1, 23); // GMAC0 -Field Clock_gate_uart3 (Clock_gate1, 1, 16); // UART3 -Field Clock_gate_i2s0_tx (Clock_gate1, 1, 9); // I2S0_dev_tclk -Field Clock_gate_i2s0_rx (Clock_gate1, 1, 8); // I2S0_dev_rclk -Field Clock_gate_hash (Clock_gate1, 1, 6); // HASH -Field Clock_gate_pwm (Clock_gate1, 1, 5); // PWM -Field Clock_gate_cdbus (Clock_gate1, 1, 2); // CDBUS -Field Clock_gate_can1 (Clock_gate1, 1, 1); // CAN1 -Field Clock_gate_can0 (Clock_gate1, 1, 0); // CAN0 + Clock_divider_can0 (Divider_can0, 0xff, 0), // CAN0CDR + Clock_divider_can1 (Divider_can1, 0xff, 0), // CAN1CDR + Clock_divider_cdbus (Divider_cdbus, 0xff, 0), // CDBUSCDR + Clock_divider_cim (Divider_cim, 0xff, 0), // CIMCDR + Clock_divider_cpu (Clock_control, 0x0f, 0), // CDIV + Clock_divider_ddr (Divider_ddr, 0x0f, 0), // DDRCDR + Clock_divider_hclock0 (Clock_control, 0x0f, 8), // H0DIV (fast AHB peripherals) + Clock_divider_hclock2 (Clock_control, 0x0f, 12), // H2DIV (fast AHB peripherals) + Clock_divider_i2s0_m (Divider0_i2s0, 0x1ff, 20), // I2SDIV_M + Clock_divider_i2s0_n (Divider0_i2s0, 0xfffff, 0), // I2SDIV_N + Clock_divider_i2s0_d (Divider1_i2s0, 0xfffff, 0), // I2SDIV_D + Clock_divider_i2s1_m (Divider0_i2s1, 0x1ff, 20), // I2SDIV_M + Clock_divider_i2s1_n (Divider0_i2s1, 0xfffff, 0), // I2SDIV_N + Clock_divider_i2s1_d (Divider1_i2s1, 0xfffff, 0), // I2SDIV_D + Clock_divider_l2cache (Clock_control, 0x0f, 4), // L2CDIV + Clock_divider_lcd (Divider_lcd, 0xff, 0), // LPCDR + Clock_divider_mac (Divider_mac, 0xff, 0), // MACCDR + Clock_divider_msc0 (Divider_msc0, 0xff, 0), // MSC0CDR + Clock_divider_msc1 (Divider_msc1, 0xff, 0), // MSC1CDR + Clock_divider_pclock (Clock_control, 0x0f, 16), // PDIV (slow APB peripherals) + Clock_divider_pwm (Divider_pwm, 0x0f, 0), // PWMCDR + Clock_divider_sfc (Divider_sfc, 0xff, 0), // SFCCDR + Clock_divider_ssi (Divider_ssi, 0xff, 0), // SSICDR -Field Pll_enable_A (Pll_control_A, 1, 0); // APLLEN -Field Pll_enable_E (Pll_control_E, 1, 0); // EPLLEN -Field Pll_enable_M (Pll_control_M, 1, 0); // MPLLEN - -Field Pll_stable_A (Pll_control_A, 1, 3); // APLL_ON -Field Pll_stable_E (Pll_control_E, 1, 3); // EPLL_ON -Field Pll_stable_M (Pll_control_M, 1, 3); // MPLL_ON - -Field Pll_bypass_A (Pll_control_A, 1, 30); // APLL_BP -Field Pll_bypass_E (Pll_control_E, 1, 26); // EPLL_BP -Field Pll_bypass_M (Pll_control_M, 1, 28); // MPLL_BP + Clock_gate_main (Clock_control, 1, 23), // GATE_SCLKA + Clock_gate_ddr (Clock_gate0, 1, 31), // DDR + Clock_gate_ahb0 (Clock_gate0, 1, 29), // AHB0 + Clock_gate_apb0 (Clock_gate0, 1, 28), // APB0 + Clock_gate_rtc (Clock_gate0, 1, 27), // RTC + Clock_gate_aes (Clock_gate0, 1, 24), // AES + Clock_gate_lcd_pixel (Clock_gate0, 1, 23), // LCD + Clock_gate_cim (Clock_gate0, 1, 22), // CIM + Clock_gate_dma (Clock_gate0, 1, 21), // PDMA + Clock_gate_ost (Clock_gate0, 1, 20), // OST + Clock_gate_ssi0 (Clock_gate0, 1, 19), // SSI0 + Clock_gate_timer (Clock_gate0, 1, 18), // TCU + Clock_gate_dtrng (Clock_gate0, 1, 17), // DTRNG + Clock_gate_uart2 (Clock_gate0, 1, 16), // UART2 + Clock_gate_uart1 (Clock_gate0, 1, 15), // UART1 + Clock_gate_uart0 (Clock_gate0, 1, 14), // UART0 + Clock_gate_sadc (Clock_gate0, 1, 13), // SADC + Clock_gate_audio (Clock_gate0, 1, 11), // AUDIO + Clock_gate_ssi_slv (Clock_gate0, 1, 10), // SSI_SLV + Clock_gate_i2c1 (Clock_gate0, 1, 8), // I2C1 + Clock_gate_i2c0 (Clock_gate0, 1, 7), // I2C0 + Clock_gate_msc1 (Clock_gate0, 1, 5), // MSC1 + Clock_gate_msc0 (Clock_gate0, 1, 4), // MSC0 + Clock_gate_otg (Clock_gate0, 1, 3), // OTG + Clock_gate_sfc (Clock_gate0, 1, 2), // SFC + Clock_gate_efuse (Clock_gate0, 1, 1), // EFUSE + Clock_gate_nemc (Clock_gate0, 1, 0), // NEMC + Clock_gate_arb (Clock_gate1, 1, 30), // ARB + Clock_gate_mipi_csi (Clock_gate1, 1, 28), // MIPI_CSI + Clock_gate_intc (Clock_gate1, 1, 26), // INTC + Clock_gate_gmac0 (Clock_gate1, 1, 23), // GMAC0 + Clock_gate_uart3 (Clock_gate1, 1, 16), // UART3 + Clock_gate_i2s0_tx (Clock_gate1, 1, 9), // I2S0_dev_tclk + Clock_gate_i2s0_rx (Clock_gate1, 1, 8), // I2S0_dev_rclk + Clock_gate_hash (Clock_gate1, 1, 6), // HASH + Clock_gate_pwm (Clock_gate1, 1, 5), // PWM + Clock_gate_cdbus (Clock_gate1, 1, 2), // CDBUS + Clock_gate_can1 (Clock_gate1, 1, 1), // CAN1 + Clock_gate_can0 (Clock_gate1, 1, 0), // CAN0 -Field Pll_multiplier_A (Pll_control_A, 0x1fff, 20); // APLLM -Field Pll_multiplier_E (Pll_control_E, 0x1fff, 20); // EPLLM -Field Pll_multiplier_M (Pll_control_M, 0x1fff, 20); // MPLLM + Pll_enable_A (Pll_control_A, 1, 0), // APLLEN + Pll_enable_E (Pll_control_E, 1, 0), // EPLLEN + Pll_enable_M (Pll_control_M, 1, 0), // MPLLEN -Field Pll_input_division_A (Pll_control_A, 0x3f, 14); // APLLN -Field Pll_input_division_E (Pll_control_E, 0x3f, 14); // EPLLN -Field Pll_input_division_M (Pll_control_M, 0x3f, 14); // MPLLN + Pll_stable_A (Pll_control_A, 1, 3), // APLL_ON + Pll_stable_E (Pll_control_E, 1, 3), // EPLL_ON + Pll_stable_M (Pll_control_M, 1, 3), // MPLL_ON + + Pll_bypass_A (Pll_control_A, 1, 30), // APLL_BP + Pll_bypass_E (Pll_control_E, 1, 26), // EPLL_BP + Pll_bypass_M (Pll_control_M, 1, 28), // MPLL_BP -Field Pll_output_division1_A (Pll_control_A, 0x07, 11); // APLLOD1 -Field Pll_output_division1_E (Pll_control_E, 0x07, 11); // EPLLOD1 -Field Pll_output_division1_M (Pll_control_M, 0x07, 11); // MPLLOD1 + Pll_multiplier_A (Pll_control_A, 0x1fff, 20), // APLLM + Pll_multiplier_E (Pll_control_E, 0x1fff, 20), // EPLLM + Pll_multiplier_M (Pll_control_M, 0x1fff, 20), // MPLLM + + Pll_input_division_A (Pll_control_A, 0x3f, 14), // APLLN + Pll_input_division_E (Pll_control_E, 0x3f, 14), // EPLLN + Pll_input_division_M (Pll_control_M, 0x3f, 14), // MPLLN -Field Pll_output_division0_A (Pll_control_A, 0x07, 8); // APLLOD0 -Field Pll_output_division0_E (Pll_control_E, 0x07, 8); // EPLLOD0 -Field Pll_output_division0_M (Pll_control_M, 0x07, 8); // MPLLOD0 + Pll_output_division1_A (Pll_control_A, 0x07, 11), // APLLOD1 + Pll_output_division1_E (Pll_control_E, 0x07, 11), // EPLLOD1 + Pll_output_division1_M (Pll_control_M, 0x07, 11), // MPLLOD1 + + Pll_output_division0_A (Pll_control_A, 0x07, 8), // APLLOD0 + Pll_output_division0_E (Pll_control_E, 0x07, 8), // EPLLOD0 + Pll_output_division0_M (Pll_control_M, 0x07, 8); // MPLLOD0 @@ -248,195 +256,127 @@ Clock clock_ahb2_apb(Source(mux_core, Clock_source_hclock2)); -Clock clock_aic_bitclk; - -Clock clock_aic_pclk; - Clock clock_can0(Source(mux_bus, Clock_source_can0), - Clock_gate_can0, - Clock_change_enable_can0, - Clock_busy_can0, + Control(Clock_gate_can0, Clock_change_enable_can0, Clock_busy_can0), Divider(Clock_divider_can0)); Clock clock_can1(Source(mux_bus, Clock_source_can1), - Clock_gate_can1, - Clock_change_enable_can1, - Clock_busy_can1, + Control(Clock_gate_can1, Clock_change_enable_can1, Clock_busy_can1), Divider(Clock_divider_can1)); Clock clock_cdbus(Source(mux_dev, Clock_source_cdbus), - Clock_gate_cdbus, - Clock_change_enable_cdbus, - Clock_busy_cdbus, + Control(Clock_gate_cdbus, Clock_change_enable_cdbus, Clock_busy_cdbus), Divider(Clock_divider_cdbus)); Clock clock_cim(Source(mux_dev, Clock_source_cim), - Clock_gate_cim, - Clock_change_enable_cim, - Clock_busy_cim, + Control(Clock_gate_cim, Clock_change_enable_cim, Clock_busy_cim), Divider(Clock_divider_cim)); Clock clock_cpu(Source(mux_core, Clock_source_cpu), - Field::undefined, - Clock_change_enable_cpu, - Clock_busy_cpu, + Control(Field::undefined, Clock_change_enable_cpu, Clock_busy_cpu), Divider(Clock_divider_cpu)); Clock clock_ddr(Source(mux_core, Clock_source_ddr), - Clock_gate_ddr, - Clock_change_enable_ddr, - Clock_busy_ddr, + Control(Clock_gate_ddr, Clock_change_enable_ddr, Clock_busy_ddr), Divider(Clock_divider_ddr)); -Clock clock_dma(Source(mux_pclock), Clock_gate_dma); +Clock clock_dma(Source(mux_pclock), Control(Clock_gate_dma), Divider::undefined); -Clock clock_emac; - -Clock clock_external; +Clock_passive clock_external; Clock clock_hclock0(Source(mux_core, Clock_source_hclock0), - Clock_gate_ahb0, - Clock_change_enable_ahb0, - Field::undefined, + Control(Clock_gate_ahb0, Clock_change_enable_ahb0), Divider(Clock_divider_hclock0)); Clock clock_hclock2(Source(mux_ahb2_apb), - Clock_gate_apb0, - Clock_change_enable_ahb2, - Field::undefined, + Control(Clock_gate_apb0, Clock_change_enable_ahb2), Divider(Clock_divider_hclock2)); -Clock clock_hdmi; - -Clock clock_i2c(Source(mux_pclock), Clock_gate_i2c0); +Clock clock_i2c(Source(mux_pclock), Control(Clock_gate_i2c0), Divider::undefined); -Clock clock_i2c0(Source(mux_pclock), Clock_gate_i2c0); +Clock clock_i2c0(Source(mux_pclock), Control(Clock_gate_i2c0), Divider::undefined); -Clock clock_i2c1(Source(mux_pclock), Clock_gate_i2c1); - -Clock clock_i2s; +Clock clock_i2c1(Source(mux_pclock), Control(Clock_gate_i2c1), Divider::undefined); -Clock clock_i2s0_rx(Source(mux_i2s, Clock_source_i2s), - Clock_gate_i2s0_rx, - Clock_change_enable_i2s); +Clock_divided_i2s clock_i2s0_rx(Source(mux_i2s, Clock_source_i2s), + Control(Clock_gate_i2s0_rx, Clock_change_enable_i2s), + Divider_i2s(Clock_divider_i2s0_m, Clock_divider_i2s0_n, + Clock_divider_i2s0_d)); -Clock clock_i2s0_tx(Source(mux_i2s, Clock_source_i2s), - Clock_gate_i2s0_tx, - Clock_change_enable_i2s); - -Clock clock_kbc; - -Clock clock_lcd; +Clock_divided_i2s clock_i2s0_tx(Source(mux_i2s, Clock_source_i2s), + Control(Clock_gate_i2s0_tx, Clock_change_enable_i2s), + Divider_i2s(Clock_divider_i2s1_m, Clock_divider_i2s1_n, + Clock_divider_i2s1_d)); Clock clock_lcd_pixel(Source(mux_dev, Clock_source_lcd), - Clock_gate_lcd_pixel, - Clock_change_enable_lcd, - Clock_busy_lcd, + Control(Clock_gate_lcd_pixel, Clock_change_enable_lcd, Clock_busy_lcd), Divider(Clock_divider_lcd)); Clock clock_mac(Source(mux_dev, Clock_source_mac), - Clock_gate_gmac0, - Clock_change_enable_mac, - Clock_busy_mac, + Control(Clock_gate_gmac0, Clock_change_enable_mac, Clock_busy_mac), Divider(Clock_divider_mac)); Clock clock_main(Source(mux_core, Clock_source_main), - Clock_gate_main); + Control(Clock_gate_main)); Clock clock_msc(Source(mux_dev, Clock_source_msc0), - Clock_gate_msc0, - Clock_change_enable_msc0, - Clock_busy_msc0, + Control(Clock_gate_msc0, Clock_change_enable_msc0, Clock_busy_msc0), Divider(Clock_divider_msc0)); Clock clock_msc0(Source(mux_dev, Clock_source_msc0), - Clock_gate_msc0, - Clock_change_enable_msc0, - Clock_busy_msc0, + Control(Clock_gate_msc0, Clock_change_enable_msc0, Clock_busy_msc0), Divider(Clock_divider_msc0)); Clock clock_msc1(Source(mux_dev, Clock_source_msc1), - Clock_gate_msc1, - Clock_change_enable_msc1, - Clock_busy_msc1, + Control(Clock_gate_msc1, Clock_change_enable_msc1, Clock_busy_msc1), Divider(Clock_divider_msc1)); -Clock clock_none; +Clock_null clock_none; Clock clock_pclock(Source(mux_ahb2_apb), - Clock_gate_apb0, - Field::undefined, - Field::undefined, + Control(Clock_gate_apb0, Field::undefined, Field::undefined), Divider(Clock_divider_pclock)); Pll clock_pll_A(Source(mux_external), - Pll_enable_A, Pll_stable_A, Pll_bypass_A, + Control_pll(Pll_enable_A, Pll_stable_A, Pll_bypass_A), Divider_pll(Pll_multiplier_A, Pll_input_division_A, Pll_output_division0_A, Pll_output_division1_A)); Pll clock_pll_E(Source(mux_external), - Pll_enable_E, Pll_stable_E, Pll_bypass_E, + Control_pll(Pll_enable_E, Pll_stable_E, Pll_bypass_E), Divider_pll(Pll_multiplier_E, Pll_input_division_E, Pll_output_division0_E, Pll_output_division1_E)); Pll clock_pll_M(Source(mux_external), - Pll_enable_M, Pll_stable_M, Pll_bypass_M, + Control_pll(Pll_enable_M, Pll_stable_M, Pll_bypass_M), Divider_pll(Pll_multiplier_M, Pll_input_division_M, Pll_output_division0_M, Pll_output_division1_M)); Clock clock_pwm(Source(mux_dev, Clock_source_pwm), - Clock_gate_pwm, - Clock_change_enable_pwm, - Clock_busy_pwm, + Control(Clock_gate_pwm, Clock_change_enable_pwm, Clock_busy_pwm), Divider(Clock_divider_pwm)); Clock clock_pwm0(Source(mux_dev, Clock_source_pwm), - Clock_gate_pwm, - Clock_change_enable_pwm, - Clock_busy_pwm, + Control(Clock_gate_pwm, Clock_change_enable_pwm, Clock_busy_pwm), Divider(Clock_divider_pwm)); -Clock clock_pwm1; - -Clock clock_scc; - Clock clock_sfc(Source(mux_dev, Clock_source_sfc), - Clock_gate_sfc, - Clock_change_enable_sfc, - Clock_busy_sfc, + Control(Clock_gate_sfc, Clock_change_enable_sfc, Clock_busy_sfc), Divider(Clock_divider_sfc)); -Clock clock_smb0; - -Clock clock_smb1; - -Clock clock_smb2; - -Clock clock_smb3; - -Clock clock_smb4; - Clock clock_ssi(Source(mux_dev, Clock_source_ssi), - Clock_gate_ssi0, - Clock_change_enable_ssi, - Clock_busy_ssi, + Control(Clock_gate_ssi0, Clock_change_enable_ssi, Clock_busy_ssi), Divider(Clock_divider_ssi)); -Clock clock_timer(Source(mux_pclock), Clock_gate_timer); - -Clock clock_uart0(Source(mux_external), Clock_gate_uart0); +Clock clock_timer(Source(mux_pclock), Control(Clock_gate_timer), Divider::undefined); -Clock clock_uart1(Source(mux_external), Clock_gate_uart1); - -Clock clock_uart2(Source(mux_external), Clock_gate_uart2); +Clock clock_uart0(Source(mux_external), Control(Clock_gate_uart0), Divider::undefined); -Clock clock_uart3(Source(mux_external), Clock_gate_uart3); - -Clock clock_udc; +Clock clock_uart1(Source(mux_external), Control(Clock_gate_uart1), Divider::undefined); -Clock clock_uhc; +Clock clock_uart2(Source(mux_external), Control(Clock_gate_uart2), Divider::undefined); -Clock clock_uprt; +Clock clock_uart3(Source(mux_external), Control(Clock_gate_uart3), Divider::undefined); @@ -444,8 +384,8 @@ static Clock_base *clocks[Clock_identifier_count] = { &clock_ahb2_apb, - &clock_aic_bitclk, - &clock_aic_pclk, + &clock_none, // Clock_aic_bitclk + &clock_none, // Clock_aic_pclk &clock_can0, &clock_can1, &clock_cdbus, @@ -453,19 +393,19 @@ &clock_cpu, &clock_ddr, &clock_dma, - &clock_emac, + &clock_none, // Clock_emac &clock_external, &clock_hclock0, &clock_hclock2, - &clock_hdmi, + &clock_none, // Clock_hdmi &clock_i2c, &clock_i2c0, &clock_i2c1, - &clock_i2s, + &clock_none, // Clock_i2s &clock_i2s0_rx, &clock_i2s0_tx, - &clock_kbc, - &clock_lcd, + &clock_none, // Clock_kbc + &clock_none, // Clock_lcd &clock_lcd_pixel, &clock_mac, &clock_main, @@ -479,23 +419,23 @@ &clock_pll_M, &clock_pwm, &clock_pwm0, - &clock_pwm1, - &clock_scc, + &clock_none, // Clock_pwm1 + &clock_none, // Clock_scc &clock_sfc, - &clock_smb0, - &clock_smb1, - &clock_smb2, - &clock_smb3, - &clock_smb4, + &clock_none, // Clock_smb0 + &clock_none, // Clock_smb1 + &clock_none, // Clock_smb2 + &clock_none, // Clock_smb3 + &clock_none, // Clock_smb4 &clock_ssi, &clock_timer, &clock_uart0, &clock_uart1, &clock_uart2, &clock_uart3, - &clock_udc, - &clock_uhc, - &clock_uprt, + &clock_none, // Clock_udc + &clock_none, // Clock_uhc + &clock_none, // Clock_uprt }; @@ -533,31 +473,52 @@ uint32_t Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) { - return clocks[clock]->get_divider(_cpm_regs); + Clock *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + return clk->get_divider(_cpm_regs); + else + return 1; } void Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) { - clocks[clock]->set_divider(_cpm_regs, division); + Clock *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + clk->set_divider(_cpm_regs, division); } uint8_t Cpm_x1600_chip::get_source(enum Clock_identifiers clock) { - return clocks[clock]->get_source(_cpm_regs); + Clock_active *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + return clk->get_source(_cpm_regs); + else + return 0; } void Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) { - clocks[clock]->set_source(_cpm_regs, source); + Clock_active *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + clk->set_source(_cpm_regs, source); } uint32_t Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) { - return clocks[clock]->get_source_frequency(_cpm_regs); + Clock_active *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + return clk->get_source_frequency(_cpm_regs); + else + return 0; } uint32_t @@ -579,12 +540,15 @@ // Switch to the MPLL and attempt to set the divider. - Clock_base *lcd = clocks[Clock_lcd_pixel]; + Clock *lcd = dynamic_cast(clocks[Clock_lcd_pixel]); Clock_base *pll = clocks[Clock_pll_M]; - lcd->set_source(_cpm_regs, Source_mME_pll_M); - pll->start_clock(_cpm_regs); - lcd->set_divider(_cpm_regs, lcd->get_source_frequency(_cpm_regs) / frequency); + if (lcd != NULL) + { + lcd->set_source(_cpm_regs, Source_mME_pll_M); + pll->start_clock(_cpm_regs); + lcd->set_divider(_cpm_regs, lcd->get_source_frequency(_cpm_regs) / frequency); + } break; } @@ -599,7 +563,8 @@ { Pll *pll = dynamic_cast(clocks[clock]); - pll->set_pll_parameters(_cpm_regs, multiplier, in_divider, out_divider); + if (pll != NULL) + pll->set_parameters(_cpm_regs, multiplier, in_divider, out_divider); }