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