Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * X1830 SoC CGU driver
0004  * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
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 /* CGU register offsets */
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 /* bits within the OPCR register */
0047 #define OPCR_GATE_USBPHYCLK BIT(23)
0048 #define OPCR_SPENDN0        BIT(7)
0049 #define OPCR_SPENDN1        BIT(6)
0050 
0051 /* bits within the USBPCR register */
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     /* External clocks */
0106 
0107     [X1830_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
0108     [X1830_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
0109 
0110     /* PLLs */
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     /* Custom (SoC-specific) OTG PHY */
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     /* Muxes & dividers */
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          * The L2 cache clock is critical if caches are enabled and
0238          * disabling it or any parent clocks will hang the system.
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          * Disabling DDR clock or its parents will render DRAM
0275          * inaccessible; mark it critical.
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     /* Gate-only clocks */
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  * CGU has some children devices, this is useful for probing children devices
0470  * in the case where the device node is compatible with "simple-mfd".
0471  */
0472 CLK_OF_DECLARE_DRIVER(x1830_cgu, "ingenic,x1830-cgu", x1830_cgu_init);