# HG changeset patch # User Paul Boddie # Date 1695163077 -7200 # Node ID e4d286a20f68dc483a201680f461ae7efc0dd72d # Parent 0de8477d181b94dd4a0c2a2969620abd2b59d452 Rationalised X1600 clocks, added various operations, enhanced I2S divider functionality based on various observations and the documentation. diff -r 0de8477d181b -r e4d286a20f68 pkg/devices/include/clocks.h --- a/pkg/devices/include/clocks.h Mon Sep 18 16:40:15 2023 +0200 +++ b/pkg/devices/include/clocks.h Wed Sep 20 00:37:57 2023 +0200 @@ -27,7 +27,6 @@ enum Clock_identifiers { - Clock_ahb2_apb, Clock_aic_bitclk, Clock_aic_pclk, Clock_can0, @@ -53,10 +52,12 @@ Clock_lcd_pixel, Clock_mac, Clock_main, + Clock_mipi_csi, Clock_msc, Clock_msc0, Clock_msc1, Clock_none, + Clock_otg, Clock_pclock, Clock_pll_A, Clock_pll_E, diff -r 0de8477d181b -r e4d286a20f68 pkg/devices/lib/cpm/include/cpm-common.h --- a/pkg/devices/lib/cpm/include/cpm-common.h Mon Sep 18 16:40:15 2023 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-common.h Wed Sep 20 00:37:57 2023 +0200 @@ -149,6 +149,8 @@ uint8_t get_source(Cpm_regs ®s); void set_source(Cpm_regs ®s, uint8_t source); + enum Clock_identifiers get_source_clock(Cpm_regs ®s); + void set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock); // Clock source frequency. @@ -252,7 +254,7 @@ virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]) = 0; - virtual void set_parameters(Cpm_regs ®s, uint32_t parameters[]) = 0; + virtual int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) = 0; }; @@ -286,7 +288,7 @@ // Other operations. int get_parameters(Cpm_regs ®s, uint32_t parameters[]); - void set_parameters(Cpm_regs ®s, uint32_t parameters[]); + int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); }; @@ -321,7 +323,7 @@ // Other operations. int get_parameters(Cpm_regs ®s, uint32_t parameters[]); - void set_parameters(Cpm_regs ®s, uint32_t parameters[]); + int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); }; @@ -330,7 +332,7 @@ class Divider_i2s : public Divider_base { - Field _multiplier, _divider_N, _divider_D; + Field _multiplier, _divider_N, _divider_D, _auto_N, _auto_D; // General frequency modifiers. @@ -339,10 +341,10 @@ uint32_t get_divider_D(Cpm_regs ®s); public: - explicit Divider_i2s(Field multiplier, Field divider_N, - Field divider_D) - : _multiplier(multiplier), _divider_N(divider_N), - _divider_D(divider_D) + explicit Divider_i2s(Field multiplier, Field divider_N, Field divider_D, + Field auto_N, Field auto_D) + : _multiplier(multiplier), _divider_N(divider_N), _divider_D(divider_D), + _auto_N(auto_N), _auto_D(auto_D) { } @@ -354,7 +356,7 @@ int get_parameters(Cpm_regs ®s, uint32_t parameters[]); - void set_parameters(Cpm_regs ®s, uint32_t parameters[]); + int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); }; @@ -456,6 +458,8 @@ virtual uint8_t get_source(Cpm_regs ®s); virtual void set_source(Cpm_regs ®s, uint8_t source); + enum Clock_identifiers get_source_clock(Cpm_regs ®s); + void set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock); // Clock source frequency. @@ -484,7 +488,7 @@ virtual ~Clock_divided_base(); virtual int get_parameters(Cpm_regs ®s, uint32_t parameters[]); - virtual void set_parameters(Cpm_regs ®s, uint32_t parameters[]); + virtual int set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]); // Output frequency. diff -r 0de8477d181b -r e4d286a20f68 pkg/devices/lib/cpm/include/cpm-x1600.h --- a/pkg/devices/lib/cpm/include/cpm-x1600.h Mon Sep 18 16:40:15 2023 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-x1600.h Wed Sep 20 00:37:57 2023 +0200 @@ -55,12 +55,15 @@ // Clock dividers. int get_parameters(enum Clock_identifiers clock, uint32_t parameters[]); - void set_parameters(enum Clock_identifiers clock, uint32_t parameters[]); + int set_parameters(enum Clock_identifiers clock, int num_parameters, + uint32_t parameters[]); // Clock sources. uint8_t get_source(enum Clock_identifiers clock); void set_source(enum Clock_identifiers clock, uint8_t source); + enum Clock_identifiers get_source_clock(enum Clock_identifiers clock); + void set_source_clock(enum Clock_identifiers clock, enum Clock_identifiers source); // Source frequencies. @@ -88,11 +91,15 @@ void x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock); void x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); -int x1600_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]); -void x1600_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]); +int x1600_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, + uint32_t parameters[]); +int x1600_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, + int num_parameters, uint32_t parameters[]); uint8_t x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock); void x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source); +enum Clock_identifiers x1600_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock); +void x1600_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source); uint32_t x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock); diff -r 0de8477d181b -r e4d286a20f68 pkg/devices/lib/cpm/src/common.cc --- a/pkg/devices/lib/cpm/src/common.cc Mon Sep 18 16:40:15 2023 +0200 +++ b/pkg/devices/lib/cpm/src/common.cc Wed Sep 20 00:37:57 2023 +0200 @@ -23,6 +23,7 @@ #include "cpm-common.h" #include +#include @@ -112,22 +113,26 @@ _source.set_field(regs, source); } +enum Clock_identifiers +Source::get_source_clock(Cpm_regs ®s) +{ + return get_input(get_number() == 1 ? 0 : get_source(regs)); +} + +void +Source::set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock) +{ + for (int source = 0; source < _inputs.get_number(); source++) + if (get_input(source) == clock) + _source.set_field(regs, source); +} + // Clock source frequencies. uint32_t Source::get_frequency(Cpm_regs ®s) { - // Clocks with one source yield that input frequency. - - if (get_number() == 1) - return regs.get_clock(get_input(0))->get_frequency(regs); - - // With multiple sources, obtain the selected source for the clock. - - uint8_t source = get_source(regs); - enum Clock_identifiers input = get_input(source); - - // Return the frequency of the source. + enum Clock_identifiers input = get_source_clock(regs); if (input != Clock_undefined) return regs.get_clock(input)->get_frequency(regs); @@ -291,10 +296,16 @@ return 1; } -void -Divider::set_parameters(Cpm_regs ®s, uint32_t parameters[]) +int +Divider::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) { - set_divider(regs, parameters[0]); + if (num_parameters) + { + set_divider(regs, parameters[0]); + return 1; + } + + return 0; } @@ -367,12 +378,19 @@ return 3; } -void -Divider_pll::set_parameters(Cpm_regs ®s, uint32_t parameters[]) +int +Divider_pll::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) { - set_multiplier(regs, parameters[0]); - set_input_divider(regs, parameters[1]); - set_output_divider(regs, parameters[2]); + if (num_parameters > 2) + { + set_multiplier(regs, parameters[0]); + set_input_divider(regs, parameters[1]); + set_output_divider(regs, parameters[2]); + + return 3; + } + + return 0; } @@ -413,17 +431,43 @@ return 3; } -void -Divider_i2s::set_parameters(Cpm_regs ®s, uint32_t parameters[]) +int +Divider_i2s::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) { - // Test for N < 2M. + if (num_parameters == 1) + { + // Set automatic N and D value calculation if only one parameter is given. + + _auto_N.set_field(regs, 0); + _auto_D.set_field(regs, 0); + _multiplier.set_field(regs, parameters[0]); + + return 1; + } + else if (num_parameters > 1) + { + // Test for N < 2M. - if (parameters[1] < 2 * parameters[0] ) - return; + if (parameters[1] < 2 * parameters[0]) + return 0; + + // Set automatic D value calculation if only two parameters are given. + + _auto_N.set_field(regs, 1); + _auto_D.set_field(regs, (num_parameters == 2) ? 0 : 1); - _multiplier.set_field(regs, parameters[0]); - _divider_N.set_field(regs, parameters[1]); - _divider_D.set_field(regs, parameters[2]); + _multiplier.set_field(regs, parameters[0]); + _divider_N.set_field(regs, parameters[1]); + + // Set D explicitly if given. + + if (num_parameters > 2) + _divider_D.set_field(regs, parameters[2]); + + return num_parameters; + } + + return 0; } @@ -546,6 +590,18 @@ _get_control().change_disable(regs); } +enum Clock_identifiers +Clock_active::get_source_clock(Cpm_regs ®s) +{ + return _source.get_source_clock(regs); +} + +void +Clock_active::set_source_clock(Cpm_regs ®s, enum Clock_identifiers clock) +{ + _source.set_source_clock(regs, clock); +} + // Clock source frequencies. uint32_t @@ -584,13 +640,15 @@ return _get_divider().get_parameters(regs, parameters); } -void -Clock_divided_base::set_parameters(Cpm_regs ®s, uint32_t parameters[]) +int +Clock_divided_base::set_parameters(Cpm_regs ®s, int num_parameters, uint32_t parameters[]) { _get_control().change_enable(regs); - _get_divider().set_parameters(regs, parameters); + int n = _get_divider().set_parameters(regs, num_parameters, parameters); _get_control().wait_busy(regs); _get_control().change_disable(regs); + + return n; } @@ -604,13 +662,8 @@ uint32_t Pll::get_frequency(Cpm_regs ®s) { - if (have_clock(regs)) - { - if (!_control.pll_bypassed(regs)) - return _divider.get_frequency(regs, get_source_frequency(regs)); - else - return get_source_frequency(regs); - } + if (!_control.pll_bypassed(regs)) + return _divider.get_frequency(regs, get_source_frequency(regs)); else - return 0; + return get_source_frequency(regs); } diff -r 0de8477d181b -r e4d286a20f68 pkg/devices/lib/cpm/src/x1600.cc --- a/pkg/devices/lib/cpm/src/x1600.cc Mon Sep 18 16:40:15 2023 +0200 +++ b/pkg/devices/lib/cpm/src/x1600.cc Wed Sep 20 00:37:57 2023 +0200 @@ -98,7 +98,7 @@ 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_i2s (Divider0_i2s0, 1, 30), // 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 @@ -126,7 +126,7 @@ 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_i2s (Divider0_i2s0, 1, 29), // CE_I2S may not be change enable Clock_change_enable_lcd (Divider_lcd, 1, 29), Clock_change_enable_msc0 (Divider_msc0, 1, 29), Clock_change_enable_msc1 (Divider_msc1, 1, 29), @@ -162,6 +162,11 @@ Clock_divider_sfc (Divider_sfc, 0xff, 0), // SFCCDR Clock_divider_ssi (Divider_ssi, 0xff, 0), // SSICDR + Clock_divider_i2s0_n_auto (Divider1_i2s0, 1, 31), // I2S_NEN + Clock_divider_i2s0_d_auto (Divider1_i2s0, 1, 30), // I2S_DEN + Clock_divider_i2s1_n_auto (Divider1_i2s1, 1, 31), // I2S_NEN + Clock_divider_i2s1_d_auto (Divider1_i2s1, 1, 30), // I2S_DEN + 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 @@ -237,8 +242,9 @@ #define Clocks(...) ((enum Clock_identifiers []) {__VA_ARGS__}) static Mux mux_external (Clock_external), + mux_hclock0 (Clock_hclock0), + mux_hclock2 (Clock_hclock2), mux_pclock (Clock_pclock), - mux_ahb2_apb (Clock_ahb2_apb), mux_core (3, Clocks(Clock_none, Clock_main, Clock_pll_M)), mux_bus (4, Clocks(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external)), mux_dev (3, Clocks(Clock_main, Clock_pll_M, Clock_pll_E)), @@ -255,9 +261,7 @@ // Note the use of extra parentheses due to the annoying C++ "most vexing parse" // problem. See: https://en.wikipedia.org/wiki/Most_vexing_parse -static Clock clock_ahb2_apb(Source(mux_core, Clock_source_hclock2)), - - clock_dma((Source(mux_pclock)), (Control(Clock_gate_dma))), +static Clock clock_dma((Source(mux_hclock2)), (Control(Clock_gate_dma))), clock_i2c((Source(mux_pclock)), (Control(Clock_gate_i2c0))), @@ -267,6 +271,10 @@ clock_main(Source(mux_core, Clock_source_main), Control(Clock_gate_main)), + clock_mipi_csi((Source(mux_hclock0)), Control(Clock_gate_mipi_csi)), + + clock_otg((Source(mux_hclock2)), (Control(Clock_gate_otg))), + clock_timer((Source(mux_pclock)), (Control(Clock_gate_timer))), clock_uart0((Source(mux_external)), (Control(Clock_gate_uart0))), @@ -306,7 +314,7 @@ Control(Clock_gate_ahb0, Clock_change_enable_ahb0), Divider(Clock_divider_hclock0)), - clock_hclock2(Source(mux_ahb2_apb), + clock_hclock2(Source(mux_core, Clock_source_hclock2), Control(Clock_gate_apb0, Clock_change_enable_ahb2), Divider(Clock_divider_hclock2)), @@ -330,9 +338,9 @@ Control(Clock_gate_msc1, Clock_change_enable_msc1, Clock_busy_msc1), Divider(Clock_divider_msc1)), - clock_pclock((Source(mux_ahb2_apb)), - (Control(Clock_gate_apb0)), - (Divider(Clock_divider_pclock))), + clock_pclock(Source(mux_core, Clock_source_hclock2), + Control(Clock_gate_apb0, Clock_change_enable_ahb2), + Divider(Clock_divider_pclock)), clock_pwm(Source(mux_dev, Clock_source_pwm), Control(Clock_gate_pwm, Clock_change_enable_pwm, Clock_busy_pwm), @@ -352,14 +360,16 @@ static Clock_divided_i2s clock_i2s0_rx(Source(mux_i2s, Clock_source_i2s), - Control(Clock_gate_i2s0_rx, Clock_change_enable_i2s), + Control(Clock_gate_i2s0_rx), Divider_i2s(Clock_divider_i2s0_m, Clock_divider_i2s0_n, - Clock_divider_i2s0_d)), + Clock_divider_i2s0_d, Clock_divider_i2s0_n_auto, + Clock_divider_i2s0_d_auto)), clock_i2s0_tx(Source(mux_i2s, Clock_source_i2s), - Control(Clock_gate_i2s0_tx, Clock_change_enable_i2s), + Control(Clock_gate_i2s0_tx), Divider_i2s(Clock_divider_i2s1_m, Clock_divider_i2s1_n, - Clock_divider_i2s1_d)); + Clock_divider_i2s1_d, Clock_divider_i2s1_n_auto, + Clock_divider_i2s1_d_auto)); static Pll clock_pll_A(Source(mux_external), Control_pll(Pll_enable_A, Pll_stable_A, Pll_bypass_A), @@ -381,7 +391,6 @@ // Clock register. static Clock_base *clocks[Clock_identifier_count] = { - &clock_ahb2_apb, &clock_none, // Clock_aic_bitclk &clock_none, // Clock_aic_pclk &clock_can0, @@ -407,10 +416,12 @@ &clock_lcd_pixel, &clock_mac, &clock_main, + &clock_mipi_csi, &clock_msc, &clock_msc0, &clock_msc1, &clock_none, + &clock_otg, &clock_pclock, &clock_pll_A, &clock_pll_E, @@ -485,13 +496,15 @@ return 0; } -void -Cpm_x1600_chip::set_parameters(enum Clock_identifiers clock, uint32_t parameters[]) +int +Cpm_x1600_chip::set_parameters(enum Clock_identifiers clock, int num_parameters, uint32_t parameters[]) { Clock_divided_base *clk = dynamic_cast(clocks[clock]); if (clk != NULL) - clk->set_parameters(_cpm_regs, parameters); + return clk->set_parameters(_cpm_regs, num_parameters, parameters); + else + return 0; } uint8_t @@ -505,6 +518,26 @@ return 0; } +enum Clock_identifiers +Cpm_x1600_chip::get_source_clock(enum Clock_identifiers clock) +{ + Clock_active *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + return clk->get_source_clock(_cpm_regs); + else + return Clock_undefined; +} + +void +Cpm_x1600_chip::set_source_clock(enum Clock_identifiers clock, enum Clock_identifiers source) +{ + Clock_active *clk = dynamic_cast(clocks[clock]); + + if (clk != NULL) + clk->set_source_clock(_cpm_regs, source); +} + void Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) { @@ -553,7 +586,7 @@ lcd->set_source(_cpm_regs, Source_mME_pll_M); pll->start_clock(_cpm_regs); - lcd->set_parameters(_cpm_regs, parameters); + lcd->set_parameters(_cpm_regs, 1, parameters); } break; } @@ -606,10 +639,10 @@ return static_cast(cpm)->get_parameters(clock, parameters); } -void -x1600_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]) +int +x1600_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, int num_parameters, uint32_t parameters[]) { - return static_cast(cpm)->set_parameters(clock, parameters); + return static_cast(cpm)->set_parameters(clock, num_parameters, parameters); } uint8_t @@ -624,6 +657,18 @@ static_cast(cpm)->set_source(clock, source); } +enum Clock_identifiers +x1600_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock) +{ + return static_cast(cpm)->get_source_clock(clock); +} + +void +x1600_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source) +{ + static_cast(cpm)->set_source_clock(clock, source); +} + uint32_t x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) {