Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Based on drivers/clk/tegra/clk-emc.c
0004  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
0005  *
0006  * Author: Dmitry Osipenko <digetx@gmail.com>
0007  * Copyright (C) 2019 GRATE-DRIVER project
0008  */
0009 
0010 #define pr_fmt(fmt) "tegra-emc-clk: " fmt
0011 
0012 #include <linux/bits.h>
0013 #include <linux/clk-provider.h>
0014 #include <linux/clk/tegra.h>
0015 #include <linux/err.h>
0016 #include <linux/export.h>
0017 #include <linux/io.h>
0018 #include <linux/kernel.h>
0019 #include <linux/slab.h>
0020 
0021 #include "clk.h"
0022 
0023 #define CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK  GENMASK(7, 0)
0024 #define CLK_SOURCE_EMC_2X_CLK_SRC_MASK      GENMASK(31, 30)
0025 #define CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT     30
0026 
0027 #define MC_EMC_SAME_FREQ    BIT(16)
0028 #define USE_PLLM_UD     BIT(29)
0029 
0030 #define EMC_SRC_PLL_M       0
0031 #define EMC_SRC_PLL_C       1
0032 #define EMC_SRC_PLL_P       2
0033 #define EMC_SRC_CLK_M       3
0034 
0035 static const char * const emc_parent_clk_names[] = {
0036     "pll_m", "pll_c", "pll_p", "clk_m",
0037 };
0038 
0039 struct tegra_clk_emc {
0040     struct clk_hw hw;
0041     void __iomem *reg;
0042     bool mc_same_freq;
0043     bool want_low_jitter;
0044 
0045     tegra20_clk_emc_round_cb *round_cb;
0046     void *cb_arg;
0047 };
0048 
0049 static inline struct tegra_clk_emc *to_tegra_clk_emc(struct clk_hw *hw)
0050 {
0051     return container_of(hw, struct tegra_clk_emc, hw);
0052 }
0053 
0054 static unsigned long emc_recalc_rate(struct clk_hw *hw,
0055                      unsigned long parent_rate)
0056 {
0057     struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
0058     u32 val, div;
0059 
0060     val = readl_relaxed(emc->reg);
0061     div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
0062 
0063     return DIV_ROUND_UP(parent_rate * 2, div + 2);
0064 }
0065 
0066 static u8 emc_get_parent(struct clk_hw *hw)
0067 {
0068     struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
0069 
0070     return readl_relaxed(emc->reg) >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
0071 }
0072 
0073 static int emc_set_parent(struct clk_hw *hw, u8 index)
0074 {
0075     struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
0076     u32 val, div;
0077 
0078     val = readl_relaxed(emc->reg);
0079     val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
0080     val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
0081 
0082     div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
0083 
0084     if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
0085         val |= USE_PLLM_UD;
0086     else
0087         val &= ~USE_PLLM_UD;
0088 
0089     if (emc->mc_same_freq)
0090         val |= MC_EMC_SAME_FREQ;
0091     else
0092         val &= ~MC_EMC_SAME_FREQ;
0093 
0094     writel_relaxed(val, emc->reg);
0095 
0096     fence_udelay(1, emc->reg);
0097 
0098     return 0;
0099 }
0100 
0101 static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
0102             unsigned long parent_rate)
0103 {
0104     struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
0105     unsigned int index;
0106     u32 val, div;
0107 
0108     div = div_frac_get(rate, parent_rate, 8, 1, 0);
0109 
0110     val = readl_relaxed(emc->reg);
0111     val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
0112     val |= div;
0113 
0114     index = val >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
0115 
0116     if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
0117         val |= USE_PLLM_UD;
0118     else
0119         val &= ~USE_PLLM_UD;
0120 
0121     if (emc->mc_same_freq)
0122         val |= MC_EMC_SAME_FREQ;
0123     else
0124         val &= ~MC_EMC_SAME_FREQ;
0125 
0126     writel_relaxed(val, emc->reg);
0127 
0128     fence_udelay(1, emc->reg);
0129 
0130     return 0;
0131 }
0132 
0133 static int emc_set_rate_and_parent(struct clk_hw *hw,
0134                    unsigned long rate,
0135                    unsigned long parent_rate,
0136                    u8 index)
0137 {
0138     struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
0139     u32 val, div;
0140 
0141     div = div_frac_get(rate, parent_rate, 8, 1, 0);
0142 
0143     val = readl_relaxed(emc->reg);
0144 
0145     val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
0146     val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
0147 
0148     val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
0149     val |= div;
0150 
0151     if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
0152         val |= USE_PLLM_UD;
0153     else
0154         val &= ~USE_PLLM_UD;
0155 
0156     if (emc->mc_same_freq)
0157         val |= MC_EMC_SAME_FREQ;
0158     else
0159         val &= ~MC_EMC_SAME_FREQ;
0160 
0161     writel_relaxed(val, emc->reg);
0162 
0163     fence_udelay(1, emc->reg);
0164 
0165     return 0;
0166 }
0167 
0168 static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
0169 {
0170     struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
0171     struct clk_hw *parent_hw;
0172     unsigned long divided_rate;
0173     unsigned long parent_rate;
0174     unsigned int i;
0175     long emc_rate;
0176     int div;
0177 
0178     emc_rate = emc->round_cb(req->rate, req->min_rate, req->max_rate,
0179                  emc->cb_arg);
0180     if (emc_rate < 0)
0181         return emc_rate;
0182 
0183     for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) {
0184         parent_hw = clk_hw_get_parent_by_index(hw, i);
0185 
0186         if (req->best_parent_hw == parent_hw)
0187             parent_rate = req->best_parent_rate;
0188         else
0189             parent_rate = clk_hw_get_rate(parent_hw);
0190 
0191         if (emc_rate > parent_rate)
0192             continue;
0193 
0194         div = div_frac_get(emc_rate, parent_rate, 8, 1, 0);
0195         divided_rate = DIV_ROUND_UP(parent_rate * 2, div + 2);
0196 
0197         if (divided_rate != emc_rate)
0198             continue;
0199 
0200         req->best_parent_rate = parent_rate;
0201         req->best_parent_hw = parent_hw;
0202         req->rate = emc_rate;
0203         break;
0204     }
0205 
0206     if (i == ARRAY_SIZE(emc_parent_clk_names)) {
0207         pr_err_once("can't find parent for rate %lu emc_rate %lu\n",
0208                 req->rate, emc_rate);
0209         return -EINVAL;
0210     }
0211 
0212     return 0;
0213 }
0214 
0215 static const struct clk_ops tegra_clk_emc_ops = {
0216     .recalc_rate = emc_recalc_rate,
0217     .get_parent = emc_get_parent,
0218     .set_parent = emc_set_parent,
0219     .set_rate = emc_set_rate,
0220     .set_rate_and_parent = emc_set_rate_and_parent,
0221     .determine_rate = emc_determine_rate,
0222 };
0223 
0224 void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
0225                     void *cb_arg)
0226 {
0227     struct clk *clk = __clk_lookup("emc");
0228     struct tegra_clk_emc *emc;
0229     struct clk_hw *hw;
0230 
0231     if (clk) {
0232         hw = __clk_get_hw(clk);
0233         emc = to_tegra_clk_emc(hw);
0234 
0235         emc->round_cb = round_cb;
0236         emc->cb_arg = cb_arg;
0237     }
0238 }
0239 EXPORT_SYMBOL_GPL(tegra20_clk_set_emc_round_callback);
0240 
0241 bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw)
0242 {
0243     return to_tegra_clk_emc(emc_hw)->round_cb != NULL;
0244 }
0245 
0246 struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter)
0247 {
0248     struct tegra_clk_emc *emc;
0249     struct clk_init_data init;
0250     struct clk *clk;
0251 
0252     emc = kzalloc(sizeof(*emc), GFP_KERNEL);
0253     if (!emc)
0254         return NULL;
0255 
0256     /*
0257      * EMC stands for External Memory Controller.
0258      *
0259      * We don't want EMC clock to be disabled ever by gating its
0260      * parent and whatnot because system is busted immediately in that
0261      * case, hence the clock is marked as critical.
0262      */
0263     init.name = "emc";
0264     init.ops = &tegra_clk_emc_ops;
0265     init.flags = CLK_IS_CRITICAL;
0266     init.parent_names = emc_parent_clk_names;
0267     init.num_parents = ARRAY_SIZE(emc_parent_clk_names);
0268 
0269     emc->reg = ioaddr;
0270     emc->hw.init = &init;
0271     emc->want_low_jitter = low_jitter;
0272 
0273     clk = clk_register(NULL, &emc->hw);
0274     if (IS_ERR(clk)) {
0275         kfree(emc);
0276         return NULL;
0277     }
0278 
0279     return clk;
0280 }
0281 
0282 int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same)
0283 {
0284     struct tegra_clk_emc *emc;
0285     struct clk_hw *hw;
0286 
0287     if (!emc_clk)
0288         return -EINVAL;
0289 
0290     hw = __clk_get_hw(emc_clk);
0291     emc = to_tegra_clk_emc(hw);
0292     emc->mc_same_freq = same;
0293 
0294     return 0;
0295 }
0296 EXPORT_SYMBOL_GPL(tegra20_clk_prepare_emc_mc_same_freq);