473 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * X1830 SoC CGU driver4 * 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 0x0019#define CGU_REG_CPPCR 0x0c20#define CGU_REG_APLL 0x1021#define CGU_REG_MPLL 0x1422#define CGU_REG_CLKGR0 0x2023#define CGU_REG_OPCR 0x2424#define CGU_REG_CLKGR1 0x2825#define CGU_REG_DDRCDR 0x2c26#define CGU_REG_USBPCR 0x3c27#define CGU_REG_USBRDT 0x4028#define CGU_REG_USBVBFIL 0x4429#define CGU_REG_USBPCR1 0x4830#define CGU_REG_MACCDR 0x5431#define CGU_REG_EPLL 0x5832#define CGU_REG_I2SCDR 0x6033#define CGU_REG_LPCDR 0x6434#define CGU_REG_MSC0CDR 0x6835#define CGU_REG_I2SCDR1 0x7036#define CGU_REG_SSICDR 0x7437#define CGU_REG_CIMCDR 0x7c38#define CGU_REG_MSC1CDR 0xa439#define CGU_REG_CMP_INTR 0xb040#define CGU_REG_CMP_INTRE 0xb441#define CGU_REG_DRCG 0xd042#define CGU_REG_CPCSR 0xd443#define CGU_REG_VPLL 0xe044#define CGU_REG_MACPHYC 0xe845 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 and238 * 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 DRAM275 * 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 devices470 * 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);473