# HG changeset patch # User Paul Boddie # Date 1694879809 -7200 # Node ID 350ba4f76082a7394363fe690e2feafab2b6c9da # Parent fd56764dd69659409bc7643ca422c42b5087555e Introduced divider and frequency transformation abstractions. diff -r fd56764dd696 -r 350ba4f76082 pkg/devices/lib/cpm/include/cpm-common.h --- a/pkg/devices/lib/cpm/include/cpm-common.h Sat Sep 16 16:53:06 2023 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-common.h Sat Sep 16 17:56:49 2023 +0200 @@ -118,6 +118,8 @@ enum Clock_identifiers get_input(int num); }; + + class Source { Mux _inputs; @@ -157,6 +159,83 @@ +// Frequency transformation. + +class Transform +{ +public: + + // Output frequency. + + virtual uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency) = 0; +}; + + + +class Divider : public Transform +{ + Field _divider; + +public: + explicit Divider(Field divider) + : _divider(divider) + { + } + + explicit Divider() + : _divider(Field::undefined) + { + } + + // Clock divider. + + uint32_t get_divider(Cpm_regs ®s); + void set_divider(Cpm_regs ®s, uint32_t division); + + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency); + + // Undefined divider. + + static Divider undefined; +}; + + + +class Divider_pll : public Transform +{ + Field _multiplier, _input_division, _output_division0, _output_division1; + +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) + { + } + + // 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); + + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s, uint32_t source_frequency); + + // Other operations. + + void set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, + uint8_t in_divider, uint8_t out_divider); +}; + + + // Common clock abstraction. class Clock_base @@ -201,17 +280,15 @@ class Pll : public Clock_base { Field _enable, _stable, _bypass; - Field _multiplier, _input_division, _output_division0, _output_division1; + Divider_pll _divider; public: explicit Pll(Source source, Field enable, Field stable, Field bypass, - Field multiplier, Field input_division, - Field output_division0, Field output_division1) + Divider_pll divider) : Clock_base(source), _enable(enable), _stable(stable), _bypass(bypass), - _multiplier(multiplier), _input_division(input_division), - _output_division0(output_division0), _output_division1(output_division1) + _divider(divider) { } @@ -252,7 +329,8 @@ class Clock : public Clock_base { - Field _gate, _change_enable, _busy, _divider; + Field _gate, _change_enable, _busy; + Divider _divider; // Clock control. @@ -265,7 +343,7 @@ Field gate = Field::undefined, Field change_enable = Field::undefined, Field busy = Field::undefined, - Field divider = Field::undefined) + Divider divider = Divider::undefined) : Clock_base(source), _gate(gate), _change_enable(change_enable), _busy(busy), _divider(divider) { @@ -285,6 +363,10 @@ // Clock source. void set_source(Cpm_regs ®s, uint8_t source); + + // Output frequency. + + uint32_t get_frequency(Cpm_regs ®s); }; #endif /* __cplusplus */ diff -r fd56764dd696 -r 350ba4f76082 pkg/devices/lib/cpm/src/common.cc --- a/pkg/devices/lib/cpm/src/common.cc Sat Sep 16 16:53:06 2023 +0200 +++ b/pkg/devices/lib/cpm/src/common.cc Sat Sep 16 17:56:49 2023 +0200 @@ -146,6 +146,108 @@ +// Clock dividers. + +uint32_t +Divider::get_divider(Cpm_regs ®s) +{ + if (_divider.is_defined()) + return _divider.get_field(regs) + 1; + else + return 1; +} + +void +Divider::set_divider(Cpm_regs ®s, uint32_t division) +{ + if (_divider.is_defined()) + _divider.set_field(regs, division - 1); +} + +// Output clock frequencies. + +uint32_t +Divider::get_frequency(Cpm_regs ®s, uint32_t source_frequency) +{ + return source_frequency / get_divider(regs); +} + +// Undefined divider. + +Divider Divider::undefined; + + + +// Feedback (13-bit) multiplier. + +uint16_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) +{ + _multiplier.set_field(regs, multiplier - 1); +} + +// Input (6-bit) divider. + +uint8_t +Divider_pll::get_input_division(Cpm_regs ®s) +{ + return _input_division.get_field(regs) + 1; +} + +void +Divider_pll::set_input_division(Cpm_regs ®s, uint8_t divider) +{ + _input_division.set_field(regs, divider - 1); +} + +// Output (dual 3-bit) dividers. + +uint8_t +Divider_pll::get_output_division(Cpm_regs ®s) +{ + uint8_t d0 = _output_division0.get_field(regs); + uint8_t d1 = _output_division1.get_field(regs); + + return d0 * d1; +} + +void +Divider_pll::set_output_division(Cpm_regs ®s, uint8_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; + + _output_division0.set_field(regs, d0); + _output_division1.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)); +} + +void +Divider_pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, + uint8_t in_divider, uint8_t out_divider) +{ + set_multiplier(regs, multiplier); + set_input_division(regs, in_divider); + set_output_division(regs, out_divider); +} + + + // Clock control. int @@ -210,7 +312,7 @@ uint32_t Clock_base::get_frequency(Cpm_regs ®s) { - return get_source_frequency(regs) / get_divider(regs); + return get_source_frequency(regs); } @@ -262,13 +364,13 @@ uint16_t Pll::get_multiplier(Cpm_regs ®s) { - return _multiplier.get_field(regs) + 1; + return _divider.get_multiplier(regs); } void Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier) { - _multiplier.set_field(regs, multiplier - 1); + _divider.set_multiplier(regs, multiplier); } // Input (6-bit) divider. @@ -276,13 +378,13 @@ uint8_t Pll::get_input_division(Cpm_regs ®s) { - return _input_division.get_field(regs) + 1; + return _divider.get_input_division(regs); } void Pll::set_input_division(Cpm_regs ®s, uint8_t divider) { - _input_division.set_field(regs, divider - 1); + _divider.set_input_division(regs, divider); } // Output (dual 3-bit) dividers. @@ -290,23 +392,13 @@ uint8_t Pll::get_output_division(Cpm_regs ®s) { - uint8_t d0 = _output_division0.get_field(regs); - uint8_t d1 = _output_division1.get_field(regs); - - return d0 * d1; + return _divider.get_output_division(regs); } void Pll::set_output_division(Cpm_regs ®s, uint8_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; - - _output_division0.set_field(regs, d0); - _output_division1.set_field(regs, d1); + _divider.set_output_division(regs, divider); } uint32_t @@ -317,8 +409,7 @@ if (pll_enabled(regs)) { if (!pll_bypassed(regs)) - return (get_source_frequency(regs) * get_multiplier(regs)) / - (get_input_division(regs) * get_output_division(regs)); + return _divider.get_frequency(regs, get_source_frequency(regs)); else return get_source_frequency(regs); } @@ -327,11 +418,10 @@ } void -Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) +Pll::set_pll_parameters(Cpm_regs ®s, uint16_t multiplier, + uint8_t in_divider, uint8_t out_divider) { - set_multiplier(regs, multiplier); - set_input_division(regs, in_divider); - set_output_division(regs, out_divider); + set_pll_parameters(regs, multiplier, in_divider, out_divider); if (pll_enabled(regs) && !pll_bypassed(regs)) while (!have_pll(regs)); @@ -385,27 +475,19 @@ while (_busy.get_field(regs)); } - - // Clock dividers. uint32_t Clock::get_divider(Cpm_regs ®s) { - if (_divider.is_defined()) - return _divider.get_field(regs) + 1; - else - return 1; + return _divider.get_divider(regs); } void Clock::set_divider(Cpm_regs ®s, uint32_t division) { - if (!_divider.is_defined()) - return; - change_enable(regs); - _divider.set_field(regs, division - 1); + _divider.set_divider(regs, division); wait_busy(regs); change_disable(regs); } @@ -418,3 +500,11 @@ wait_busy(regs); 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 fd56764dd696 -r 350ba4f76082 pkg/devices/lib/cpm/src/x1600.cc --- a/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 16:53:06 2023 +0200 +++ b/pkg/devices/lib/cpm/src/x1600.cc Sat Sep 16 17:56:49 2023 +0200 @@ -256,37 +256,37 @@ Clock_gate_can0, Clock_change_enable_can0, Clock_busy_can0, - Clock_divider_can0); + Divider(Clock_divider_can0)); Clock clock_can1(Source(mux_bus, Clock_source_can1), Clock_gate_can1, Clock_change_enable_can1, Clock_busy_can1, - Clock_divider_can1); + Divider(Clock_divider_can1)); Clock clock_cdbus(Source(mux_dev, Clock_source_cdbus), Clock_gate_cdbus, Clock_change_enable_cdbus, Clock_busy_cdbus, - Clock_divider_cdbus); + Divider(Clock_divider_cdbus)); Clock clock_cim(Source(mux_dev, Clock_source_cim), Clock_gate_cim, Clock_change_enable_cim, Clock_busy_cim, - Clock_divider_cim); + Divider(Clock_divider_cim)); Clock clock_cpu(Source(mux_core, Clock_source_cpu), Field::undefined, Clock_change_enable_cpu, Clock_busy_cpu, - Clock_divider_cpu); + Divider(Clock_divider_cpu)); Clock clock_ddr(Source(mux_core, Clock_source_ddr), Clock_gate_ddr, Clock_change_enable_ddr, Clock_busy_ddr, - Clock_divider_ddr); + Divider(Clock_divider_ddr)); Clock clock_dma(Source(mux_pclock), Clock_gate_dma); @@ -298,13 +298,13 @@ Clock_gate_ahb0, Clock_change_enable_ahb0, Field::undefined, - Clock_divider_hclock0); + Divider(Clock_divider_hclock0)); Clock clock_hclock2(Source(mux_ahb2_apb), Clock_gate_apb0, Clock_change_enable_ahb2, Field::undefined, - Clock_divider_hclock2); + Divider(Clock_divider_hclock2)); Clock clock_hdmi; @@ -332,13 +332,13 @@ Clock_gate_lcd_pixel, Clock_change_enable_lcd, Clock_busy_lcd, - Clock_divider_lcd); + Divider(Clock_divider_lcd)); Clock clock_mac(Source(mux_dev, Clock_source_mac), Clock_gate_gmac0, Clock_change_enable_mac, Clock_busy_mac, - Clock_divider_mac); + Divider(Clock_divider_mac)); Clock clock_main(Source(mux_core, Clock_source_main), Clock_gate_main); @@ -347,19 +347,19 @@ Clock_gate_msc0, Clock_change_enable_msc0, Clock_busy_msc0, - Clock_divider_msc0); + Divider(Clock_divider_msc0)); Clock clock_msc0(Source(mux_dev, Clock_source_msc0), Clock_gate_msc0, Clock_change_enable_msc0, Clock_busy_msc0, - Clock_divider_msc0); + Divider(Clock_divider_msc0)); Clock clock_msc1(Source(mux_dev, Clock_source_msc1), Clock_gate_msc1, Clock_change_enable_msc1, Clock_busy_msc1, - Clock_divider_msc1); + Divider(Clock_divider_msc1)); Clock clock_none; @@ -367,34 +367,34 @@ Clock_gate_apb0, Field::undefined, Field::undefined, - Clock_divider_pclock); + Divider(Clock_divider_pclock)); Pll clock_pll_A(Source(mux_external), Pll_enable_A, Pll_stable_A, Pll_bypass_A, - Pll_multiplier_A, Pll_input_division_A, - Pll_output_division0_A, Pll_output_division1_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, - Pll_multiplier_E, Pll_input_division_E, - Pll_output_division0_E, Pll_output_division1_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, - Pll_multiplier_M, Pll_input_division_M, - Pll_output_division0_M, Pll_output_division1_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, - Clock_divider_pwm); + Divider(Clock_divider_pwm)); Clock clock_pwm0(Source(mux_dev, Clock_source_pwm), Clock_gate_pwm, Clock_change_enable_pwm, Clock_busy_pwm, - Clock_divider_pwm); + Divider(Clock_divider_pwm)); Clock clock_pwm1; @@ -404,7 +404,7 @@ Clock_gate_sfc, Clock_change_enable_sfc, Clock_busy_sfc, - Clock_divider_sfc); + Divider(Clock_divider_sfc)); Clock clock_smb0; @@ -420,7 +420,7 @@ Clock_gate_ssi0, Clock_change_enable_ssi, Clock_busy_ssi, - Clock_divider_ssi); + Divider(Clock_divider_ssi)); Clock clock_timer(Source(mux_pclock), Clock_gate_timer);