paul@160 | 1 | /* |
paul@160 | 2 | * Clock and power management. This exposes the combined functionality |
paul@160 | 3 | * provided by the X1600 and related SoCs. The power management |
paul@160 | 4 | * functionality could be exposed using a separate driver. |
paul@160 | 5 | * |
paul@248 | 6 | * Copyright (C) 2017, 2018, 2020, 2021, 2023, |
paul@248 | 7 | * 2024 Paul Boddie <paul@boddie.org.uk> |
paul@160 | 8 | * |
paul@160 | 9 | * This program is free software; you can redistribute it and/or |
paul@160 | 10 | * modify it under the terms of the GNU General Public License as |
paul@160 | 11 | * published by the Free Software Foundation; either version 2 of |
paul@160 | 12 | * the License, or (at your option) any later version. |
paul@160 | 13 | * |
paul@160 | 14 | * This program is distributed in the hope that it will be useful, |
paul@160 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@160 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@160 | 17 | * GNU General Public License for more details. |
paul@160 | 18 | * |
paul@160 | 19 | * You should have received a copy of the GNU General Public License |
paul@160 | 20 | * along with this program; if not, write to the Free Software |
paul@160 | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@160 | 22 | * Boston, MA 02110-1301, USA |
paul@160 | 23 | */ |
paul@160 | 24 | |
paul@160 | 25 | #include <l4/devices/hw_mmio_register_block.h> |
paul@160 | 26 | #include "cpm-x1600.h" |
paul@160 | 27 | |
paul@160 | 28 | |
paul@160 | 29 | |
paul@161 | 30 | // Register locations. |
paul@161 | 31 | |
paul@160 | 32 | enum Regs : unsigned |
paul@160 | 33 | { |
paul@160 | 34 | Clock_control = 0x000, // CPCCR |
paul@160 | 35 | Low_power_control = 0x004, // LCR |
paul@160 | 36 | Clock_gate0 = 0x020, // CLKGR0 |
paul@160 | 37 | Clock_gate1 = 0x028, // CLKGR1 |
paul@160 | 38 | Sleep_control = 0x024, // OPCR (oscillator and power control) |
paul@160 | 39 | Clock_status = 0x0d4, // CPCSR |
paul@211 | 40 | |
paul@211 | 41 | Divider_can0 = 0x0a0, // CAN0CDR |
paul@211 | 42 | Divider_can1 = 0x0a8, // CAN1CDR |
paul@211 | 43 | Divider_cdbus = 0x0ac, // CDBUSCDR |
paul@211 | 44 | Divider_cim = 0x078, // CIMCDR |
paul@167 | 45 | Divider_ddr = 0x02c, // DDRCDR |
paul@167 | 46 | Divider_mac = 0x054, // MACCDR |
paul@175 | 47 | Divider0_i2s0 = 0x060, // I2S0CDR |
paul@175 | 48 | Divider1_i2s0 = 0x070, // I2S0CDR1 |
paul@175 | 49 | Divider0_i2s1 = 0x07c, // I2S1CDR (from X2000 manual) |
paul@175 | 50 | Divider1_i2s1 = 0x080, // I2S1CDR1 (from X2000 manual) |
paul@167 | 51 | Divider_lcd = 0x064, // LPCDR |
paul@211 | 52 | Divider_macphy0 = 0x0e4, // MPHY0C |
paul@167 | 53 | Divider_msc0 = 0x068, // MSC0CDR |
paul@167 | 54 | Divider_msc1 = 0x0a4, // MSC1CDR |
paul@211 | 55 | Divider_pwm = 0x06c, // PWMCDR |
paul@167 | 56 | Divider_sfc = 0x074, // SFCCDR |
paul@167 | 57 | Divider_ssi = 0x05c, // SSICDR |
paul@211 | 58 | |
paul@160 | 59 | Cpm_interrupt = 0x0b0, // CPM_INTR |
paul@160 | 60 | Cpm_interrupt_en = 0x0b4, // CPM_INTRE |
paul@160 | 61 | Cpm_swi = 0x0bc, // CPM_SFTINT |
paul@211 | 62 | Cpm_scratch = 0x034, // CPSPR |
paul@160 | 63 | Cpm_scratch_prot = 0x038, // CPSPPR |
paul@211 | 64 | |
paul@211 | 65 | Gate_ddr = 0x0d0, // DRCG |
paul@211 | 66 | |
paul@160 | 67 | Usb_param_control0 = 0x03c, // USBPCR |
paul@160 | 68 | Usb_reset_detect = 0x040, // USBRDT |
paul@160 | 69 | Usb_vbus_jitter = 0x044, // USBVBFIL |
paul@160 | 70 | Usb_param_control1 = 0x048, // USBPCR1 |
paul@211 | 71 | |
paul@160 | 72 | Pll_control = 0x00c, // CPPCR |
paul@160 | 73 | Pll_control_A = 0x010, // CPAPCR |
paul@160 | 74 | Pll_control_M = 0x014, // CPMPCR |
paul@160 | 75 | Pll_control_E = 0x018, // CPEPCR |
paul@160 | 76 | Pll_fraction_A = 0x084, // CPAPACR |
paul@160 | 77 | Pll_fraction_M = 0x088, // CPMPACR |
paul@160 | 78 | Pll_fraction_E = 0x08c, // CPEPACR |
paul@160 | 79 | }; |
paul@160 | 80 | |
paul@160 | 81 | |
paul@160 | 82 | |
paul@167 | 83 | // Register field definitions. |
paul@167 | 84 | |
paul@175 | 85 | static Field Clock_source_main (Clock_control, 3, 30), // SEL_SRC (output to SCLK_A) |
paul@175 | 86 | Clock_source_cpu (Clock_control, 3, 28), // SEL_CPLL (output to CCLK) |
paul@175 | 87 | Clock_source_hclock0 (Clock_control, 3, 26), // SEL_H0PLL (output to AHB0) |
paul@175 | 88 | Clock_source_hclock2 (Clock_control, 3, 24), // SEL_H2PLL (output to AHB2) |
paul@175 | 89 | Clock_source_can0 (Divider_can0, 3, 30), // CA0CS |
paul@175 | 90 | Clock_source_can1 (Divider_can1, 3, 30), // CA1CS |
paul@175 | 91 | Clock_source_cdbus (Divider_cdbus, 3, 30), // CDCS |
paul@175 | 92 | Clock_source_cim (Divider_cim, 3, 30), // CIMPCS |
paul@175 | 93 | Clock_source_ddr (Divider_ddr, 3, 30), // DCS |
paul@201 | 94 | Clock_source_i2s0 (Divider0_i2s0, 1, 30), // I2PCS |
paul@201 | 95 | Clock_source_i2s1 (Divider0_i2s1, 1, 30), // I2PCS |
paul@175 | 96 | Clock_source_lcd (Divider_lcd, 3, 30), // LPCS |
paul@175 | 97 | Clock_source_mac (Divider_mac, 3, 30), // MACPCS |
paul@175 | 98 | Clock_source_msc0 (Divider_msc0, 3, 30), // MPCS |
paul@175 | 99 | Clock_source_msc1 (Divider_msc1, 3, 30), // MPCS |
paul@175 | 100 | Clock_source_pwm (Divider_pwm, 3, 30), // PWMPCS |
paul@239 | 101 | Clock_source_rtc (Sleep_control, 0x01, 2), // ERCS |
paul@175 | 102 | Clock_source_sfc (Divider_sfc, 3, 30), // SFCS |
paul@175 | 103 | Clock_source_ssi (Divider_ssi, 3, 30), // SPCS |
paul@167 | 104 | |
paul@276 | 105 | Clock_stop_ddr (Divider_ddr, 1, 27, true), |
paul@276 | 106 | Clock_stop_mac (Divider_mac, 1, 27, true), |
paul@276 | 107 | Clock_stop_lcd (Divider_lcd, 1, 27, true), |
paul@276 | 108 | Clock_stop_msc0 (Divider_msc0, 1, 27, true), |
paul@276 | 109 | Clock_stop_msc1 (Divider_msc1, 1, 27, true), |
paul@276 | 110 | Clock_stop_sfc (Divider_sfc, 1, 27, true), |
paul@276 | 111 | Clock_stop_ssi (Divider_ssi, 1, 27, true), |
paul@276 | 112 | Clock_stop_cim (Divider_cim, 1, 27, true), |
paul@276 | 113 | Clock_stop_pwm (Divider_pwm, 1, 27, true), |
paul@276 | 114 | Clock_stop_can0 (Divider_can0, 1, 27, true), |
paul@276 | 115 | Clock_stop_can1 (Divider_can1, 1, 27, true), |
paul@276 | 116 | Clock_stop_cdbus (Divider_cdbus, 1, 27, true), |
paul@276 | 117 | |
paul@175 | 118 | Clock_busy_cpu (Clock_status, 1, 0), |
paul@211 | 119 | Clock_busy_hclock0 (Clock_status, 1, 1), |
paul@211 | 120 | Clock_busy_hclock2 (Clock_status, 1, 2), |
paul@175 | 121 | Clock_busy_ddr (Divider_ddr, 1, 28), |
paul@175 | 122 | Clock_busy_mac (Divider_mac, 1, 28), |
paul@175 | 123 | Clock_busy_lcd (Divider_lcd, 1, 28), |
paul@175 | 124 | Clock_busy_msc0 (Divider_msc0, 1, 28), |
paul@175 | 125 | Clock_busy_msc1 (Divider_msc1, 1, 28), |
paul@175 | 126 | Clock_busy_sfc (Divider_sfc, 1, 28), |
paul@175 | 127 | Clock_busy_ssi (Divider_ssi, 1, 28), |
paul@175 | 128 | Clock_busy_cim (Divider_cim, 1, 28), |
paul@175 | 129 | Clock_busy_pwm (Divider_pwm, 1, 28), |
paul@175 | 130 | Clock_busy_can0 (Divider_can0, 1, 28), |
paul@175 | 131 | Clock_busy_can1 (Divider_can1, 1, 28), |
paul@175 | 132 | Clock_busy_cdbus (Divider_cdbus, 1, 28), |
paul@167 | 133 | |
paul@175 | 134 | Clock_change_enable_cpu (Clock_control, 1, 22), |
paul@175 | 135 | Clock_change_enable_ahb0 (Clock_control, 1, 21), |
paul@175 | 136 | Clock_change_enable_ahb2 (Clock_control, 1, 20), |
paul@175 | 137 | Clock_change_enable_ddr (Divider_ddr, 1, 29), |
paul@175 | 138 | Clock_change_enable_mac (Divider_mac, 1, 29), |
paul@201 | 139 | Clock_gate_i2s0 (Divider0_i2s0, 1, 29), // CE_I2S is gate, not change enable |
paul@201 | 140 | Clock_gate_i2s1 (Divider0_i2s1, 1, 29), // CE_I2S is gate, not change enable |
paul@175 | 141 | Clock_change_enable_lcd (Divider_lcd, 1, 29), |
paul@175 | 142 | Clock_change_enable_msc0 (Divider_msc0, 1, 29), |
paul@175 | 143 | Clock_change_enable_msc1 (Divider_msc1, 1, 29), |
paul@175 | 144 | Clock_change_enable_sfc (Divider_sfc, 1, 29), |
paul@175 | 145 | Clock_change_enable_ssi (Divider_ssi, 1, 29), |
paul@175 | 146 | Clock_change_enable_cim (Divider_cim, 1, 29), |
paul@175 | 147 | Clock_change_enable_pwm (Divider_pwm, 1, 29), |
paul@175 | 148 | Clock_change_enable_can0 (Divider_can0, 1, 29), |
paul@175 | 149 | Clock_change_enable_can1 (Divider_can1, 1, 29), |
paul@175 | 150 | Clock_change_enable_cdbus (Divider_cdbus, 1, 29), |
paul@167 | 151 | |
paul@211 | 152 | Clock_divider_cpu (Clock_control, 0x0f, 0), // CDIV |
paul@211 | 153 | Clock_divider_hclock0 (Clock_control, 0x0f, 8), // H0DIV (fast AHB peripherals) |
paul@211 | 154 | Clock_divider_hclock2 (Clock_control, 0x0f, 12), // H2DIV (fast AHB peripherals) |
paul@211 | 155 | Clock_divider_l2cache (Clock_control, 0x0f, 4), // L2CDIV |
paul@211 | 156 | Clock_divider_pclock (Clock_control, 0x0f, 16), // PDIV (slow APB peripherals) |
paul@175 | 157 | Clock_divider_can0 (Divider_can0, 0xff, 0), // CAN0CDR |
paul@175 | 158 | Clock_divider_can1 (Divider_can1, 0xff, 0), // CAN1CDR |
paul@175 | 159 | Clock_divider_cdbus (Divider_cdbus, 0xff, 0), // CDBUSCDR |
paul@175 | 160 | Clock_divider_cim (Divider_cim, 0xff, 0), // CIMCDR |
paul@175 | 161 | Clock_divider_ddr (Divider_ddr, 0x0f, 0), // DDRCDR |
paul@175 | 162 | Clock_divider_i2s0_m (Divider0_i2s0, 0x1ff, 20), // I2SDIV_M |
paul@175 | 163 | Clock_divider_i2s0_n (Divider0_i2s0, 0xfffff, 0), // I2SDIV_N |
paul@175 | 164 | Clock_divider_i2s0_d (Divider1_i2s0, 0xfffff, 0), // I2SDIV_D |
paul@175 | 165 | Clock_divider_i2s1_m (Divider0_i2s1, 0x1ff, 20), // I2SDIV_M |
paul@175 | 166 | Clock_divider_i2s1_n (Divider0_i2s1, 0xfffff, 0), // I2SDIV_N |
paul@175 | 167 | Clock_divider_i2s1_d (Divider1_i2s1, 0xfffff, 0), // I2SDIV_D |
paul@175 | 168 | Clock_divider_lcd (Divider_lcd, 0xff, 0), // LPCDR |
paul@175 | 169 | Clock_divider_mac (Divider_mac, 0xff, 0), // MACCDR |
paul@175 | 170 | Clock_divider_msc0 (Divider_msc0, 0xff, 0), // MSC0CDR |
paul@175 | 171 | Clock_divider_msc1 (Divider_msc1, 0xff, 0), // MSC1CDR |
paul@175 | 172 | Clock_divider_pwm (Divider_pwm, 0x0f, 0), // PWMCDR |
paul@175 | 173 | Clock_divider_sfc (Divider_sfc, 0xff, 0), // SFCCDR |
paul@175 | 174 | Clock_divider_ssi (Divider_ssi, 0xff, 0), // SSICDR |
paul@168 | 175 | |
paul@185 | 176 | Clock_divider_i2s0_n_auto (Divider1_i2s0, 1, 31), // I2S_NEN |
paul@185 | 177 | Clock_divider_i2s0_d_auto (Divider1_i2s0, 1, 30), // I2S_DEN |
paul@185 | 178 | Clock_divider_i2s1_n_auto (Divider1_i2s1, 1, 31), // I2S_NEN |
paul@185 | 179 | Clock_divider_i2s1_d_auto (Divider1_i2s1, 1, 30), // I2S_DEN |
paul@185 | 180 | |
paul@201 | 181 | Clock_gate_main (Clock_control, 1, 23, true), // GATE_SCLKA |
paul@201 | 182 | Clock_gate_ddr (Clock_gate0, 1, 31, true), // DDR |
paul@201 | 183 | Clock_gate_ahb0 (Clock_gate0, 1, 29, true), // AHB0 |
paul@201 | 184 | Clock_gate_apb0 (Clock_gate0, 1, 28, true), // APB0 |
paul@201 | 185 | Clock_gate_rtc (Clock_gate0, 1, 27, true), // RTC |
paul@201 | 186 | Clock_gate_aes (Clock_gate0, 1, 24, true), // AES |
paul@201 | 187 | Clock_gate_lcd_pixel (Clock_gate0, 1, 23, true), // LCD |
paul@201 | 188 | Clock_gate_cim (Clock_gate0, 1, 22, true), // CIM |
paul@201 | 189 | Clock_gate_dma (Clock_gate0, 1, 21, true), // PDMA |
paul@201 | 190 | Clock_gate_ost (Clock_gate0, 1, 20, true), // OST |
paul@201 | 191 | Clock_gate_ssi0 (Clock_gate0, 1, 19, true), // SSI0 |
paul@201 | 192 | Clock_gate_timer (Clock_gate0, 1, 18, true), // TCU |
paul@201 | 193 | Clock_gate_dtrng (Clock_gate0, 1, 17, true), // DTRNG |
paul@201 | 194 | Clock_gate_uart2 (Clock_gate0, 1, 16, true), // UART2 |
paul@201 | 195 | Clock_gate_uart1 (Clock_gate0, 1, 15, true), // UART1 |
paul@201 | 196 | Clock_gate_uart0 (Clock_gate0, 1, 14, true), // UART0 |
paul@201 | 197 | Clock_gate_sadc (Clock_gate0, 1, 13, true), // SADC |
paul@211 | 198 | Clock_gate_aic (Clock_gate0, 1, 11, true), // AUDIO |
paul@201 | 199 | Clock_gate_ssi_slv (Clock_gate0, 1, 10, true), // SSI_SLV |
paul@201 | 200 | Clock_gate_i2c1 (Clock_gate0, 1, 8, true), // I2C1 |
paul@201 | 201 | Clock_gate_i2c0 (Clock_gate0, 1, 7, true), // I2C0 |
paul@201 | 202 | Clock_gate_msc1 (Clock_gate0, 1, 5, true), // MSC1 |
paul@201 | 203 | Clock_gate_msc0 (Clock_gate0, 1, 4, true), // MSC0 |
paul@201 | 204 | Clock_gate_otg (Clock_gate0, 1, 3, true), // OTG |
paul@201 | 205 | Clock_gate_sfc (Clock_gate0, 1, 2, true), // SFC |
paul@201 | 206 | Clock_gate_efuse (Clock_gate0, 1, 1, true), // EFUSE |
paul@201 | 207 | Clock_gate_nemc (Clock_gate0, 1, 0, true), // NEMC |
paul@201 | 208 | Clock_gate_arb (Clock_gate1, 1, 30, true), // ARB |
paul@201 | 209 | Clock_gate_mipi_csi (Clock_gate1, 1, 28, true), // MIPI_CSI |
paul@201 | 210 | Clock_gate_intc (Clock_gate1, 1, 26, true), // INTC |
paul@201 | 211 | Clock_gate_gmac0 (Clock_gate1, 1, 23, true), // GMAC0 |
paul@201 | 212 | Clock_gate_uart3 (Clock_gate1, 1, 16, true), // UART3 |
paul@201 | 213 | Clock_gate_i2s0_tx (Clock_gate1, 1, 9, true), // I2S0_dev_tclk |
paul@201 | 214 | Clock_gate_i2s0_rx (Clock_gate1, 1, 8, true), // I2S0_dev_rclk |
paul@201 | 215 | Clock_gate_hash (Clock_gate1, 1, 6, true), // HASH |
paul@201 | 216 | Clock_gate_pwm (Clock_gate1, 1, 5, true), // PWM |
paul@201 | 217 | Clock_gate_cdbus (Clock_gate1, 1, 2, true), // CDBUS |
paul@201 | 218 | Clock_gate_can1 (Clock_gate1, 1, 1, true), // CAN1 |
paul@201 | 219 | Clock_gate_can0 (Clock_gate1, 1, 0, true), // CAN0 |
paul@243 | 220 | Clock_gate_usb_phy (Sleep_control, 1, 23, true), // gate_usbphy_clk |
paul@168 | 221 | |
paul@175 | 222 | Pll_enable_A (Pll_control_A, 1, 0), // APLLEN |
paul@175 | 223 | Pll_enable_E (Pll_control_E, 1, 0), // EPLLEN |
paul@175 | 224 | Pll_enable_M (Pll_control_M, 1, 0), // MPLLEN |
paul@168 | 225 | |
paul@175 | 226 | Pll_stable_A (Pll_control_A, 1, 3), // APLL_ON |
paul@175 | 227 | Pll_stable_E (Pll_control_E, 1, 3), // EPLL_ON |
paul@175 | 228 | Pll_stable_M (Pll_control_M, 1, 3), // MPLL_ON |
paul@175 | 229 | |
paul@175 | 230 | Pll_bypass_A (Pll_control_A, 1, 30), // APLL_BP |
paul@175 | 231 | Pll_bypass_E (Pll_control_E, 1, 26), // EPLL_BP |
paul@175 | 232 | Pll_bypass_M (Pll_control_M, 1, 28), // MPLL_BP |
paul@168 | 233 | |
paul@187 | 234 | Pll_multiplier_A (Pll_control_A, 0xfff, 20), // APLLM |
paul@187 | 235 | Pll_multiplier_E (Pll_control_E, 0x3f, 20), // EPLLM (observed) |
paul@187 | 236 | Pll_multiplier_M (Pll_control_M, 0xfff, 20), // MPLLM |
paul@175 | 237 | |
paul@175 | 238 | Pll_input_division_A (Pll_control_A, 0x3f, 14), // APLLN |
paul@175 | 239 | Pll_input_division_E (Pll_control_E, 0x3f, 14), // EPLLN |
paul@175 | 240 | Pll_input_division_M (Pll_control_M, 0x3f, 14), // MPLLN |
paul@168 | 241 | |
paul@175 | 242 | Pll_output_division1_A (Pll_control_A, 0x07, 11), // APLLOD1 |
paul@175 | 243 | Pll_output_division1_E (Pll_control_E, 0x07, 11), // EPLLOD1 |
paul@175 | 244 | Pll_output_division1_M (Pll_control_M, 0x07, 11), // MPLLOD1 |
paul@175 | 245 | |
paul@175 | 246 | Pll_output_division0_A (Pll_control_A, 0x07, 8), // APLLOD0 |
paul@175 | 247 | Pll_output_division0_E (Pll_control_E, 0x07, 8), // EPLLOD0 |
paul@175 | 248 | Pll_output_division0_M (Pll_control_M, 0x07, 8); // MPLLOD0 |
paul@167 | 249 | |
paul@167 | 250 | |
paul@167 | 251 | |
paul@169 | 252 | // Multiplexer instances. |
paul@169 | 253 | |
paul@169 | 254 | #define Clocks(...) ((enum Clock_identifiers []) {__VA_ARGS__}) |
paul@243 | 255 | #define Specific(CLOCK) ((enum Clock_identifiers) (CLOCK)) |
paul@169 | 256 | |
paul@243 | 257 | static Mux mux_external (Clock_external), |
paul@211 | 258 | |
paul@211 | 259 | // Clocks being propagated to others. |
paul@211 | 260 | |
paul@211 | 261 | mux_hclock0 (Clock_hclock0), |
paul@211 | 262 | mux_hclock2 (Clock_hclock2), |
paul@211 | 263 | mux_pclock (Clock_pclock), |
paul@211 | 264 | mux_hclock2_pclock (Clock_hclock2_pclock), |
paul@211 | 265 | mux_i2s0_rx (Clock_i2s0), |
paul@211 | 266 | mux_i2s0_tx (Clock_i2s1), |
paul@243 | 267 | mux_usb_phy (Specific(Clock_usb_phy_12MHz)), |
paul@211 | 268 | |
paul@211 | 269 | // Main peripheral and bus clock sources. |
paul@211 | 270 | |
paul@211 | 271 | mux_bus (4, Clocks(Clock_main, Clock_pll_M, Clock_pll_E, Clock_external)), |
paul@176 | 272 | mux_core (3, Clocks(Clock_none, Clock_main, Clock_pll_M)), |
paul@176 | 273 | mux_dev (3, Clocks(Clock_main, Clock_pll_M, Clock_pll_E)), |
paul@211 | 274 | mux_main (3, Clocks(Clock_none, Clock_external, Clock_pll_A)), |
paul@239 | 275 | mux_i2s (2, Clocks(Clock_main, Clock_pll_E)), |
paul@284 | 276 | mux_rtc (2, Clocks(Clock_external_div, Clock_rtc_external)); |
paul@169 | 277 | |
paul@169 | 278 | |
paul@169 | 279 | |
paul@165 | 280 | // Clock instances. |
paul@165 | 281 | |
paul@183 | 282 | static Clock_null clock_none; |
paul@183 | 283 | |
paul@239 | 284 | static Clock_passive clock_external(24000000), |
paul@243 | 285 | clock_rtc_external(32768), |
paul@243 | 286 | clock_usb_phy_12MHz(12000000); |
paul@165 | 287 | |
paul@183 | 288 | // Note the use of extra parentheses due to the annoying C++ "most vexing parse" |
paul@183 | 289 | // problem. See: https://en.wikipedia.org/wiki/Most_vexing_parse |
paul@165 | 290 | |
paul@211 | 291 | static Clock clock_aic((Source(mux_hclock2)), (Control(Clock_gate_aic))), |
paul@201 | 292 | |
paul@201 | 293 | clock_dma((Source(mux_hclock2)), (Control(Clock_gate_dma))), |
paul@184 | 294 | |
paul@184 | 295 | clock_i2c0((Source(mux_pclock)), (Control(Clock_gate_i2c0))), |
paul@184 | 296 | |
paul@184 | 297 | clock_i2c1((Source(mux_pclock)), (Control(Clock_gate_i2c1))), |
paul@184 | 298 | |
paul@201 | 299 | clock_i2s0(Source(mux_i2s, Clock_source_i2s0), Control(Clock_gate_i2s0)), |
paul@201 | 300 | |
paul@201 | 301 | clock_i2s1(Source(mux_i2s, Clock_source_i2s1), Control(Clock_gate_i2s1)), |
paul@201 | 302 | |
paul@192 | 303 | clock_main(Source(mux_main, Clock_source_main), Control(Clock_gate_main)), |
paul@184 | 304 | |
paul@185 | 305 | clock_mipi_csi((Source(mux_hclock0)), Control(Clock_gate_mipi_csi)), |
paul@185 | 306 | |
paul@244 | 307 | clock_nemc((Source(mux_hclock2)), (Control(Clock_gate_nemc))), |
paul@244 | 308 | |
paul@211 | 309 | clock_otg0((Source(mux_hclock2)), (Control(Clock_gate_otg))), |
paul@185 | 310 | |
paul@239 | 311 | clock_rtc(Source(mux_rtc, Clock_source_rtc), (Control(Clock_gate_rtc))), |
paul@239 | 312 | |
paul@244 | 313 | clock_sadc((Source(mux_hclock2)), (Control(Clock_gate_sadc))), |
paul@244 | 314 | |
paul@248 | 315 | // Input pins can also be configured for the timer. |
paul@248 | 316 | // NOTE: Support the prescaling for EXCLK. |
paul@248 | 317 | |
paul@248 | 318 | clock_timer((Source(mux_external)), (Control(Clock_gate_timer))), |
paul@184 | 319 | |
paul@184 | 320 | clock_uart0((Source(mux_external)), (Control(Clock_gate_uart0))), |
paul@184 | 321 | |
paul@184 | 322 | clock_uart1((Source(mux_external)), (Control(Clock_gate_uart1))), |
paul@184 | 323 | |
paul@184 | 324 | clock_uart2((Source(mux_external)), (Control(Clock_gate_uart2))), |
paul@184 | 325 | |
paul@211 | 326 | clock_uart3((Source(mux_external)), (Control(Clock_gate_uart3))), |
paul@211 | 327 | |
paul@243 | 328 | clock_usb_phy((Source(mux_usb_phy)), (Control(Clock_gate_usb_phy))), |
paul@243 | 329 | |
paul@211 | 330 | // Special parent clock for hclock2 and pclock. |
paul@211 | 331 | |
paul@211 | 332 | clock_hclock2_pclock(Source(mux_core, Clock_source_hclock2), |
paul@211 | 333 | Control(Clock_gate_apb0, Clock_change_enable_ahb2)); |
paul@184 | 334 | |
paul@184 | 335 | static Clock_divided |
paul@184 | 336 | clock_can0(Source(mux_bus, Clock_source_can0), |
paul@276 | 337 | Control(Clock_gate_can0, Clock_change_enable_can0, Clock_busy_can0, |
paul@276 | 338 | Clock_stop_can0), |
paul@184 | 339 | Divider(Clock_divider_can0)), |
paul@184 | 340 | |
paul@184 | 341 | clock_can1(Source(mux_bus, Clock_source_can1), |
paul@276 | 342 | Control(Clock_gate_can1, Clock_change_enable_can1, Clock_busy_can1, |
paul@276 | 343 | Clock_stop_can1), |
paul@184 | 344 | Divider(Clock_divider_can1)), |
paul@184 | 345 | |
paul@184 | 346 | clock_cdbus(Source(mux_dev, Clock_source_cdbus), |
paul@276 | 347 | Control(Clock_gate_cdbus, Clock_change_enable_cdbus, Clock_busy_cdbus, |
paul@276 | 348 | Clock_stop_cdbus), |
paul@184 | 349 | Divider(Clock_divider_cdbus)), |
paul@184 | 350 | |
paul@184 | 351 | clock_cim(Source(mux_dev, Clock_source_cim), |
paul@276 | 352 | Control(Clock_gate_cim, Clock_change_enable_cim, Clock_busy_cim, |
paul@276 | 353 | Clock_stop_cim), |
paul@184 | 354 | Divider(Clock_divider_cim)), |
paul@184 | 355 | |
paul@184 | 356 | clock_cpu(Source(mux_core, Clock_source_cpu), |
paul@184 | 357 | Control(Field::undefined, Clock_change_enable_cpu, Clock_busy_cpu), |
paul@184 | 358 | Divider(Clock_divider_cpu)), |
paul@184 | 359 | |
paul@184 | 360 | clock_ddr(Source(mux_core, Clock_source_ddr), |
paul@276 | 361 | Control(Clock_gate_ddr, Clock_change_enable_ddr, Clock_busy_ddr, |
paul@276 | 362 | Clock_stop_ddr), |
paul@184 | 363 | Divider(Clock_divider_ddr)), |
paul@184 | 364 | |
paul@184 | 365 | clock_hclock0(Source(mux_core, Clock_source_hclock0), |
paul@184 | 366 | Control(Clock_gate_ahb0, Clock_change_enable_ahb0), |
paul@184 | 367 | Divider(Clock_divider_hclock0)), |
paul@184 | 368 | |
paul@211 | 369 | clock_hclock2((Source(mux_hclock2_pclock)), (Divider(Clock_divider_hclock2))), |
paul@184 | 370 | |
paul@240 | 371 | clock_l2cache(Source(mux_core, Clock_source_cpu), |
paul@240 | 372 | Control(Field::undefined, Clock_change_enable_cpu, Clock_busy_cpu), |
paul@240 | 373 | Divider(Clock_divider_l2cache)), |
paul@240 | 374 | |
paul@184 | 375 | clock_lcd_pixel(Source(mux_dev, Clock_source_lcd), |
paul@276 | 376 | Control(Clock_gate_lcd_pixel, Clock_change_enable_lcd, Clock_busy_lcd, |
paul@276 | 377 | Clock_stop_lcd), |
paul@184 | 378 | Divider(Clock_divider_lcd)), |
paul@165 | 379 | |
paul@184 | 380 | clock_mac(Source(mux_dev, Clock_source_mac), |
paul@276 | 381 | Control(Clock_gate_gmac0, Clock_change_enable_mac, Clock_busy_mac, |
paul@276 | 382 | Clock_stop_mac), |
paul@184 | 383 | Divider(Clock_divider_mac)), |
paul@184 | 384 | |
paul@184 | 385 | clock_msc0(Source(mux_dev, Clock_source_msc0), |
paul@276 | 386 | Control(Clock_gate_msc0, Clock_change_enable_msc0, Clock_busy_msc0, |
paul@276 | 387 | Clock_stop_msc0), |
paul@244 | 388 | Divider(Clock_divider_msc0, 2)), |
paul@184 | 389 | |
paul@184 | 390 | clock_msc1(Source(mux_dev, Clock_source_msc1), |
paul@276 | 391 | Control(Clock_gate_msc1, Clock_change_enable_msc1, Clock_busy_msc1, |
paul@276 | 392 | Clock_stop_msc1), |
paul@244 | 393 | Divider(Clock_divider_msc1, 2)), |
paul@184 | 394 | |
paul@211 | 395 | clock_pclock((Source(mux_hclock2_pclock)), (Divider(Clock_divider_pclock))), |
paul@184 | 396 | |
paul@184 | 397 | clock_pwm0(Source(mux_dev, Clock_source_pwm), |
paul@276 | 398 | Control(Clock_gate_pwm, Clock_change_enable_pwm, Clock_busy_pwm, |
paul@276 | 399 | Clock_stop_pwm), |
paul@184 | 400 | Divider(Clock_divider_pwm)), |
paul@165 | 401 | |
paul@184 | 402 | clock_sfc(Source(mux_dev, Clock_source_sfc), |
paul@276 | 403 | Control(Clock_gate_sfc, Clock_change_enable_sfc, Clock_busy_sfc, |
paul@276 | 404 | Clock_stop_sfc), |
paul@184 | 405 | Divider(Clock_divider_sfc)), |
paul@165 | 406 | |
paul@211 | 407 | clock_ssi0(Source(mux_dev, Clock_source_ssi), |
paul@276 | 408 | Control(Clock_gate_ssi0, Clock_change_enable_ssi, Clock_busy_ssi, |
paul@276 | 409 | Clock_stop_ssi), |
paul@211 | 410 | Divider(Clock_divider_ssi)); |
paul@184 | 411 | |
paul@239 | 412 | static Clock_divided_fixed |
paul@284 | 413 | clock_external_div((Source(mux_external)), (Divider_fixed(512))); |
paul@239 | 414 | |
paul@184 | 415 | static Clock_divided_i2s |
paul@201 | 416 | clock_i2s0_rx(Source(mux_i2s0_rx), |
paul@185 | 417 | Control(Clock_gate_i2s0_rx), |
paul@184 | 418 | Divider_i2s(Clock_divider_i2s0_m, Clock_divider_i2s0_n, |
paul@185 | 419 | Clock_divider_i2s0_d, Clock_divider_i2s0_n_auto, |
paul@185 | 420 | Clock_divider_i2s0_d_auto)), |
paul@165 | 421 | |
paul@201 | 422 | clock_i2s0_tx(Source(mux_i2s0_tx), |
paul@185 | 423 | Control(Clock_gate_i2s0_tx), |
paul@184 | 424 | Divider_i2s(Clock_divider_i2s1_m, Clock_divider_i2s1_n, |
paul@185 | 425 | Clock_divider_i2s1_d, Clock_divider_i2s1_n_auto, |
paul@185 | 426 | Clock_divider_i2s1_d_auto)); |
paul@184 | 427 | |
paul@211 | 428 | const double x1600_pll_intermediate_min = 600000000, |
paul@211 | 429 | x1600_pll_intermediate_max = 2400000000; |
paul@211 | 430 | |
paul@184 | 431 | static Pll clock_pll_A(Source(mux_external), |
paul@184 | 432 | Control_pll(Pll_enable_A, Pll_stable_A, Pll_bypass_A), |
paul@184 | 433 | Divider_pll(Pll_multiplier_A, Pll_input_division_A, |
paul@211 | 434 | Pll_output_division0_A, Pll_output_division1_A, |
paul@247 | 435 | x1600_pll_intermediate_min, x1600_pll_intermediate_max)), |
paul@165 | 436 | |
paul@184 | 437 | clock_pll_E(Source(mux_external), |
paul@184 | 438 | Control_pll(Pll_enable_E, Pll_stable_E, Pll_bypass_E), |
paul@184 | 439 | Divider_pll(Pll_multiplier_E, Pll_input_division_E, |
paul@211 | 440 | Pll_output_division0_E, Pll_output_division1_E, |
paul@247 | 441 | x1600_pll_intermediate_min, x1600_pll_intermediate_max)), |
paul@184 | 442 | |
paul@184 | 443 | clock_pll_M(Source(mux_external), |
paul@184 | 444 | Control_pll(Pll_enable_M, Pll_stable_M, Pll_bypass_M), |
paul@184 | 445 | Divider_pll(Pll_multiplier_M, Pll_input_division_M, |
paul@211 | 446 | Pll_output_division0_M, Pll_output_division1_M, |
paul@247 | 447 | x1600_pll_intermediate_min, x1600_pll_intermediate_max)); |
paul@165 | 448 | |
paul@165 | 449 | |
paul@165 | 450 | |
paul@165 | 451 | // Clock register. |
paul@165 | 452 | |
paul@243 | 453 | static Clock_base *clocks[Clock_x1600_identifier_count] = { |
paul@243 | 454 | &clock_none, |
paul@243 | 455 | |
paul@211 | 456 | &clock_aic, |
paul@211 | 457 | &clock_none, // Clock_aic_bitclk |
paul@211 | 458 | &clock_none, // Clock_aic_pclk |
paul@165 | 459 | &clock_can0, |
paul@165 | 460 | &clock_can1, |
paul@165 | 461 | &clock_cdbus, |
paul@165 | 462 | &clock_cim, |
paul@165 | 463 | &clock_cpu, |
paul@165 | 464 | &clock_ddr, |
paul@165 | 465 | &clock_dma, |
paul@211 | 466 | &clock_none, // Clock_emac |
paul@165 | 467 | &clock_external, |
paul@284 | 468 | &clock_external_div, |
paul@165 | 469 | &clock_hclock0, |
paul@165 | 470 | &clock_hclock2, |
paul@211 | 471 | &clock_hclock2_pclock, |
paul@211 | 472 | &clock_none, // Clock_hdmi |
paul@165 | 473 | &clock_i2c0, |
paul@165 | 474 | &clock_i2c1, |
paul@211 | 475 | &clock_none, // Clock_i2c2 |
paul@211 | 476 | &clock_none, // Clock_i2c3 |
paul@211 | 477 | &clock_none, // Clock_i2c4 |
paul@211 | 478 | &clock_i2s0, // supplies i2s0_rx |
paul@165 | 479 | &clock_i2s0_rx, |
paul@165 | 480 | &clock_i2s0_tx, |
paul@211 | 481 | &clock_i2s1, // supplies i2s0_tx |
paul@211 | 482 | &clock_none, // Clock_i2s1_rx |
paul@211 | 483 | &clock_none, // Clock_i2s1_tx |
paul@211 | 484 | &clock_none, // Clock_kbc |
paul@240 | 485 | &clock_l2cache, |
paul@211 | 486 | &clock_none, // Clock_lcd |
paul@165 | 487 | &clock_lcd_pixel, |
paul@211 | 488 | &clock_none, // Clock_lcd_pixel1 |
paul@165 | 489 | &clock_mac, |
paul@165 | 490 | &clock_main, |
paul@284 | 491 | &clock_none, // Clock_mclock |
paul@185 | 492 | &clock_mipi_csi, |
paul@211 | 493 | &clock_none, // Clock_msc |
paul@165 | 494 | &clock_msc0, |
paul@165 | 495 | &clock_msc1, |
paul@211 | 496 | &clock_none, // Clock_msc2 |
paul@244 | 497 | &clock_nemc, |
paul@211 | 498 | &clock_otg0, |
paul@211 | 499 | &clock_none, // Clock_otg1 |
paul@165 | 500 | &clock_pclock, |
paul@215 | 501 | &clock_none, // Clock_pcm |
paul@284 | 502 | &clock_none, // Clock_pll |
paul@165 | 503 | &clock_pll_A, |
paul@165 | 504 | &clock_pll_E, |
paul@165 | 505 | &clock_pll_M, |
paul@211 | 506 | &clock_none, // Clock_pll_V |
paul@165 | 507 | &clock_pwm0, |
paul@211 | 508 | &clock_none, // Clock_pwm1 |
paul@239 | 509 | &clock_rtc, |
paul@239 | 510 | &clock_rtc_external, |
paul@244 | 511 | &clock_sadc, |
paul@211 | 512 | &clock_none, // Clock_scc |
paul@165 | 513 | &clock_sfc, |
paul@211 | 514 | &clock_none, // Clock_ssi |
paul@211 | 515 | &clock_ssi0, |
paul@211 | 516 | &clock_none, // Clock_ssi1 |
paul@211 | 517 | &clock_none, // Clock_ssi2 |
paul@165 | 518 | &clock_timer, |
paul@165 | 519 | &clock_uart0, |
paul@165 | 520 | &clock_uart1, |
paul@165 | 521 | &clock_uart2, |
paul@165 | 522 | &clock_uart3, |
paul@214 | 523 | &clock_none, // Clock_uart4 |
paul@211 | 524 | &clock_none, // Clock_udc |
paul@211 | 525 | &clock_none, // Clock_uhc |
paul@211 | 526 | &clock_none, // Clock_uprt |
paul@243 | 527 | &clock_usb_phy, |
paul@213 | 528 | &clock_none, // Clock_vpu |
paul@243 | 529 | |
paul@243 | 530 | /* X1600-specific clocks. */ |
paul@243 | 531 | |
paul@243 | 532 | &clock_usb_phy_12MHz, |
paul@165 | 533 | }; |
paul@165 | 534 | |
paul@165 | 535 | |
paul@165 | 536 | |
paul@211 | 537 | // Peripheral abstraction. |
paul@161 | 538 | |
paul@211 | 539 | Cpm_x1600_chip::Cpm_x1600_chip(l4_addr_t addr) |
paul@211 | 540 | : Cpm_chip(addr, clocks) |
paul@160 | 541 | { |
paul@160 | 542 | } |
paul@160 | 543 | |
paul@284 | 544 | Cpm_chip * |
paul@284 | 545 | x1600_cpm_chip(l4_addr_t cpm_base) |
paul@284 | 546 | { |
paul@284 | 547 | return new Cpm_x1600_chip(cpm_base); |
paul@284 | 548 | } |
paul@284 | 549 | |
paul@160 | 550 | |
paul@160 | 551 | |
paul@160 | 552 | // C language interface functions. |
paul@160 | 553 | |
paul@160 | 554 | void |
paul@160 | 555 | *x1600_cpm_init(l4_addr_t cpm_base) |
paul@160 | 556 | { |
paul@211 | 557 | return (void *) new Cpm_x1600_chip(cpm_base); |
paul@160 | 558 | } |
paul@160 | 559 | |
paul@176 | 560 | const char * |
paul@176 | 561 | x1600_cpm_clock_type(void *cpm, enum Clock_identifiers clock) |
paul@176 | 562 | { |
paul@284 | 563 | return static_cast<Cpm_chip *>(cpm)->clock_type(clock); |
paul@176 | 564 | } |
paul@176 | 565 | |
paul@160 | 566 | int |
paul@160 | 567 | x1600_cpm_have_clock(void *cpm, enum Clock_identifiers clock) |
paul@160 | 568 | { |
paul@284 | 569 | return static_cast<Cpm_chip *>(cpm)->have_clock(clock); |
paul@160 | 570 | } |
paul@160 | 571 | |
paul@160 | 572 | void |
paul@160 | 573 | x1600_cpm_start_clock(void *cpm, enum Clock_identifiers clock) |
paul@160 | 574 | { |
paul@284 | 575 | static_cast<Cpm_chip *>(cpm)->start_clock(clock); |
paul@160 | 576 | } |
paul@160 | 577 | |
paul@160 | 578 | void |
paul@160 | 579 | x1600_cpm_stop_clock(void *cpm, enum Clock_identifiers clock) |
paul@160 | 580 | { |
paul@284 | 581 | static_cast<Cpm_chip *>(cpm)->stop_clock(clock); |
paul@160 | 582 | } |
paul@160 | 583 | |
paul@178 | 584 | int |
paul@178 | 585 | x1600_cpm_get_parameters(void *cpm, enum Clock_identifiers clock, uint32_t parameters[]) |
paul@184 | 586 | { |
paul@284 | 587 | return static_cast<Cpm_chip *>(cpm)->get_parameters(clock, parameters); |
paul@160 | 588 | } |
paul@160 | 589 | |
paul@185 | 590 | int |
paul@185 | 591 | x1600_cpm_set_parameters(void *cpm, enum Clock_identifiers clock, int num_parameters, uint32_t parameters[]) |
paul@184 | 592 | { |
paul@284 | 593 | return static_cast<Cpm_chip *>(cpm)->set_parameters(clock, num_parameters, parameters); |
paul@160 | 594 | } |
paul@160 | 595 | |
paul@160 | 596 | uint8_t |
paul@161 | 597 | x1600_cpm_get_source(void *cpm, enum Clock_identifiers clock) |
paul@184 | 598 | { |
paul@284 | 599 | return static_cast<Cpm_chip *>(cpm)->get_source(clock); |
paul@160 | 600 | } |
paul@160 | 601 | |
paul@160 | 602 | void |
paul@161 | 603 | x1600_cpm_set_source(void *cpm, enum Clock_identifiers clock, uint8_t source) |
paul@184 | 604 | { |
paul@284 | 605 | static_cast<Cpm_chip *>(cpm)->set_source(clock, source); |
paul@160 | 606 | } |
paul@160 | 607 | |
paul@185 | 608 | enum Clock_identifiers |
paul@185 | 609 | x1600_cpm_get_source_clock(void *cpm, enum Clock_identifiers clock) |
paul@185 | 610 | { |
paul@284 | 611 | return static_cast<Cpm_chip *>(cpm)->get_source_clock(clock); |
paul@185 | 612 | } |
paul@185 | 613 | |
paul@185 | 614 | void |
paul@185 | 615 | x1600_cpm_set_source_clock(void *cpm, enum Clock_identifiers clock, enum Clock_identifiers source) |
paul@185 | 616 | { |
paul@284 | 617 | static_cast<Cpm_chip *>(cpm)->set_source_clock(clock, source); |
paul@185 | 618 | } |
paul@185 | 619 | |
paul@213 | 620 | uint64_t |
paul@161 | 621 | x1600_cpm_get_source_frequency(void *cpm, enum Clock_identifiers clock) |
paul@184 | 622 | { |
paul@284 | 623 | return static_cast<Cpm_chip *>(cpm)->get_source_frequency(clock); |
paul@160 | 624 | } |
paul@160 | 625 | |
paul@213 | 626 | uint64_t |
paul@160 | 627 | x1600_cpm_get_frequency(void *cpm, enum Clock_identifiers clock) |
paul@160 | 628 | { |
paul@284 | 629 | return static_cast<Cpm_chip *>(cpm)->get_frequency(clock); |
paul@160 | 630 | } |
paul@160 | 631 | |
paul@187 | 632 | int |
paul@213 | 633 | x1600_cpm_set_frequency(void *cpm, enum Clock_identifiers clock, uint64_t frequency) |
paul@160 | 634 | { |
paul@284 | 635 | return static_cast<Cpm_chip *>(cpm)->set_frequency(clock, frequency); |
paul@160 | 636 | } |