jz4760-cgu.c (11139B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * JZ4760 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 <linux/clk.h> 14 15#include <dt-bindings/clock/ingenic,jz4760-cgu.h> 16 17#include "cgu.h" 18#include "pm.h" 19 20#define MHZ (1000 * 1000) 21 22/* 23 * CPM registers offset address definition 24 */ 25#define CGU_REG_CPCCR 0x00 26#define CGU_REG_LCR 0x04 27#define CGU_REG_CPPCR0 0x10 28#define CGU_REG_CLKGR0 0x20 29#define CGU_REG_OPCR 0x24 30#define CGU_REG_CLKGR1 0x28 31#define CGU_REG_CPPCR1 0x30 32#define CGU_REG_USBPCR 0x3c 33#define CGU_REG_USBCDR 0x50 34#define CGU_REG_I2SCDR 0x60 35#define CGU_REG_LPCDR 0x64 36#define CGU_REG_MSCCDR 0x68 37#define CGU_REG_UHCCDR 0x6c 38#define CGU_REG_SSICDR 0x74 39#define CGU_REG_CIMCDR 0x7c 40#define CGU_REG_GPSCDR 0x80 41#define CGU_REG_PCMCDR 0x84 42#define CGU_REG_GPUCDR 0x88 43 44static const s8 pll_od_encoding[8] = { 45 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, 46}; 47 48static const u8 jz4760_cgu_cpccr_div_table[] = { 49 1, 2, 3, 4, 6, 8, 50}; 51 52static const u8 jz4760_cgu_pll_half_div_table[] = { 53 2, 1, 54}; 55 56static void 57jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info, 58 unsigned long rate, unsigned long parent_rate, 59 unsigned int *pm, unsigned int *pn, unsigned int *pod) 60{ 61 unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 2; 62 63 /* The frequency after the N divider must be between 1 and 50 MHz. */ 64 n = parent_rate / (1 * MHZ); 65 66 /* The N divider must be >= 2. */ 67 n = clamp_val(n, 2, 1 << pll_info->n_bits); 68 69 for (;; n >>= 1) { 70 od = (unsigned int)-1; 71 72 do { 73 m = (rate / MHZ) * (1 << ++od) * n / (parent_rate / MHZ); 74 } while ((m > m_max || m & 1) && (od < 4)); 75 76 if (od < 4 && m >= 4 && m <= m_max) 77 break; 78 } 79 80 *pm = m; 81 *pn = n; 82 *pod = 1 << od; 83} 84 85static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = { 86 87 /* External clocks */ 88 89 [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT }, 90 [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, 91 92 /* PLLs */ 93 94 [JZ4760_CLK_PLL0] = { 95 "pll0", CGU_CLK_PLL, 96 .parents = { JZ4760_CLK_EXT }, 97 .pll = { 98 .reg = CGU_REG_CPPCR0, 99 .rate_multiplier = 1, 100 .m_shift = 23, 101 .m_bits = 8, 102 .m_offset = 0, 103 .n_shift = 18, 104 .n_bits = 4, 105 .n_offset = 0, 106 .od_shift = 16, 107 .od_bits = 2, 108 .od_max = 8, 109 .od_encoding = pll_od_encoding, 110 .bypass_reg = CGU_REG_CPPCR0, 111 .bypass_bit = 9, 112 .enable_bit = 8, 113 .stable_bit = 10, 114 .calc_m_n_od = jz4760_cgu_calc_m_n_od, 115 }, 116 }, 117 118 [JZ4760_CLK_PLL1] = { 119 /* TODO: PLL1 can depend on PLL0 */ 120 "pll1", CGU_CLK_PLL, 121 .parents = { JZ4760_CLK_EXT }, 122 .pll = { 123 .reg = CGU_REG_CPPCR1, 124 .rate_multiplier = 1, 125 .m_shift = 23, 126 .m_bits = 8, 127 .m_offset = 0, 128 .n_shift = 18, 129 .n_bits = 4, 130 .n_offset = 0, 131 .od_shift = 16, 132 .od_bits = 2, 133 .od_max = 8, 134 .od_encoding = pll_od_encoding, 135 .bypass_bit = -1, 136 .enable_bit = 7, 137 .stable_bit = 6, 138 .calc_m_n_od = jz4760_cgu_calc_m_n_od, 139 }, 140 }, 141 142 /* Main clocks */ 143 144 [JZ4760_CLK_CCLK] = { 145 "cclk", CGU_CLK_DIV, 146 /* 147 * Disabling the CPU clock or any parent clocks will hang the 148 * system; mark it critical. 149 */ 150 .flags = CLK_IS_CRITICAL, 151 .parents = { JZ4760_CLK_PLL0, }, 152 .div = { 153 CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0, 154 jz4760_cgu_cpccr_div_table, 155 }, 156 }, 157 [JZ4760_CLK_HCLK] = { 158 "hclk", CGU_CLK_DIV, 159 .parents = { JZ4760_CLK_PLL0, }, 160 .div = { 161 CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0, 162 jz4760_cgu_cpccr_div_table, 163 }, 164 }, 165 [JZ4760_CLK_SCLK] = { 166 "sclk", CGU_CLK_DIV, 167 .parents = { JZ4760_CLK_PLL0, }, 168 .div = { 169 CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0, 170 jz4760_cgu_cpccr_div_table, 171 }, 172 }, 173 [JZ4760_CLK_H2CLK] = { 174 "h2clk", CGU_CLK_DIV, 175 .parents = { JZ4760_CLK_PLL0, }, 176 .div = { 177 CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0, 178 jz4760_cgu_cpccr_div_table, 179 }, 180 }, 181 [JZ4760_CLK_MCLK] = { 182 "mclk", CGU_CLK_DIV, 183 /* 184 * Disabling MCLK or its parents will render DRAM 185 * inaccessible; mark it critical. 186 */ 187 .flags = CLK_IS_CRITICAL, 188 .parents = { JZ4760_CLK_PLL0, }, 189 .div = { 190 CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0, 191 jz4760_cgu_cpccr_div_table, 192 }, 193 }, 194 [JZ4760_CLK_PCLK] = { 195 "pclk", CGU_CLK_DIV, 196 .parents = { JZ4760_CLK_PLL0, }, 197 .div = { 198 CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0, 199 jz4760_cgu_cpccr_div_table, 200 }, 201 }, 202 203 /* Divided clocks */ 204 205 [JZ4760_CLK_PLL0_HALF] = { 206 "pll0_half", CGU_CLK_DIV, 207 .parents = { JZ4760_CLK_PLL0 }, 208 .div = { 209 CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0, 210 jz4760_cgu_pll_half_div_table, 211 }, 212 }, 213 214 /* Those divided clocks can connect to PLL0 or PLL1 */ 215 216 [JZ4760_CLK_UHC] = { 217 "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 218 .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, }, 219 .mux = { CGU_REG_UHCCDR, 31, 1 }, 220 .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 }, 221 .gate = { CGU_REG_CLKGR0, 24 }, 222 }, 223 [JZ4760_CLK_GPU] = { 224 "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 225 .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, }, 226 .mux = { CGU_REG_GPUCDR, 31, 1 }, 227 .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 }, 228 .gate = { CGU_REG_CLKGR1, 9 }, 229 }, 230 [JZ4760_CLK_LPCLK_DIV] = { 231 "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX, 232 .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, }, 233 .mux = { CGU_REG_LPCDR, 29, 1 }, 234 .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 235 }, 236 [JZ4760_CLK_TVE] = { 237 "tve", CGU_CLK_GATE | CGU_CLK_MUX, 238 .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, }, 239 .mux = { CGU_REG_LPCDR, 31, 1 }, 240 .gate = { CGU_REG_CLKGR0, 27 }, 241 }, 242 [JZ4760_CLK_LPCLK] = { 243 "lpclk", CGU_CLK_GATE | CGU_CLK_MUX, 244 .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, }, 245 .mux = { CGU_REG_LPCDR, 30, 1 }, 246 .gate = { CGU_REG_CLKGR0, 28 }, 247 }, 248 [JZ4760_CLK_GPS] = { 249 "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 250 .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, }, 251 .mux = { CGU_REG_GPSCDR, 31, 1 }, 252 .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 }, 253 .gate = { CGU_REG_CLKGR0, 22 }, 254 }, 255 256 /* Those divided clocks can connect to EXT, PLL0 or PLL1 */ 257 258 [JZ4760_CLK_PCM] = { 259 "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 260 .parents = { JZ4760_CLK_EXT, -1, 261 JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 }, 262 .mux = { CGU_REG_PCMCDR, 30, 2 }, 263 .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) }, 264 .gate = { CGU_REG_CLKGR1, 8 }, 265 }, 266 [JZ4760_CLK_I2S] = { 267 "i2s", CGU_CLK_DIV | CGU_CLK_MUX, 268 .parents = { JZ4760_CLK_EXT, -1, 269 JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 }, 270 .mux = { CGU_REG_I2SCDR, 30, 2 }, 271 .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) }, 272 }, 273 [JZ4760_CLK_OTG] = { 274 "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, 275 .parents = { JZ4760_CLK_EXT, -1, 276 JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 }, 277 .mux = { CGU_REG_USBCDR, 30, 2 }, 278 .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 }, 279 .gate = { CGU_REG_CLKGR0, 2 }, 280 }, 281 282 /* Those divided clocks can connect to EXT or PLL0 */ 283 [JZ4760_CLK_MMC_MUX] = { 284 "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV, 285 .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, }, 286 .mux = { CGU_REG_MSCCDR, 31, 1 }, 287 .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) }, 288 }, 289 [JZ4760_CLK_SSI_MUX] = { 290 "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX, 291 .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, }, 292 .mux = { CGU_REG_SSICDR, 31, 1 }, 293 .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) }, 294 }, 295 296 /* These divided clock can connect to PLL0 only */ 297 [JZ4760_CLK_CIM] = { 298 "cim", CGU_CLK_DIV | CGU_CLK_GATE, 299 .parents = { JZ4760_CLK_PLL0_HALF }, 300 .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 }, 301 .gate = { CGU_REG_CLKGR0, 26 }, 302 }, 303 304 /* Gate-only clocks */ 305 306 [JZ4760_CLK_SSI0] = { 307 "ssi0", CGU_CLK_GATE, 308 .parents = { JZ4760_CLK_SSI_MUX, }, 309 .gate = { CGU_REG_CLKGR0, 4 }, 310 }, 311 [JZ4760_CLK_SSI1] = { 312 "ssi1", CGU_CLK_GATE, 313 .parents = { JZ4760_CLK_SSI_MUX, }, 314 .gate = { CGU_REG_CLKGR0, 19 }, 315 }, 316 [JZ4760_CLK_SSI2] = { 317 "ssi2", CGU_CLK_GATE, 318 .parents = { JZ4760_CLK_SSI_MUX, }, 319 .gate = { CGU_REG_CLKGR0, 20 }, 320 }, 321 [JZ4760_CLK_DMA] = { 322 "dma", CGU_CLK_GATE, 323 .parents = { JZ4760_CLK_H2CLK, }, 324 .gate = { CGU_REG_CLKGR0, 21 }, 325 }, 326 [JZ4760_CLK_MDMA] = { 327 "mdma", CGU_CLK_GATE, 328 .parents = { JZ4760_CLK_HCLK, }, 329 .gate = { CGU_REG_CLKGR0, 25 }, 330 }, 331 [JZ4760_CLK_BDMA] = { 332 "bdma", CGU_CLK_GATE, 333 .parents = { JZ4760_CLK_HCLK, }, 334 .gate = { CGU_REG_CLKGR1, 0 }, 335 }, 336 [JZ4760_CLK_I2C0] = { 337 "i2c0", CGU_CLK_GATE, 338 .parents = { JZ4760_CLK_EXT, }, 339 .gate = { CGU_REG_CLKGR0, 5 }, 340 }, 341 [JZ4760_CLK_I2C1] = { 342 "i2c1", CGU_CLK_GATE, 343 .parents = { JZ4760_CLK_EXT, }, 344 .gate = { CGU_REG_CLKGR0, 6 }, 345 }, 346 [JZ4760_CLK_UART0] = { 347 "uart0", CGU_CLK_GATE, 348 .parents = { JZ4760_CLK_EXT, }, 349 .gate = { CGU_REG_CLKGR0, 15 }, 350 }, 351 [JZ4760_CLK_UART1] = { 352 "uart1", CGU_CLK_GATE, 353 .parents = { JZ4760_CLK_EXT, }, 354 .gate = { CGU_REG_CLKGR0, 16 }, 355 }, 356 [JZ4760_CLK_UART2] = { 357 "uart2", CGU_CLK_GATE, 358 .parents = { JZ4760_CLK_EXT, }, 359 .gate = { CGU_REG_CLKGR0, 17 }, 360 }, 361 [JZ4760_CLK_UART3] = { 362 "uart3", CGU_CLK_GATE, 363 .parents = { JZ4760_CLK_EXT, }, 364 .gate = { CGU_REG_CLKGR0, 18 }, 365 }, 366 [JZ4760_CLK_IPU] = { 367 "ipu", CGU_CLK_GATE, 368 .parents = { JZ4760_CLK_HCLK, }, 369 .gate = { CGU_REG_CLKGR0, 29 }, 370 }, 371 [JZ4760_CLK_ADC] = { 372 "adc", CGU_CLK_GATE, 373 .parents = { JZ4760_CLK_EXT, }, 374 .gate = { CGU_REG_CLKGR0, 14 }, 375 }, 376 [JZ4760_CLK_AIC] = { 377 "aic", CGU_CLK_GATE, 378 .parents = { JZ4760_CLK_EXT, }, 379 .gate = { CGU_REG_CLKGR0, 8 }, 380 }, 381 [JZ4760_CLK_VPU] = { 382 "vpu", CGU_CLK_GATE, 383 .parents = { JZ4760_CLK_HCLK, }, 384 .gate = { CGU_REG_LCR, 30, false, 150 }, 385 }, 386 [JZ4760_CLK_MMC0] = { 387 "mmc0", CGU_CLK_GATE, 388 .parents = { JZ4760_CLK_MMC_MUX, }, 389 .gate = { CGU_REG_CLKGR0, 3 }, 390 }, 391 [JZ4760_CLK_MMC1] = { 392 "mmc1", CGU_CLK_GATE, 393 .parents = { JZ4760_CLK_MMC_MUX, }, 394 .gate = { CGU_REG_CLKGR0, 11 }, 395 }, 396 [JZ4760_CLK_MMC2] = { 397 "mmc2", CGU_CLK_GATE, 398 .parents = { JZ4760_CLK_MMC_MUX, }, 399 .gate = { CGU_REG_CLKGR0, 12 }, 400 }, 401 [JZ4760_CLK_UHC_PHY] = { 402 "uhc_phy", CGU_CLK_GATE, 403 .parents = { JZ4760_CLK_UHC, }, 404 .gate = { CGU_REG_OPCR, 5 }, 405 }, 406 [JZ4760_CLK_OTG_PHY] = { 407 "usb_phy", CGU_CLK_GATE, 408 .parents = { JZ4760_CLK_OTG }, 409 .gate = { CGU_REG_OPCR, 7, true, 50 }, 410 }, 411 412 /* Custom clocks */ 413 [JZ4760_CLK_EXT512] = { 414 "ext/512", CGU_CLK_FIXDIV, 415 .parents = { JZ4760_CLK_EXT }, 416 .fixdiv = { 512 }, 417 }, 418 [JZ4760_CLK_RTC] = { 419 "rtc", CGU_CLK_MUX, 420 .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, }, 421 .mux = { CGU_REG_OPCR, 2, 1}, 422 }, 423}; 424 425static void __init jz4760_cgu_init(struct device_node *np) 426{ 427 struct ingenic_cgu *cgu; 428 int retval; 429 430 cgu = ingenic_cgu_new(jz4760_cgu_clocks, 431 ARRAY_SIZE(jz4760_cgu_clocks), np); 432 if (!cgu) { 433 pr_err("%s: failed to initialise CGU\n", __func__); 434 return; 435 } 436 437 retval = ingenic_cgu_register_clocks(cgu); 438 if (retval) 439 pr_err("%s: failed to register CGU Clocks\n", __func__); 440 441 ingenic_cgu_register_syscore_ops(cgu); 442} 443 444/* We only probe via devicetree, no need for a platform driver */ 445CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init); 446 447/* JZ4760B has some small differences, but we don't implement them. */ 448CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);