Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * JZ4760 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 <linux/clk.h>
0014 
0015 #include <dt-bindings/clock/ingenic,jz4760-cgu.h>
0016 
0017 #include "cgu.h"
0018 #include "pm.h"
0019 
0020 #define MHZ (1000 * 1000)
0021 
0022 /*
0023  * CPM registers offset address definition
0024  */
0025 #define CGU_REG_CPCCR       0x00
0026 #define CGU_REG_LCR     0x04
0027 #define CGU_REG_CPPCR0      0x10
0028 #define CGU_REG_CLKGR0      0x20
0029 #define CGU_REG_OPCR        0x24
0030 #define CGU_REG_CLKGR1      0x28
0031 #define CGU_REG_CPPCR1      0x30
0032 #define CGU_REG_USBPCR      0x3c
0033 #define CGU_REG_USBCDR      0x50
0034 #define CGU_REG_I2SCDR      0x60
0035 #define CGU_REG_LPCDR       0x64
0036 #define CGU_REG_MSCCDR      0x68
0037 #define CGU_REG_UHCCDR      0x6c
0038 #define CGU_REG_SSICDR      0x74
0039 #define CGU_REG_CIMCDR      0x7c
0040 #define CGU_REG_GPSCDR      0x80
0041 #define CGU_REG_PCMCDR      0x84
0042 #define CGU_REG_GPUCDR      0x88
0043 
0044 static const s8 pll_od_encoding[8] = {
0045     0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
0046 };
0047 
0048 static const u8 jz4760_cgu_cpccr_div_table[] = {
0049     1, 2, 3, 4, 6, 8,
0050 };
0051 
0052 static const u8 jz4760_cgu_pll_half_div_table[] = {
0053     2, 1,
0054 };
0055 
0056 static void
0057 jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
0058                unsigned long rate, unsigned long parent_rate,
0059                unsigned int *pm, unsigned int *pn, unsigned int *pod)
0060 {
0061     unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 2;
0062 
0063     /* The frequency after the N divider must be between 1 and 50 MHz. */
0064     n = parent_rate / (1 * MHZ);
0065 
0066     /* The N divider must be >= 2. */
0067     n = clamp_val(n, 2, 1 << pll_info->n_bits);
0068 
0069     for (;; n >>= 1) {
0070         od = (unsigned int)-1;
0071 
0072         do {
0073             m = (rate / MHZ) * (1 << ++od) * n / (parent_rate / MHZ);
0074         } while ((m > m_max || m & 1) && (od < 4));
0075 
0076         if (od < 4 && m >= 4 && m <= m_max)
0077             break;
0078     }
0079 
0080     *pm = m;
0081     *pn = n;
0082     *pod = 1 << od;
0083 }
0084 
0085 static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
0086 
0087     /* External clocks */
0088 
0089     [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
0090     [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
0091 
0092     /* PLLs */
0093 
0094     [JZ4760_CLK_PLL0] = {
0095         "pll0", CGU_CLK_PLL,
0096         .parents = { JZ4760_CLK_EXT },
0097         .pll = {
0098             .reg = CGU_REG_CPPCR0,
0099             .rate_multiplier = 1,
0100             .m_shift = 23,
0101             .m_bits = 8,
0102             .m_offset = 0,
0103             .n_shift = 18,
0104             .n_bits = 4,
0105             .n_offset = 0,
0106             .od_shift = 16,
0107             .od_bits = 2,
0108             .od_max = 8,
0109             .od_encoding = pll_od_encoding,
0110             .bypass_reg = CGU_REG_CPPCR0,
0111             .bypass_bit = 9,
0112             .enable_bit = 8,
0113             .stable_bit = 10,
0114             .calc_m_n_od = jz4760_cgu_calc_m_n_od,
0115         },
0116     },
0117 
0118     [JZ4760_CLK_PLL1] = {
0119         /* TODO: PLL1 can depend on PLL0 */
0120         "pll1", CGU_CLK_PLL,
0121         .parents = { JZ4760_CLK_EXT },
0122         .pll = {
0123             .reg = CGU_REG_CPPCR1,
0124             .rate_multiplier = 1,
0125             .m_shift = 23,
0126             .m_bits = 8,
0127             .m_offset = 0,
0128             .n_shift = 18,
0129             .n_bits = 4,
0130             .n_offset = 0,
0131             .od_shift = 16,
0132             .od_bits = 2,
0133             .od_max = 8,
0134             .od_encoding = pll_od_encoding,
0135             .bypass_bit = -1,
0136             .enable_bit = 7,
0137             .stable_bit = 6,
0138             .calc_m_n_od = jz4760_cgu_calc_m_n_od,
0139         },
0140     },
0141 
0142     /* Main clocks */
0143 
0144     [JZ4760_CLK_CCLK] = {
0145         "cclk", CGU_CLK_DIV,
0146         /*
0147          * Disabling the CPU clock or any parent clocks will hang the
0148          * system; mark it critical.
0149          */
0150         .flags = CLK_IS_CRITICAL,
0151         .parents = { JZ4760_CLK_PLL0, },
0152         .div = {
0153             CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
0154             jz4760_cgu_cpccr_div_table,
0155         },
0156     },
0157     [JZ4760_CLK_HCLK] = {
0158         "hclk", CGU_CLK_DIV,
0159         .parents = { JZ4760_CLK_PLL0, },
0160         .div = {
0161             CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
0162             jz4760_cgu_cpccr_div_table,
0163         },
0164     },
0165     [JZ4760_CLK_SCLK] = {
0166         "sclk", CGU_CLK_DIV,
0167         .parents = { JZ4760_CLK_PLL0, },
0168         .div = {
0169             CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
0170             jz4760_cgu_cpccr_div_table,
0171         },
0172     },
0173     [JZ4760_CLK_H2CLK] = {
0174         "h2clk", CGU_CLK_DIV,
0175         .parents = { JZ4760_CLK_PLL0, },
0176         .div = {
0177             CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
0178             jz4760_cgu_cpccr_div_table,
0179         },
0180     },
0181     [JZ4760_CLK_MCLK] = {
0182         "mclk", CGU_CLK_DIV,
0183         /*
0184          * Disabling MCLK or its parents will render DRAM
0185          * inaccessible; mark it critical.
0186          */
0187         .flags = CLK_IS_CRITICAL,
0188         .parents = { JZ4760_CLK_PLL0, },
0189         .div = {
0190             CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
0191             jz4760_cgu_cpccr_div_table,
0192         },
0193     },
0194     [JZ4760_CLK_PCLK] = {
0195         "pclk", CGU_CLK_DIV,
0196         .parents = { JZ4760_CLK_PLL0, },
0197         .div = {
0198             CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
0199             jz4760_cgu_cpccr_div_table,
0200         },
0201     },
0202 
0203     /* Divided clocks */
0204 
0205     [JZ4760_CLK_PLL0_HALF] = {
0206         "pll0_half", CGU_CLK_DIV,
0207         .parents = { JZ4760_CLK_PLL0 },
0208         .div = {
0209             CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
0210             jz4760_cgu_pll_half_div_table,
0211         },
0212     },
0213 
0214     /* Those divided clocks can connect to PLL0 or PLL1 */
0215 
0216     [JZ4760_CLK_UHC] = {
0217         "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0218         .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
0219         .mux = { CGU_REG_UHCCDR, 31, 1 },
0220         .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
0221         .gate = { CGU_REG_CLKGR0, 24 },
0222     },
0223     [JZ4760_CLK_GPU] = {
0224         "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0225         .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
0226         .mux = { CGU_REG_GPUCDR, 31, 1 },
0227         .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
0228         .gate = { CGU_REG_CLKGR1, 9 },
0229     },
0230     [JZ4760_CLK_LPCLK_DIV] = {
0231         "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
0232         .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
0233         .mux = { CGU_REG_LPCDR, 29, 1 },
0234         .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
0235     },
0236     [JZ4760_CLK_TVE] = {
0237         "tve", CGU_CLK_GATE | CGU_CLK_MUX,
0238         .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
0239         .mux = { CGU_REG_LPCDR, 31, 1 },
0240         .gate = { CGU_REG_CLKGR0, 27 },
0241     },
0242     [JZ4760_CLK_LPCLK] = {
0243         "lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
0244         .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
0245         .mux = { CGU_REG_LPCDR, 30, 1 },
0246         .gate = { CGU_REG_CLKGR0, 28 },
0247     },
0248     [JZ4760_CLK_GPS] = {
0249         "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0250         .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
0251         .mux = { CGU_REG_GPSCDR, 31, 1 },
0252         .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
0253         .gate = { CGU_REG_CLKGR0, 22 },
0254     },
0255 
0256     /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
0257 
0258     [JZ4760_CLK_PCM] = {
0259         "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0260         .parents = { JZ4760_CLK_EXT, -1,
0261             JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
0262         .mux = { CGU_REG_PCMCDR, 30, 2 },
0263         .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
0264         .gate = { CGU_REG_CLKGR1, 8 },
0265     },
0266     [JZ4760_CLK_I2S] = {
0267         "i2s", CGU_CLK_DIV | CGU_CLK_MUX,
0268         .parents = { JZ4760_CLK_EXT, -1,
0269             JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
0270         .mux = { CGU_REG_I2SCDR, 30, 2 },
0271         .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
0272     },
0273     [JZ4760_CLK_OTG] = {
0274         "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
0275         .parents = { JZ4760_CLK_EXT, -1,
0276             JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
0277         .mux = { CGU_REG_USBCDR, 30, 2 },
0278         .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
0279         .gate = { CGU_REG_CLKGR0, 2 },
0280     },
0281 
0282     /* Those divided clocks can connect to EXT or PLL0 */
0283     [JZ4760_CLK_MMC_MUX] = {
0284         "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
0285         .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
0286         .mux = { CGU_REG_MSCCDR, 31, 1 },
0287         .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
0288     },
0289     [JZ4760_CLK_SSI_MUX] = {
0290         "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
0291         .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
0292         .mux = { CGU_REG_SSICDR, 31, 1 },
0293         .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
0294     },
0295 
0296     /* These divided clock can connect to PLL0 only */
0297     [JZ4760_CLK_CIM] = {
0298         "cim", CGU_CLK_DIV | CGU_CLK_GATE,
0299         .parents = { JZ4760_CLK_PLL0_HALF },
0300         .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
0301         .gate = { CGU_REG_CLKGR0, 26 },
0302     },
0303 
0304     /* Gate-only clocks */
0305 
0306     [JZ4760_CLK_SSI0] = {
0307         "ssi0", CGU_CLK_GATE,
0308         .parents = { JZ4760_CLK_SSI_MUX, },
0309         .gate = { CGU_REG_CLKGR0, 4 },
0310     },
0311     [JZ4760_CLK_SSI1] = {
0312         "ssi1", CGU_CLK_GATE,
0313         .parents = { JZ4760_CLK_SSI_MUX, },
0314         .gate = { CGU_REG_CLKGR0, 19 },
0315     },
0316     [JZ4760_CLK_SSI2] = {
0317         "ssi2", CGU_CLK_GATE,
0318         .parents = { JZ4760_CLK_SSI_MUX, },
0319         .gate = { CGU_REG_CLKGR0, 20 },
0320     },
0321     [JZ4760_CLK_DMA] = {
0322         "dma", CGU_CLK_GATE,
0323         .parents = { JZ4760_CLK_H2CLK, },
0324         .gate = { CGU_REG_CLKGR0, 21 },
0325     },
0326     [JZ4760_CLK_MDMA] = {
0327         "mdma", CGU_CLK_GATE,
0328         .parents = { JZ4760_CLK_HCLK, },
0329         .gate = { CGU_REG_CLKGR0, 25 },
0330     },
0331     [JZ4760_CLK_BDMA] = {
0332         "bdma", CGU_CLK_GATE,
0333         .parents = { JZ4760_CLK_HCLK, },
0334         .gate = { CGU_REG_CLKGR1, 0 },
0335     },
0336     [JZ4760_CLK_I2C0] = {
0337         "i2c0", CGU_CLK_GATE,
0338         .parents = { JZ4760_CLK_EXT, },
0339         .gate = { CGU_REG_CLKGR0, 5 },
0340     },
0341     [JZ4760_CLK_I2C1] = {
0342         "i2c1", CGU_CLK_GATE,
0343         .parents = { JZ4760_CLK_EXT, },
0344         .gate = { CGU_REG_CLKGR0, 6 },
0345     },
0346     [JZ4760_CLK_UART0] = {
0347         "uart0", CGU_CLK_GATE,
0348         .parents = { JZ4760_CLK_EXT, },
0349         .gate = { CGU_REG_CLKGR0, 15 },
0350     },
0351     [JZ4760_CLK_UART1] = {
0352         "uart1", CGU_CLK_GATE,
0353         .parents = { JZ4760_CLK_EXT, },
0354         .gate = { CGU_REG_CLKGR0, 16 },
0355     },
0356     [JZ4760_CLK_UART2] = {
0357         "uart2", CGU_CLK_GATE,
0358         .parents = { JZ4760_CLK_EXT, },
0359         .gate = { CGU_REG_CLKGR0, 17 },
0360     },
0361     [JZ4760_CLK_UART3] = {
0362         "uart3", CGU_CLK_GATE,
0363         .parents = { JZ4760_CLK_EXT, },
0364         .gate = { CGU_REG_CLKGR0, 18 },
0365     },
0366     [JZ4760_CLK_IPU] = {
0367         "ipu", CGU_CLK_GATE,
0368         .parents = { JZ4760_CLK_HCLK, },
0369         .gate = { CGU_REG_CLKGR0, 29 },
0370     },
0371     [JZ4760_CLK_ADC] = {
0372         "adc", CGU_CLK_GATE,
0373         .parents = { JZ4760_CLK_EXT, },
0374         .gate = { CGU_REG_CLKGR0, 14 },
0375     },
0376     [JZ4760_CLK_AIC] = {
0377         "aic", CGU_CLK_GATE,
0378         .parents = { JZ4760_CLK_EXT, },
0379         .gate = { CGU_REG_CLKGR0, 8 },
0380     },
0381     [JZ4760_CLK_VPU] = {
0382         "vpu", CGU_CLK_GATE,
0383         .parents = { JZ4760_CLK_HCLK, },
0384         .gate = { CGU_REG_LCR, 30, false, 150 },
0385     },
0386     [JZ4760_CLK_MMC0] = {
0387         "mmc0", CGU_CLK_GATE,
0388         .parents = { JZ4760_CLK_MMC_MUX, },
0389         .gate = { CGU_REG_CLKGR0, 3 },
0390     },
0391     [JZ4760_CLK_MMC1] = {
0392         "mmc1", CGU_CLK_GATE,
0393         .parents = { JZ4760_CLK_MMC_MUX, },
0394         .gate = { CGU_REG_CLKGR0, 11 },
0395     },
0396     [JZ4760_CLK_MMC2] = {
0397         "mmc2", CGU_CLK_GATE,
0398         .parents = { JZ4760_CLK_MMC_MUX, },
0399         .gate = { CGU_REG_CLKGR0, 12 },
0400     },
0401     [JZ4760_CLK_UHC_PHY] = {
0402         "uhc_phy", CGU_CLK_GATE,
0403         .parents = { JZ4760_CLK_UHC, },
0404         .gate = { CGU_REG_OPCR, 5 },
0405     },
0406     [JZ4760_CLK_OTG_PHY] = {
0407         "usb_phy", CGU_CLK_GATE,
0408         .parents = { JZ4760_CLK_OTG },
0409         .gate = { CGU_REG_OPCR, 7, true, 50 },
0410     },
0411 
0412     /* Custom clocks */
0413     [JZ4760_CLK_EXT512] = {
0414         "ext/512", CGU_CLK_FIXDIV,
0415         .parents = { JZ4760_CLK_EXT },
0416         .fixdiv = { 512 },
0417     },
0418     [JZ4760_CLK_RTC] = {
0419         "rtc", CGU_CLK_MUX,
0420         .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
0421         .mux = { CGU_REG_OPCR, 2, 1},
0422     },
0423 };
0424 
0425 static void __init jz4760_cgu_init(struct device_node *np)
0426 {
0427     struct ingenic_cgu *cgu;
0428     int retval;
0429 
0430     cgu = ingenic_cgu_new(jz4760_cgu_clocks,
0431                   ARRAY_SIZE(jz4760_cgu_clocks), np);
0432     if (!cgu) {
0433         pr_err("%s: failed to initialise CGU\n", __func__);
0434         return;
0435     }
0436 
0437     retval = ingenic_cgu_register_clocks(cgu);
0438     if (retval)
0439         pr_err("%s: failed to register CGU Clocks\n", __func__);
0440 
0441     ingenic_cgu_register_syscore_ops(cgu);
0442 }
0443 
0444 /* We only probe via devicetree, no need for a platform driver */
0445 CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
0446 
0447 /* JZ4760B has some small differences, but we don't implement them. */
0448 CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);