1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * JZ4770 SoC CGU driver 4 * Copyright 2018, Paul Cercueil <paul@crapouillou.net> 5 */ 6 7 #include <linux/bitops.h> 8 #include <linux/clk-provider.h> 9 #include <linux/delay.h> 10 #include <linux/io.h> 11 #include <linux/of.h> 12 13 #include <dt-bindings/clock/jz4770-cgu.h> 14 15 #include "cgu.h" 16 #include "pm.h" 17 18 /* 19 * CPM registers offset address definition 20 */ 21 #define CGU_REG_CPCCR 0x00 22 #define CGU_REG_LCR 0x04 23 #define CGU_REG_CPPCR0 0x10 24 #define CGU_REG_CLKGR0 0x20 25 #define CGU_REG_OPCR 0x24 26 #define CGU_REG_CLKGR1 0x28 27 #define CGU_REG_CPPCR1 0x30 28 #define CGU_REG_USBPCR1 0x48 29 #define CGU_REG_USBCDR 0x50 30 #define CGU_REG_I2SCDR 0x60 31 #define CGU_REG_LPCDR 0x64 32 #define CGU_REG_MSC0CDR 0x68 33 #define CGU_REG_UHCCDR 0x6c 34 #define CGU_REG_SSICDR 0x74 35 #define CGU_REG_CIMCDR 0x7c 36 #define CGU_REG_GPSCDR 0x80 37 #define CGU_REG_PCMCDR 0x84 38 #define CGU_REG_GPUCDR 0x88 39 #define CGU_REG_MSC1CDR 0xA4 40 #define CGU_REG_MSC2CDR 0xA8 41 #define CGU_REG_BCHCDR 0xAC 42 43 /* bits within the OPCR register */ 44 #define OPCR_SPENDH BIT(5) /* UHC PHY suspend */ 45 46 /* bits within the USBPCR1 register */ 47 #define USBPCR1_UHC_POWER BIT(5) /* UHC PHY power down */ 48 49 static struct ingenic_cgu *cgu; 50 51 static int jz4770_uhc_phy_enable(struct clk_hw *hw) 52 { 53 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; 54 void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1; 55 56 writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr); 57 writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1); 58 return 0; 59 } 60 61 static void jz4770_uhc_phy_disable(struct clk_hw *hw) 62 { 63 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; 64 void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1; 65 66 writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1); 67 writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr); 68 } 69 70 static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw) 71 { 72 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; 73 void __iomem *reg_usbpcr1 = cgu->base + CGU_REG_USBPCR1; 74 75 return !(readl(reg_opcr) & OPCR_SPENDH) && 76 (readl(reg_usbpcr1) & USBPCR1_UHC_POWER); 77 } 78 79 static const struct clk_ops jz4770_uhc_phy_ops = { 80 .enable = jz4770_uhc_phy_enable, 81 .disable = jz4770_uhc_phy_disable, 82 .is_enabled = jz4770_uhc_phy_is_enabled, 83 }; 84 85 static const s8 pll_od_encoding[8] = { 86 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, 87 }; 88 89 static const u8 jz4770_cgu_cpccr_div_table[] = { 90 1, 2, 3, 4, 6, 8, 12, 91 }; 92 93 static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = { 94 95 /* External clocks */ 96 97 [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT }, 98 [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, 99 100 /* PLLs */ 101 102 [JZ4770_CLK_PLL0] = { 103 "pll0", CGU_CLK_PLL, 104 .parents = { JZ4770_CLK_EXT }, 105 .pll = { 106 .reg = CGU_REG_CPPCR0, 107 .rate_multiplier = 1, 108 .m_shift = 24, 109 .m_bits = 7, 110 .m_offset = 1, 111 .n_shift = 18, 112 .n_bits = 5, 113 .n_offset = 1, 114 .od_shift = 16, 115 .od_bits = 2, 116 .od_max = 8, 117 .od_encoding = pll_od_encoding, 118 .bypass_reg = CGU_REG_CPPCR0, 119 .bypass_bit = 9, 120 .enable_bit = 8, 121 .stable_bit = 10, 122 }, 123 }, 124 125 [JZ4770_CLK_PLL1] = { 126 /* TODO: PLL1 can depend on PLL0 */ 127 "pll1", CGU_CLK_PLL, 128 .parents = { JZ4770_CLK_EXT }, 129 .pll = { 130 .reg = CGU_REG_CPPCR1, 131 .rate_multiplier = 1, 132 .m_shift = 24, 133 .m_bits = 7, 134 .m_offset = 1, 135 .n_shift = 18, 136 .n_bits = 5, 137 .n_offset = 1, 138 .od_shift = 16, 139 .od_bits = 2, 140 .od_max = 8, 141 .od_encoding = pll_od_encoding, 142 .bypass_reg = CGU_REG_CPPCR1, 143 .no_bypass_bit = true, 144 .enable_bit = 7, 145 .stable_bit = 6, 146 }, 147 }, 148 149 /* Main clocks */ 150 151 [JZ4770_CLK_CCLK] = { 152 "cclk", CGU_CLK_DIV, 153 .parents = { JZ4770_CLK_PLL0, }, 154 .div = { 155 CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 156 jz4770_cgu_cpccr_div_table, 157 }, 158 }, 159 [JZ4770_CLK_H0CLK] = { 160 "h0clk", CGU_CLK_DIV, 161 .parents = { JZ4770_CLK_PLL0, }, 162 .div = { 163 CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 164 jz4770_cgu_cpccr_div_table, 165 }, 166 }, 167 [JZ4770_CLK_H1CLK] = { 168 "h1clk", CGU_CLK_DIV | CGU_CLK_GATE, 169 .parents = { JZ4770_CLK_PLL0, }, 170 .div = { 171 CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 172 jz4770_cgu_cpccr_div_table, 173 }, 174 .gate = { CGU_REG_CLKGR1, 7 }, 175 }, 176 [JZ4770_CLK_H2CLK] = { 177 "h2clk", CGU_CLK_DIV, 178 .parents = { JZ4770_CLK_PLL0, }, 179 .div = { 180 CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 181 jz4770_cgu_cpccr_div_table, 182 }, 183 }, 184 [JZ4770_CLK_C1CLK] = { 185 "c1clk", CGU_CLK_DIV | CGU_CLK_GATE, 186 .parents = { JZ4770_CLK_PLL0, }, 187 .div = { 188 CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 189 jz4770_cgu_cpccr_div_table, 190 }, 191 .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle 192 }, 193 [JZ4770_CLK_PCLK] = { 194 "pclk", CGU_CLK_DIV, 195 .parents = { JZ4770_CLK_PLL0, }, 196 .div = { 197 CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 198 jz4770_cgu_cpccr_div_table, 199 }, 200 }, 201 202 /* Those divided clocks can connect to PLL0 or PLL1 */ 203 204 [JZ4770_CLK_MMC0_MUX] = { 205 "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 206 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 207 .mux = { CGU_REG_MSC0CDR, 30, 1 }, 208 .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 }, 209 .gate = { CGU_REG_MSC0CDR, 31 }, 210 }, 211 [JZ4770_CLK_MMC1_MUX] = { 212 "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 213 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 214 .mux = { CGU_REG_MSC1CDR, 30, 1 }, 215 .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 }, 216 .gate = { CGU_REG_MSC1CDR, 31 }, 217 }, 218 [JZ4770_CLK_MMC2_MUX] = { 219 "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 220 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 221 .mux = { CGU_REG_MSC2CDR, 30, 1 }, 222 .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 }, 223 .gate = { CGU_REG_MSC2CDR, 31 }, 224 }, 225 [JZ4770_CLK_CIM] = { 226 "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 227 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 228 .mux = { CGU_REG_CIMCDR, 31, 1 }, 229 .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 }, 230 .gate = { CGU_REG_CLKGR0, 26 }, 231 }, 232 [JZ4770_CLK_UHC] = { 233 "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 234 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 235 .mux = { CGU_REG_UHCCDR, 29, 1 }, 236 .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 }, 237 .gate = { CGU_REG_CLKGR0, 24 }, 238 }, 239 [JZ4770_CLK_GPU] = { 240 "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 241 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 }, 242 .mux = { CGU_REG_GPUCDR, 31, 1 }, 243 .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 }, 244 .gate = { CGU_REG_CLKGR1, 9 }, 245 }, 246 [JZ4770_CLK_BCH] = { 247 "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 248 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 249 .mux = { CGU_REG_BCHCDR, 31, 1 }, 250 .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 }, 251 .gate = { CGU_REG_CLKGR0, 1 }, 252 }, 253 [JZ4770_CLK_LPCLK_MUX] = { 254 "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 255 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 256 .mux = { CGU_REG_LPCDR, 29, 1 }, 257 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 258 .gate = { CGU_REG_CLKGR0, 28 }, 259 }, 260 [JZ4770_CLK_GPS] = { 261 "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 262 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 263 .mux = { CGU_REG_GPSCDR, 31, 1 }, 264 .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 }, 265 .gate = { CGU_REG_CLKGR0, 22 }, 266 }, 267 268 /* Those divided clocks can connect to EXT, PLL0 or PLL1 */ 269 270 [JZ4770_CLK_SSI_MUX] = { 271 "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX, 272 .parents = { JZ4770_CLK_EXT, -1, 273 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 274 .mux = { CGU_REG_SSICDR, 30, 2 }, 275 .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 }, 276 }, 277 [JZ4770_CLK_PCM_MUX] = { 278 "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX, 279 .parents = { JZ4770_CLK_EXT, -1, 280 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 281 .mux = { CGU_REG_PCMCDR, 30, 2 }, 282 .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 }, 283 }, 284 [JZ4770_CLK_I2S] = { 285 "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 286 .parents = { JZ4770_CLK_EXT, -1, 287 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 288 .mux = { CGU_REG_I2SCDR, 30, 2 }, 289 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, 290 .gate = { CGU_REG_CLKGR1, 13 }, 291 }, 292 [JZ4770_CLK_OTG] = { 293 "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 294 .parents = { JZ4770_CLK_EXT, -1, 295 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 296 .mux = { CGU_REG_USBCDR, 30, 2 }, 297 .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 }, 298 .gate = { CGU_REG_CLKGR0, 2 }, 299 }, 300 301 /* Gate-only clocks */ 302 303 [JZ4770_CLK_SSI0] = { 304 "ssi0", CGU_CLK_GATE, 305 .parents = { JZ4770_CLK_SSI_MUX, }, 306 .gate = { CGU_REG_CLKGR0, 4 }, 307 }, 308 [JZ4770_CLK_SSI1] = { 309 "ssi1", CGU_CLK_GATE, 310 .parents = { JZ4770_CLK_SSI_MUX, }, 311 .gate = { CGU_REG_CLKGR0, 19 }, 312 }, 313 [JZ4770_CLK_SSI2] = { 314 "ssi2", CGU_CLK_GATE, 315 .parents = { JZ4770_CLK_SSI_MUX, }, 316 .gate = { CGU_REG_CLKGR0, 20 }, 317 }, 318 [JZ4770_CLK_PCM0] = { 319 "pcm0", CGU_CLK_GATE, 320 .parents = { JZ4770_CLK_PCM_MUX, }, 321 .gate = { CGU_REG_CLKGR1, 8 }, 322 }, 323 [JZ4770_CLK_PCM1] = { 324 "pcm1", CGU_CLK_GATE, 325 .parents = { JZ4770_CLK_PCM_MUX, }, 326 .gate = { CGU_REG_CLKGR1, 10 }, 327 }, 328 [JZ4770_CLK_DMA] = { 329 "dma", CGU_CLK_GATE, 330 .parents = { JZ4770_CLK_H2CLK, }, 331 .gate = { CGU_REG_CLKGR0, 21 }, 332 }, 333 [JZ4770_CLK_I2C0] = { 334 "i2c0", CGU_CLK_GATE, 335 .parents = { JZ4770_CLK_EXT, }, 336 .gate = { CGU_REG_CLKGR0, 5 }, 337 }, 338 [JZ4770_CLK_I2C1] = { 339 "i2c1", CGU_CLK_GATE, 340 .parents = { JZ4770_CLK_EXT, }, 341 .gate = { CGU_REG_CLKGR0, 6 }, 342 }, 343 [JZ4770_CLK_I2C2] = { 344 "i2c2", CGU_CLK_GATE, 345 .parents = { JZ4770_CLK_EXT, }, 346 .gate = { CGU_REG_CLKGR1, 15 }, 347 }, 348 [JZ4770_CLK_UART0] = { 349 "uart0", CGU_CLK_GATE, 350 .parents = { JZ4770_CLK_EXT, }, 351 .gate = { CGU_REG_CLKGR0, 15 }, 352 }, 353 [JZ4770_CLK_UART1] = { 354 "uart1", CGU_CLK_GATE, 355 .parents = { JZ4770_CLK_EXT, }, 356 .gate = { CGU_REG_CLKGR0, 16 }, 357 }, 358 [JZ4770_CLK_UART2] = { 359 "uart2", CGU_CLK_GATE, 360 .parents = { JZ4770_CLK_EXT, }, 361 .gate = { CGU_REG_CLKGR0, 17 }, 362 }, 363 [JZ4770_CLK_UART3] = { 364 "uart3", CGU_CLK_GATE, 365 .parents = { JZ4770_CLK_EXT, }, 366 .gate = { CGU_REG_CLKGR0, 18 }, 367 }, 368 [JZ4770_CLK_IPU] = { 369 "ipu", CGU_CLK_GATE, 370 .parents = { JZ4770_CLK_H0CLK, }, 371 .gate = { CGU_REG_CLKGR0, 29 }, 372 }, 373 [JZ4770_CLK_ADC] = { 374 "adc", CGU_CLK_GATE, 375 .parents = { JZ4770_CLK_EXT, }, 376 .gate = { CGU_REG_CLKGR0, 14 }, 377 }, 378 [JZ4770_CLK_AIC] = { 379 "aic", CGU_CLK_GATE, 380 .parents = { JZ4770_CLK_EXT, }, 381 .gate = { CGU_REG_CLKGR0, 8 }, 382 }, 383 [JZ4770_CLK_AUX] = { 384 "aux", CGU_CLK_GATE, 385 .parents = { JZ4770_CLK_C1CLK, }, 386 .gate = { CGU_REG_CLKGR1, 14 }, 387 }, 388 [JZ4770_CLK_VPU] = { 389 "vpu", CGU_CLK_GATE, 390 .parents = { JZ4770_CLK_H1CLK, }, 391 .gate = { CGU_REG_LCR, 30, false, 150 }, 392 }, 393 [JZ4770_CLK_MMC0] = { 394 "mmc0", CGU_CLK_GATE, 395 .parents = { JZ4770_CLK_MMC0_MUX, }, 396 .gate = { CGU_REG_CLKGR0, 3 }, 397 }, 398 [JZ4770_CLK_MMC1] = { 399 "mmc1", CGU_CLK_GATE, 400 .parents = { JZ4770_CLK_MMC1_MUX, }, 401 .gate = { CGU_REG_CLKGR0, 11 }, 402 }, 403 [JZ4770_CLK_MMC2] = { 404 "mmc2", CGU_CLK_GATE, 405 .parents = { JZ4770_CLK_MMC2_MUX, }, 406 .gate = { CGU_REG_CLKGR0, 12 }, 407 }, 408 [JZ4770_CLK_OTG_PHY] = { 409 "usb_phy", CGU_CLK_GATE, 410 .parents = { JZ4770_CLK_OTG }, 411 .gate = { CGU_REG_OPCR, 7, true, 50 }, 412 }, 413 414 /* Custom clocks */ 415 416 [JZ4770_CLK_UHC_PHY] = { 417 "uhc_phy", CGU_CLK_CUSTOM, 418 .parents = { JZ4770_CLK_UHC, -1, -1, -1 }, 419 .custom = { &jz4770_uhc_phy_ops }, 420 }, 421 422 [JZ4770_CLK_EXT512] = { 423 "ext/512", CGU_CLK_FIXDIV, 424 .parents = { JZ4770_CLK_EXT }, 425 .fixdiv = { 512 }, 426 }, 427 428 [JZ4770_CLK_RTC] = { 429 "rtc", CGU_CLK_MUX, 430 .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, }, 431 .mux = { CGU_REG_OPCR, 2, 1}, 432 }, 433 }; 434 435 static void __init jz4770_cgu_init(struct device_node *np) 436 { 437 int retval; 438 439 cgu = ingenic_cgu_new(jz4770_cgu_clocks, 440 ARRAY_SIZE(jz4770_cgu_clocks), np); 441 if (!cgu) { 442 pr_err("%s: failed to initialise CGU\n", __func__); 443 return; 444 } 445 446 retval = ingenic_cgu_register_clocks(cgu); 447 if (retval) 448 pr_err("%s: failed to register CGU Clocks\n", __func__); 449 450 ingenic_cgu_register_syscore_ops(cgu); 451 } 452 453 /* We only probe via devicetree, no need for a platform driver */ 454 CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init); 455