x1830-cgu.c (11587B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * X1830 SoC CGU driver 4 * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> 5 */ 6 7#include <linux/clk-provider.h> 8#include <linux/delay.h> 9#include <linux/io.h> 10#include <linux/of.h> 11 12#include <dt-bindings/clock/ingenic,x1830-cgu.h> 13 14#include "cgu.h" 15#include "pm.h" 16 17/* CGU register offsets */ 18#define CGU_REG_CPCCR 0x00 19#define CGU_REG_CPPCR 0x0c 20#define CGU_REG_APLL 0x10 21#define CGU_REG_MPLL 0x14 22#define CGU_REG_CLKGR0 0x20 23#define CGU_REG_OPCR 0x24 24#define CGU_REG_CLKGR1 0x28 25#define CGU_REG_DDRCDR 0x2c 26#define CGU_REG_USBPCR 0x3c 27#define CGU_REG_USBRDT 0x40 28#define CGU_REG_USBVBFIL 0x44 29#define CGU_REG_USBPCR1 0x48 30#define CGU_REG_MACCDR 0x54 31#define CGU_REG_EPLL 0x58 32#define CGU_REG_I2SCDR 0x60 33#define CGU_REG_LPCDR 0x64 34#define CGU_REG_MSC0CDR 0x68 35#define CGU_REG_I2SCDR1 0x70 36#define CGU_REG_SSICDR 0x74 37#define CGU_REG_CIMCDR 0x7c 38#define CGU_REG_MSC1CDR 0xa4 39#define CGU_REG_CMP_INTR 0xb0 40#define CGU_REG_CMP_INTRE 0xb4 41#define CGU_REG_DRCG 0xd0 42#define CGU_REG_CPCSR 0xd4 43#define CGU_REG_VPLL 0xe0 44#define CGU_REG_MACPHYC 0xe8 45 46/* bits within the OPCR register */ 47#define OPCR_GATE_USBPHYCLK BIT(23) 48#define OPCR_SPENDN0 BIT(7) 49#define OPCR_SPENDN1 BIT(6) 50 51/* bits within the USBPCR register */ 52#define USBPCR_SIDDQ BIT(21) 53#define USBPCR_OTG_DISABLE BIT(20) 54 55static struct ingenic_cgu *cgu; 56 57static int x1830_usb_phy_enable(struct clk_hw *hw) 58{ 59 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; 60 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR; 61 62 writel((readl(reg_opcr) | OPCR_SPENDN0) & ~OPCR_GATE_USBPHYCLK, reg_opcr); 63 writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr); 64 return 0; 65} 66 67static void x1830_usb_phy_disable(struct clk_hw *hw) 68{ 69 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; 70 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR; 71 72 writel((readl(reg_opcr) & ~OPCR_SPENDN0) | OPCR_GATE_USBPHYCLK, reg_opcr); 73 writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr); 74} 75 76static int x1830_usb_phy_is_enabled(struct clk_hw *hw) 77{ 78 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; 79 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR; 80 81 return (readl(reg_opcr) & OPCR_SPENDN0) && 82 !(readl(reg_usbpcr) & USBPCR_SIDDQ) && 83 !(readl(reg_usbpcr) & USBPCR_OTG_DISABLE); 84} 85 86static const struct clk_ops x1830_otg_phy_ops = { 87 .enable = x1830_usb_phy_enable, 88 .disable = x1830_usb_phy_disable, 89 .is_enabled = x1830_usb_phy_is_enabled, 90}; 91 92static const s8 pll_od_encoding[64] = { 93 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, 94 -1, -1, -1, -1, -1, -1, -1, 0x4, 95 -1, -1, -1, -1, -1, -1, -1, -1, 96 -1, -1, -1, -1, -1, -1, -1, 0x5, 97 -1, -1, -1, -1, -1, -1, -1, -1, 98 -1, -1, -1, -1, -1, -1, -1, -1, 99 -1, -1, -1, -1, -1, -1, -1, -1, 100 -1, -1, -1, -1, -1, -1, -1, 0x6, 101}; 102 103static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = { 104 105 /* External clocks */ 106 107 [X1830_CLK_EXCLK] = { "ext", CGU_CLK_EXT }, 108 [X1830_CLK_RTCLK] = { "rtc", CGU_CLK_EXT }, 109 110 /* PLLs */ 111 112 [X1830_CLK_APLL] = { 113 "apll", CGU_CLK_PLL, 114 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 115 .pll = { 116 .reg = CGU_REG_APLL, 117 .rate_multiplier = 2, 118 .m_shift = 20, 119 .m_bits = 9, 120 .m_offset = 1, 121 .n_shift = 14, 122 .n_bits = 6, 123 .n_offset = 1, 124 .od_shift = 11, 125 .od_bits = 3, 126 .od_max = 64, 127 .od_encoding = pll_od_encoding, 128 .bypass_reg = CGU_REG_CPPCR, 129 .bypass_bit = 30, 130 .enable_bit = 0, 131 .stable_bit = 3, 132 }, 133 }, 134 135 [X1830_CLK_MPLL] = { 136 "mpll", CGU_CLK_PLL, 137 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 138 .pll = { 139 .reg = CGU_REG_MPLL, 140 .rate_multiplier = 2, 141 .m_shift = 20, 142 .m_bits = 9, 143 .m_offset = 1, 144 .n_shift = 14, 145 .n_bits = 6, 146 .n_offset = 1, 147 .od_shift = 11, 148 .od_bits = 3, 149 .od_max = 64, 150 .od_encoding = pll_od_encoding, 151 .bypass_reg = CGU_REG_CPPCR, 152 .bypass_bit = 28, 153 .enable_bit = 0, 154 .stable_bit = 3, 155 }, 156 }, 157 158 [X1830_CLK_EPLL] = { 159 "epll", CGU_CLK_PLL, 160 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 161 .pll = { 162 .reg = CGU_REG_EPLL, 163 .rate_multiplier = 2, 164 .m_shift = 20, 165 .m_bits = 9, 166 .m_offset = 1, 167 .n_shift = 14, 168 .n_bits = 6, 169 .n_offset = 1, 170 .od_shift = 11, 171 .od_bits = 3, 172 .od_max = 64, 173 .od_encoding = pll_od_encoding, 174 .bypass_reg = CGU_REG_CPPCR, 175 .bypass_bit = 24, 176 .enable_bit = 0, 177 .stable_bit = 3, 178 }, 179 }, 180 181 [X1830_CLK_VPLL] = { 182 "vpll", CGU_CLK_PLL, 183 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 184 .pll = { 185 .reg = CGU_REG_VPLL, 186 .rate_multiplier = 2, 187 .m_shift = 20, 188 .m_bits = 9, 189 .m_offset = 1, 190 .n_shift = 14, 191 .n_bits = 6, 192 .n_offset = 1, 193 .od_shift = 11, 194 .od_bits = 3, 195 .od_max = 64, 196 .od_encoding = pll_od_encoding, 197 .bypass_reg = CGU_REG_CPPCR, 198 .bypass_bit = 26, 199 .enable_bit = 0, 200 .stable_bit = 3, 201 }, 202 }, 203 204 /* Custom (SoC-specific) OTG PHY */ 205 206 [X1830_CLK_OTGPHY] = { 207 "otg_phy", CGU_CLK_CUSTOM, 208 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 209 .custom = { &x1830_otg_phy_ops }, 210 }, 211 212 /* Muxes & dividers */ 213 214 [X1830_CLK_SCLKA] = { 215 "sclk_a", CGU_CLK_MUX, 216 .parents = { -1, X1830_CLK_EXCLK, X1830_CLK_APLL, -1 }, 217 .mux = { CGU_REG_CPCCR, 30, 2 }, 218 }, 219 220 [X1830_CLK_CPUMUX] = { 221 "cpu_mux", CGU_CLK_MUX, 222 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 223 .mux = { CGU_REG_CPCCR, 28, 2 }, 224 }, 225 226 [X1830_CLK_CPU] = { 227 "cpu", CGU_CLK_DIV | CGU_CLK_GATE, 228 .flags = CLK_IS_CRITICAL, 229 .parents = { X1830_CLK_CPUMUX, -1, -1, -1 }, 230 .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, 231 .gate = { CGU_REG_CLKGR1, 15 }, 232 }, 233 234 [X1830_CLK_L2CACHE] = { 235 "l2cache", CGU_CLK_DIV, 236 /* 237 * The L2 cache clock is critical if caches are enabled and 238 * disabling it or any parent clocks will hang the system. 239 */ 240 .flags = CLK_IS_CRITICAL, 241 .parents = { X1830_CLK_CPUMUX, -1, -1, -1 }, 242 .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, 243 }, 244 245 [X1830_CLK_AHB0] = { 246 "ahb0", CGU_CLK_MUX | CGU_CLK_DIV, 247 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 248 .mux = { CGU_REG_CPCCR, 26, 2 }, 249 .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 }, 250 }, 251 252 [X1830_CLK_AHB2PMUX] = { 253 "ahb2_apb_mux", CGU_CLK_MUX, 254 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 255 .mux = { CGU_REG_CPCCR, 24, 2 }, 256 }, 257 258 [X1830_CLK_AHB2] = { 259 "ahb2", CGU_CLK_DIV, 260 .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 }, 261 .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 }, 262 }, 263 264 [X1830_CLK_PCLK] = { 265 "pclk", CGU_CLK_DIV | CGU_CLK_GATE, 266 .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 }, 267 .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 }, 268 .gate = { CGU_REG_CLKGR1, 14 }, 269 }, 270 271 [X1830_CLK_DDR] = { 272 "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 273 /* 274 * Disabling DDR clock or its parents will render DRAM 275 * inaccessible; mark it critical. 276 */ 277 .flags = CLK_IS_CRITICAL, 278 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 279 .mux = { CGU_REG_DDRCDR, 30, 2 }, 280 .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 }, 281 .gate = { CGU_REG_CLKGR0, 31 }, 282 }, 283 284 [X1830_CLK_MAC] = { 285 "mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 286 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 287 X1830_CLK_VPLL, X1830_CLK_EPLL }, 288 .mux = { CGU_REG_MACCDR, 30, 2 }, 289 .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 }, 290 .gate = { CGU_REG_CLKGR1, 4 }, 291 }, 292 293 [X1830_CLK_LCD] = { 294 "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 295 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 296 X1830_CLK_VPLL, X1830_CLK_EPLL }, 297 .mux = { CGU_REG_LPCDR, 30, 2 }, 298 .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 }, 299 .gate = { CGU_REG_CLKGR1, 9 }, 300 }, 301 302 [X1830_CLK_MSCMUX] = { 303 "msc_mux", CGU_CLK_MUX, 304 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 305 X1830_CLK_VPLL, X1830_CLK_EPLL }, 306 .mux = { CGU_REG_MSC0CDR, 30, 2 }, 307 }, 308 309 [X1830_CLK_MSC0] = { 310 "msc0", CGU_CLK_DIV | CGU_CLK_GATE, 311 .parents = { X1830_CLK_MSCMUX, -1, -1, -1 }, 312 .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, 313 .gate = { CGU_REG_CLKGR0, 4 }, 314 }, 315 316 [X1830_CLK_MSC1] = { 317 "msc1", CGU_CLK_DIV | CGU_CLK_GATE, 318 .parents = { X1830_CLK_MSCMUX, -1, -1, -1 }, 319 .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 }, 320 .gate = { CGU_REG_CLKGR0, 5 }, 321 }, 322 323 [X1830_CLK_SSIPLL] = { 324 "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV, 325 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 326 X1830_CLK_VPLL, X1830_CLK_EPLL }, 327 .mux = { CGU_REG_SSICDR, 30, 2 }, 328 .div = { CGU_REG_SSICDR, 0, 1, 8, 28, 27, 26 }, 329 }, 330 331 [X1830_CLK_SSIPLL_DIV2] = { 332 "ssi_pll_div2", CGU_CLK_FIXDIV, 333 .parents = { X1830_CLK_SSIPLL }, 334 .fixdiv = { 2 }, 335 }, 336 337 [X1830_CLK_SSIMUX] = { 338 "ssi_mux", CGU_CLK_MUX, 339 .parents = { X1830_CLK_EXCLK, X1830_CLK_SSIPLL_DIV2, -1, -1 }, 340 .mux = { CGU_REG_SSICDR, 29, 1 }, 341 }, 342 343 [X1830_CLK_EXCLK_DIV512] = { 344 "exclk_div512", CGU_CLK_FIXDIV, 345 .parents = { X1830_CLK_EXCLK }, 346 .fixdiv = { 512 }, 347 }, 348 349 [X1830_CLK_RTC] = { 350 "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE, 351 .parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK }, 352 .mux = { CGU_REG_OPCR, 2, 1}, 353 .gate = { CGU_REG_CLKGR0, 29 }, 354 }, 355 356 /* Gate-only clocks */ 357 358 [X1830_CLK_EMC] = { 359 "emc", CGU_CLK_GATE, 360 .parents = { X1830_CLK_AHB2, -1, -1, -1 }, 361 .gate = { CGU_REG_CLKGR0, 0 }, 362 }, 363 364 [X1830_CLK_EFUSE] = { 365 "efuse", CGU_CLK_GATE, 366 .parents = { X1830_CLK_AHB2, -1, -1, -1 }, 367 .gate = { CGU_REG_CLKGR0, 1 }, 368 }, 369 370 [X1830_CLK_OTG] = { 371 "otg", CGU_CLK_GATE, 372 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 373 .gate = { CGU_REG_CLKGR0, 3 }, 374 }, 375 376 [X1830_CLK_SSI0] = { 377 "ssi0", CGU_CLK_GATE, 378 .parents = { X1830_CLK_SSIMUX, -1, -1, -1 }, 379 .gate = { CGU_REG_CLKGR0, 6 }, 380 }, 381 382 [X1830_CLK_SMB0] = { 383 "smb0", CGU_CLK_GATE, 384 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 385 .gate = { CGU_REG_CLKGR0, 7 }, 386 }, 387 388 [X1830_CLK_SMB1] = { 389 "smb1", CGU_CLK_GATE, 390 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 391 .gate = { CGU_REG_CLKGR0, 8 }, 392 }, 393 394 [X1830_CLK_SMB2] = { 395 "smb2", CGU_CLK_GATE, 396 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 397 .gate = { CGU_REG_CLKGR0, 9 }, 398 }, 399 400 [X1830_CLK_UART0] = { 401 "uart0", CGU_CLK_GATE, 402 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 403 .gate = { CGU_REG_CLKGR0, 14 }, 404 }, 405 406 [X1830_CLK_UART1] = { 407 "uart1", CGU_CLK_GATE, 408 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 409 .gate = { CGU_REG_CLKGR0, 15 }, 410 }, 411 412 [X1830_CLK_SSI1] = { 413 "ssi1", CGU_CLK_GATE, 414 .parents = { X1830_CLK_SSIMUX, -1, -1, -1 }, 415 .gate = { CGU_REG_CLKGR0, 19 }, 416 }, 417 418 [X1830_CLK_SFC] = { 419 "sfc", CGU_CLK_GATE, 420 .parents = { X1830_CLK_SSIPLL, -1, -1, -1 }, 421 .gate = { CGU_REG_CLKGR0, 20 }, 422 }, 423 424 [X1830_CLK_PDMA] = { 425 "pdma", CGU_CLK_GATE, 426 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 427 .gate = { CGU_REG_CLKGR0, 21 }, 428 }, 429 430 [X1830_CLK_TCU] = { 431 "tcu", CGU_CLK_GATE, 432 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 433 .gate = { CGU_REG_CLKGR0, 30 }, 434 }, 435 436 [X1830_CLK_DTRNG] = { 437 "dtrng", CGU_CLK_GATE, 438 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 439 .gate = { CGU_REG_CLKGR1, 1 }, 440 }, 441 442 [X1830_CLK_OST] = { 443 "ost", CGU_CLK_GATE, 444 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 445 .gate = { CGU_REG_CLKGR1, 11 }, 446 }, 447}; 448 449static void __init x1830_cgu_init(struct device_node *np) 450{ 451 int retval; 452 453 cgu = ingenic_cgu_new(x1830_cgu_clocks, 454 ARRAY_SIZE(x1830_cgu_clocks), np); 455 if (!cgu) { 456 pr_err("%s: failed to initialise CGU\n", __func__); 457 return; 458 } 459 460 retval = ingenic_cgu_register_clocks(cgu); 461 if (retval) { 462 pr_err("%s: failed to register CGU Clocks\n", __func__); 463 return; 464 } 465 466 ingenic_cgu_register_syscore_ops(cgu); 467} 468/* 469 * CGU has some children devices, this is useful for probing children devices 470 * in the case where the device node is compatible with "simple-mfd". 471 */ 472CLK_OF_DECLARE_DRIVER(x1830_cgu, "ingenic,x1830-cgu", x1830_cgu_init);