Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * JZ4770 SoC CGU driver
0004  * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
0005  */
0006 
0007 #include <linux/bitops.h>
0008 #include <linux/clk-provider.h>
0009 #include <linux/delay.h>
0010 #include <linux/io.h>
0011 #include <linux/of.h>
0012 
0013 #include <dt-bindings/clock/ingenic,jz4770-cgu.h>
0014 
0015 #include "cgu.h"
0016 #include "pm.h"
0017 
0018 /*
0019  * CPM registers offset address definition
0020  */
0021 #define CGU_REG_CPCCR       0x00
0022 #define CGU_REG_LCR     0x04
0023 #define CGU_REG_CPPCR0      0x10
0024 #define CGU_REG_CLKGR0      0x20
0025 #define CGU_REG_OPCR        0x24
0026 #define CGU_REG_CLKGR1      0x28
0027 #define CGU_REG_CPPCR1      0x30
0028 #define CGU_REG_USBPCR1     0x48
0029 #define CGU_REG_USBCDR      0x50
0030 #define CGU_REG_I2SCDR      0x60
0031 #define CGU_REG_LPCDR       0x64
0032 #define CGU_REG_MSC0CDR     0x68
0033 #define CGU_REG_UHCCDR      0x6c
0034 #define CGU_REG_SSICDR      0x74
0035 #define CGU_REG_CIMCDR      0x7c
0036 #define CGU_REG_GPSCDR      0x80
0037 #define CGU_REG_PCMCDR      0x84
0038 #define CGU_REG_GPUCDR      0x88
0039 #define CGU_REG_MSC1CDR     0xA4
0040 #define CGU_REG_MSC2CDR     0xA8
0041 #define CGU_REG_BCHCDR      0xAC
0042 
0043 /* bits within the OPCR register */
0044 #define OPCR_SPENDH     BIT(5)      /* UHC PHY suspend */
0045 
0046 /* bits within the USBPCR1 register */
0047 #define USBPCR1_UHC_POWER   BIT(5)      /* UHC PHY power down */
0048 
0049 static struct ingenic_cgu *cgu;
0050 
0051 static int jz4770_uhc_phy_enable(struct clk_hw *hw)
0052 {
0053     void __iomem *reg_opcr      = cgu->base + CGU_REG_OPCR;
0054     void __iomem *reg_usbpcr1   = cgu->base + CGU_REG_USBPCR1;
0055 
0056     writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
0057     writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
0058     return 0;
0059 }
0060 
0061 static void jz4770_uhc_phy_disable(struct clk_hw *hw)
0062 {
0063     void __iomem *reg_opcr      = cgu->base + CGU_REG_OPCR;
0064     void __iomem *reg_usbpcr1   = cgu->base + CGU_REG_USBPCR1;
0065 
0066     writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
0067     writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
0068 }
0069 
0070 static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
0071 {
0072     void __iomem *reg_opcr      = cgu->base + CGU_REG_OPCR;
0073     void __iomem *reg_usbpcr1   = cgu->base + CGU_REG_USBPCR1;
0074 
0075     return !(readl(reg_opcr) & OPCR_SPENDH) &&
0076         (readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
0077 }
0078 
0079 static const struct clk_ops jz4770_uhc_phy_ops = {
0080     .enable = jz4770_uhc_phy_enable,
0081     .disable = jz4770_uhc_phy_disable,
0082     .is_enabled = jz4770_uhc_phy_is_enabled,
0083 };
0084 
0085 static const s8 pll_od_encoding[8] = {
0086     0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
0087 };
0088 
0089 static const u8 jz4770_cgu_cpccr_div_table[] = {
0090     1, 2, 3, 4, 6, 8, 12,
0091 };
0092 
0093 static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
0094 
0095     /* External clocks */
0096 
0097     [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
0098     [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
0099 
0100     /* PLLs */
0101 
0102     [JZ4770_CLK_PLL0] = {
0103         "pll0", CGU_CLK_PLL,
0104         .parents = { JZ4770_CLK_EXT },
0105         .pll = {
0106             .reg = CGU_REG_CPPCR0,
0107             .rate_multiplier = 1,
0108             .m_shift = 24,
0109             .m_bits = 7,
0110             .m_offset = 1,
0111             .n_shift = 18,
0112             .n_bits = 5,
0113             .n_offset = 1,
0114             .od_shift = 16,
0115             .od_bits = 2,
0116             .od_max = 8,
0117             .od_encoding = pll_od_encoding,
0118             .bypass_reg = CGU_REG_CPPCR0,
0119             .bypass_bit = 9,
0120             .enable_bit = 8,
0121             .stable_bit = 10,
0122         },
0123     },
0124 
0125     [JZ4770_CLK_PLL1] = {
0126         /* TODO: PLL1 can depend on PLL0 */
0127         "pll1", CGU_CLK_PLL,
0128         .parents = { JZ4770_CLK_EXT },
0129         .pll = {
0130             .reg = CGU_REG_CPPCR1,
0131             .rate_multiplier = 1,
0132             .m_shift = 24,
0133             .m_bits = 7,
0134             .m_offset = 1,
0135             .n_shift = 18,
0136             .n_bits = 5,
0137             .n_offset = 1,
0138             .od_shift = 16,
0139             .od_bits = 2,
0140             .od_max = 8,
0141             .od_encoding = pll_od_encoding,
0142             .bypass_bit = -1,
0143             .enable_bit = 7,
0144             .stable_bit = 6,
0145         },
0146     },
0147 
0148     /* Main clocks */
0149 
0150     [JZ4770_CLK_CCLK] = {
0151         "cclk", CGU_CLK_DIV,
0152         /*
0153          * Disabling the CPU clock or any parent clocks will hang the
0154          * system; mark it critical.
0155          */
0156         .flags = CLK_IS_CRITICAL,
0157         .parents = { JZ4770_CLK_PLL0, },
0158         .div = {
0159             CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
0160             jz4770_cgu_cpccr_div_table,
0161         },
0162     },
0163     [JZ4770_CLK_H0CLK] = {
0164         "h0clk", CGU_CLK_DIV,
0165         .parents = { JZ4770_CLK_PLL0, },
0166         .div = {
0167             CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
0168             jz4770_cgu_cpccr_div_table,
0169         },
0170     },
0171     [JZ4770_CLK_H1CLK] = {
0172         "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
0173         .parents = { JZ4770_CLK_PLL0, },
0174         .div = {
0175             CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
0176             jz4770_cgu_cpccr_div_table,
0177         },
0178         .gate = { CGU_REG_CLKGR1, 7 },
0179     },
0180     [JZ4770_CLK_H2CLK] = {
0181         "h2clk", CGU_CLK_DIV,
0182         .parents = { JZ4770_CLK_PLL0, },
0183         .div = {
0184             CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
0185             jz4770_cgu_cpccr_div_table,
0186         },
0187     },
0188     [JZ4770_CLK_C1CLK] = {
0189         "c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
0190         .parents = { JZ4770_CLK_PLL0, },
0191         .div = {
0192             CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
0193             jz4770_cgu_cpccr_div_table,
0194         },
0195         .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
0196     },
0197     [JZ4770_CLK_PCLK] = {
0198         "pclk", CGU_CLK_DIV,
0199         .parents = { JZ4770_CLK_PLL0, },
0200         .div = {
0201             CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
0202             jz4770_cgu_cpccr_div_table,
0203         },
0204     },
0205 
0206     /* Those divided clocks can connect to PLL0 or PLL1 */
0207 
0208     [JZ4770_CLK_MMC0_MUX] = {
0209         "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0210         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0211         .mux = { CGU_REG_MSC0CDR, 30, 1 },
0212         .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
0213         .gate = { CGU_REG_MSC0CDR, 31 },
0214     },
0215     [JZ4770_CLK_MMC1_MUX] = {
0216         "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0217         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0218         .mux = { CGU_REG_MSC1CDR, 30, 1 },
0219         .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
0220         .gate = { CGU_REG_MSC1CDR, 31 },
0221     },
0222     [JZ4770_CLK_MMC2_MUX] = {
0223         "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0224         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0225         .mux = { CGU_REG_MSC2CDR, 30, 1 },
0226         .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
0227         .gate = { CGU_REG_MSC2CDR, 31 },
0228     },
0229     [JZ4770_CLK_CIM] = {
0230         "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0231         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0232         .mux = { CGU_REG_CIMCDR, 31, 1 },
0233         .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
0234         .gate = { CGU_REG_CLKGR0, 26 },
0235     },
0236     [JZ4770_CLK_UHC] = {
0237         "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0238         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0239         .mux = { CGU_REG_UHCCDR, 29, 1 },
0240         .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
0241         .gate = { CGU_REG_CLKGR0, 24 },
0242     },
0243     [JZ4770_CLK_GPU] = {
0244         "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0245         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
0246         .mux = { CGU_REG_GPUCDR, 31, 1 },
0247         .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
0248         .gate = { CGU_REG_CLKGR1, 9 },
0249     },
0250     [JZ4770_CLK_BCH] = {
0251         "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0252         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0253         .mux = { CGU_REG_BCHCDR, 31, 1 },
0254         .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
0255         .gate = { CGU_REG_CLKGR0, 1 },
0256     },
0257     [JZ4770_CLK_LPCLK_MUX] = {
0258         "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0259         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0260         .mux = { CGU_REG_LPCDR, 29, 1 },
0261         .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
0262         .gate = { CGU_REG_CLKGR0, 28 },
0263     },
0264     [JZ4770_CLK_GPS] = {
0265         "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0266         .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
0267         .mux = { CGU_REG_GPSCDR, 31, 1 },
0268         .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
0269         .gate = { CGU_REG_CLKGR0, 22 },
0270     },
0271 
0272     /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
0273 
0274     [JZ4770_CLK_SSI_MUX] = {
0275         "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
0276         .parents = { JZ4770_CLK_EXT, -1,
0277             JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
0278         .mux = { CGU_REG_SSICDR, 30, 2 },
0279         .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
0280     },
0281     [JZ4770_CLK_PCM_MUX] = {
0282         "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
0283         .parents = { JZ4770_CLK_EXT, -1,
0284             JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
0285         .mux = { CGU_REG_PCMCDR, 30, 2 },
0286         .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
0287     },
0288     [JZ4770_CLK_I2S] = {
0289         "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0290         .parents = { JZ4770_CLK_EXT, -1,
0291             JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
0292         .mux = { CGU_REG_I2SCDR, 30, 2 },
0293         .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
0294         .gate = { CGU_REG_CLKGR1, 13 },
0295     },
0296     [JZ4770_CLK_OTG] = {
0297         "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0298         .parents = { JZ4770_CLK_EXT, -1,
0299             JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
0300         .mux = { CGU_REG_USBCDR, 30, 2 },
0301         .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
0302         .gate = { CGU_REG_CLKGR0, 2 },
0303     },
0304 
0305     /* Gate-only clocks */
0306 
0307     [JZ4770_CLK_SSI0] = {
0308         "ssi0", CGU_CLK_GATE,
0309         .parents = { JZ4770_CLK_SSI_MUX, },
0310         .gate = { CGU_REG_CLKGR0, 4 },
0311     },
0312     [JZ4770_CLK_SSI1] = {
0313         "ssi1", CGU_CLK_GATE,
0314         .parents = { JZ4770_CLK_SSI_MUX, },
0315         .gate = { CGU_REG_CLKGR0, 19 },
0316     },
0317     [JZ4770_CLK_SSI2] = {
0318         "ssi2", CGU_CLK_GATE,
0319         .parents = { JZ4770_CLK_SSI_MUX, },
0320         .gate = { CGU_REG_CLKGR0, 20 },
0321     },
0322     [JZ4770_CLK_PCM0] = {
0323         "pcm0", CGU_CLK_GATE,
0324         .parents = { JZ4770_CLK_PCM_MUX, },
0325         .gate = { CGU_REG_CLKGR1, 8 },
0326     },
0327     [JZ4770_CLK_PCM1] = {
0328         "pcm1", CGU_CLK_GATE,
0329         .parents = { JZ4770_CLK_PCM_MUX, },
0330         .gate = { CGU_REG_CLKGR1, 10 },
0331     },
0332     [JZ4770_CLK_DMA] = {
0333         "dma", CGU_CLK_GATE,
0334         .parents = { JZ4770_CLK_H2CLK, },
0335         .gate = { CGU_REG_CLKGR0, 21 },
0336     },
0337     [JZ4770_CLK_BDMA] = {
0338         "bdma", CGU_CLK_GATE,
0339         .parents = { JZ4770_CLK_H2CLK, },
0340         .gate = { CGU_REG_CLKGR1, 0 },
0341     },
0342     [JZ4770_CLK_I2C0] = {
0343         "i2c0", CGU_CLK_GATE,
0344         .parents = { JZ4770_CLK_EXT, },
0345         .gate = { CGU_REG_CLKGR0, 5 },
0346     },
0347     [JZ4770_CLK_I2C1] = {
0348         "i2c1", CGU_CLK_GATE,
0349         .parents = { JZ4770_CLK_EXT, },
0350         .gate = { CGU_REG_CLKGR0, 6 },
0351     },
0352     [JZ4770_CLK_I2C2] = {
0353         "i2c2", CGU_CLK_GATE,
0354         .parents = { JZ4770_CLK_EXT, },
0355         .gate = { CGU_REG_CLKGR1, 15 },
0356     },
0357     [JZ4770_CLK_UART0] = {
0358         "uart0", CGU_CLK_GATE,
0359         .parents = { JZ4770_CLK_EXT, },
0360         .gate = { CGU_REG_CLKGR0, 15 },
0361     },
0362     [JZ4770_CLK_UART1] = {
0363         "uart1", CGU_CLK_GATE,
0364         .parents = { JZ4770_CLK_EXT, },
0365         .gate = { CGU_REG_CLKGR0, 16 },
0366     },
0367     [JZ4770_CLK_UART2] = {
0368         "uart2", CGU_CLK_GATE,
0369         .parents = { JZ4770_CLK_EXT, },
0370         .gate = { CGU_REG_CLKGR0, 17 },
0371     },
0372     [JZ4770_CLK_UART3] = {
0373         "uart3", CGU_CLK_GATE,
0374         .parents = { JZ4770_CLK_EXT, },
0375         .gate = { CGU_REG_CLKGR0, 18 },
0376     },
0377     [JZ4770_CLK_IPU] = {
0378         "ipu", CGU_CLK_GATE,
0379         .parents = { JZ4770_CLK_H0CLK, },
0380         .gate = { CGU_REG_CLKGR0, 29 },
0381     },
0382     [JZ4770_CLK_ADC] = {
0383         "adc", CGU_CLK_GATE,
0384         .parents = { JZ4770_CLK_EXT, },
0385         .gate = { CGU_REG_CLKGR0, 14 },
0386     },
0387     [JZ4770_CLK_AIC] = {
0388         "aic", CGU_CLK_GATE,
0389         .parents = { JZ4770_CLK_EXT, },
0390         .gate = { CGU_REG_CLKGR0, 8 },
0391     },
0392     [JZ4770_CLK_AUX] = {
0393         "aux", CGU_CLK_GATE,
0394         .parents = { JZ4770_CLK_C1CLK, },
0395         .gate = { CGU_REG_CLKGR1, 14 },
0396     },
0397     [JZ4770_CLK_VPU] = {
0398         "vpu", CGU_CLK_GATE,
0399         .parents = { JZ4770_CLK_H1CLK, },
0400         .gate = { CGU_REG_LCR, 30, false, 150 },
0401     },
0402     [JZ4770_CLK_MMC0] = {
0403         "mmc0", CGU_CLK_GATE,
0404         .parents = { JZ4770_CLK_MMC0_MUX, },
0405         .gate = { CGU_REG_CLKGR0, 3 },
0406     },
0407     [JZ4770_CLK_MMC1] = {
0408         "mmc1", CGU_CLK_GATE,
0409         .parents = { JZ4770_CLK_MMC1_MUX, },
0410         .gate = { CGU_REG_CLKGR0, 11 },
0411     },
0412     [JZ4770_CLK_MMC2] = {
0413         "mmc2", CGU_CLK_GATE,
0414         .parents = { JZ4770_CLK_MMC2_MUX, },
0415         .gate = { CGU_REG_CLKGR0, 12 },
0416     },
0417     [JZ4770_CLK_OTG_PHY] = {
0418         "usb_phy", CGU_CLK_GATE,
0419         .parents = { JZ4770_CLK_OTG },
0420         .gate = { CGU_REG_OPCR, 7, true, 50 },
0421     },
0422 
0423     /* Custom clocks */
0424 
0425     [JZ4770_CLK_UHC_PHY] = {
0426         "uhc_phy", CGU_CLK_CUSTOM,
0427         .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
0428         .custom = { &jz4770_uhc_phy_ops },
0429     },
0430 
0431     [JZ4770_CLK_EXT512] = {
0432         "ext/512", CGU_CLK_FIXDIV,
0433         .parents = { JZ4770_CLK_EXT },
0434         .fixdiv = { 512 },
0435     },
0436 
0437     [JZ4770_CLK_RTC] = {
0438         "rtc", CGU_CLK_MUX,
0439         .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
0440         .mux = { CGU_REG_OPCR, 2, 1},
0441     },
0442 };
0443 
0444 static void __init jz4770_cgu_init(struct device_node *np)
0445 {
0446     int retval;
0447 
0448     cgu = ingenic_cgu_new(jz4770_cgu_clocks,
0449                   ARRAY_SIZE(jz4770_cgu_clocks), np);
0450     if (!cgu) {
0451         pr_err("%s: failed to initialise CGU\n", __func__);
0452         return;
0453     }
0454 
0455     retval = ingenic_cgu_register_clocks(cgu);
0456     if (retval)
0457         pr_err("%s: failed to register CGU Clocks\n", __func__);
0458 
0459     ingenic_cgu_register_syscore_ops(cgu);
0460 }
0461 
0462 /* We only probe via devicetree, no need for a platform driver */
0463 CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);