0001
0002
0003
0004
0005
0006
0007 #include <linux/clk-provider.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011
0012 #include <dt-bindings/clock/ingenic,x1830-cgu.h>
0013
0014 #include "cgu.h"
0015 #include "pm.h"
0016
0017
0018 #define CGU_REG_CPCCR 0x00
0019 #define CGU_REG_CPPCR 0x0c
0020 #define CGU_REG_APLL 0x10
0021 #define CGU_REG_MPLL 0x14
0022 #define CGU_REG_CLKGR0 0x20
0023 #define CGU_REG_OPCR 0x24
0024 #define CGU_REG_CLKGR1 0x28
0025 #define CGU_REG_DDRCDR 0x2c
0026 #define CGU_REG_USBPCR 0x3c
0027 #define CGU_REG_USBRDT 0x40
0028 #define CGU_REG_USBVBFIL 0x44
0029 #define CGU_REG_USBPCR1 0x48
0030 #define CGU_REG_MACCDR 0x54
0031 #define CGU_REG_EPLL 0x58
0032 #define CGU_REG_I2SCDR 0x60
0033 #define CGU_REG_LPCDR 0x64
0034 #define CGU_REG_MSC0CDR 0x68
0035 #define CGU_REG_I2SCDR1 0x70
0036 #define CGU_REG_SSICDR 0x74
0037 #define CGU_REG_CIMCDR 0x7c
0038 #define CGU_REG_MSC1CDR 0xa4
0039 #define CGU_REG_CMP_INTR 0xb0
0040 #define CGU_REG_CMP_INTRE 0xb4
0041 #define CGU_REG_DRCG 0xd0
0042 #define CGU_REG_CPCSR 0xd4
0043 #define CGU_REG_VPLL 0xe0
0044 #define CGU_REG_MACPHYC 0xe8
0045
0046
0047 #define OPCR_GATE_USBPHYCLK BIT(23)
0048 #define OPCR_SPENDN0 BIT(7)
0049 #define OPCR_SPENDN1 BIT(6)
0050
0051
0052 #define USBPCR_SIDDQ BIT(21)
0053 #define USBPCR_OTG_DISABLE BIT(20)
0054
0055 static struct ingenic_cgu *cgu;
0056
0057 static int x1830_usb_phy_enable(struct clk_hw *hw)
0058 {
0059 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
0060 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
0061
0062 writel((readl(reg_opcr) | OPCR_SPENDN0) & ~OPCR_GATE_USBPHYCLK, reg_opcr);
0063 writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
0064 return 0;
0065 }
0066
0067 static void x1830_usb_phy_disable(struct clk_hw *hw)
0068 {
0069 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
0070 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
0071
0072 writel((readl(reg_opcr) & ~OPCR_SPENDN0) | OPCR_GATE_USBPHYCLK, reg_opcr);
0073 writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
0074 }
0075
0076 static int x1830_usb_phy_is_enabled(struct clk_hw *hw)
0077 {
0078 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
0079 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
0080
0081 return (readl(reg_opcr) & OPCR_SPENDN0) &&
0082 !(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
0083 !(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
0084 }
0085
0086 static const struct clk_ops x1830_otg_phy_ops = {
0087 .enable = x1830_usb_phy_enable,
0088 .disable = x1830_usb_phy_disable,
0089 .is_enabled = x1830_usb_phy_is_enabled,
0090 };
0091
0092 static const s8 pll_od_encoding[64] = {
0093 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
0094 -1, -1, -1, -1, -1, -1, -1, 0x4,
0095 -1, -1, -1, -1, -1, -1, -1, -1,
0096 -1, -1, -1, -1, -1, -1, -1, 0x5,
0097 -1, -1, -1, -1, -1, -1, -1, -1,
0098 -1, -1, -1, -1, -1, -1, -1, -1,
0099 -1, -1, -1, -1, -1, -1, -1, -1,
0100 -1, -1, -1, -1, -1, -1, -1, 0x6,
0101 };
0102
0103 static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = {
0104
0105
0106
0107 [X1830_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
0108 [X1830_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
0109
0110
0111
0112 [X1830_CLK_APLL] = {
0113 "apll", CGU_CLK_PLL,
0114 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0115 .pll = {
0116 .reg = CGU_REG_APLL,
0117 .rate_multiplier = 2,
0118 .m_shift = 20,
0119 .m_bits = 9,
0120 .m_offset = 1,
0121 .n_shift = 14,
0122 .n_bits = 6,
0123 .n_offset = 1,
0124 .od_shift = 11,
0125 .od_bits = 3,
0126 .od_max = 64,
0127 .od_encoding = pll_od_encoding,
0128 .bypass_reg = CGU_REG_CPPCR,
0129 .bypass_bit = 30,
0130 .enable_bit = 0,
0131 .stable_bit = 3,
0132 },
0133 },
0134
0135 [X1830_CLK_MPLL] = {
0136 "mpll", CGU_CLK_PLL,
0137 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0138 .pll = {
0139 .reg = CGU_REG_MPLL,
0140 .rate_multiplier = 2,
0141 .m_shift = 20,
0142 .m_bits = 9,
0143 .m_offset = 1,
0144 .n_shift = 14,
0145 .n_bits = 6,
0146 .n_offset = 1,
0147 .od_shift = 11,
0148 .od_bits = 3,
0149 .od_max = 64,
0150 .od_encoding = pll_od_encoding,
0151 .bypass_reg = CGU_REG_CPPCR,
0152 .bypass_bit = 28,
0153 .enable_bit = 0,
0154 .stable_bit = 3,
0155 },
0156 },
0157
0158 [X1830_CLK_EPLL] = {
0159 "epll", CGU_CLK_PLL,
0160 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0161 .pll = {
0162 .reg = CGU_REG_EPLL,
0163 .rate_multiplier = 2,
0164 .m_shift = 20,
0165 .m_bits = 9,
0166 .m_offset = 1,
0167 .n_shift = 14,
0168 .n_bits = 6,
0169 .n_offset = 1,
0170 .od_shift = 11,
0171 .od_bits = 3,
0172 .od_max = 64,
0173 .od_encoding = pll_od_encoding,
0174 .bypass_reg = CGU_REG_CPPCR,
0175 .bypass_bit = 24,
0176 .enable_bit = 0,
0177 .stable_bit = 3,
0178 },
0179 },
0180
0181 [X1830_CLK_VPLL] = {
0182 "vpll", CGU_CLK_PLL,
0183 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0184 .pll = {
0185 .reg = CGU_REG_VPLL,
0186 .rate_multiplier = 2,
0187 .m_shift = 20,
0188 .m_bits = 9,
0189 .m_offset = 1,
0190 .n_shift = 14,
0191 .n_bits = 6,
0192 .n_offset = 1,
0193 .od_shift = 11,
0194 .od_bits = 3,
0195 .od_max = 64,
0196 .od_encoding = pll_od_encoding,
0197 .bypass_reg = CGU_REG_CPPCR,
0198 .bypass_bit = 26,
0199 .enable_bit = 0,
0200 .stable_bit = 3,
0201 },
0202 },
0203
0204
0205
0206 [X1830_CLK_OTGPHY] = {
0207 "otg_phy", CGU_CLK_CUSTOM,
0208 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0209 .custom = { &x1830_otg_phy_ops },
0210 },
0211
0212
0213
0214 [X1830_CLK_SCLKA] = {
0215 "sclk_a", CGU_CLK_MUX,
0216 .parents = { -1, X1830_CLK_EXCLK, X1830_CLK_APLL, -1 },
0217 .mux = { CGU_REG_CPCCR, 30, 2 },
0218 },
0219
0220 [X1830_CLK_CPUMUX] = {
0221 "cpu_mux", CGU_CLK_MUX,
0222 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
0223 .mux = { CGU_REG_CPCCR, 28, 2 },
0224 },
0225
0226 [X1830_CLK_CPU] = {
0227 "cpu", CGU_CLK_DIV | CGU_CLK_GATE,
0228 .flags = CLK_IS_CRITICAL,
0229 .parents = { X1830_CLK_CPUMUX, -1, -1, -1 },
0230 .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
0231 .gate = { CGU_REG_CLKGR1, 15 },
0232 },
0233
0234 [X1830_CLK_L2CACHE] = {
0235 "l2cache", CGU_CLK_DIV,
0236
0237
0238
0239
0240 .flags = CLK_IS_CRITICAL,
0241 .parents = { X1830_CLK_CPUMUX, -1, -1, -1 },
0242 .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
0243 },
0244
0245 [X1830_CLK_AHB0] = {
0246 "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
0247 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
0248 .mux = { CGU_REG_CPCCR, 26, 2 },
0249 .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },
0250 },
0251
0252 [X1830_CLK_AHB2PMUX] = {
0253 "ahb2_apb_mux", CGU_CLK_MUX,
0254 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
0255 .mux = { CGU_REG_CPCCR, 24, 2 },
0256 },
0257
0258 [X1830_CLK_AHB2] = {
0259 "ahb2", CGU_CLK_DIV,
0260 .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 },
0261 .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
0262 },
0263
0264 [X1830_CLK_PCLK] = {
0265 "pclk", CGU_CLK_DIV | CGU_CLK_GATE,
0266 .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 },
0267 .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
0268 .gate = { CGU_REG_CLKGR1, 14 },
0269 },
0270
0271 [X1830_CLK_DDR] = {
0272 "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
0273
0274
0275
0276
0277 .flags = CLK_IS_CRITICAL,
0278 .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
0279 .mux = { CGU_REG_DDRCDR, 30, 2 },
0280 .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },
0281 .gate = { CGU_REG_CLKGR0, 31 },
0282 },
0283
0284 [X1830_CLK_MAC] = {
0285 "mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
0286 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
0287 X1830_CLK_VPLL, X1830_CLK_EPLL },
0288 .mux = { CGU_REG_MACCDR, 30, 2 },
0289 .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },
0290 .gate = { CGU_REG_CLKGR1, 4 },
0291 },
0292
0293 [X1830_CLK_LCD] = {
0294 "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
0295 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
0296 X1830_CLK_VPLL, X1830_CLK_EPLL },
0297 .mux = { CGU_REG_LPCDR, 30, 2 },
0298 .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },
0299 .gate = { CGU_REG_CLKGR1, 9 },
0300 },
0301
0302 [X1830_CLK_MSCMUX] = {
0303 "msc_mux", CGU_CLK_MUX,
0304 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
0305 X1830_CLK_VPLL, X1830_CLK_EPLL },
0306 .mux = { CGU_REG_MSC0CDR, 30, 2 },
0307 },
0308
0309 [X1830_CLK_MSC0] = {
0310 "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
0311 .parents = { X1830_CLK_MSCMUX, -1, -1, -1 },
0312 .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
0313 .gate = { CGU_REG_CLKGR0, 4 },
0314 },
0315
0316 [X1830_CLK_MSC1] = {
0317 "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
0318 .parents = { X1830_CLK_MSCMUX, -1, -1, -1 },
0319 .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },
0320 .gate = { CGU_REG_CLKGR0, 5 },
0321 },
0322
0323 [X1830_CLK_SSIPLL] = {
0324 "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
0325 .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
0326 X1830_CLK_VPLL, X1830_CLK_EPLL },
0327 .mux = { CGU_REG_SSICDR, 30, 2 },
0328 .div = { CGU_REG_SSICDR, 0, 1, 8, 28, 27, 26 },
0329 },
0330
0331 [X1830_CLK_SSIPLL_DIV2] = {
0332 "ssi_pll_div2", CGU_CLK_FIXDIV,
0333 .parents = { X1830_CLK_SSIPLL },
0334 .fixdiv = { 2 },
0335 },
0336
0337 [X1830_CLK_SSIMUX] = {
0338 "ssi_mux", CGU_CLK_MUX,
0339 .parents = { X1830_CLK_EXCLK, X1830_CLK_SSIPLL_DIV2, -1, -1 },
0340 .mux = { CGU_REG_SSICDR, 29, 1 },
0341 },
0342
0343 [X1830_CLK_EXCLK_DIV512] = {
0344 "exclk_div512", CGU_CLK_FIXDIV,
0345 .parents = { X1830_CLK_EXCLK },
0346 .fixdiv = { 512 },
0347 },
0348
0349 [X1830_CLK_RTC] = {
0350 "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
0351 .parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK },
0352 .mux = { CGU_REG_OPCR, 2, 1},
0353 .gate = { CGU_REG_CLKGR0, 29 },
0354 },
0355
0356
0357
0358 [X1830_CLK_EMC] = {
0359 "emc", CGU_CLK_GATE,
0360 .parents = { X1830_CLK_AHB2, -1, -1, -1 },
0361 .gate = { CGU_REG_CLKGR0, 0 },
0362 },
0363
0364 [X1830_CLK_EFUSE] = {
0365 "efuse", CGU_CLK_GATE,
0366 .parents = { X1830_CLK_AHB2, -1, -1, -1 },
0367 .gate = { CGU_REG_CLKGR0, 1 },
0368 },
0369
0370 [X1830_CLK_OTG] = {
0371 "otg", CGU_CLK_GATE,
0372 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0373 .gate = { CGU_REG_CLKGR0, 3 },
0374 },
0375
0376 [X1830_CLK_SSI0] = {
0377 "ssi0", CGU_CLK_GATE,
0378 .parents = { X1830_CLK_SSIMUX, -1, -1, -1 },
0379 .gate = { CGU_REG_CLKGR0, 6 },
0380 },
0381
0382 [X1830_CLK_SMB0] = {
0383 "smb0", CGU_CLK_GATE,
0384 .parents = { X1830_CLK_PCLK, -1, -1, -1 },
0385 .gate = { CGU_REG_CLKGR0, 7 },
0386 },
0387
0388 [X1830_CLK_SMB1] = {
0389 "smb1", CGU_CLK_GATE,
0390 .parents = { X1830_CLK_PCLK, -1, -1, -1 },
0391 .gate = { CGU_REG_CLKGR0, 8 },
0392 },
0393
0394 [X1830_CLK_SMB2] = {
0395 "smb2", CGU_CLK_GATE,
0396 .parents = { X1830_CLK_PCLK, -1, -1, -1 },
0397 .gate = { CGU_REG_CLKGR0, 9 },
0398 },
0399
0400 [X1830_CLK_UART0] = {
0401 "uart0", CGU_CLK_GATE,
0402 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0403 .gate = { CGU_REG_CLKGR0, 14 },
0404 },
0405
0406 [X1830_CLK_UART1] = {
0407 "uart1", CGU_CLK_GATE,
0408 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0409 .gate = { CGU_REG_CLKGR0, 15 },
0410 },
0411
0412 [X1830_CLK_SSI1] = {
0413 "ssi1", CGU_CLK_GATE,
0414 .parents = { X1830_CLK_SSIMUX, -1, -1, -1 },
0415 .gate = { CGU_REG_CLKGR0, 19 },
0416 },
0417
0418 [X1830_CLK_SFC] = {
0419 "sfc", CGU_CLK_GATE,
0420 .parents = { X1830_CLK_SSIPLL, -1, -1, -1 },
0421 .gate = { CGU_REG_CLKGR0, 20 },
0422 },
0423
0424 [X1830_CLK_PDMA] = {
0425 "pdma", CGU_CLK_GATE,
0426 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0427 .gate = { CGU_REG_CLKGR0, 21 },
0428 },
0429
0430 [X1830_CLK_TCU] = {
0431 "tcu", CGU_CLK_GATE,
0432 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0433 .gate = { CGU_REG_CLKGR0, 30 },
0434 },
0435
0436 [X1830_CLK_DTRNG] = {
0437 "dtrng", CGU_CLK_GATE,
0438 .parents = { X1830_CLK_PCLK, -1, -1, -1 },
0439 .gate = { CGU_REG_CLKGR1, 1 },
0440 },
0441
0442 [X1830_CLK_OST] = {
0443 "ost", CGU_CLK_GATE,
0444 .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
0445 .gate = { CGU_REG_CLKGR1, 11 },
0446 },
0447 };
0448
0449 static void __init x1830_cgu_init(struct device_node *np)
0450 {
0451 int retval;
0452
0453 cgu = ingenic_cgu_new(x1830_cgu_clocks,
0454 ARRAY_SIZE(x1830_cgu_clocks), np);
0455 if (!cgu) {
0456 pr_err("%s: failed to initialise CGU\n", __func__);
0457 return;
0458 }
0459
0460 retval = ingenic_cgu_register_clocks(cgu);
0461 if (retval) {
0462 pr_err("%s: failed to register CGU Clocks\n", __func__);
0463 return;
0464 }
0465
0466 ingenic_cgu_register_syscore_ops(cgu);
0467 }
0468
0469
0470
0471
0472 CLK_OF_DECLARE_DRIVER(x1830_cgu, "ingenic,x1830-cgu", x1830_cgu_init);