# HG changeset patch # User Paul Boddie # Date 1694730703 -7200 # Node ID 1dc8b79654efb0a8c13dca159db9263b8c00b7f7 # Parent 8db009384d0bbedba72a83a89222d46f84b5964b Introduced more comprehensive clock abstractions. diff -r 8db009384d0b -r 1dc8b79654ef pkg/devices/lib/cpm/include/cpm-x1600.h --- a/pkg/devices/lib/cpm/include/cpm-x1600.h Thu Sep 14 18:51:41 2023 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-x1600.h Fri Sep 15 00:31:43 2023 +0200 @@ -32,6 +32,23 @@ #include +/* Register access type. */ + +class Cpm_regs +{ + Hw::Register_block<32> _regs; + +public: + uint32_t exclk_freq; + + explicit Cpm_regs(l4_addr_t addr, uint32_t exclk_freq); + + // Utility methods. + + uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); + void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); +}; + /* A simple abstraction for accessing the CPM registers. * A proper device could inherit from Hw::Device and use an * Int_property for _exclk_freq. */ @@ -41,39 +58,7 @@ private: Hw::Register_block<32> _regs; uint32_t _exclk_freq; - - // Utility methods. - - uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); - void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); - - // PLL control. - - int have_pll(uint32_t pll_reg); - int pll_enabled(uint32_t pll_reg); - int pll_bypassed(uint32_t pll_reg); - void pll_disable(uint32_t pll_reg); - void pll_enable(uint32_t pll_reg); - - // General frequency modifiers. - - uint16_t get_multiplier(uint32_t pll_reg); - void set_multiplier(uint32_t pll_reg, uint16_t multiplier); - uint8_t get_input_division(uint32_t pll_reg); - void set_input_division(uint32_t pll_reg, uint8_t divider); - uint8_t get_output_division(uint32_t pll_reg); - void set_output_division(uint32_t pll_reg, uint8_t divider); - - // Input frequencies. - - uint32_t get_pll_frequency(uint32_t pll_reg); - uint32_t get_input_frequency(enum Clock_input_identifiers clock); - - // Clock control. - - void change_disable(enum Clock_identifiers clock); - void change_enable(enum Clock_identifiers clock); - void wait_busy(enum Clock_identifiers clock); + Cpm_regs _cpm_regs; public: Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq); @@ -103,7 +88,8 @@ // Other operations. - void set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); + void set_pll_parameters(enum Clock_identifiers clock, uint16_t multiplier, + uint8_t in_divider, uint8_t out_divider); }; #endif /* __cplusplus */ diff -r 8db009384d0b -r 1dc8b79654ef pkg/devices/lib/cpm/src/x1600.cc --- a/pkg/devices/lib/cpm/src/x1600.cc Thu Sep 14 18:51:41 2023 +0200 +++ b/pkg/devices/lib/cpm/src/x1600.cc Fri Sep 15 00:31:43 2023 +0200 @@ -263,12 +263,107 @@ +// Common clock abstraction. + +class Clock_base +{ +protected: + + // Clock sources and source selection. + + int num_inputs; + enum Clock_identifiers *inputs; + uint32_t source_reg; + enum Clock_source_bits source_bit; + +public: + explicit Clock_base(int num_inputs = 0, + enum Clock_identifiers inputs[] = NULL, + uint32_t source_reg = Reg_undefined, + enum Clock_source_bits source_bit = Clock_source_undefined) + : num_inputs(num_inputs), inputs(inputs), + source_reg(source_reg), source_bit(source_bit) + { + } + + // Clock control. + + virtual int have_clock(Cpm_regs ®s); + virtual void start_clock(Cpm_regs ®s); + virtual void stop_clock(Cpm_regs ®s); + + // Clock divider. + + virtual uint32_t get_divider(Cpm_regs ®s); + virtual void set_divider(Cpm_regs ®s, uint32_t division); + + // Clock source. + + virtual uint8_t get_source(Cpm_regs ®s); + virtual void set_source(Cpm_regs ®s, uint8_t source); + + // Clock source frequency. + + virtual uint32_t get_source_frequency(Cpm_regs ®s); + + // Output frequency. + + virtual uint32_t get_frequency(Cpm_regs ®s); +}; + + + +// PLL descriptions. + +class Pll : public Clock_base +{ + uint32_t control_reg; + enum Pll_bypass_bits bypass_bit; + +public: + explicit Pll(int num_inputs, enum Clock_identifiers inputs[], + uint32_t control_reg, enum Pll_bypass_bits bypass_bit) + : Clock_base(num_inputs, inputs), control_reg(control_reg), bypass_bit(bypass_bit) + { + } + + // 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. -struct Clock_desc +class Clock : public Clock_base { - uint32_t source_reg; - enum Clock_source_bits source_bit; uint32_t gate_reg; enum Clock_gate_bits gate_bit; uint32_t change_enable_reg; @@ -278,322 +373,665 @@ uint32_t divider_reg; enum Clock_divider_bits divider_bit; uint32_t divider_mask; - int num_inputs; - enum Clock_identifiers inputs[4]; -}; -#define Clock_desc_undefined {Reg_undefined, Clock_source_undefined, \ - Reg_undefined, Clock_gate_undefined, \ - Reg_undefined, Clock_change_enable_undefined, \ - Reg_undefined, Clock_busy_undefined, \ - Reg_undefined, Clock_divider_undefined, 0, \ - 0, {}} - -static struct Clock_desc clock_desc[Clock_identifier_count] = { - - /* Clock_ahb2_apb */ {Clock_control, Clock_source_hclock2, - Reg_undefined, Clock_gate_undefined, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 3, {Clock_none, Clock_main, Clock_pll_M}}, - - /* Clock_aic_bitclk */ Clock_desc_undefined, - - /* Clock_aic_pclk */ Clock_desc_undefined, - - /* Clock_can0 */ {Can_divider0, Clock_source_can0, - Clock_gate1, Clock_gate_can0, - Can_divider0, Clock_change_enable_can0, - Can_divider0, Clock_busy_can0, - Can_divider0, Clock_divider_can0, 0xff, - 4, {Clock_main, Clock_pll_M, Clock_pll_E, Clock_external}}, - - /* Clock_can1 */ {Can_divider1, Clock_source_can1, - Clock_gate1, Clock_gate_can1, - Can_divider1, Clock_change_enable_can1, - Can_divider1, Clock_busy_can1, - Can_divider1, Clock_divider_can1, 0xff, - 4, {Clock_main, Clock_pll_M, Clock_pll_E, Clock_external}}, - - /* Clock_cdbus */ {Cdbus_divider, Clock_source_cdbus, - Clock_gate1, Clock_gate_cdbus, - Cdbus_divider, Clock_change_enable_cdbus, - Cdbus_divider, Clock_busy_cdbus, - Cdbus_divider, Clock_divider_cdbus, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_cim */ {Cim_divider, Clock_source_cim, - Clock_gate0, Clock_gate_cim, - Cim_divider, Clock_change_enable_cim, - Cim_divider, Clock_busy_cim, - Cim_divider, Clock_divider_cim, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_cpu */ {Clock_control, Clock_source_cpu, - Reg_undefined, Clock_gate_undefined, - Clock_control, Clock_change_enable_cpu, - Clock_status, Clock_busy_cpu, - Clock_control, Clock_divider_cpu, 0x0f, - 3, {Clock_none, Clock_main, Clock_pll_M}}, - - /* Clock_ddr */ {Ddr_divider, Clock_source_ddr, - Clock_gate0, Clock_gate_ddr, - Ddr_divider, Clock_change_enable_ddr, - Ddr_divider, Clock_busy_ddr, - Ddr_divider, Clock_divider_ddr, 0x0f, - 3, {Clock_none, Clock_main, Clock_pll_M}}, - - /* Clock_dma */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_dma, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_pclock}}, + // Clock control. - /* Clock_emac */ Clock_desc_undefined, - - /* Clock_external */ {Reg_undefined, Clock_source_undefined, - Reg_undefined, Clock_gate_undefined, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 0, {}}, - - /* Clock_hclock0 */ {Clock_control, Clock_source_hclock0, - Clock_gate0, Clock_gate_ahb0, - Clock_control, Clock_change_enable_ahb0, - Reg_undefined, Clock_busy_undefined, - Clock_control, Clock_divider_hclock0, 0x0f, - 3, {Clock_none, Clock_main, Clock_pll_M}}, - - /* Clock_hclock2 */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_apb0, - Clock_control, Clock_change_enable_ahb2, - Reg_undefined, Clock_busy_undefined, - Clock_control, Clock_divider_hclock2, 0x0f, - 1, {Clock_ahb2_apb}}, - - /* Clock_hdmi */ Clock_desc_undefined, - - /* Clock_i2c */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_i2c0, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_pclock}}, - - /* Clock_i2c0 */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_i2c0, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_pclock}}, - - /* Clock_i2c1 */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_i2c1, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_pclock}}, - - /* Clock_i2s */ Clock_desc_undefined, - - /* Clock_i2s0_rx */ {I2s_divider0, Clock_source_i2s, - Clock_gate1, Clock_gate_i2s0_rx, - I2s_divider0, Clock_change_enable_i2s, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, // NOTE: To define. - 2, {Clock_main, Clock_pll_E}}, - - /* Clock_i2s0_tx */ {I2s_divider0, Clock_source_i2s, - Clock_gate1, Clock_gate_i2s0_tx, - I2s_divider0, Clock_change_enable_i2s, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, // NOTE: To define. - 2, {Clock_main, Clock_pll_E}}, - - /* Clock_kbc */ Clock_desc_undefined, - - /* Clock_lcd */ Clock_desc_undefined, - - /* Clock_lcd_pixel */ {Lcd_divider, Clock_source_lcd, - Clock_gate0, Clock_gate_lcd_pixel, - Lcd_divider, Clock_change_enable_lcd, - Lcd_divider, Clock_busy_lcd, - Lcd_divider, Clock_divider_lcd, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, + void change_disable(Cpm_regs ®s); + void change_enable(Cpm_regs ®s); + void wait_busy(Cpm_regs ®s); - /* Clock_mac */ {Mac_divider, Clock_source_mac, - Clock_gate1, Clock_gate_gmac0, - Mac_divider, Clock_change_enable_mac, - Mac_divider, Clock_busy_mac, - Mac_divider, Clock_divider_mac, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_main */ {Clock_control, Clock_source_main, - Clock_control, Clock_gate_main, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 3, {Clock_none, Clock_external, Clock_pll_A}}, - - /* Clock_msc */ {Msc_divider0, Clock_source_msc0, - Clock_gate0, Clock_gate_msc0, - Msc_divider0, Clock_change_enable_msc0, - Msc_divider0, Clock_busy_msc0, - Msc_divider0, Clock_divider_msc0, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_msc0 */ {Msc_divider0, Clock_source_msc0, - Clock_gate0, Clock_gate_msc0, - Msc_divider0, Clock_change_enable_msc0, - Msc_divider0, Clock_busy_msc0, - Msc_divider0, Clock_divider_msc0, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_msc1 */ {Msc_divider1, Clock_source_msc1, - Clock_gate0, Clock_gate_msc1, - Msc_divider1, Clock_change_enable_msc1, - Msc_divider1, Clock_busy_msc1, - Msc_divider1, Clock_divider_msc1, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_none */ {Reg_undefined, Clock_source_undefined, - Reg_undefined, Clock_gate_undefined, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 0, {}}, - - /* Clock_pclock */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_apb0, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Clock_control, Clock_divider_pclock, 0x0f, - 1, {Clock_ahb2_apb}}, - - /* Clock_pll_A */ {Reg_undefined, Clock_source_undefined, - Reg_undefined, Clock_gate_undefined, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, - - /* Clock_pll_E */ {Reg_undefined, Clock_source_undefined, - Reg_undefined, Clock_gate_undefined, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, - - /* Clock_pll_M */ {Reg_undefined, Clock_source_undefined, - Reg_undefined, Clock_gate_undefined, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, +public: + explicit Clock(int num_inputs = 0, + enum Clock_identifiers inputs[] = NULL, + uint32_t source_reg = Reg_undefined, + enum Clock_source_bits source_bit = Clock_source_undefined, + uint32_t gate_reg = Reg_undefined, + enum Clock_gate_bits gate_bit = Clock_gate_undefined, + uint32_t change_enable_reg = Reg_undefined, + enum Clock_change_enable_bits change_enable_bit = Clock_change_enable_undefined, + uint32_t busy_reg = Reg_undefined, + enum Clock_busy_bits busy_bit = Clock_busy_undefined, + uint32_t divider_reg = Reg_undefined, + enum Clock_divider_bits divider_bit = Clock_divider_undefined, + uint32_t divider_mask = 0) + : Clock_base(num_inputs, inputs, source_reg, source_bit), + gate_reg(gate_reg), gate_bit(gate_bit), + change_enable_reg(change_enable_reg), change_enable_bit(change_enable_bit), + busy_reg(busy_reg), busy_bit(busy_bit), + divider_reg(divider_reg), divider_bit(divider_bit), divider_mask(divider_mask) + { + } - /* Clock_pwm */ {Pwm_divider, Clock_source_pwm, - Clock_gate1, Clock_gate_pwm, - Pwm_divider, Clock_change_enable_pwm, - Pwm_divider, Clock_busy_pwm, - Pwm_divider, Clock_divider_pwm, 0x0f, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_pwm0 */ {Pwm_divider, Clock_source_pwm, - Clock_gate1, Clock_gate_pwm, - Pwm_divider, Clock_change_enable_pwm, - Pwm_divider, Clock_busy_pwm, - Pwm_divider, Clock_divider_pwm, 0x0f, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_pwm1 */ Clock_desc_undefined, + // Clock control. - /* Clock_scc */ Clock_desc_undefined, - - /* Clock_sfc */ {Sfc_divider, Clock_source_sfc, - Clock_gate0, Clock_gate_sfc, - Sfc_divider, Clock_change_enable_sfc, - Sfc_divider, Clock_busy_sfc, - Sfc_divider, Clock_divider_sfc, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_smb0 */ Clock_desc_undefined, - - /* Clock_smb1 */ Clock_desc_undefined, - - /* Clock_smb2 */ Clock_desc_undefined, - - /* Clock_smb3 */ Clock_desc_undefined, - - /* Clock_smb4 */ Clock_desc_undefined, + int have_clock(Cpm_regs ®s); + void start_clock(Cpm_regs ®s); + void stop_clock(Cpm_regs ®s); - /* Clock_ssi */ {Ssi_divider, Clock_source_ssi, - Clock_gate0, Clock_gate_ssi0, - Ssi_divider, Clock_change_enable_ssi, - Ssi_divider, Clock_busy_ssi, - Ssi_divider, Clock_divider_ssi, 0xff, - 3, {Clock_main, Clock_pll_M, Clock_pll_E}}, - - /* Clock_timer */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_timer, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_pclock}}, - - /* Clock_uart0 */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_uart0, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, + // Clock divider. - /* Clock_uart1 */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_uart1, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, + uint32_t get_divider(Cpm_regs ®s); + void set_divider(Cpm_regs ®s, uint32_t division); - /* Clock_uart2 */ {Reg_undefined, Clock_source_undefined, - Clock_gate0, Clock_gate_uart2, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, + // Clock source. - /* Clock_uart3 */ {Reg_undefined, Clock_source_undefined, - Clock_gate1, Clock_gate_uart3, - Reg_undefined, Clock_change_enable_undefined, - Reg_undefined, Clock_busy_undefined, - Reg_undefined, Clock_divider_undefined, 0, - 1, {Clock_external}}, - - /* Clock_udc */ Clock_desc_undefined, - - /* Clock_uhc */ Clock_desc_undefined, - - /* Clock_uprt */ Clock_desc_undefined, + void set_source(Cpm_regs ®s, uint8_t source); }; -// Convenience functions. +// Clock instances. + +#define Clock_inputs(...) ((enum Clock_identifiers []) {__VA_ARGS__}) + +Clock clock_ahb2_apb(3, Clock_inputs(Clock_none, Clock_main, Clock_pll_M), + Clock_control, Clock_source_hclock2); + +Clock clock_aic_bitclk; + +Clock clock_aic_pclk; + +Clock clock_can0(4, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external), + Can_divider0, Clock_source_can0, + Clock_gate1, Clock_gate_can0, + Can_divider0, Clock_change_enable_can0, + Can_divider0, Clock_busy_can0, + Can_divider0, Clock_divider_can0, 0xff); + +Clock clock_can1(4, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external), + Can_divider1, Clock_source_can1, + Clock_gate1, Clock_gate_can1, + Can_divider1, Clock_change_enable_can1, + Can_divider1, Clock_busy_can1, + Can_divider1, Clock_divider_can1, 0xff); + +Clock clock_cdbus(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Cdbus_divider, Clock_source_cdbus, + Clock_gate1, Clock_gate_cdbus, + Cdbus_divider, Clock_change_enable_cdbus, + Cdbus_divider, Clock_busy_cdbus, + Cdbus_divider, Clock_divider_cdbus, 0xff); + +Clock clock_cim(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Cim_divider, Clock_source_cim, + Clock_gate0, Clock_gate_cim, + Cim_divider, Clock_change_enable_cim, + Cim_divider, Clock_busy_cim, + Cim_divider, Clock_divider_cim, 0xff); + +Clock clock_cpu(3, Clock_inputs(Clock_none, Clock_main, Clock_pll_M), + Clock_control, Clock_source_cpu, + Reg_undefined, Clock_gate_undefined, + Clock_control, Clock_change_enable_cpu, + Clock_status, Clock_busy_cpu, + Clock_control, Clock_divider_cpu, 0x0f); + +Clock clock_ddr(3, Clock_inputs(Clock_none, Clock_main, Clock_pll_M), + Ddr_divider, Clock_source_ddr, + Clock_gate0, Clock_gate_ddr, + Ddr_divider, Clock_change_enable_ddr, + Ddr_divider, Clock_busy_ddr, + Ddr_divider, Clock_divider_ddr, 0x0f); + +Clock clock_dma(1, Clock_inputs(Clock_pclock), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_dma); + +Clock clock_emac; + +Clock clock_external; + +Clock clock_hclock0(3, Clock_inputs(Clock_none, Clock_main, Clock_pll_M), + Clock_control, Clock_source_hclock0, + Clock_gate0, Clock_gate_ahb0, + Clock_control, Clock_change_enable_ahb0, + Reg_undefined, Clock_busy_undefined, + Clock_control, Clock_divider_hclock0, 0x0f); + +Clock clock_hclock2(1, Clock_inputs(Clock_ahb2_apb), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_apb0, + Clock_control, Clock_change_enable_ahb2, + Reg_undefined, Clock_busy_undefined, + Clock_control, Clock_divider_hclock2, 0x0f); + +Clock clock_hdmi; + +Clock clock_i2c(1, Clock_inputs(Clock_pclock), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_i2c0); + +Clock clock_i2c0(1, Clock_inputs(Clock_pclock), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_i2c0); + +Clock clock_i2c1(1, Clock_inputs(Clock_pclock), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_i2c1); + +Clock clock_i2s; + +Clock clock_i2s0_rx(2, Clock_inputs(Clock_main, Clock_pll_E), + I2s_divider0, Clock_source_i2s, + Clock_gate1, Clock_gate_i2s0_rx, + I2s_divider0, Clock_change_enable_i2s); + +Clock clock_i2s0_tx(2, Clock_inputs(Clock_main, Clock_pll_E), + I2s_divider0, Clock_source_i2s, + Clock_gate1, Clock_gate_i2s0_tx, + I2s_divider0, Clock_change_enable_i2s); + +Clock clock_kbc; + +Clock clock_lcd; + +Clock clock_lcd_pixel(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Lcd_divider, Clock_source_lcd, + Clock_gate0, Clock_gate_lcd_pixel, + Lcd_divider, Clock_change_enable_lcd, + Lcd_divider, Clock_busy_lcd, + Lcd_divider, Clock_divider_lcd, 0xff); + +Clock clock_mac(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Mac_divider, Clock_source_mac, + Clock_gate1, Clock_gate_gmac0, + Mac_divider, Clock_change_enable_mac, + Mac_divider, Clock_busy_mac, + Mac_divider, Clock_divider_mac, 0xff); + +Clock clock_main(3, Clock_inputs(Clock_none, Clock_external, Clock_pll_A), + Clock_control, Clock_source_main, + Clock_control, Clock_gate_main); + +Clock clock_msc(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Msc_divider0, Clock_source_msc0, + Clock_gate0, Clock_gate_msc0, + Msc_divider0, Clock_change_enable_msc0, + Msc_divider0, Clock_busy_msc0, + Msc_divider0, Clock_divider_msc0, 0xff); + +Clock clock_msc0(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Msc_divider0, Clock_source_msc0, + Clock_gate0, Clock_gate_msc0, + Msc_divider0, Clock_change_enable_msc0, + Msc_divider0, Clock_busy_msc0, + Msc_divider0, Clock_divider_msc0, 0xff); + +Clock clock_msc1(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Msc_divider1, Clock_source_msc1, + Clock_gate0, Clock_gate_msc1, + Msc_divider1, Clock_change_enable_msc1, + Msc_divider1, Clock_busy_msc1, + Msc_divider1, Clock_divider_msc1, 0xff); + +Clock clock_none; -static uint8_t get_clock_gate_bit(enum Clock_identifiers clock) +Clock clock_pclock(1, Clock_inputs(Clock_ahb2_apb), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_apb0, + Reg_undefined, Clock_change_enable_undefined, + Reg_undefined, Clock_busy_undefined, + Clock_control, Clock_divider_pclock, 0x0f); + +Pll clock_pll_A(1, Clock_inputs(Clock_external), + Pll_control_A, Pll_bypass_A); + +Pll clock_pll_E(1, Clock_inputs(Clock_external), + Pll_control_E, Pll_bypass_E); + +Pll clock_pll_M(1, Clock_inputs(Clock_external), + Pll_control_M, Pll_bypass_M); + +Clock clock_pwm(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Pwm_divider, Clock_source_pwm, + Clock_gate1, Clock_gate_pwm, + Pwm_divider, Clock_change_enable_pwm, + Pwm_divider, Clock_busy_pwm, + Pwm_divider, Clock_divider_pwm, 0x0f); + +Clock clock_pwm0(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Pwm_divider, Clock_source_pwm, + Clock_gate1, Clock_gate_pwm, + Pwm_divider, Clock_change_enable_pwm, + Pwm_divider, Clock_busy_pwm, + Pwm_divider, Clock_divider_pwm, 0x0f); + +Clock clock_pwm1; + +Clock clock_scc; + +Clock clock_sfc(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Sfc_divider, Clock_source_sfc, + Clock_gate0, Clock_gate_sfc, + Sfc_divider, Clock_change_enable_sfc, + Sfc_divider, Clock_busy_sfc, + Sfc_divider, Clock_divider_sfc, 0xff); + +Clock clock_smb0; + +Clock clock_smb1; + +Clock clock_smb2; + +Clock clock_smb3; + +Clock clock_smb4; + +Clock clock_ssi(3, Clock_inputs(Clock_main, Clock_pll_M, Clock_pll_E), + Ssi_divider, Clock_source_ssi, + Clock_gate0, Clock_gate_ssi0, + Ssi_divider, Clock_change_enable_ssi, + Ssi_divider, Clock_busy_ssi, + Ssi_divider, Clock_divider_ssi, 0xff); + +Clock clock_timer(1, Clock_inputs(Clock_pclock), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_timer); + +Clock clock_uart0(1, Clock_inputs(Clock_external), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_uart0); + +Clock clock_uart1(1, Clock_inputs(Clock_external), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_uart1); + +Clock clock_uart2(1, Clock_inputs(Clock_external), + Reg_undefined, Clock_source_undefined, + Clock_gate0, Clock_gate_uart2); + +Clock clock_uart3(1, Clock_inputs(Clock_external), + Reg_undefined, Clock_source_undefined, + Clock_gate1, Clock_gate_uart3); + +Clock clock_udc; + +Clock clock_uhc; + +Clock clock_uprt; + + + +// Clock register. + +static Clock_base *clocks[Clock_identifier_count] = { + &clock_ahb2_apb, + &clock_aic_bitclk, + &clock_aic_pclk, + &clock_can0, + &clock_can1, + &clock_cdbus, + &clock_cim, + &clock_cpu, + &clock_ddr, + &clock_dma, + &clock_emac, + &clock_external, + &clock_hclock0, + &clock_hclock2, + &clock_hdmi, + &clock_i2c, + &clock_i2c0, + &clock_i2c1, + &clock_i2s, + &clock_i2s0_rx, + &clock_i2s0_tx, + &clock_kbc, + &clock_lcd, + &clock_lcd_pixel, + &clock_mac, + &clock_main, + &clock_msc, + &clock_msc0, + &clock_msc1, + &clock_none, + &clock_pclock, + &clock_pll_A, + &clock_pll_E, + &clock_pll_M, + &clock_pwm, + &clock_pwm0, + &clock_pwm1, + &clock_scc, + &clock_sfc, + &clock_smb0, + &clock_smb1, + &clock_smb2, + &clock_smb3, + &clock_smb4, + &clock_ssi, + &clock_timer, + &clock_uart0, + &clock_uart1, + &clock_uart2, + &clock_uart3, + &clock_udc, + &clock_uhc, + &clock_uprt, +}; + + + +// Register access. + +Cpm_regs::Cpm_regs(l4_addr_t addr, uint32_t exclk_freq) +: exclk_freq(exclk_freq) { - enum Clock_gate_bits bit = clock_desc[clock].gate_bit; - - return bit != Clock_gate_undefined ? (uint8_t) bit : 0; + _regs = new Hw::Mmio_register_block<32>(addr); } -static uint32_t get_clock_gate_mask(enum Clock_identifiers clock) +// Utility methods. + +uint32_t +Cpm_regs::get_field(uint32_t reg, uint32_t mask, uint8_t shift) +{ + return (_regs[reg] & (mask << shift)) >> shift; +} + +void +Cpm_regs::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) +{ + _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); +} + + + +// Clock control. + +int +Clock_base::have_clock(Cpm_regs ®s) +{ + (void) regs; + return true; +} + +void +Clock_base::start_clock(Cpm_regs ®s) +{ + (void) regs; +} + +void +Clock_base::stop_clock(Cpm_regs ®s) +{ + (void) regs; +} + +// Default divider. + +uint32_t +Clock_base::get_divider(Cpm_regs ®s) +{ + (void) regs; + return 1; +} + +void +Clock_base::set_divider(Cpm_regs ®s, uint32_t division) +{ + (void) regs; + (void) division; +} + +// Clock sources. + +uint8_t +Clock_base::get_source(Cpm_regs ®s) +{ + if (source_bit != Clock_source_undefined) + return regs.get_field(source_reg, Source_mask, source_bit); + else + return 0; +} + +void +Clock_base::set_source(Cpm_regs ®s, uint8_t source) +{ + if (source_bit == Clock_source_undefined) + return; + + regs.set_field(source_reg, Source_mask, source_bit, source); +} + +// Clock source frequencies. + +uint32_t +Clock_base::get_source_frequency(Cpm_regs ®s) +{ + // Return the external clock frequency without any input clock. + + if (num_inputs == 0) + return regs.exclk_freq; + + // Clocks with one source yield that input frequency. + + else if (num_inputs == 1) + return clocks[inputs[0]]->get_frequency(regs); + + // With multiple sources, obtain the selected source for the clock. + + uint8_t source = get_source(regs); + + // Return the frequency of the source. + + if (source < num_inputs) + return clocks[inputs[source]]->get_frequency(regs); + else + return 0; +} + +// Output clock frequencies. + +uint32_t +Clock_base::get_frequency(Cpm_regs ®s) +{ + return get_source_frequency(regs) / get_divider(regs); +} + + + +// PLL-specific control. + +int +Pll::have_pll(Cpm_regs ®s) +{ + return regs.get_field(control_reg, 1, Pll_stable); +} + +int +Pll::pll_enabled(Cpm_regs ®s) +{ + return regs.get_field(control_reg, 1, Pll_enabled); +} + +int +Pll::pll_bypassed(Cpm_regs ®s) +{ + return regs.get_field(control_reg, 1, bypass_bit); +} + +// Clock control. + +int +Pll::have_clock(Cpm_regs ®s) +{ + return have_pll(regs) && pll_enabled(regs); +} + +void +Pll::start_clock(Cpm_regs ®s) +{ + regs.set_field(control_reg, 1, Pll_enabled, 1); + while (!have_pll(regs)); +} + +void +Pll::stop_clock(Cpm_regs ®s) { - enum Clock_gate_bits bit = clock_desc[clock].gate_bit; + regs.set_field(control_reg, 1, Pll_enabled, 0); + while (have_pll(regs)); +} + +// Feedback (13-bit) multiplier. + +uint16_t +Pll::get_multiplier(Cpm_regs ®s) +{ + return regs.get_field(control_reg, 0x1fff, Pll_multiplier) + 1; +} + +void +Pll::set_multiplier(Cpm_regs ®s, uint16_t multiplier) +{ + regs.set_field(control_reg, 0x1fff, Pll_multiplier, multiplier - 1); +} + +// Input (6-bit) divider. + +uint8_t +Pll::get_input_division(Cpm_regs ®s) +{ + return regs.get_field(control_reg, 0x3f, Pll_input_division) + 1; +} + +void +Pll::set_input_division(Cpm_regs ®s, uint8_t divider) +{ + regs.set_field(control_reg, 0x3f, Pll_input_division, divider - 1); +} + +// Output (dual 3-bit) dividers. + +uint8_t +Pll::get_output_division(Cpm_regs ®s) +{ + uint8_t d0 = regs.get_field(control_reg, 0x07, Pll_output_division0); + uint8_t d1 = regs.get_field(control_reg, 0x07, Pll_output_division1); + + return d0 * d1; +} + +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; + + regs.set_field(control_reg, 0x07, Pll_output_division0, d0); + regs.set_field(control_reg, 0x07, Pll_output_division1, d1); +} + +uint32_t +Pll::get_frequency(Cpm_regs ®s) +{ + // Test for PLL enable and not PLL bypass. + + if (pll_enabled(regs)) + { + if (!pll_bypassed(regs)) + return (get_source_frequency(regs) * get_multiplier(regs)) / + (get_input_division(regs) * get_output_division(regs)); + else + return get_source_frequency(regs); + } + else + return 0; +} + +void +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); - return bit != Clock_gate_undefined ? 1 : 0; + if (pll_enabled(regs) && !pll_bypassed(regs)) + while (!have_pll(regs)); +} + + + +// Clock control. + +void +Clock::change_disable(Cpm_regs ®s) +{ + if (change_enable_bit != Clock_change_enable_undefined) + regs.set_field(change_enable_reg, 1, change_enable_bit, 0); +} + +void +Clock::change_enable(Cpm_regs ®s) +{ + if (change_enable_bit != Clock_change_enable_undefined) + regs.set_field(change_enable_reg, 1, change_enable_bit, 1); +} + +int +Clock::have_clock(Cpm_regs ®s) +{ + if (gate_bit != Clock_gate_undefined) + return !regs.get_field(gate_reg, 1, gate_bit); + else + return true; +} + +void +Clock::start_clock(Cpm_regs ®s) +{ + if (gate_bit != Clock_gate_undefined) + regs.set_field(gate_reg, 1, gate_bit, 0); +} + +void +Clock::stop_clock(Cpm_regs ®s) +{ + if (gate_bit != Clock_gate_undefined) + regs.set_field(gate_reg, 1, gate_bit, 1); +} + +void +Clock::wait_busy(Cpm_regs ®s) +{ + if (busy_bit != Clock_busy_undefined) + while (regs.get_field(busy_reg, 1, busy_bit)); +} + + + +// Clock dividers. + +uint32_t +Clock::get_divider(Cpm_regs ®s) +{ + if (divider_bit != Clock_divider_undefined) + return regs.get_field(divider_reg, divider_mask, divider_bit) + 1; + else + return 1; +} + +void +Clock::set_divider(Cpm_regs ®s, uint32_t division) +{ + if (divider_bit == Clock_divider_undefined) + return; + + change_enable(regs); + regs.set_field(divider_reg, divider_mask, divider_bit, division - 1); + wait_busy(regs); + change_disable(regs); +} + +void +Clock::set_source(Cpm_regs ®s, uint8_t source) +{ + change_enable(regs); + Clock_base::set_source(regs, source); + wait_busy(regs); + change_disable(regs); } @@ -603,316 +1041,65 @@ // definitions. Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq) -: _exclk_freq(exclk_freq) +: _cpm_regs(addr, exclk_freq) { - _regs = new Hw::Mmio_register_block<32>(addr); - // add_cid("cpm"); // add_cid("cpm-x1600"); - // register_property("exclk_freq", &_exclk_freq); -} - - - -// Utility methods. - -uint32_t -Cpm_x1600_chip::get_field(uint32_t reg, uint32_t mask, uint8_t shift) -{ - return (_regs[reg] & (mask << shift)) >> shift; -} - -void -Cpm_x1600_chip::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) -{ - _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); -} - - - -// Clock/timer control. - -void -Cpm_x1600_chip::change_disable(enum Clock_identifiers clock) -{ - enum Clock_change_enable_bits bit = clock_desc[clock].change_enable_bit; - - if (bit != Clock_change_enable_undefined) - set_field(clock_desc[clock].change_enable_reg, 1, bit, 0); -} - -void -Cpm_x1600_chip::change_enable(enum Clock_identifiers clock) -{ - enum Clock_change_enable_bits bit = clock_desc[clock].change_enable_bit; - - if (bit != Clock_change_enable_undefined) - set_field(clock_desc[clock].change_enable_reg, 1, bit, 1); + // register_property("exclk_freq", &exclk_freq); } int Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) { - if (clock_desc[clock].gate_bit != Clock_gate_undefined) - return !get_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), - get_clock_gate_bit(clock)); - else - return true; + return clocks[clock]->have_clock(_cpm_regs); } void Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) { - if (clock_desc[clock].gate_bit != Clock_gate_undefined) - set_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), - get_clock_gate_bit(clock), 0); + clocks[clock]->start_clock(_cpm_regs); } void Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) { - if (clock_desc[clock].gate_bit != Clock_gate_undefined) - set_field(clock_desc[clock].gate_reg, get_clock_gate_mask(clock), - get_clock_gate_bit(clock), 1); -} - -void -Cpm_x1600_chip::wait_busy(enum Clock_identifiers clock) -{ - enum Clock_busy_bits bit = clock_desc[clock].busy_bit; - - if (bit != Clock_busy_undefined) - while (get_field(clock_desc[clock].busy_reg, 1, bit)); -} - - - -// PLL control. - -// Return whether the PLL is stable. - -int -Cpm_x1600_chip::have_pll(uint32_t pll_reg) -{ - return get_field(pll_reg, 1, Pll_stable); -} - -int -Cpm_x1600_chip::pll_enabled(uint32_t pll_reg) -{ - return get_field(pll_reg, 1, Pll_enabled); -} - -int -Cpm_x1600_chip::pll_bypassed(uint32_t pll_reg) -{ - uint8_t bit; - unsigned mask = 1; - - switch (pll_reg) - { - case Pll_control_A: bit = Pll_bypass_A; break; - case Pll_control_M: bit = Pll_bypass_M; break; - case Pll_control_E: bit = Pll_bypass_E; break; - default: bit = 0; mask = 0; break; - } - - return get_field(Pll_control, mask, bit); -} - -void -Cpm_x1600_chip::pll_enable(uint32_t pll_reg) -{ - set_field(pll_reg, 1, Pll_enabled, 1); - while (!have_pll(pll_reg)); -} - -void -Cpm_x1600_chip::pll_disable(uint32_t pll_reg) -{ - set_field(pll_reg, 1, Pll_enabled, 0); - while (have_pll(pll_reg)); -} - -// Feedback (13-bit) multiplier. - -uint16_t -Cpm_x1600_chip::get_multiplier(uint32_t pll_reg) -{ - return get_field(pll_reg, 0x1fff, Pll_multiplier) + 1; + clocks[clock]->stop_clock(_cpm_regs); } -void -Cpm_x1600_chip::set_multiplier(uint32_t pll_reg, uint16_t multiplier) -{ - set_field(pll_reg, 0x1fff, Pll_multiplier, multiplier - 1); -} - -// Input (6-bit) divider. - -uint8_t -Cpm_x1600_chip::get_input_division(uint32_t pll_reg) -{ - return get_field(pll_reg, 0x3f, Pll_input_division) + 1; -} - -void -Cpm_x1600_chip::set_input_division(uint32_t pll_reg, uint8_t divider) -{ - set_field(pll_reg, 0x3f, Pll_input_division, divider - 1); -} - -// Output (dual 3-bit) dividers. - -uint8_t -Cpm_x1600_chip::get_output_division(uint32_t pll_reg) -{ - uint8_t d0 = get_field(pll_reg, 0x07, Pll_output_division0); - uint8_t d1 = get_field(pll_reg, 0x07, Pll_output_division1); - - return d0 * d1; -} - -void -Cpm_x1600_chip::set_output_division(uint32_t pll_reg, 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; - - set_field(pll_reg, 0x07, Pll_output_division0, d0); - set_field(pll_reg, 0x07, Pll_output_division1, d1); -} - -uint32_t -Cpm_x1600_chip::get_pll_frequency(uint32_t pll_reg) -{ - // Test for PLL enable and not PLL bypass. - - if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) - return (_exclk_freq * get_multiplier(pll_reg)) / - (get_input_division(pll_reg) * get_output_division(pll_reg)); - else - return _exclk_freq; -} - -void -Cpm_x1600_chip::set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) -{ - set_multiplier(pll_reg, multiplier); - set_input_division(pll_reg, in_divider); - set_output_division(pll_reg, out_divider); - - if (pll_enabled(pll_reg) && !pll_bypassed(pll_reg)) - while (!have_pll(pll_reg)); -} - - - -// Clock dividers. - uint32_t Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) { - if (clock_desc[clock].divider_bit != Clock_divider_undefined) - return get_field(clock_desc[clock].divider_reg, clock_desc[clock].divider_mask, - clock_desc[clock].divider_bit) + 1; - else - return 1; + return clocks[clock]->get_divider(_cpm_regs); } void Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) { - if (clock_desc[clock].divider_bit == Clock_divider_undefined) - return; - - change_enable(clock); - set_field(clock_desc[clock].divider_reg, clock_desc[clock].divider_mask, - clock_desc[clock].divider_bit, division - 1); - wait_busy(clock); - change_disable(clock); + clocks[clock]->set_divider(_cpm_regs, division); } - - -// Clock sources. - uint8_t Cpm_x1600_chip::get_source(enum Clock_identifiers clock) { - if (clock_desc[clock].source_bit != Clock_source_undefined) - return get_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit); - else - return 0; + return clocks[clock]->get_source(_cpm_regs); } void Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) { - if (clock_desc[clock].source_bit == Clock_source_undefined) - return; - - change_enable(clock); - set_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit, source); - wait_busy(clock); - change_disable(clock); + clocks[clock]->set_source(_cpm_regs, source); } - - -// Clock source frequencies. - uint32_t Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) { - struct Clock_desc desc = clock_desc[clock]; - - if (desc.num_inputs == 0) - { - switch (clock) - { - case Clock_external: return _exclk_freq; - default: return 0; - } - } - - // Clocks with one source yield that input frequency, although PLLs are - // handled specially. - - else if (desc.num_inputs == 1) - { - switch (clock) - { - case Clock_pll_A: return get_pll_frequency(Pll_control_A); - case Clock_pll_E: return get_pll_frequency(Pll_control_E); - case Clock_pll_M: return get_pll_frequency(Pll_control_M); - default: return get_frequency(desc.inputs[0]); - } - } - - // With multiple sources, obtain the selected source for the clock. - - uint8_t source = get_source(clock); - - // Return the frequency of the source. - - if (source < desc.num_inputs) - return get_frequency(desc.inputs[source]); - else - return 0; + return clocks[clock]->get_source_frequency(_cpm_regs); } - - -// Output clock frequencies. - uint32_t Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) { - return get_source_frequency(clock) / get_divider(clock); + return clocks[clock]->get_frequency(_cpm_regs); } void @@ -924,19 +1111,33 @@ // EPLL). case Clock_lcd_pixel: + { // Switch to the MPLL and attempt to set the divider. - set_source(Clock_lcd_pixel, Source_mME_pll_M); - pll_enable(Pll_control_M); - set_divider(Clock_lcd_pixel, get_source_frequency(clock) / frequency); + Clock_base *lcd = 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); break; + } default: break; } } +void +Cpm_x1600_chip::set_pll_parameters(enum Clock_identifiers clock, uint16_t multiplier, + uint8_t in_divider, uint8_t out_divider) +{ + Pll *pll = dynamic_cast(clocks[clock]); + + pll->set_pll_parameters(_cpm_regs, multiplier, in_divider, out_divider); +} + // C language interface functions. @@ -968,8 +1169,6 @@ static_cast(cpm)->stop_clock(clock); } - - uint32_t x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock) { @@ -982,8 +1181,6 @@ return static_cast(cpm)->set_divider(clock, divider); } - - uint8_t x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) { @@ -996,16 +1193,12 @@ static_cast(cpm)->set_source(clock, source); } - - uint32_t x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) { return static_cast(cpm)->get_source_frequency(clock); } - - uint32_t x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) { @@ -1018,10 +1211,8 @@ static_cast(cpm)->set_frequency(clock, frequency); } - - void x1600_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider) { - static_cast(cpm)->set_pll_parameters(Pll_control_M, multiplier, in_divider, out_divider); + static_cast(cpm)->set_pll_parameters(Clock_pll_M, multiplier, in_divider, out_divider); }