jz4770-cgu.c (11979B)
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/ingenic,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 49static struct ingenic_cgu *cgu; 50 51static 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 61static 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 70static 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 79static 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 85static const s8 pll_od_encoding[8] = { 86 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, 87}; 88 89static const u8 jz4770_cgu_cpccr_div_table[] = { 90 1, 2, 3, 4, 6, 8, 12, 91}; 92 93static 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_bit = -1, 143 .enable_bit = 7, 144 .stable_bit = 6, 145 }, 146 }, 147 148 /* Main clocks */ 149 150 [JZ4770_CLK_CCLK] = { 151 "cclk", CGU_CLK_DIV, 152 /* 153 * Disabling the CPU clock or any parent clocks will hang the 154 * system; mark it critical. 155 */ 156 .flags = CLK_IS_CRITICAL, 157 .parents = { JZ4770_CLK_PLL0, }, 158 .div = { 159 CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0, 160 jz4770_cgu_cpccr_div_table, 161 }, 162 }, 163 [JZ4770_CLK_H0CLK] = { 164 "h0clk", CGU_CLK_DIV, 165 .parents = { JZ4770_CLK_PLL0, }, 166 .div = { 167 CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0, 168 jz4770_cgu_cpccr_div_table, 169 }, 170 }, 171 [JZ4770_CLK_H1CLK] = { 172 "h1clk", CGU_CLK_DIV | CGU_CLK_GATE, 173 .parents = { JZ4770_CLK_PLL0, }, 174 .div = { 175 CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0, 176 jz4770_cgu_cpccr_div_table, 177 }, 178 .gate = { CGU_REG_CLKGR1, 7 }, 179 }, 180 [JZ4770_CLK_H2CLK] = { 181 "h2clk", CGU_CLK_DIV, 182 .parents = { JZ4770_CLK_PLL0, }, 183 .div = { 184 CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0, 185 jz4770_cgu_cpccr_div_table, 186 }, 187 }, 188 [JZ4770_CLK_C1CLK] = { 189 "c1clk", CGU_CLK_DIV | CGU_CLK_GATE, 190 .parents = { JZ4770_CLK_PLL0, }, 191 .div = { 192 CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0, 193 jz4770_cgu_cpccr_div_table, 194 }, 195 .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle 196 }, 197 [JZ4770_CLK_PCLK] = { 198 "pclk", CGU_CLK_DIV, 199 .parents = { JZ4770_CLK_PLL0, }, 200 .div = { 201 CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0, 202 jz4770_cgu_cpccr_div_table, 203 }, 204 }, 205 206 /* Those divided clocks can connect to PLL0 or PLL1 */ 207 208 [JZ4770_CLK_MMC0_MUX] = { 209 "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 210 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 211 .mux = { CGU_REG_MSC0CDR, 30, 1 }, 212 .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 }, 213 .gate = { CGU_REG_MSC0CDR, 31 }, 214 }, 215 [JZ4770_CLK_MMC1_MUX] = { 216 "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 217 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 218 .mux = { CGU_REG_MSC1CDR, 30, 1 }, 219 .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 }, 220 .gate = { CGU_REG_MSC1CDR, 31 }, 221 }, 222 [JZ4770_CLK_MMC2_MUX] = { 223 "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 224 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 225 .mux = { CGU_REG_MSC2CDR, 30, 1 }, 226 .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 }, 227 .gate = { CGU_REG_MSC2CDR, 31 }, 228 }, 229 [JZ4770_CLK_CIM] = { 230 "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 231 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 232 .mux = { CGU_REG_CIMCDR, 31, 1 }, 233 .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 }, 234 .gate = { CGU_REG_CLKGR0, 26 }, 235 }, 236 [JZ4770_CLK_UHC] = { 237 "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 238 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 239 .mux = { CGU_REG_UHCCDR, 29, 1 }, 240 .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 }, 241 .gate = { CGU_REG_CLKGR0, 24 }, 242 }, 243 [JZ4770_CLK_GPU] = { 244 "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 245 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 }, 246 .mux = { CGU_REG_GPUCDR, 31, 1 }, 247 .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 }, 248 .gate = { CGU_REG_CLKGR1, 9 }, 249 }, 250 [JZ4770_CLK_BCH] = { 251 "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 252 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 253 .mux = { CGU_REG_BCHCDR, 31, 1 }, 254 .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 }, 255 .gate = { CGU_REG_CLKGR0, 1 }, 256 }, 257 [JZ4770_CLK_LPCLK_MUX] = { 258 "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 259 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 260 .mux = { CGU_REG_LPCDR, 29, 1 }, 261 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 262 .gate = { CGU_REG_CLKGR0, 28 }, 263 }, 264 [JZ4770_CLK_GPS] = { 265 "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 266 .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, }, 267 .mux = { CGU_REG_GPSCDR, 31, 1 }, 268 .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 }, 269 .gate = { CGU_REG_CLKGR0, 22 }, 270 }, 271 272 /* Those divided clocks can connect to EXT, PLL0 or PLL1 */ 273 274 [JZ4770_CLK_SSI_MUX] = { 275 "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX, 276 .parents = { JZ4770_CLK_EXT, -1, 277 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 278 .mux = { CGU_REG_SSICDR, 30, 2 }, 279 .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 }, 280 }, 281 [JZ4770_CLK_PCM_MUX] = { 282 "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX, 283 .parents = { JZ4770_CLK_EXT, -1, 284 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 285 .mux = { CGU_REG_PCMCDR, 30, 2 }, 286 .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 }, 287 }, 288 [JZ4770_CLK_I2S] = { 289 "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 290 .parents = { JZ4770_CLK_EXT, -1, 291 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 292 .mux = { CGU_REG_I2SCDR, 30, 2 }, 293 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, 294 .gate = { CGU_REG_CLKGR1, 13 }, 295 }, 296 [JZ4770_CLK_OTG] = { 297 "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 298 .parents = { JZ4770_CLK_EXT, -1, 299 JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 }, 300 .mux = { CGU_REG_USBCDR, 30, 2 }, 301 .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 }, 302 .gate = { CGU_REG_CLKGR0, 2 }, 303 }, 304 305 /* Gate-only clocks */ 306 307 [JZ4770_CLK_SSI0] = { 308 "ssi0", CGU_CLK_GATE, 309 .parents = { JZ4770_CLK_SSI_MUX, }, 310 .gate = { CGU_REG_CLKGR0, 4 }, 311 }, 312 [JZ4770_CLK_SSI1] = { 313 "ssi1", CGU_CLK_GATE, 314 .parents = { JZ4770_CLK_SSI_MUX, }, 315 .gate = { CGU_REG_CLKGR0, 19 }, 316 }, 317 [JZ4770_CLK_SSI2] = { 318 "ssi2", CGU_CLK_GATE, 319 .parents = { JZ4770_CLK_SSI_MUX, }, 320 .gate = { CGU_REG_CLKGR0, 20 }, 321 }, 322 [JZ4770_CLK_PCM0] = { 323 "pcm0", CGU_CLK_GATE, 324 .parents = { JZ4770_CLK_PCM_MUX, }, 325 .gate = { CGU_REG_CLKGR1, 8 }, 326 }, 327 [JZ4770_CLK_PCM1] = { 328 "pcm1", CGU_CLK_GATE, 329 .parents = { JZ4770_CLK_PCM_MUX, }, 330 .gate = { CGU_REG_CLKGR1, 10 }, 331 }, 332 [JZ4770_CLK_DMA] = { 333 "dma", CGU_CLK_GATE, 334 .parents = { JZ4770_CLK_H2CLK, }, 335 .gate = { CGU_REG_CLKGR0, 21 }, 336 }, 337 [JZ4770_CLK_BDMA] = { 338 "bdma", CGU_CLK_GATE, 339 .parents = { JZ4770_CLK_H2CLK, }, 340 .gate = { CGU_REG_CLKGR1, 0 }, 341 }, 342 [JZ4770_CLK_I2C0] = { 343 "i2c0", CGU_CLK_GATE, 344 .parents = { JZ4770_CLK_EXT, }, 345 .gate = { CGU_REG_CLKGR0, 5 }, 346 }, 347 [JZ4770_CLK_I2C1] = { 348 "i2c1", CGU_CLK_GATE, 349 .parents = { JZ4770_CLK_EXT, }, 350 .gate = { CGU_REG_CLKGR0, 6 }, 351 }, 352 [JZ4770_CLK_I2C2] = { 353 "i2c2", CGU_CLK_GATE, 354 .parents = { JZ4770_CLK_EXT, }, 355 .gate = { CGU_REG_CLKGR1, 15 }, 356 }, 357 [JZ4770_CLK_UART0] = { 358 "uart0", CGU_CLK_GATE, 359 .parents = { JZ4770_CLK_EXT, }, 360 .gate = { CGU_REG_CLKGR0, 15 }, 361 }, 362 [JZ4770_CLK_UART1] = { 363 "uart1", CGU_CLK_GATE, 364 .parents = { JZ4770_CLK_EXT, }, 365 .gate = { CGU_REG_CLKGR0, 16 }, 366 }, 367 [JZ4770_CLK_UART2] = { 368 "uart2", CGU_CLK_GATE, 369 .parents = { JZ4770_CLK_EXT, }, 370 .gate = { CGU_REG_CLKGR0, 17 }, 371 }, 372 [JZ4770_CLK_UART3] = { 373 "uart3", CGU_CLK_GATE, 374 .parents = { JZ4770_CLK_EXT, }, 375 .gate = { CGU_REG_CLKGR0, 18 }, 376 }, 377 [JZ4770_CLK_IPU] = { 378 "ipu", CGU_CLK_GATE, 379 .parents = { JZ4770_CLK_H0CLK, }, 380 .gate = { CGU_REG_CLKGR0, 29 }, 381 }, 382 [JZ4770_CLK_ADC] = { 383 "adc", CGU_CLK_GATE, 384 .parents = { JZ4770_CLK_EXT, }, 385 .gate = { CGU_REG_CLKGR0, 14 }, 386 }, 387 [JZ4770_CLK_AIC] = { 388 "aic", CGU_CLK_GATE, 389 .parents = { JZ4770_CLK_EXT, }, 390 .gate = { CGU_REG_CLKGR0, 8 }, 391 }, 392 [JZ4770_CLK_AUX] = { 393 "aux", CGU_CLK_GATE, 394 .parents = { JZ4770_CLK_C1CLK, }, 395 .gate = { CGU_REG_CLKGR1, 14 }, 396 }, 397 [JZ4770_CLK_VPU] = { 398 "vpu", CGU_CLK_GATE, 399 .parents = { JZ4770_CLK_H1CLK, }, 400 .gate = { CGU_REG_LCR, 30, false, 150 }, 401 }, 402 [JZ4770_CLK_MMC0] = { 403 "mmc0", CGU_CLK_GATE, 404 .parents = { JZ4770_CLK_MMC0_MUX, }, 405 .gate = { CGU_REG_CLKGR0, 3 }, 406 }, 407 [JZ4770_CLK_MMC1] = { 408 "mmc1", CGU_CLK_GATE, 409 .parents = { JZ4770_CLK_MMC1_MUX, }, 410 .gate = { CGU_REG_CLKGR0, 11 }, 411 }, 412 [JZ4770_CLK_MMC2] = { 413 "mmc2", CGU_CLK_GATE, 414 .parents = { JZ4770_CLK_MMC2_MUX, }, 415 .gate = { CGU_REG_CLKGR0, 12 }, 416 }, 417 [JZ4770_CLK_OTG_PHY] = { 418 "usb_phy", CGU_CLK_GATE, 419 .parents = { JZ4770_CLK_OTG }, 420 .gate = { CGU_REG_OPCR, 7, true, 50 }, 421 }, 422 423 /* Custom clocks */ 424 425 [JZ4770_CLK_UHC_PHY] = { 426 "uhc_phy", CGU_CLK_CUSTOM, 427 .parents = { JZ4770_CLK_UHC, -1, -1, -1 }, 428 .custom = { &jz4770_uhc_phy_ops }, 429 }, 430 431 [JZ4770_CLK_EXT512] = { 432 "ext/512", CGU_CLK_FIXDIV, 433 .parents = { JZ4770_CLK_EXT }, 434 .fixdiv = { 512 }, 435 }, 436 437 [JZ4770_CLK_RTC] = { 438 "rtc", CGU_CLK_MUX, 439 .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, }, 440 .mux = { CGU_REG_OPCR, 2, 1}, 441 }, 442}; 443 444static void __init jz4770_cgu_init(struct device_node *np) 445{ 446 int retval; 447 448 cgu = ingenic_cgu_new(jz4770_cgu_clocks, 449 ARRAY_SIZE(jz4770_cgu_clocks), np); 450 if (!cgu) { 451 pr_err("%s: failed to initialise CGU\n", __func__); 452 return; 453 } 454 455 retval = ingenic_cgu_register_clocks(cgu); 456 if (retval) 457 pr_err("%s: failed to register CGU Clocks\n", __func__); 458 459 ingenic_cgu_register_syscore_ops(cgu); 460} 461 462/* We only probe via devicetree, no need for a platform driver */ 463CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);