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 55 static struct ingenic_cgu *cgu; 56 57 static 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 67 static 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 76 static 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 86 static 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 92 static 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 103 static 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 .parents = { X1830_CLK_CPUMUX, -1, -1, -1 }, 229 .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, 230 .gate = { CGU_REG_CLKGR1, 15 }, 231 }, 232 233 [X1830_CLK_L2CACHE] = { 234 "l2cache", CGU_CLK_DIV, 235 .parents = { X1830_CLK_CPUMUX, -1, -1, -1 }, 236 .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, 237 }, 238 239 [X1830_CLK_AHB0] = { 240 "ahb0", CGU_CLK_MUX | CGU_CLK_DIV, 241 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 242 .mux = { CGU_REG_CPCCR, 26, 2 }, 243 .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 }, 244 }, 245 246 [X1830_CLK_AHB2PMUX] = { 247 "ahb2_apb_mux", CGU_CLK_MUX, 248 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 249 .mux = { CGU_REG_CPCCR, 24, 2 }, 250 }, 251 252 [X1830_CLK_AHB2] = { 253 "ahb2", CGU_CLK_DIV, 254 .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 }, 255 .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 }, 256 }, 257 258 [X1830_CLK_PCLK] = { 259 "pclk", CGU_CLK_DIV | CGU_CLK_GATE, 260 .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 }, 261 .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 }, 262 .gate = { CGU_REG_CLKGR1, 14 }, 263 }, 264 265 [X1830_CLK_DDR] = { 266 "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 267 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 }, 268 .mux = { CGU_REG_DDRCDR, 30, 2 }, 269 .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 }, 270 .gate = { CGU_REG_CLKGR0, 31 }, 271 }, 272 273 [X1830_CLK_MAC] = { 274 "mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 275 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 276 X1830_CLK_VPLL, X1830_CLK_EPLL }, 277 .mux = { CGU_REG_MACCDR, 30, 2 }, 278 .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 }, 279 .gate = { CGU_REG_CLKGR1, 4 }, 280 }, 281 282 [X1830_CLK_LCD] = { 283 "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 284 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 285 X1830_CLK_VPLL, X1830_CLK_EPLL }, 286 .mux = { CGU_REG_LPCDR, 30, 2 }, 287 .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 }, 288 .gate = { CGU_REG_CLKGR1, 9 }, 289 }, 290 291 [X1830_CLK_MSCMUX] = { 292 "msc_mux", CGU_CLK_MUX, 293 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 294 X1830_CLK_VPLL, X1830_CLK_EPLL }, 295 .mux = { CGU_REG_MSC0CDR, 30, 2 }, 296 }, 297 298 [X1830_CLK_MSC0] = { 299 "msc0", CGU_CLK_DIV | CGU_CLK_GATE, 300 .parents = { X1830_CLK_MSCMUX, -1, -1, -1 }, 301 .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, 302 .gate = { CGU_REG_CLKGR0, 4 }, 303 }, 304 305 [X1830_CLK_MSC1] = { 306 "msc1", CGU_CLK_DIV | CGU_CLK_GATE, 307 .parents = { X1830_CLK_MSCMUX, -1, -1, -1 }, 308 .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 }, 309 .gate = { CGU_REG_CLKGR0, 5 }, 310 }, 311 312 [X1830_CLK_SSIPLL] = { 313 "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV, 314 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL, 315 X1830_CLK_VPLL, X1830_CLK_EPLL }, 316 .mux = { CGU_REG_SSICDR, 30, 2 }, 317 .div = { CGU_REG_SSICDR, 0, 1, 8, 28, 27, 26 }, 318 }, 319 320 [X1830_CLK_SSIPLL_DIV2] = { 321 "ssi_pll_div2", CGU_CLK_FIXDIV, 322 .parents = { X1830_CLK_SSIPLL }, 323 .fixdiv = { 2 }, 324 }, 325 326 [X1830_CLK_SSIMUX] = { 327 "ssi_mux", CGU_CLK_MUX, 328 .parents = { X1830_CLK_EXCLK, X1830_CLK_SSIPLL_DIV2, -1, -1 }, 329 .mux = { CGU_REG_SSICDR, 29, 1 }, 330 }, 331 332 [X1830_CLK_EXCLK_DIV512] = { 333 "exclk_div512", CGU_CLK_FIXDIV, 334 .parents = { X1830_CLK_EXCLK }, 335 .fixdiv = { 512 }, 336 }, 337 338 [X1830_CLK_RTC] = { 339 "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE, 340 .parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK }, 341 .mux = { CGU_REG_OPCR, 2, 1}, 342 .gate = { CGU_REG_CLKGR0, 29 }, 343 }, 344 345 /* Gate-only clocks */ 346 347 [X1830_CLK_EMC] = { 348 "emc", CGU_CLK_GATE, 349 .parents = { X1830_CLK_AHB2, -1, -1, -1 }, 350 .gate = { CGU_REG_CLKGR0, 0 }, 351 }, 352 353 [X1830_CLK_EFUSE] = { 354 "efuse", CGU_CLK_GATE, 355 .parents = { X1830_CLK_AHB2, -1, -1, -1 }, 356 .gate = { CGU_REG_CLKGR0, 1 }, 357 }, 358 359 [X1830_CLK_OTG] = { 360 "otg", CGU_CLK_GATE, 361 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 362 .gate = { CGU_REG_CLKGR0, 3 }, 363 }, 364 365 [X1830_CLK_SSI0] = { 366 "ssi0", CGU_CLK_GATE, 367 .parents = { X1830_CLK_SSIMUX, -1, -1, -1 }, 368 .gate = { CGU_REG_CLKGR0, 6 }, 369 }, 370 371 [X1830_CLK_SMB0] = { 372 "smb0", CGU_CLK_GATE, 373 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 374 .gate = { CGU_REG_CLKGR0, 7 }, 375 }, 376 377 [X1830_CLK_SMB1] = { 378 "smb1", CGU_CLK_GATE, 379 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 380 .gate = { CGU_REG_CLKGR0, 8 }, 381 }, 382 383 [X1830_CLK_SMB2] = { 384 "smb2", CGU_CLK_GATE, 385 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 386 .gate = { CGU_REG_CLKGR0, 9 }, 387 }, 388 389 [X1830_CLK_UART0] = { 390 "uart0", CGU_CLK_GATE, 391 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 392 .gate = { CGU_REG_CLKGR0, 14 }, 393 }, 394 395 [X1830_CLK_UART1] = { 396 "uart1", CGU_CLK_GATE, 397 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 398 .gate = { CGU_REG_CLKGR0, 15 }, 399 }, 400 401 [X1830_CLK_SSI1] = { 402 "ssi1", CGU_CLK_GATE, 403 .parents = { X1830_CLK_SSIMUX, -1, -1, -1 }, 404 .gate = { CGU_REG_CLKGR0, 19 }, 405 }, 406 407 [X1830_CLK_SFC] = { 408 "sfc", CGU_CLK_GATE, 409 .parents = { X1830_CLK_SSIPLL, -1, -1, -1 }, 410 .gate = { CGU_REG_CLKGR0, 20 }, 411 }, 412 413 [X1830_CLK_PDMA] = { 414 "pdma", CGU_CLK_GATE, 415 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 416 .gate = { CGU_REG_CLKGR0, 21 }, 417 }, 418 419 [X1830_CLK_TCU] = { 420 "tcu", CGU_CLK_GATE, 421 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 422 .gate = { CGU_REG_CLKGR0, 30 }, 423 }, 424 425 [X1830_CLK_DTRNG] = { 426 "dtrng", CGU_CLK_GATE, 427 .parents = { X1830_CLK_PCLK, -1, -1, -1 }, 428 .gate = { CGU_REG_CLKGR1, 1 }, 429 }, 430 431 [X1830_CLK_OST] = { 432 "ost", CGU_CLK_GATE, 433 .parents = { X1830_CLK_EXCLK, -1, -1, -1 }, 434 .gate = { CGU_REG_CLKGR1, 11 }, 435 }, 436 }; 437 438 static void __init x1830_cgu_init(struct device_node *np) 439 { 440 int retval; 441 442 cgu = ingenic_cgu_new(x1830_cgu_clocks, 443 ARRAY_SIZE(x1830_cgu_clocks), np); 444 if (!cgu) { 445 pr_err("%s: failed to initialise CGU\n", __func__); 446 return; 447 } 448 449 retval = ingenic_cgu_register_clocks(cgu); 450 if (retval) { 451 pr_err("%s: failed to register CGU Clocks\n", __func__); 452 return; 453 } 454 455 ingenic_cgu_register_syscore_ops(cgu); 456 } 457 /* 458 * CGU has some children devices, this is useful for probing children devices 459 * in the case where the device node is compatible with "simple-mfd". 460 */ 461 CLK_OF_DECLARE_DRIVER(x1830_cgu, "ingenic,x1830-cgu", x1830_cgu_init); 462