# HG changeset patch # User Paul Boddie # Date 1694643182 -7200 # Node ID 50a620eb5cd2097645910a7745f77aa853a686c8 # Parent 2eafeaedb1f7259bd2d8f5edb25306370f9fd338 Introduced clock definitions and simplified the CPM peripheral interface. diff -r 2eafeaedb1f7 -r 50a620eb5cd2 pkg/devices/include/clocks.h --- a/pkg/devices/include/clocks.h Thu Sep 14 00:11:14 2023 +0200 +++ b/pkg/devices/include/clocks.h Thu Sep 14 00:13:02 2023 +0200 @@ -33,9 +33,12 @@ Clock_can1, Clock_cdbus, Clock_cim, + Clock_cpu, Clock_ddr, Clock_dma, Clock_emac, + Clock_hclock0, + Clock_hclock2, Clock_hdmi, Clock_i2c, Clock_i2c0, @@ -47,9 +50,11 @@ Clock_lcd, Clock_lcd_pixel, Clock_mac, + Clock_main, Clock_msc, Clock_msc0, Clock_msc1, + Clock_pclock, Clock_pwm, Clock_pwm0, Clock_pwm1, @@ -70,7 +75,6 @@ Clock_uhc, Clock_uprt, Clock_identifier_count, /* not a clock: limit for array definition */ - Clock_identifier_any /* not a clock: indicates any clock */ }; // vim: tabstop=2 expandtab shiftwidth=2 diff -r 2eafeaedb1f7 -r 50a620eb5cd2 pkg/devices/lib/cpm/include/cpm-x1600.h --- a/pkg/devices/lib/cpm/include/cpm-x1600.h Thu Sep 14 00:11:14 2023 +0200 +++ b/pkg/devices/lib/cpm/include/cpm-x1600.h Thu Sep 14 00:13:02 2023 +0200 @@ -32,6 +32,20 @@ #include +enum Clock_input_identifiers +{ + Clock_input_ahb2_apb, + Clock_input_external, + Clock_input_main, + Clock_input_none, + Clock_input_pll_A, + Clock_input_pll_E, + Clock_input_pll_M, + Clock_input_identifier_count, /* not a clock: limit for array definition */ +}; + + + /* A simple abstraction for accessing the CPM registers. * A proper device could inherit from Hw::Device and use an * Int_property for _exclk_freq. */ @@ -46,7 +60,6 @@ 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); - uint8_t _get_divider(uint32_t reg, uint32_t mask, uint8_t shift); // PLL control. @@ -65,80 +78,46 @@ uint8_t get_output_division(uint32_t pll_reg); void set_output_division(uint32_t pll_reg, uint8_t divider); - // Clock dividers. - - void set_lcd_pixel_divider(uint8_t controller, uint16_t division); - // Input frequencies. uint32_t get_pll_frequency(uint32_t pll_reg); - - // Clock sources. - - void set_hclock2_source(uint8_t source); - void set_lcd_source(uint8_t controller, uint8_t source); + uint32_t get_input_frequency(enum Clock_input_identifiers clock); // Clock control. - uint32_t get_clock_gate_register(enum Clock_identifiers clock); - uint32_t get_clock_gate_value(enum Clock_identifiers clock); + void change_disable(enum Clock_identifiers clock); + void change_enable(enum Clock_identifiers clock); + void wait_busy(enum Clock_identifiers clock); public: - void set_pclock_source(uint8_t source); Cpm_x1600_chip(l4_addr_t addr, uint32_t exclk_freq); int have_clock(enum Clock_identifiers clock); void start_clock(enum Clock_identifiers clock); void stop_clock(enum Clock_identifiers clock); - // Clock divider values. + // Clock dividers. - uint8_t get_cpu_divider(); - uint8_t get_hclock0_divider(); - uint8_t get_hclock2_divider(); - uint8_t get_pclock_divider(); - uint8_t get_lcd_pixel_divider(uint8_t controller = 0); - uint8_t get_memory_divider(); + uint32_t get_divider(enum Clock_identifiers clock); + void set_divider(enum Clock_identifiers clock, uint32_t divider); - // Input frequencies. - - uint8_t get_main_source(); - uint32_t get_main_frequency(); - - // Clock sources, providing the input frequency. + // Clock sources. - uint8_t get_cpu_source(); - uint8_t get_hclock0_source(); - uint8_t get_hclock2_source(); - uint8_t get_lcd_source(uint8_t controller); - uint8_t get_lcd_source() { return get_lcd_source(0); } - uint8_t get_memory_source(); - uint8_t get_pclock_source(); + uint8_t get_source(enum Clock_identifiers clock); + void set_source(enum Clock_identifiers clock, uint8_t source); - uint32_t get_cpu_source_frequency(); - uint32_t get_hclock0_source_frequency(); - uint32_t get_hclock2_source_frequency(); - uint32_t get_lcd_source_frequency(uint8_t controller); - uint32_t get_lcd_source_frequency() { return get_lcd_source_frequency(0); } - uint32_t get_memory_source_frequency(); - uint32_t get_pclock_source_frequency(); - - // Final, calculated frequencies. + // Source frequencies. - uint32_t get_cpu_frequency(); - uint32_t get_hclock0_frequency(); - uint32_t get_hclock2_frequency(); - uint32_t get_memory_frequency(); - uint32_t get_pclock_frequency(); + uint32_t get_source_frequency(enum Clock_identifiers clock); - uint32_t get_apll_frequency(); - uint32_t get_epll_frequency(); - uint32_t get_mpll_frequency(); - - void set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); + // Output clock frequencies. uint32_t get_frequency(enum Clock_identifiers clock); void set_frequency(enum Clock_identifiers clock, uint32_t frequency); + + // Other operations. + + void set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); }; #endif /* __cplusplus */ @@ -155,39 +134,13 @@ void x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock); void x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock); -uint8_t x1600_cpm_get_cpu_divider(void *cpm); -uint8_t x1600_cpm_get_hclock0_divider(void *cpm); -uint8_t x1600_cpm_get_hclock2_divider(void *cpm); -uint8_t x1600_cpm_get_lcd_pixel_divider(void *cpm); -uint8_t x1600_cpm_get_memory_divider(void *cpm); -uint8_t x1600_cpm_get_pclock_divider(void *cpm); - -uint8_t x1600_cpm_get_hclock0_source(void *cpm); -uint8_t x1600_cpm_get_hclock2_source(void *cpm); -uint8_t x1600_cpm_get_lcd_source(void *cpm); -uint8_t x1600_cpm_get_memory_source(void *cpm); -uint8_t x1600_cpm_get_pclock_source(void *cpm); +uint32_t x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock); +void x1600_cpm_set_divider(void *cpm, enum Clock_identifiers clock, uint32_t divider); -uint32_t x1600_cpm_get_hclock0_source_frequency(void *cpm); -uint32_t x1600_cpm_get_hclock2_source_frequency(void *cpm); -uint32_t x1600_cpm_get_lcd_source_frequency(void *cpm); -uint32_t x1600_cpm_get_memory_source_frequency(void *cpm); -uint32_t x1600_cpm_get_pclock_source_frequency(void *cpm); - -void x1600_cpm_set_pclock_source(void *cpm, uint8_t source); +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); -uint8_t x1600_cpm_get_main_source(void *cpm); -uint32_t x1600_cpm_get_main_frequency(void *cpm); - -uint32_t x1600_cpm_get_cpu_frequency(void *cpm); -uint32_t x1600_cpm_get_hclock0_frequency(void *cpm); -uint32_t x1600_cpm_get_hclock2_frequency(void *cpm); -uint32_t x1600_cpm_get_memory_frequency(void *cpm); -uint32_t x1600_cpm_get_pclock_frequency(void *cpm); - -uint32_t x1600_cpm_get_apll_frequency(void *cpm); -uint32_t x1600_cpm_get_epll_frequency(void *cpm); -uint32_t x1600_cpm_get_mpll_frequency(void *cpm); +uint32_t x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock); uint32_t x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock); void x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint32_t frequency); diff -r 2eafeaedb1f7 -r 50a620eb5cd2 pkg/devices/lib/cpm/src/x1600.cc --- a/pkg/devices/lib/cpm/src/x1600.cc Thu Sep 14 00:11:14 2023 +0200 +++ b/pkg/devices/lib/cpm/src/x1600.cc Thu Sep 14 00:13:02 2023 +0200 @@ -24,9 +24,12 @@ #include #include "cpm-x1600.h" #include +#include +// Register locations. + enum Regs : unsigned { Clock_control = 0x000, // CPCCR @@ -67,21 +70,10 @@ Pll_fraction_A = 0x084, // CPAPACR Pll_fraction_M = 0x088, // CPMPACR Pll_fraction_E = 0x08c, // CPEPACR -}; - -enum Clock_bits : unsigned -{ - // Clock_control - Clock_gate_A = 23, // GATE_SCLKA - Clock_cpu_change_enable = 22, // CE_CPU - Clock_ahb0_change_enable = 21, // CE_AHB0 - Clock_ahb2_change_enable = 20, // CE_AHB2 - Clock_pclock_divider = 16, // PDIV (slow APB peripherals) - Clock_hclock2_divider = 12, // H2DIV (fast AHB peripherals) - Clock_hclock0_divider = 8, // H0DIV (fast AHB peripherals) - Clock_l2cache_divider = 4, // L2CDIV - Clock_cpu_divider = 0, // CDIV + // Special value + + Reg_undefined = 0xfff, }; enum Clock_source_bits : unsigned @@ -93,84 +85,44 @@ Clock_source_hclock0 = 26, // SEL_H0PLL (output to AHB0) Clock_source_hclock2 = 24, // SEL_H2PLL (output to AHB2) - // Ddr_divider - - Clock_source_ddr = 30, // DCS - - // I2s_divider0 - - Clock_source_i2s = 31, // I2PCS - - // Lcd_divider - - Clock_source_lcd = 30, // LPCS - - // Mac_divider - - Clock_source_mac = 30, // MACPCS - - // Msc_divider0, Msc_divider1 - - Clock_source_msc0 = 30, // MPCS - Clock_source_msc1 = 30, // MPCS - - // Sfc_divider - - Clock_source_sfc = 30, // SFCS - - // Ssi_divider - - Clock_source_ssi = 30, // SPCS - - // Cim_divider - - Clock_source_cim = 30, // CIMPCS - - // Pwm_divider - - Clock_source_pwm = 30, // PWMPCS - - // Can_divider0, Can_divider1 + // Divider registers Clock_source_can0 = 30, // CA0CS Clock_source_can1 = 30, // CA1CS + Clock_source_cdbus = 30, // CDCS + Clock_source_cim = 30, // CIMPCS + Clock_source_ddr = 30, // DCS + Clock_source_i2s = 31, // I2PCS + Clock_source_lcd = 30, // LPCS + Clock_source_mac = 30, // MACPCS + Clock_source_msc0 = 30, // MPCS + Clock_source_msc1 = 30, // MPCS + Clock_source_pwm = 30, // PWMPCS + Clock_source_sfc = 30, // SFCS + Clock_source_ssi = 30, // SPCS - // Cdbus_divider + // Special value - Clock_source_cdbus = 30, // CDCS + Clock_source_undefined = 32, }; -enum Clock_sources : unsigned +enum Clock_source_values : unsigned { - // Clock_source_main - - Source_external = 1, // EXCLK - Source_pll_A = 2, // APLL - - // Stoppable clock sources: - // Clock_source_cpu, Clock_source_hclock0, Clock_source_hclock2, - // Clock_source_ddr + Source_mME_main = 0, + Source_mME_pll_M = 1, + Source_mME_pll_E = 2, - Source_mux_stopped = 0, - Source_mux_main = 1, // SCLK_A - Source_mux_pll_M = 2, // MPLL + // Special value - // Unstoppable clock sources: - // Clock_source_mac, Clock_source_i2s, Clock_source_lcd, Clock_source_msc0, - // Clock_source_msc1, Clock_source_sfc, Clock_source_ssi, Clock_source_cim, - // Clock_source_pwm, Clock_source_can0, Clock_source_can1, Clock_source_cdbus - - Source_main = 0, // SCLK_A - Source_pll_M = 1, // MPLL - Source_pll_E = 2, // EPLL - - Source_i2s_pll_E = 1, // EPLL - - Source_can_external = 3, // EXCLK + Source_mask = 0x3, }; enum Clock_gate_bits : unsigned { + // Clock_control + + Clock_gate_main = 23, // GATE_SCLKA + // Clock_gate0 Clock_gate_ddr = 31, // DDR @@ -220,111 +172,74 @@ Clock_gate_undefined = 32, }; -// Clock gate register correspondences. +enum Clock_change_enable_bits : unsigned +{ + Clock_change_enable_cpu = 22, + Clock_change_enable_ahb0 = 21, + Clock_change_enable_ahb2 = 20, + Clock_change_enable_ddr = 29, + Clock_change_enable_mac = 29, + Clock_change_enable_i2s = 29, + Clock_change_enable_lcd = 29, + Clock_change_enable_msc0 = 29, + Clock_change_enable_msc1 = 29, + Clock_change_enable_sfc = 29, + Clock_change_enable_ssi = 29, + Clock_change_enable_cim = 29, + Clock_change_enable_pwm = 29, + Clock_change_enable_can0 = 29, + Clock_change_enable_can1 = 29, + Clock_change_enable_cdbus = 29, -static uint32_t clock_gate_reg[Clock_identifier_count] = { - /* Clock_aic_bitclk */ 0, - /* Clock_aic_pclk */ 0, - /* Clock_can0 */ Clock_gate1, - /* Clock_can1 */ Clock_gate1, - /* Clock_cdbus */ Clock_gate1, - /* Clock_cim */ Clock_gate0, - /* Clock_ddr */ Clock_gate0, - /* Clock_dma */ Clock_gate0, - /* Clock_emac */ 0, - /* Clock_hdmi */ 0, - /* Clock_i2c */ Clock_gate0, - /* Clock_i2c0 */ Clock_gate0, - /* Clock_i2c1 */ Clock_gate0, - /* Clock_i2s */ 0, - /* Clock_i2s0_rx */ Clock_gate1, - /* Clock_i2s0_tx */ Clock_gate1, - /* Clock_kbc */ 0, - /* Clock_lcd */ 0, - /* Clock_lcd_pixel */ Clock_gate0, - /* Clock_mac */ Clock_gate1, - /* Clock_msc */ Clock_gate0, - /* Clock_msc0 */ Clock_gate0, - /* Clock_msc1 */ Clock_gate0, - /* Clock_pwm */ Clock_gate1, - /* Clock_pwm0 */ Clock_gate1, - /* Clock_pwm1 */ 0, - /* Clock_scc */ 0, - /* Clock_sfc */ Clock_gate0, - /* Clock_smb0 */ 0, - /* Clock_smb1 */ 0, - /* Clock_smb2 */ 0, - /* Clock_smb3 */ 0, - /* Clock_smb4 */ 0, - /* Clock_ssi */ Clock_gate0, - /* Clock_timer */ Clock_gate0, - /* Clock_uart0 */ Clock_gate0, - /* Clock_uart1 */ Clock_gate0, - /* Clock_uart2 */ Clock_gate0, - /* Clock_uart3 */ Clock_gate1, - /* Clock_udc */ 0, - /* Clock_uhc */ 0, - /* Clock_uprt */ 0, + // Special value + + Clock_change_enable_undefined = 32, }; -// Clock gate register bit correspondences. +enum Clock_busy_bits : unsigned +{ + Clock_busy_cpu = 0, + Clock_busy_ddr = 28, + Clock_busy_mac = 28, + Clock_busy_lcd = 28, + Clock_busy_msc0 = 28, + Clock_busy_msc1 = 28, + Clock_busy_sfc = 28, + Clock_busy_ssi = 28, + Clock_busy_cim = 28, + Clock_busy_pwm = 28, + Clock_busy_can0 = 28, + Clock_busy_can1 = 28, + Clock_busy_cdbus = 28, -static enum Clock_gate_bits clock_gate_bit[Clock_identifier_count] = { - /* Clock_aic_bitclk */ Clock_gate_undefined, - /* Clock_aic_pclk */ Clock_gate_undefined, - /* Clock_can0 */ Clock_gate_can0, - /* Clock_can1 */ Clock_gate_can1, - /* Clock_cdbus */ Clock_gate_cdbus, - /* Clock_cim */ Clock_gate_cim, - /* Clock_ddr */ Clock_gate_ddr, - /* Clock_dma */ Clock_gate_dma, - /* Clock_emac */ Clock_gate_undefined, - /* Clock_hdmi */ Clock_gate_undefined, - /* Clock_i2c */ Clock_gate_i2c0, - /* Clock_i2c0 */ Clock_gate_i2c0, - /* Clock_i2c1 */ Clock_gate_i2c1, - /* Clock_i2s */ Clock_gate_undefined, - /* Clock_i2s0_rx */ Clock_gate_i2s0_rx, - /* Clock_i2s0_tx */ Clock_gate_i2s0_tx, - /* Clock_kbc */ Clock_gate_undefined, - /* Clock_lcd */ Clock_gate_undefined, - /* Clock_lcd_pixel */ Clock_gate_lcd_pixel, - /* Clock_mac */ Clock_gate_gmac0, - /* Clock_msc */ Clock_gate_msc0, - /* Clock_msc0 */ Clock_gate_msc0, - /* Clock_msc1 */ Clock_gate_msc1, - /* Clock_pwm */ Clock_gate_pwm, - /* Clock_pwm0 */ Clock_gate_pwm, - /* Clock_pwm1 */ Clock_gate_undefined, - /* Clock_scc */ Clock_gate_undefined, - /* Clock_sfc */ Clock_gate_sfc, - /* Clock_smb0 */ Clock_gate_undefined, - /* Clock_smb1 */ Clock_gate_undefined, - /* Clock_smb2 */ Clock_gate_undefined, - /* Clock_smb3 */ Clock_gate_undefined, - /* Clock_smb4 */ Clock_gate_undefined, - /* Clock_ssi */ Clock_gate_ssi0, - /* Clock_timer */ Clock_gate_timer, - /* Clock_uart0 */ Clock_gate_uart0, - /* Clock_uart1 */ Clock_gate_uart1, - /* Clock_uart2 */ Clock_gate_uart2, - /* Clock_uart3 */ Clock_gate_uart3, - /* Clock_udc */ Clock_gate_undefined, - /* Clock_uhc */ Clock_gate_undefined, - /* Clock_uprt */ Clock_gate_undefined, + // Special value + + Clock_busy_undefined = 32, }; -enum Divider_bits : unsigned +enum Clock_divider_bits : unsigned { - Ddr_divider_value = 0, // DDRCDR - Lcd_divider_value = 0, // LPCDR -}; + Clock_divider_can0 = 0, // CAN0CDR + Clock_divider_can1 = 0, // CAN1CDR + Clock_divider_cdbus = 0, // CDBUSCDR + Clock_divider_cim = 0, // CIMCDR + Clock_divider_cpu = 0, // CDIV + Clock_divider_ddr = 0, // DDRCDR + Clock_divider_hclock0 = 8, // H0DIV (fast AHB peripherals) + Clock_divider_hclock2 = 12, // H2DIV (fast AHB peripherals) + Clock_divider_l2cache = 4, // L2CDIV + Clock_divider_lcd = 0, // LPCDR + Clock_divider_mac = 0, // MACCDR + Clock_divider_msc0 = 0, // MSC0CDR + Clock_divider_msc1 = 0, // MSC1CDR + Clock_divider_pclock = 16, // PDIV (slow APB peripherals) + Clock_divider_pwm = 0, // PWMCDR + Clock_divider_sfc = 0, // SFCCDR + Clock_divider_ssi = 0, // SSICDR -enum Clock_status_values : unsigned -{ - Lcd_change_enable = 0x20000000, // CE_LCD - Lcd_change_busy = 0x10000000, // LCD_BUSY - Lcd_clock_stop = 0x08000000, // LCD_STOP + // Special value + + Clock_divider_undefined = 32, }; enum Pll_bits : unsigned @@ -348,6 +263,335 @@ +// Clock input descriptions. + +struct Clock_input_desc +{ + uint32_t source_reg; + enum Clock_source_bits source_bit; + int num_inputs; + enum Clock_input_identifiers inputs[3]; +}; + +struct Clock_input_desc clock_input_desc[Clock_input_identifier_count] = { + + /* Clock_input_ahb2_apb */ {Clock_control, Clock_source_hclock2, + 3, {Clock_input_none, Clock_input_main, Clock_input_pll_M}}, + + /* Clock_input_external */ {Reg_undefined, Clock_source_undefined, + 0, {}}, + + /* Clock_input_main */ {Clock_control, Clock_source_main, + 3, {Clock_input_none, Clock_input_external, Clock_input_pll_A}}, + + /* Clock_input_none */ {Reg_undefined, Clock_source_undefined, + 0, {}}, + + /* Clock_input_pll_A */ {Reg_undefined, Clock_source_undefined, + 1, {Clock_input_external}}, + + /* Clock_input_pll_E */ {Reg_undefined, Clock_source_undefined, + 1, {Clock_input_external}}, + + /* Clock_input_pll_M */ {Reg_undefined, Clock_source_undefined, + 1, {Clock_input_external}}, +}; + + + +// Clock descriptions. + +struct Clock_desc +{ + 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; + enum Clock_change_enable_bits change_enable_bit; + uint32_t busy_reg; + enum Clock_busy_bits busy_bit; + uint32_t divider_reg; + enum Clock_divider_bits divider_bit; + uint32_t divider_mask; + int num_inputs; + enum Clock_input_identifiers inputs[4]; +}; + +#define Clock_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_aic_bitclk */ Clock_undefined, + + /* Clock_aic_pclk */ Clock_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_input_main, Clock_input_pll_M, Clock_input_pll_E, Clock_input_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_input_main, Clock_input_pll_M, Clock_input_pll_E, Clock_input_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_input_main, Clock_input_pll_M, Clock_input_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_input_main, Clock_input_pll_M, Clock_input_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_input_none, Clock_input_main, Clock_input_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_input_none, Clock_input_main, Clock_input_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_input_ahb2_apb}}, + + /* Clock_emac */ Clock_undefined, + + /* 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_input_none, Clock_input_main, Clock_input_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_input_ahb2_apb}}, + + /* Clock_hdmi */ Clock_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_input_ahb2_apb}}, + + /* 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_input_ahb2_apb}}, + + /* 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_input_ahb2_apb}}, + + /* Clock_i2s */ Clock_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_input_main, Clock_input_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_input_main, Clock_input_pll_E}}, + + /* Clock_kbc */ Clock_undefined, + + /* Clock_lcd */ Clock_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_input_main, Clock_input_pll_M, Clock_input_pll_E}}, + + /* 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_input_main, Clock_input_pll_M, Clock_input_pll_E}}, + + /* Clock_main */ {Reg_undefined, Clock_source_undefined, + Clock_control, Clock_gate_main, + Reg_undefined, Clock_change_enable_undefined, + Reg_undefined, Clock_busy_undefined, + Reg_undefined, Clock_divider_undefined, 0, + 1, {Clock_input_main}}, + + /* 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_input_main, Clock_input_pll_M, Clock_input_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_input_main, Clock_input_pll_M, Clock_input_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_input_main, Clock_input_pll_M, Clock_input_pll_E}}, + + /* 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_input_ahb2_apb}}, + + /* 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_input_main, Clock_input_pll_M, Clock_input_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_input_main, Clock_input_pll_M, Clock_input_pll_E}}, + + /* Clock_pwm1 */ Clock_undefined, + + /* Clock_scc */ Clock_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_input_main, Clock_input_pll_M, Clock_input_pll_E}}, + + /* Clock_smb0 */ Clock_undefined, + + /* Clock_smb1 */ Clock_undefined, + + /* Clock_smb2 */ Clock_undefined, + + /* Clock_smb3 */ Clock_undefined, + + /* Clock_smb4 */ Clock_undefined, + + /* 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_input_main, Clock_input_pll_M, Clock_input_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_input_ahb2_apb}}, + + /* 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_input_ahb2_apb}}, + + /* 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_input_ahb2_apb}}, + + /* 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_input_ahb2_apb}}, + + /* 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_input_ahb2_apb}}, + + /* Clock_udc */ Clock_undefined, + + /* Clock_uhc */ Clock_undefined, + + /* Clock_uprt */ Clock_undefined, +}; + + + +// Convenience functions. + +static uint8_t get_clock_gate_bit(enum Clock_identifiers clock) +{ + enum Clock_gate_bits bit = clock_desc[clock].gate_bit; + + return bit != Clock_gate_undefined ? (uint8_t) bit : 0; +} + +static uint32_t get_clock_gate_mask(enum Clock_identifiers clock) +{ + enum Clock_gate_bits bit = clock_desc[clock].gate_bit; + + return bit != Clock_gate_undefined ? 1 : 0; +} + + + // If implemented as a Hw::Device, various properties would be // initialised in the constructor and obtained from the device tree // definitions. @@ -362,42 +606,6 @@ // register_property("exclk_freq", &_exclk_freq); } -// Clock/timer control. - -uint32_t -Cpm_x1600_chip::get_clock_gate_register(enum Clock_identifiers clock) -{ - return clock_gate_reg[clock]; -} - -uint32_t -Cpm_x1600_chip::get_clock_gate_value(enum Clock_identifiers clock) -{ - return 1 << clock_gate_bit[clock]; -} - -int -Cpm_x1600_chip::have_clock(enum Clock_identifiers clock) -{ - return !(_regs[get_clock_gate_register(clock)] & get_clock_gate_value(clock)); -} - -void -Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) -{ - uint32_t gate = get_clock_gate_register(clock); - - _regs[gate] = _regs[gate] & ~get_clock_gate_value(clock); -} - -void -Cpm_x1600_chip::stop_clock(enum Clock_identifiers clock) -{ - uint32_t gate = get_clock_gate_register(clock); - - _regs[gate] = _regs[gate] | get_clock_gate_value(clock); -} - // Utility methods. @@ -414,12 +622,61 @@ _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); } -// General clock divider access. + + +// 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); +} -uint8_t -Cpm_x1600_chip::_get_divider(uint32_t reg, uint32_t mask, uint8_t shift) +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; +} + +void +Cpm_x1600_chip::start_clock(enum Clock_identifiers clock) { - return get_field(reg, mask, shift) + 1; + 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); +} + +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)); } @@ -431,43 +688,44 @@ int Cpm_x1600_chip::have_pll(uint32_t pll_reg) { - return _regs[pll_reg] & (1 << Pll_stable); + return get_field(pll_reg, 1, Pll_stable); } int Cpm_x1600_chip::pll_enabled(uint32_t pll_reg) { - return _regs[pll_reg] & (1 << Pll_enabled); + return get_field(pll_reg, 1, Pll_enabled); } int Cpm_x1600_chip::pll_bypassed(uint32_t pll_reg) { - uint32_t mask; + uint8_t bit; + unsigned mask = 1; switch (pll_reg) { - case Pll_control_A: mask = (1 << Pll_bypass_A); break; - case Pll_control_M: mask = (1 << Pll_bypass_M); break; - case Pll_control_E: mask = (1 << Pll_bypass_E); break; - default: mask = 0; break; + 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 _regs[Pll_control] & mask; + return get_field(Pll_control, mask, bit); } void Cpm_x1600_chip::pll_enable(uint32_t pll_reg) { - _regs[pll_reg] = _regs[pll_reg] | (1 << Pll_enabled); - while (!(_regs[pll_reg] & (1 << Pll_stable))); + set_field(pll_reg, 1, Pll_enabled, 1); + while (!have_pll(pll_reg)); } void Cpm_x1600_chip::pll_disable(uint32_t pll_reg) { - _regs[pll_reg] = _regs[pll_reg] & ~(1 << Pll_enabled); - while (_regs[pll_reg] & (1 << Pll_stable)); + set_field(pll_reg, 1, Pll_enabled, 0); + while (have_pll(pll_reg)); } // Feedback (13-bit) multiplier. @@ -547,78 +805,29 @@ -// CPU clock (CCLK) divider. +// Clock dividers. -uint8_t -Cpm_x1600_chip::get_cpu_divider() -{ - return _get_divider(Clock_control, 0xf, Clock_cpu_divider); -} - -// Fast peripheral clock (H0CLK) divider. - -uint8_t -Cpm_x1600_chip::get_hclock0_divider() +uint32_t +Cpm_x1600_chip::get_divider(enum Clock_identifiers clock) { - return _get_divider(Clock_control, 0xf, Clock_hclock0_divider); -} - -// Fast peripheral clock (H2CLK) divider. - -uint8_t -Cpm_x1600_chip::get_hclock2_divider() -{ - return _get_divider(Clock_control, 0xf, Clock_hclock2_divider); -} - -// Slow peripheral clock (PCLK) divider. - -uint8_t -Cpm_x1600_chip::get_pclock_divider() -{ - return _get_divider(Clock_control, 0xf, Clock_pclock_divider); + 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; } -// LCD clock (LPCLK) divider for LCD pixel clock. - -uint8_t -Cpm_x1600_chip::get_lcd_pixel_divider(uint8_t controller) +void +Cpm_x1600_chip::set_divider(enum Clock_identifiers clock, uint32_t division) { - (void) controller; - return _get_divider(Lcd_divider, 0xff, Lcd_divider_value); -} - -// Memory clock (DDR_CLK) divider. - -uint8_t -Cpm_x1600_chip::get_memory_divider() -{ - return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); -} - -// LCD pixel clock divider. - -void -Cpm_x1600_chip::set_lcd_pixel_divider(uint8_t controller, uint16_t division) -{ - if (controller > 0) + if (clock_desc[clock].divider_bit == Clock_divider_undefined) return; - if ((division < 1) || (division > 256)) - return; - - // Enable change. - - _regs[Lcd_divider] = _regs[Lcd_divider] | Lcd_change_enable; - - // Set the divider. - - set_field(Lcd_divider, 0xff, Lcd_divider_value, division - 1); - - // Restart clock and disable change. - - while (_regs[Lcd_divider] & Lcd_change_busy); - _regs[Lcd_divider] = _regs[Lcd_divider] & ~Lcd_change_enable; + 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); } @@ -626,251 +835,106 @@ // Clock sources. uint8_t -Cpm_x1600_chip::get_memory_source() -{ - return get_field(Ddr_divider, 0x3, Clock_source_ddr); -} - -uint32_t -Cpm_x1600_chip::get_memory_source_frequency() -{ - switch (get_memory_source()) - { - case Source_mux_main: - return get_main_frequency(); - case Source_mux_pll_M: - return get_pll_frequency(Pll_control_M); - default: - return 0; - } -} - -uint8_t -Cpm_x1600_chip::get_cpu_source() -{ - return get_field(Clock_control, 0x3, Clock_source_cpu); -} - -uint32_t -Cpm_x1600_chip::get_cpu_source_frequency() +Cpm_x1600_chip::get_source(enum Clock_identifiers clock) { - switch (get_cpu_source()) - { - case Source_mux_main: - return get_main_frequency(); - case Source_mux_pll_M: - return get_pll_frequency(Pll_control_M); - default: - return 0; - } -} - -uint8_t -Cpm_x1600_chip::get_hclock0_source() -{ - return get_field(Clock_control, 0x3, Clock_source_hclock0); -} - -uint32_t -Cpm_x1600_chip::get_hclock0_source_frequency() -{ - switch (get_hclock0_source()) - { - case Source_mux_main: - return get_main_frequency(); - case Source_mux_pll_M: - return get_pll_frequency(Pll_control_M); - default: - return 0; - } -} - -uint8_t -Cpm_x1600_chip::get_hclock2_source() -{ - return get_field(Clock_control, 0x3, Clock_source_hclock2); -} - -uint32_t -Cpm_x1600_chip::get_hclock2_source_frequency() -{ - switch (get_hclock2_source()) - { - case Source_mux_main: - return get_main_frequency(); - case Source_mux_pll_M: - return get_pll_frequency(Pll_control_M); - default: - return 0; - } + 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; } void -Cpm_x1600_chip::set_hclock2_source(uint8_t source) -{ - set_field(Clock_control, 0x3, Clock_source_hclock2, source); -} - -uint8_t -Cpm_x1600_chip::get_lcd_source(uint8_t controller) -{ - (void) controller; - return get_field(Lcd_divider, 0x3, Clock_source_lcd); -} - -uint32_t -Cpm_x1600_chip::get_lcd_source_frequency(uint8_t controller) +Cpm_x1600_chip::set_source(enum Clock_identifiers clock, uint8_t source) { - switch (get_lcd_source(controller)) - { - case Source_main: - return get_main_frequency(); - case Source_pll_M: - return get_pll_frequency(Pll_control_M); - case Source_pll_E: - return get_pll_frequency(Pll_control_E); - default: - return 0; - } -} - -void -Cpm_x1600_chip::set_lcd_source(uint8_t controller, uint8_t source) -{ - if (controller > 0) + if (clock_desc[clock].source_bit == Clock_source_undefined) return; - // Stop clock and enable change. - - _regs[Lcd_divider] = _regs[Lcd_divider] | Lcd_change_enable | Lcd_clock_stop; - - // Set the source. - - set_field(Lcd_divider, 0x03, Clock_source_lcd, source); - - // Restart clock and disable change. - - while (_regs[Lcd_divider] & Lcd_change_busy); - _regs[Lcd_divider] = _regs[Lcd_divider] & ~(Lcd_change_enable | Lcd_clock_stop); -} - -uint8_t -Cpm_x1600_chip::get_pclock_source() -{ - return get_hclock2_source(); -} - -uint32_t -Cpm_x1600_chip::get_pclock_source_frequency() -{ - return get_hclock2_source_frequency(); -} - -void -Cpm_x1600_chip::set_pclock_source(uint8_t source) -{ - set_hclock2_source(source); + change_enable(clock); + set_field(clock_desc[clock].source_reg, Source_mask, clock_desc[clock].source_bit, source); + wait_busy(clock); + change_disable(clock); } -// Source frequency, used by various clock sources. +// Clock source frequencies. + +uint32_t +Cpm_x1600_chip::get_input_frequency(enum Clock_input_identifiers clock) +{ + struct Clock_input_desc desc = clock_input_desc[clock]; + + // Clocks with no inputs provide a frequency. + + if (desc.num_inputs == 0) + { + switch (clock) + { + case Clock_input_external: return _exclk_freq; + default: return 0; + } + } + + // Of the input clocks, only PLLs have a single input. -uint8_t -Cpm_x1600_chip::get_main_source() -{ - return get_field(Clock_control, 0x3, Clock_source_main); + else if (desc.num_inputs == 1) + { + switch (clock) + { + case Clock_input_pll_A: return get_pll_frequency(Pll_control_A); + case Clock_input_pll_E: return get_pll_frequency(Pll_control_E); + case Clock_input_pll_M: return get_pll_frequency(Pll_control_M); + default: return 0; + } + } + + // With multiple sources, obtain the selected source for the clock. + + uint8_t source = get_field(desc.source_reg, Source_mask, desc.source_bit); + + // Return the frequency of the source. + + if (source < desc.num_inputs) + return get_input_frequency(desc.inputs[source]); + else + return 0; } uint32_t -Cpm_x1600_chip::get_main_frequency() -{ - switch (get_main_source()) - { - case Source_pll_A: - return get_pll_frequency(Pll_control_A); - case Source_external: - return _exclk_freq; - default: - return 0; - } -} - -// Clock frequency for the CPU. - -uint32_t -Cpm_x1600_chip::get_cpu_frequency() -{ - return get_cpu_source_frequency() / get_cpu_divider(); -} - -// Clock frequency for fast peripherals. - -uint32_t -Cpm_x1600_chip::get_hclock0_frequency() -{ - return get_hclock0_source_frequency() / get_hclock0_divider(); -} - -// Clock frequency for fast peripherals. - -uint32_t -Cpm_x1600_chip::get_hclock2_frequency() +Cpm_x1600_chip::get_source_frequency(enum Clock_identifiers clock) { - return get_hclock2_source_frequency() / get_hclock2_divider(); -} + struct Clock_desc desc = clock_desc[clock]; -// Clock frequency for slow peripherals. + // Undefined clocks return zero. -uint32_t -Cpm_x1600_chip::get_pclock_frequency() -{ - return get_pclock_source_frequency() / get_pclock_divider(); -} + if (desc.num_inputs == 0) + return 0; -// Clock frequency for the memory. + // Clocks with one source yield that input frequency. -uint32_t -Cpm_x1600_chip::get_memory_frequency() -{ - return get_memory_source_frequency() / get_memory_divider(); -} + else if (desc.num_inputs == 1) + return get_input_frequency(desc.inputs[0]); + + // With multiple sources, obtain the selected source for the clock. + + uint8_t source = get_source(clock); -uint32_t -Cpm_x1600_chip::get_apll_frequency() -{ - return get_pll_frequency(Pll_control_A); -} + // Return the frequency of the source. -uint32_t -Cpm_x1600_chip::get_epll_frequency() -{ - return get_pll_frequency(Pll_control_E); -} - -uint32_t -Cpm_x1600_chip::get_mpll_frequency() -{ - return get_pll_frequency(Pll_control_M); + if (source < desc.num_inputs) + return get_input_frequency(desc.inputs[source]); + else + return 0; } +// Output clock frequencies. + uint32_t Cpm_x1600_chip::get_frequency(enum Clock_identifiers clock) { - switch (clock) - { - // NOTE: Returning only the frequency for controller 0. - - case Clock_lcd_pixel: - return get_lcd_source_frequency(0) / get_lcd_pixel_divider(0); - - // NOTE: Consider a better error result. - - default: - return 0; - } + return get_source_frequency(clock) / get_divider(clock); } void @@ -885,9 +949,9 @@ // Switch to the MPLL and attempt to set the divider. - set_lcd_source(0, Source_pll_M); + set_source(Clock_lcd_pixel, Source_mME_pll_M); pll_enable(Pll_control_M); - set_lcd_pixel_divider(0, get_lcd_source_frequency() / frequency); + set_divider(Clock_lcd_pixel, get_source_frequency(clock) / frequency); break; default: @@ -928,172 +992,38 @@ -uint8_t -x1600_cpm_get_cpu_divider(void *cpm) +uint32_t +x1600_cpm_get_divider(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_cpu_divider(); -} - -uint8_t -x1600_cpm_get_hclock0_divider(void *cpm) -{ - return static_cast(cpm)->get_hclock0_divider(); + return static_cast(cpm)->get_divider(clock); } -uint8_t -x1600_cpm_get_hclock2_divider(void *cpm) -{ - return static_cast(cpm)->get_hclock2_divider(); -} - -uint8_t -x1600_cpm_get_lcd_pixel_divider(void *cpm) +void +x1600_cpm_set_divider(void *cpm, enum Clock_identifiers clock, uint32_t divider) { - return static_cast(cpm)->get_lcd_pixel_divider(); -} - -uint8_t -x1600_cpm_get_memory_divider(void *cpm) -{ - return static_cast(cpm)->get_memory_divider(); -} - -uint8_t -x1600_cpm_get_pclock_divider(void *cpm) -{ - return static_cast(cpm)->get_pclock_divider(); + return static_cast(cpm)->set_divider(clock, divider); } uint8_t -x1600_cpm_get_hclock0_source(void *cpm) -{ - return static_cast(cpm)->get_hclock0_source(); -} - -uint8_t -x1600_cpm_get_hclock2_source(void *cpm) -{ - return static_cast(cpm)->get_hclock2_source(); -} - -uint8_t -x1600_cpm_get_lcd_source(void *cpm) +x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_lcd_source(); -} - -uint8_t -x1600_cpm_get_memory_source(void *cpm) -{ - return static_cast(cpm)->get_memory_source(); -} - -uint8_t -x1600_cpm_get_pclock_source(void *cpm) -{ - return static_cast(cpm)->get_pclock_source(); + return static_cast(cpm)->get_source(clock); } void -x1600_cpm_set_pclock_source(void *cpm, uint8_t source) +x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) { - static_cast(cpm)->set_pclock_source(source); + static_cast(cpm)->set_source(clock, source); } uint32_t -x1600_cpm_get_hclock0_source_frequency(void *cpm) -{ - return static_cast(cpm)->get_hclock0_source_frequency(); -} - -uint32_t -x1600_cpm_get_hclock2_source_frequency(void *cpm) -{ - return static_cast(cpm)->get_hclock2_source_frequency(); -} - -uint32_t -x1600_cpm_get_lcd_source_frequency(void *cpm) -{ - return static_cast(cpm)->get_lcd_source_frequency(); -} - -uint32_t -x1600_cpm_get_memory_source_frequency(void *cpm) -{ - return static_cast(cpm)->get_memory_source_frequency(); -} - -uint32_t -x1600_cpm_get_pclock_source_frequency(void *cpm) -{ - return static_cast(cpm)->get_pclock_source_frequency(); -} - - - -uint8_t -x1600_cpm_get_main_source(void *cpm) -{ - return static_cast(cpm)->get_main_source(); -} - -uint32_t -x1600_cpm_get_main_frequency(void *cpm) +x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) { - return static_cast(cpm)->get_main_frequency(); -} - -uint32_t -x1600_cpm_get_cpu_frequency(void *cpm) -{ - return static_cast(cpm)->get_cpu_frequency(); -} - -uint32_t -x1600_cpm_get_hclock0_frequency(void *cpm) -{ - return static_cast(cpm)->get_hclock0_frequency(); -} - -uint32_t -x1600_cpm_get_hclock2_frequency(void *cpm) -{ - return static_cast(cpm)->get_hclock2_frequency(); -} - -uint32_t -x1600_cpm_get_memory_frequency(void *cpm) -{ - return static_cast(cpm)->get_memory_frequency(); -} - -uint32_t -x1600_cpm_get_pclock_frequency(void *cpm) -{ - return static_cast(cpm)->get_pclock_frequency(); -} - -uint32_t -x1600_cpm_get_apll_frequency(void *cpm) -{ - return static_cast(cpm)->get_apll_frequency(); -} - -uint32_t -x1600_cpm_get_epll_frequency(void *cpm) -{ - return static_cast(cpm)->get_epll_frequency(); -} - -uint32_t -x1600_cpm_get_mpll_frequency(void *cpm) -{ - return static_cast(cpm)->get_mpll_frequency(); + return static_cast(cpm)->get_source_frequency(clock); } @@ -1110,6 +1040,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) {