Thomas Gleixner | b886d83c | 2019-06-01 10:08:55 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 2 | /* |
| 3 | * Marvell PXA3xxx family clocks |
| 4 | * |
| 5 | * Copyright (C) 2014 Robert Jarzmik |
| 6 | * |
| 7 | * Heavily inspired from former arch/arm/mach-pxa/pxa3xx.c |
| 8 | * |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 9 | * For non-devicetree platforms. Once pxa is fully converted to devicetree, this |
| 10 | * should go away. |
| 11 | */ |
| 12 | #include <linux/io.h> |
| 13 | #include <linux/clk.h> |
| 14 | #include <linux/clk-provider.h> |
| 15 | #include <linux/clkdev.h> |
| 16 | #include <linux/of.h> |
Arnd Bergmann | 08d3df8 | 2019-09-01 22:26:10 +0200 | [diff] [blame] | 17 | #include <linux/soc/pxa/cpu.h> |
Arnd Bergmann | fd13f81 | 2019-09-18 17:42:52 +0200 | [diff] [blame] | 18 | #include <linux/soc/pxa/smemc.h> |
Arnd Bergmann | 5c6603e | 2019-09-18 15:34:10 +0200 | [diff] [blame] | 19 | #include <linux/clk/pxa.h> |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 20 | |
| 21 | #include <dt-bindings/clock/pxa-clock.h> |
| 22 | #include "clk-pxa.h" |
| 23 | |
| 24 | #define KHz 1000 |
| 25 | #define MHz (1000 * 1000) |
| 26 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 27 | #define ACCR (0x0000) /* Application Subsystem Clock Configuration Register */ |
| 28 | #define ACSR (0x0004) /* Application Subsystem Clock Status Register */ |
| 29 | #define AICSR (0x0008) /* Application Subsystem Interrupt Control/Status Register */ |
| 30 | #define CKENA (0x000C) /* A Clock Enable Register */ |
| 31 | #define CKENB (0x0010) /* B Clock Enable Register */ |
| 32 | #define CKENC (0x0024) /* C Clock Enable Register */ |
| 33 | #define AC97_DIV (0x0014) /* AC97 clock divisor value register */ |
| 34 | |
| 35 | #define ACCR_XPDIS (1 << 31) /* Core PLL Output Disable */ |
| 36 | #define ACCR_SPDIS (1 << 30) /* System PLL Output Disable */ |
| 37 | #define ACCR_D0CS (1 << 26) /* D0 Mode Clock Select */ |
| 38 | #define ACCR_PCCE (1 << 11) /* Power Mode Change Clock Enable */ |
| 39 | #define ACCR_DDR_D0CS (1 << 7) /* DDR SDRAM clock frequency in D0CS (PXA31x only) */ |
| 40 | |
| 41 | #define ACCR_SMCFS_MASK (0x7 << 23) /* Static Memory Controller Frequency Select */ |
| 42 | #define ACCR_SFLFS_MASK (0x3 << 18) /* Frequency Select for Internal Memory Controller */ |
| 43 | #define ACCR_XSPCLK_MASK (0x3 << 16) /* Core Frequency during Frequency Change */ |
| 44 | #define ACCR_HSS_MASK (0x3 << 14) /* System Bus-Clock Frequency Select */ |
| 45 | #define ACCR_DMCFS_MASK (0x3 << 12) /* Dynamic Memory Controller Clock Frequency Select */ |
| 46 | #define ACCR_XN_MASK (0x7 << 8) /* Core PLL Turbo-Mode-to-Run-Mode Ratio */ |
| 47 | #define ACCR_XL_MASK (0x1f) /* Core PLL Run-Mode-to-Oscillator Ratio */ |
| 48 | |
| 49 | #define ACCR_SMCFS(x) (((x) & 0x7) << 23) |
| 50 | #define ACCR_SFLFS(x) (((x) & 0x3) << 18) |
| 51 | #define ACCR_XSPCLK(x) (((x) & 0x3) << 16) |
| 52 | #define ACCR_HSS(x) (((x) & 0x3) << 14) |
| 53 | #define ACCR_DMCFS(x) (((x) & 0x3) << 12) |
| 54 | #define ACCR_XN(x) (((x) & 0x7) << 8) |
| 55 | #define ACCR_XL(x) ((x) & 0x1f) |
| 56 | |
| 57 | /* |
| 58 | * Clock Enable Bit |
| 59 | */ |
| 60 | #define CKEN_LCD 1 /* < LCD Clock Enable */ |
| 61 | #define CKEN_USBH 2 /* < USB host clock enable */ |
| 62 | #define CKEN_CAMERA 3 /* < Camera interface clock enable */ |
| 63 | #define CKEN_NAND 4 /* < NAND Flash Controller Clock Enable */ |
| 64 | #define CKEN_USB2 6 /* < USB 2.0 client clock enable. */ |
| 65 | #define CKEN_DMC 8 /* < Dynamic Memory Controller clock enable */ |
| 66 | #define CKEN_SMC 9 /* < Static Memory Controller clock enable */ |
| 67 | #define CKEN_ISC 10 /* < Internal SRAM Controller clock enable */ |
| 68 | #define CKEN_BOOT 11 /* < Boot rom clock enable */ |
| 69 | #define CKEN_MMC1 12 /* < MMC1 Clock enable */ |
| 70 | #define CKEN_MMC2 13 /* < MMC2 clock enable */ |
| 71 | #define CKEN_KEYPAD 14 /* < Keypand Controller Clock Enable */ |
| 72 | #define CKEN_CIR 15 /* < Consumer IR Clock Enable */ |
| 73 | #define CKEN_USIM0 17 /* < USIM[0] Clock Enable */ |
| 74 | #define CKEN_USIM1 18 /* < USIM[1] Clock Enable */ |
| 75 | #define CKEN_TPM 19 /* < TPM clock enable */ |
| 76 | #define CKEN_UDC 20 /* < UDC clock enable */ |
| 77 | #define CKEN_BTUART 21 /* < BTUART clock enable */ |
| 78 | #define CKEN_FFUART 22 /* < FFUART clock enable */ |
| 79 | #define CKEN_STUART 23 /* < STUART clock enable */ |
| 80 | #define CKEN_AC97 24 /* < AC97 clock enable */ |
| 81 | #define CKEN_TOUCH 25 /* < Touch screen Interface Clock Enable */ |
| 82 | #define CKEN_SSP1 26 /* < SSP1 clock enable */ |
| 83 | #define CKEN_SSP2 27 /* < SSP2 clock enable */ |
| 84 | #define CKEN_SSP3 28 /* < SSP3 clock enable */ |
| 85 | #define CKEN_SSP4 29 /* < SSP4 clock enable */ |
| 86 | #define CKEN_MSL0 30 /* < MSL0 clock enable */ |
| 87 | #define CKEN_PWM0 32 /* < PWM[0] clock enable */ |
| 88 | #define CKEN_PWM1 33 /* < PWM[1] clock enable */ |
| 89 | #define CKEN_I2C 36 /* < I2C clock enable */ |
| 90 | #define CKEN_INTC 38 /* < Interrupt controller clock enable */ |
| 91 | #define CKEN_GPIO 39 /* < GPIO clock enable */ |
| 92 | #define CKEN_1WIRE 40 /* < 1-wire clock enable */ |
| 93 | #define CKEN_HSIO2 41 /* < HSIO2 clock enable */ |
| 94 | #define CKEN_MINI_IM 48 /* < Mini-IM */ |
| 95 | #define CKEN_MINI_LCD 49 /* < Mini LCD */ |
| 96 | |
| 97 | #define CKEN_MMC3 5 /* < MMC3 Clock Enable */ |
| 98 | #define CKEN_MVED 43 /* < MVED clock enable */ |
| 99 | |
| 100 | /* Note: GCU clock enable bit differs on PXA300/PXA310 and PXA320 */ |
| 101 | #define CKEN_PXA300_GCU 42 /* Graphics controller clock enable */ |
| 102 | #define CKEN_PXA320_GCU 7 /* Graphics controller clock enable */ |
| 103 | |
| 104 | |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 105 | enum { |
| 106 | PXA_CORE_60Mhz = 0, |
| 107 | PXA_CORE_RUN, |
| 108 | PXA_CORE_TURBO, |
| 109 | }; |
| 110 | |
| 111 | enum { |
| 112 | PXA_BUS_60Mhz = 0, |
| 113 | PXA_BUS_HSS, |
| 114 | }; |
| 115 | |
| 116 | /* crystal frequency to HSIO bus frequency multiplier (HSS) */ |
| 117 | static unsigned char hss_mult[4] = { 8, 12, 16, 24 }; |
| 118 | |
| 119 | /* crystal frequency to static memory controller multiplier (SMCFS) */ |
| 120 | static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, }; |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 121 | static const char * const get_freq_khz[] = { |
| 122 | "core", "ring_osc_60mhz", "run", "cpll", "system_bus" |
| 123 | }; |
| 124 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 125 | static void __iomem *clk_regs; |
| 126 | |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 127 | /* |
| 128 | * Get the clock frequency as reflected by ACSR and the turbo flag. |
| 129 | * We assume these values have been applied via a fcs. |
| 130 | * If info is not 0 we also display the current settings. |
| 131 | */ |
| 132 | unsigned int pxa3xx_get_clk_frequency_khz(int info) |
| 133 | { |
| 134 | struct clk *clk; |
| 135 | unsigned long clks[5]; |
| 136 | int i; |
| 137 | |
| 138 | for (i = 0; i < 5; i++) { |
| 139 | clk = clk_get(NULL, get_freq_khz[i]); |
| 140 | if (IS_ERR(clk)) { |
| 141 | clks[i] = 0; |
| 142 | } else { |
| 143 | clks[i] = clk_get_rate(clk); |
| 144 | clk_put(clk); |
| 145 | } |
| 146 | } |
| 147 | if (info) { |
| 148 | pr_info("RO Mode clock: %ld.%02ldMHz\n", |
| 149 | clks[1] / 1000000, (clks[0] % 1000000) / 10000); |
| 150 | pr_info("Run Mode clock: %ld.%02ldMHz\n", |
| 151 | clks[2] / 1000000, (clks[1] % 1000000) / 10000); |
| 152 | pr_info("Turbo Mode clock: %ld.%02ldMHz\n", |
| 153 | clks[3] / 1000000, (clks[2] % 1000000) / 10000); |
| 154 | pr_info("System bus clock: %ld.%02ldMHz\n", |
| 155 | clks[4] / 1000000, (clks[4] % 1000000) / 10000); |
| 156 | } |
Robert Jarzmik | 4b5fb7d | 2015-07-12 22:49:53 +0200 | [diff] [blame] | 157 | return (unsigned int)clks[0] / KHz; |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 158 | } |
| 159 | |
Arnd Bergmann | 5c6603e | 2019-09-18 15:34:10 +0200 | [diff] [blame] | 160 | void pxa3xx_clk_update_accr(u32 disable, u32 enable, u32 xclkcfg, u32 mask) |
| 161 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 162 | u32 accr = readl(clk_regs + ACCR); |
Arnd Bergmann | 5c6603e | 2019-09-18 15:34:10 +0200 | [diff] [blame] | 163 | |
| 164 | accr &= ~disable; |
| 165 | accr |= enable; |
| 166 | |
Arnd Bergmann | 23200a4 | 2023-05-11 12:58:33 +0200 | [diff] [blame] | 167 | writel(accr, clk_regs + ACCR); |
Arnd Bergmann | 5c6603e | 2019-09-18 15:34:10 +0200 | [diff] [blame] | 168 | if (xclkcfg) |
| 169 | __asm__("mcr p14, 0, %0, c6, c0, 0\n" : : "r"(xclkcfg)); |
| 170 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 171 | while ((readl(clk_regs + ACSR) & mask) != (accr & mask)) |
Arnd Bergmann | 5c6603e | 2019-09-18 15:34:10 +0200 | [diff] [blame] | 172 | cpu_relax(); |
| 173 | } |
| 174 | |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 175 | static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw, |
| 176 | unsigned long parent_rate) |
| 177 | { |
| 178 | unsigned long ac97_div, rate; |
| 179 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 180 | ac97_div = readl(clk_regs + AC97_DIV); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 181 | |
| 182 | /* This may loose precision for some rates but won't for the |
| 183 | * standard 24.576MHz. |
| 184 | */ |
| 185 | rate = parent_rate / 2; |
| 186 | rate /= ((ac97_div >> 12) & 0x7fff); |
| 187 | rate *= (ac97_div & 0xfff); |
| 188 | |
| 189 | return rate; |
| 190 | } |
| 191 | PARENTS(clk_pxa3xx_ac97) = { "spll_624mhz" }; |
| 192 | RATE_RO_OPS(clk_pxa3xx_ac97, "ac97"); |
| 193 | |
| 194 | static unsigned long clk_pxa3xx_smemc_get_rate(struct clk_hw *hw, |
| 195 | unsigned long parent_rate) |
| 196 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 197 | unsigned long acsr = readl(clk_regs + ACSR); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 198 | |
| 199 | return (parent_rate / 48) * smcfs_mult[(acsr >> 23) & 0x7] / |
Arnd Bergmann | fd13f81 | 2019-09-18 17:42:52 +0200 | [diff] [blame] | 200 | pxa3xx_smemc_get_memclkdiv(); |
| 201 | |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 202 | } |
| 203 | PARENTS(clk_pxa3xx_smemc) = { "spll_624mhz" }; |
| 204 | RATE_RO_OPS(clk_pxa3xx_smemc, "smemc"); |
| 205 | |
| 206 | static bool pxa3xx_is_ring_osc_forced(void) |
| 207 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 208 | unsigned long acsr = readl(clk_regs + ACSR); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 209 | |
| 210 | return acsr & ACCR_D0CS; |
| 211 | } |
| 212 | |
| 213 | PARENTS(pxa3xx_pbus) = { "ring_osc_60mhz", "spll_624mhz" }; |
| 214 | PARENTS(pxa3xx_32Khz_bus) = { "osc_32_768khz", "osc_32_768khz" }; |
| 215 | PARENTS(pxa3xx_13MHz_bus) = { "osc_13mhz", "osc_13mhz" }; |
| 216 | PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" }; |
| 217 | PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" }; |
| 218 | PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" }; |
| 219 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 220 | #define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? CKENB : CKENA) |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 221 | #define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \ |
| 222 | div_hp, bit, is_lp, flags) \ |
| 223 | PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \ |
| 224 | mult_hp, div_hp, is_lp, CKEN_AB(bit), \ |
| 225 | (CKEN_ ## bit % 32), flags) |
| 226 | #define PXA3XX_PBUS_CKEN(dev_id, con_id, bit, mult_lp, div_lp, \ |
| 227 | mult_hp, div_hp, delay) \ |
| 228 | PXA3XX_CKEN(dev_id, con_id, pxa3xx_pbus_parents, mult_lp, \ |
| 229 | div_lp, mult_hp, div_hp, bit, pxa3xx_is_ring_osc_forced, 0) |
| 230 | #define PXA3XX_CKEN_1RATE(dev_id, con_id, bit, parents) \ |
| 231 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ |
| 232 | CKEN_AB(bit), (CKEN_ ## bit % 32), 0) |
| 233 | |
| 234 | static struct desc_clk_cken pxa3xx_clocks[] __initdata = { |
| 235 | PXA3XX_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 4, 1, 42, 1), |
| 236 | PXA3XX_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 4, 1, 42, 1), |
| 237 | PXA3XX_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 4, 1, 42, 1), |
| 238 | PXA3XX_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 5, 1, 19, 0), |
| 239 | PXA3XX_PBUS_CKEN("pxa27x-udc", NULL, UDC, 1, 4, 1, 13, 5), |
| 240 | PXA3XX_PBUS_CKEN("pxa27x-ohci", NULL, USBH, 1, 4, 1, 13, 0), |
| 241 | PXA3XX_PBUS_CKEN("pxa3xx-u2d", NULL, USB2, 1, 4, 1, 13, 0), |
| 242 | PXA3XX_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 6, 1, 48, 0), |
| 243 | PXA3XX_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 6, 1, 48, 0), |
| 244 | PXA3XX_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC1, 1, 4, 1, 24, 0), |
| 245 | PXA3XX_PBUS_CKEN("pxa2xx-mci.1", NULL, MMC2, 1, 4, 1, 24, 0), |
| 246 | PXA3XX_PBUS_CKEN("pxa2xx-mci.2", NULL, MMC3, 1, 4, 1, 24, 0), |
| 247 | |
| 248 | PXA3XX_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD, |
| 249 | pxa3xx_32Khz_bus_parents), |
| 250 | PXA3XX_CKEN_1RATE("pxa3xx-ssp.0", NULL, SSP1, pxa3xx_13MHz_bus_parents), |
| 251 | PXA3XX_CKEN_1RATE("pxa3xx-ssp.1", NULL, SSP2, pxa3xx_13MHz_bus_parents), |
| 252 | PXA3XX_CKEN_1RATE("pxa3xx-ssp.2", NULL, SSP3, pxa3xx_13MHz_bus_parents), |
| 253 | PXA3XX_CKEN_1RATE("pxa3xx-ssp.3", NULL, SSP4, pxa3xx_13MHz_bus_parents), |
| 254 | |
| 255 | PXA3XX_CKEN(NULL, "AC97CLK", pxa3xx_ac97_bus_parents, 1, 4, 1, 1, AC97, |
| 256 | pxa3xx_is_ring_osc_forced, 0), |
| 257 | PXA3XX_CKEN(NULL, "CAMCLK", pxa3xx_sbus_parents, 1, 2, 1, 1, CAMERA, |
| 258 | pxa3xx_is_ring_osc_forced, 0), |
| 259 | PXA3XX_CKEN("pxa2xx-fb", NULL, pxa3xx_sbus_parents, 1, 1, 1, 1, LCD, |
| 260 | pxa3xx_is_ring_osc_forced, 0), |
| 261 | PXA3XX_CKEN("pxa2xx-pcmcia", NULL, pxa3xx_smemcbus_parents, 1, 4, |
| 262 | 1, 1, SMC, pxa3xx_is_ring_osc_forced, CLK_IGNORE_UNUSED), |
| 263 | }; |
| 264 | |
| 265 | static struct desc_clk_cken pxa300_310_clocks[] __initdata = { |
| 266 | |
| 267 | PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0), |
| 268 | PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0), |
| 269 | PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents), |
| 270 | }; |
| 271 | |
| 272 | static struct desc_clk_cken pxa320_clocks[] __initdata = { |
| 273 | PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 6, 0), |
| 274 | PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA320_GCU, 1, 1, 1, 1, 0), |
| 275 | PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents), |
| 276 | }; |
| 277 | |
| 278 | static struct desc_clk_cken pxa93x_clocks[] __initdata = { |
| 279 | |
| 280 | PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0), |
| 281 | PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0), |
| 282 | PXA3XX_CKEN_1RATE("pxa93x-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents), |
| 283 | }; |
| 284 | |
| 285 | static unsigned long clk_pxa3xx_system_bus_get_rate(struct clk_hw *hw, |
| 286 | unsigned long parent_rate) |
| 287 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 288 | unsigned long acsr = readl(clk_regs + ACSR); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 289 | unsigned int hss = (acsr >> 14) & 0x3; |
| 290 | |
| 291 | if (pxa3xx_is_ring_osc_forced()) |
| 292 | return parent_rate; |
| 293 | return parent_rate / 48 * hss_mult[hss]; |
| 294 | } |
| 295 | |
| 296 | static u8 clk_pxa3xx_system_bus_get_parent(struct clk_hw *hw) |
| 297 | { |
| 298 | if (pxa3xx_is_ring_osc_forced()) |
| 299 | return PXA_BUS_60Mhz; |
| 300 | else |
| 301 | return PXA_BUS_HSS; |
| 302 | } |
| 303 | |
| 304 | PARENTS(clk_pxa3xx_system_bus) = { "ring_osc_60mhz", "spll_624mhz" }; |
| 305 | MUX_RO_RATE_RO_OPS(clk_pxa3xx_system_bus, "system_bus"); |
| 306 | |
| 307 | static unsigned long clk_pxa3xx_core_get_rate(struct clk_hw *hw, |
| 308 | unsigned long parent_rate) |
| 309 | { |
| 310 | return parent_rate; |
| 311 | } |
| 312 | |
| 313 | static u8 clk_pxa3xx_core_get_parent(struct clk_hw *hw) |
| 314 | { |
| 315 | unsigned long xclkcfg; |
| 316 | unsigned int t; |
| 317 | |
| 318 | if (pxa3xx_is_ring_osc_forced()) |
| 319 | return PXA_CORE_60Mhz; |
| 320 | |
| 321 | /* Read XCLKCFG register turbo bit */ |
| 322 | __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg)); |
| 323 | t = xclkcfg & 0x1; |
| 324 | |
| 325 | if (t) |
| 326 | return PXA_CORE_TURBO; |
| 327 | return PXA_CORE_RUN; |
| 328 | } |
| 329 | PARENTS(clk_pxa3xx_core) = { "ring_osc_60mhz", "run", "cpll" }; |
| 330 | MUX_RO_RATE_RO_OPS(clk_pxa3xx_core, "core"); |
| 331 | |
| 332 | static unsigned long clk_pxa3xx_run_get_rate(struct clk_hw *hw, |
| 333 | unsigned long parent_rate) |
| 334 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 335 | unsigned long acsr = readl(clk_regs + ACSR); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 336 | unsigned int xn = (acsr & ACCR_XN_MASK) >> 8; |
| 337 | unsigned int t, xclkcfg; |
| 338 | |
| 339 | /* Read XCLKCFG register turbo bit */ |
| 340 | __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg)); |
| 341 | t = xclkcfg & 0x1; |
| 342 | |
| 343 | return t ? (parent_rate / xn) * 2 : parent_rate; |
| 344 | } |
| 345 | PARENTS(clk_pxa3xx_run) = { "cpll" }; |
| 346 | RATE_RO_OPS(clk_pxa3xx_run, "run"); |
| 347 | |
| 348 | static unsigned long clk_pxa3xx_cpll_get_rate(struct clk_hw *hw, |
| 349 | unsigned long parent_rate) |
| 350 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 351 | unsigned long acsr = readl(clk_regs + ACSR); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 352 | unsigned int xn = (acsr & ACCR_XN_MASK) >> 8; |
| 353 | unsigned int xl = acsr & ACCR_XL_MASK; |
| 354 | unsigned int t, xclkcfg; |
| 355 | |
| 356 | /* Read XCLKCFG register turbo bit */ |
| 357 | __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg)); |
| 358 | t = xclkcfg & 0x1; |
| 359 | |
| 360 | pr_info("RJK: parent_rate=%lu, xl=%u, xn=%u\n", parent_rate, xl, xn); |
| 361 | return t ? parent_rate * xl * xn : parent_rate * xl; |
| 362 | } |
| 363 | PARENTS(clk_pxa3xx_cpll) = { "osc_13mhz" }; |
| 364 | RATE_RO_OPS(clk_pxa3xx_cpll, "cpll"); |
| 365 | |
| 366 | static void __init pxa3xx_register_core(void) |
| 367 | { |
| 368 | clk_register_clk_pxa3xx_cpll(); |
| 369 | clk_register_clk_pxa3xx_run(); |
| 370 | |
| 371 | clkdev_pxa_register(CLK_CORE, "core", NULL, |
| 372 | clk_register_clk_pxa3xx_core()); |
| 373 | } |
| 374 | |
| 375 | static void __init pxa3xx_register_plls(void) |
| 376 | { |
| 377 | clk_register_fixed_rate(NULL, "osc_13mhz", NULL, |
Stephen Boyd | 2c63935 | 2016-03-01 10:59:56 -0800 | [diff] [blame] | 378 | CLK_GET_RATE_NOCACHE, |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 379 | 13 * MHz); |
Robert Jarzmik | fc20654 | 2018-06-27 21:41:23 +0200 | [diff] [blame] | 380 | clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, |
| 381 | clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, |
| 382 | CLK_GET_RATE_NOCACHE, |
| 383 | 32768)); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 384 | clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL, |
Stephen Boyd | 2c63935 | 2016-03-01 10:59:56 -0800 | [diff] [blame] | 385 | CLK_GET_RATE_NOCACHE, |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 386 | 120 * MHz); |
Stephen Boyd | 2c63935 | 2016-03-01 10:59:56 -0800 | [diff] [blame] | 387 | clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 388 | clk_register_fixed_factor(NULL, "spll_624mhz", "osc_13mhz", 0, 48, 1); |
| 389 | clk_register_fixed_factor(NULL, "ring_osc_60mhz", "ring_osc_120mhz", |
| 390 | 0, 1, 2); |
| 391 | } |
| 392 | |
| 393 | #define DUMMY_CLK(_con_id, _dev_id, _parent) \ |
| 394 | { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent } |
| 395 | struct dummy_clk { |
| 396 | const char *con_id; |
| 397 | const char *dev_id; |
| 398 | const char *parent; |
| 399 | }; |
| 400 | static struct dummy_clk dummy_clks[] __initdata = { |
| 401 | DUMMY_CLK(NULL, "pxa93x-gpio", "osc_13mhz"), |
| 402 | DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"), |
| 403 | DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"), |
| 404 | DUMMY_CLK(NULL, "pxa3xx-pwri2c.1", "osc_13mhz"), |
| 405 | }; |
| 406 | |
| 407 | static void __init pxa3xx_dummy_clocks_init(void) |
| 408 | { |
| 409 | struct clk *clk; |
| 410 | struct dummy_clk *d; |
| 411 | const char *name; |
| 412 | int i; |
| 413 | |
| 414 | for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) { |
| 415 | d = &dummy_clks[i]; |
| 416 | name = d->dev_id ? d->dev_id : d->con_id; |
| 417 | clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1); |
| 418 | clk_register_clkdev(clk, d->con_id, d->dev_id); |
| 419 | } |
| 420 | } |
| 421 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 422 | static void __init pxa3xx_base_clocks_init(void __iomem *oscc_reg) |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 423 | { |
Igor Grinberg | 869de5c | 2017-12-26 15:30:36 +0200 | [diff] [blame] | 424 | struct clk *clk; |
| 425 | |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 426 | pxa3xx_register_plls(); |
| 427 | pxa3xx_register_core(); |
| 428 | clk_register_clk_pxa3xx_system_bus(); |
| 429 | clk_register_clk_pxa3xx_ac97(); |
| 430 | clk_register_clk_pxa3xx_smemc(); |
Igor Grinberg | 869de5c | 2017-12-26 15:30:36 +0200 | [diff] [blame] | 431 | clk = clk_register_gate(NULL, "CLK_POUT", |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 432 | "osc_13mhz", 0, oscc_reg, 11, 0, NULL); |
Igor Grinberg | 869de5c | 2017-12-26 15:30:36 +0200 | [diff] [blame] | 433 | clk_register_clkdev(clk, "CLK_POUT", NULL); |
Robert Jarzmik | c7739ae | 2015-02-14 15:54:58 +0100 | [diff] [blame] | 434 | clkdev_pxa_register(CLK_OSTIMER, "OSTIMER0", NULL, |
| 435 | clk_register_fixed_factor(NULL, "os-timer0", |
| 436 | "osc_13mhz", 0, 1, 4)); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 437 | } |
| 438 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 439 | int __init pxa3xx_clocks_init(void __iomem *regs, void __iomem *oscc_reg) |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 440 | { |
| 441 | int ret; |
| 442 | |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 443 | clk_regs = regs; |
| 444 | pxa3xx_base_clocks_init(oscc_reg); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 445 | pxa3xx_dummy_clocks_init(); |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 446 | ret = clk_pxa_cken_init(pxa3xx_clocks, ARRAY_SIZE(pxa3xx_clocks), regs); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 447 | if (ret) |
| 448 | return ret; |
| 449 | if (cpu_is_pxa320()) |
| 450 | return clk_pxa_cken_init(pxa320_clocks, |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 451 | ARRAY_SIZE(pxa320_clocks), regs); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 452 | if (cpu_is_pxa300() || cpu_is_pxa310()) |
| 453 | return clk_pxa_cken_init(pxa300_310_clocks, |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 454 | ARRAY_SIZE(pxa300_310_clocks), regs); |
| 455 | return clk_pxa_cken_init(pxa93x_clocks, ARRAY_SIZE(pxa93x_clocks), regs); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 456 | } |
| 457 | |
| 458 | static void __init pxa3xx_dt_clocks_init(struct device_node *np) |
| 459 | { |
Arnd Bergmann | 3c816d9 | 2019-09-18 20:54:17 +0200 | [diff] [blame] | 460 | pxa3xx_clocks_init(ioremap(0x41340000, 0x10), ioremap(0x41350000, 4)); |
Robert Jarzmik | 9bbb8a3 | 2015-01-06 21:45:38 +0100 | [diff] [blame] | 461 | clk_pxa_dt_common_init(np); |
| 462 | } |
| 463 | CLK_OF_DECLARE(pxa_clks, "marvell,pxa300-clocks", pxa3xx_dt_clocks_init); |