Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2012, 2013, NVIDIA CORPORATION.  All rights reserved.
0004  */
0005 
0006 #include <linux/io.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/of.h>
0009 #include <linux/of_address.h>
0010 #include <linux/delay.h>
0011 #include <linux/export.h>
0012 #include <linux/clk/tegra.h>
0013 
0014 #include "clk.h"
0015 #include "clk-id.h"
0016 
0017 #define PLLX_BASE 0xe0
0018 #define PLLX_MISC 0xe4
0019 #define PLLX_MISC2 0x514
0020 #define PLLX_MISC3 0x518
0021 
0022 #define CCLKG_BURST_POLICY 0x368
0023 #define CCLKLP_BURST_POLICY 0x370
0024 #define SCLK_BURST_POLICY 0x028
0025 #define SYSTEM_CLK_RATE 0x030
0026 #define SCLK_DIVIDER 0x2c
0027 
0028 static DEFINE_SPINLOCK(sysrate_lock);
0029 
0030 enum tegra_super_gen {
0031     gen4 = 4,
0032     gen5,
0033 };
0034 
0035 struct tegra_super_gen_info {
0036     enum tegra_super_gen gen;
0037     const char **sclk_parents;
0038     const char **cclk_g_parents;
0039     const char **cclk_lp_parents;
0040     int num_sclk_parents;
0041     int num_cclk_g_parents;
0042     int num_cclk_lp_parents;
0043 };
0044 
0045 static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
0046                    "pll_p", "pll_p_out2", "unused",
0047                    "clk_32k", "pll_m_out1" };
0048 
0049 static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
0050                     "pll_p", "pll_p_out4", "unused",
0051                     "unused", "pll_x", "unused", "unused",
0052                     "unused", "unused", "unused", "unused",
0053                     "dfllCPU_out" };
0054 
0055 static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
0056                      "pll_p", "pll_p_out4", "unused",
0057                      "unused", "pll_x", "pll_x_out0" };
0058 
0059 static const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
0060     .gen = gen4,
0061     .sclk_parents = sclk_parents,
0062     .cclk_g_parents = cclk_g_parents,
0063     .cclk_lp_parents = cclk_lp_parents,
0064     .num_sclk_parents = ARRAY_SIZE(sclk_parents),
0065     .num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents),
0066     .num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents),
0067 };
0068 
0069 static const char *sclk_parents_gen5[] = { "clk_m", "pll_c_out1", "pll_c4_out3",
0070                    "pll_p", "pll_p_out2", "pll_c4_out1",
0071                    "clk_32k", "pll_c4_out2" };
0072 
0073 static const char *cclk_g_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
0074                     "pll_p", "pll_p_out4", "unused",
0075                     "unused", "pll_x", "unused", "unused",
0076                     "unused", "unused", "unused", "unused",
0077                     "dfllCPU_out" };
0078 
0079 static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
0080                     "pll_p", "pll_p_out4", "unused",
0081                     "unused", "pll_x", "unused", "unused",
0082                     "unused", "unused", "unused", "unused",
0083                     "dfllCPU_out" };
0084 
0085 static const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
0086     .gen = gen5,
0087     .sclk_parents = sclk_parents_gen5,
0088     .cclk_g_parents = cclk_g_parents_gen5,
0089     .cclk_lp_parents = cclk_lp_parents_gen5,
0090     .num_sclk_parents = ARRAY_SIZE(sclk_parents_gen5),
0091     .num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents_gen5),
0092     .num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents_gen5),
0093 };
0094 
0095 static void __init tegra_sclk_init(void __iomem *clk_base,
0096                 struct tegra_clk *tegra_clks,
0097                 const struct tegra_super_gen_info *gen_info)
0098 {
0099     struct clk *clk;
0100     struct clk **dt_clk;
0101 
0102     /* SCLK_MUX */
0103     dt_clk = tegra_lookup_dt_id(tegra_clk_sclk_mux, tegra_clks);
0104     if (dt_clk) {
0105         clk = tegra_clk_register_super_mux("sclk_mux",
0106                         gen_info->sclk_parents,
0107                         gen_info->num_sclk_parents,
0108                         CLK_SET_RATE_PARENT,
0109                         clk_base + SCLK_BURST_POLICY,
0110                         0, 4, 0, 0, NULL);
0111         *dt_clk = clk;
0112 
0113 
0114         /* SCLK */
0115         dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
0116         if (dt_clk) {
0117             clk = clk_register_divider(NULL, "sclk", "sclk_mux",
0118                         CLK_IS_CRITICAL,
0119                         clk_base + SCLK_DIVIDER, 0, 8,
0120                         0, &sysrate_lock);
0121             *dt_clk = clk;
0122         }
0123     } else {
0124         /* SCLK */
0125         dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
0126         if (dt_clk) {
0127             clk = tegra_clk_register_super_mux("sclk",
0128                         gen_info->sclk_parents,
0129                         gen_info->num_sclk_parents,
0130                         CLK_SET_RATE_PARENT |
0131                         CLK_IS_CRITICAL,
0132                         clk_base + SCLK_BURST_POLICY,
0133                         0, 4, 0, 0, NULL);
0134             *dt_clk = clk;
0135         }
0136     }
0137 
0138     /* HCLK */
0139     dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks);
0140     if (dt_clk) {
0141         clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
0142                    clk_base + SYSTEM_CLK_RATE, 4, 2, 0,
0143                    &sysrate_lock);
0144         clk = clk_register_gate(NULL, "hclk", "hclk_div",
0145                 CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
0146                 clk_base + SYSTEM_CLK_RATE,
0147                 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
0148         *dt_clk = clk;
0149     }
0150 
0151     /* PCLK */
0152     dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks);
0153     if (!dt_clk)
0154         return;
0155 
0156     clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
0157                    clk_base + SYSTEM_CLK_RATE, 0, 2, 0,
0158                    &sysrate_lock);
0159     clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT |
0160                 CLK_IS_CRITICAL, clk_base + SYSTEM_CLK_RATE,
0161                 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
0162     *dt_clk = clk;
0163 }
0164 
0165 static void __init tegra_super_clk_init(void __iomem *clk_base,
0166                 void __iomem *pmc_base,
0167                 struct tegra_clk *tegra_clks,
0168                 struct tegra_clk_pll_params *params,
0169                 const struct tegra_super_gen_info *gen_info)
0170 {
0171     struct clk *clk;
0172     struct clk **dt_clk;
0173 
0174     /* CCLKG */
0175     dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
0176     if (dt_clk) {
0177         if (gen_info->gen == gen5) {
0178             clk = tegra_clk_register_super_mux("cclk_g",
0179                     gen_info->cclk_g_parents,
0180                     gen_info->num_cclk_g_parents,
0181                     CLK_SET_RATE_PARENT,
0182                     clk_base + CCLKG_BURST_POLICY,
0183                     TEGRA210_CPU_CLK, 4, 8, 0, NULL);
0184         } else {
0185             clk = tegra_clk_register_super_mux("cclk_g",
0186                     gen_info->cclk_g_parents,
0187                     gen_info->num_cclk_g_parents,
0188                     CLK_SET_RATE_PARENT,
0189                     clk_base + CCLKG_BURST_POLICY,
0190                     0, 4, 0, 0, NULL);
0191         }
0192         *dt_clk = clk;
0193     }
0194 
0195     /* CCLKLP */
0196     dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
0197     if (dt_clk) {
0198         if (gen_info->gen == gen5) {
0199             /*
0200              * TEGRA210_CPU_CLK flag is not needed for cclk_lp as
0201              * cluster switching is not currently supported on
0202              * Tegra210 and also cpu_lp is not used.
0203              */
0204             clk = tegra_clk_register_super_mux("cclk_lp",
0205                     gen_info->cclk_lp_parents,
0206                     gen_info->num_cclk_lp_parents,
0207                     CLK_SET_RATE_PARENT,
0208                     clk_base + CCLKLP_BURST_POLICY,
0209                     0, 4, 8, 0, NULL);
0210         } else {
0211             clk = tegra_clk_register_super_mux("cclk_lp",
0212                     gen_info->cclk_lp_parents,
0213                     gen_info->num_cclk_lp_parents,
0214                     CLK_SET_RATE_PARENT,
0215                     clk_base + CCLKLP_BURST_POLICY,
0216                     TEGRA_DIVIDER_2, 4, 8, 9, NULL);
0217         }
0218         *dt_clk = clk;
0219     }
0220 
0221     tegra_sclk_init(clk_base, tegra_clks, gen_info);
0222 
0223 #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
0224     defined(CONFIG_ARCH_TEGRA_124_SOC) || \
0225     defined(CONFIG_ARCH_TEGRA_210_SOC)
0226     /* PLLX */
0227     dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
0228     if (!dt_clk)
0229         return;
0230 
0231 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
0232     if (gen_info->gen == gen5)
0233         clk = tegra_clk_register_pllc_tegra210("pll_x", "pll_ref",
0234             clk_base, pmc_base, CLK_IGNORE_UNUSED, params, NULL);
0235     else
0236 #endif
0237         clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base,
0238                 pmc_base, CLK_IGNORE_UNUSED, params, NULL);
0239 
0240     *dt_clk = clk;
0241 
0242     /* PLLX_OUT0 */
0243 
0244     dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x_out0, tegra_clks);
0245     if (!dt_clk)
0246         return;
0247     clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x",
0248                     CLK_SET_RATE_PARENT, 1, 2);
0249     *dt_clk = clk;
0250 #endif
0251 }
0252 
0253 void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
0254                 void __iomem *pmc_base,
0255                 struct tegra_clk *tegra_clks,
0256                 struct tegra_clk_pll_params *params)
0257 {
0258     tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
0259                  &tegra_super_gen_info_gen4);
0260 }
0261 
0262 void __init tegra_super_clk_gen5_init(void __iomem *clk_base,
0263                 void __iomem *pmc_base,
0264                 struct tegra_clk *tegra_clks,
0265                 struct tegra_clk_pll_params *params)
0266 {
0267     tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
0268                  &tegra_super_gen_info_gen5);
0269 }