linux/drivers/clk/tegra/clk-tegra20-emc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Based on drivers/clk/tegra/clk-emc.c
   4 * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
   5 *
   6 * Author: Dmitry Osipenko <digetx@gmail.com>
   7 * Copyright (C) 2019 GRATE-DRIVER project
   8 */
   9
  10#define pr_fmt(fmt)     "tegra-emc-clk: " fmt
  11
  12#include <linux/bits.h>
  13#include <linux/clk-provider.h>
  14#include <linux/clk/tegra.h>
  15#include <linux/err.h>
  16#include <linux/io.h>
  17#include <linux/kernel.h>
  18#include <linux/slab.h>
  19
  20#include "clk.h"
  21
  22#define CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK      GENMASK(7, 0)
  23#define CLK_SOURCE_EMC_2X_CLK_SRC_MASK          GENMASK(31, 30)
  24#define CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT         30
  25
  26#define MC_EMC_SAME_FREQ        BIT(16)
  27#define USE_PLLM_UD             BIT(29)
  28
  29#define EMC_SRC_PLL_M           0
  30#define EMC_SRC_PLL_C           1
  31#define EMC_SRC_PLL_P           2
  32#define EMC_SRC_CLK_M           3
  33
  34static const char * const emc_parent_clk_names[] = {
  35        "pll_m", "pll_c", "pll_p", "clk_m",
  36};
  37
  38struct tegra_clk_emc {
  39        struct clk_hw hw;
  40        void __iomem *reg;
  41        bool mc_same_freq;
  42        bool want_low_jitter;
  43
  44        tegra20_clk_emc_round_cb *round_cb;
  45        void *cb_arg;
  46};
  47
  48static inline struct tegra_clk_emc *to_tegra_clk_emc(struct clk_hw *hw)
  49{
  50        return container_of(hw, struct tegra_clk_emc, hw);
  51}
  52
  53static unsigned long emc_recalc_rate(struct clk_hw *hw,
  54                                     unsigned long parent_rate)
  55{
  56        struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
  57        u32 val, div;
  58
  59        val = readl_relaxed(emc->reg);
  60        div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
  61
  62        return DIV_ROUND_UP(parent_rate * 2, div + 2);
  63}
  64
  65static u8 emc_get_parent(struct clk_hw *hw)
  66{
  67        struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
  68
  69        return readl_relaxed(emc->reg) >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
  70}
  71
  72static int emc_set_parent(struct clk_hw *hw, u8 index)
  73{
  74        struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
  75        u32 val, div;
  76
  77        val = readl_relaxed(emc->reg);
  78        val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
  79        val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
  80
  81        div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
  82
  83        if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
  84                val |= USE_PLLM_UD;
  85        else
  86                val &= ~USE_PLLM_UD;
  87
  88        if (emc->mc_same_freq)
  89                val |= MC_EMC_SAME_FREQ;
  90        else
  91                val &= ~MC_EMC_SAME_FREQ;
  92
  93        writel_relaxed(val, emc->reg);
  94
  95        fence_udelay(1, emc->reg);
  96
  97        return 0;
  98}
  99
 100static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
 101                        unsigned long parent_rate)
 102{
 103        struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
 104        unsigned int index;
 105        u32 val, div;
 106
 107        div = div_frac_get(rate, parent_rate, 8, 1, 0);
 108
 109        val = readl_relaxed(emc->reg);
 110        val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
 111        val |= div;
 112
 113        index = val >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
 114
 115        if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
 116                val |= USE_PLLM_UD;
 117        else
 118                val &= ~USE_PLLM_UD;
 119
 120        if (emc->mc_same_freq)
 121                val |= MC_EMC_SAME_FREQ;
 122        else
 123                val &= ~MC_EMC_SAME_FREQ;
 124
 125        writel_relaxed(val, emc->reg);
 126
 127        fence_udelay(1, emc->reg);
 128
 129        return 0;
 130}
 131
 132static int emc_set_rate_and_parent(struct clk_hw *hw,
 133                                   unsigned long rate,
 134                                   unsigned long parent_rate,
 135                                   u8 index)
 136{
 137        struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
 138        u32 val, div;
 139
 140        div = div_frac_get(rate, parent_rate, 8, 1, 0);
 141
 142        val = readl_relaxed(emc->reg);
 143
 144        val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
 145        val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
 146
 147        val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
 148        val |= div;
 149
 150        if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
 151                val |= USE_PLLM_UD;
 152        else
 153                val &= ~USE_PLLM_UD;
 154
 155        if (emc->mc_same_freq)
 156                val |= MC_EMC_SAME_FREQ;
 157        else
 158                val &= ~MC_EMC_SAME_FREQ;
 159
 160        writel_relaxed(val, emc->reg);
 161
 162        fence_udelay(1, emc->reg);
 163
 164        return 0;
 165}
 166
 167static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 168{
 169        struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
 170        struct clk_hw *parent_hw;
 171        unsigned long divided_rate;
 172        unsigned long parent_rate;
 173        unsigned int i;
 174        long emc_rate;
 175        int div;
 176
 177        emc_rate = emc->round_cb(req->rate, req->min_rate, req->max_rate,
 178                                 emc->cb_arg);
 179        if (emc_rate < 0)
 180                return emc_rate;
 181
 182        for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) {
 183                parent_hw = clk_hw_get_parent_by_index(hw, i);
 184
 185                if (req->best_parent_hw == parent_hw)
 186                        parent_rate = req->best_parent_rate;
 187                else
 188                        parent_rate = clk_hw_get_rate(parent_hw);
 189
 190                if (emc_rate > parent_rate)
 191                        continue;
 192
 193                div = div_frac_get(emc_rate, parent_rate, 8, 1, 0);
 194                divided_rate = DIV_ROUND_UP(parent_rate * 2, div + 2);
 195
 196                if (divided_rate != emc_rate)
 197                        continue;
 198
 199                req->best_parent_rate = parent_rate;
 200                req->best_parent_hw = parent_hw;
 201                req->rate = emc_rate;
 202                break;
 203        }
 204
 205        if (i == ARRAY_SIZE(emc_parent_clk_names)) {
 206                pr_err_once("can't find parent for rate %lu emc_rate %lu\n",
 207                            req->rate, emc_rate);
 208                return -EINVAL;
 209        }
 210
 211        return 0;
 212}
 213
 214static const struct clk_ops tegra_clk_emc_ops = {
 215        .recalc_rate = emc_recalc_rate,
 216        .get_parent = emc_get_parent,
 217        .set_parent = emc_set_parent,
 218        .set_rate = emc_set_rate,
 219        .set_rate_and_parent = emc_set_rate_and_parent,
 220        .determine_rate = emc_determine_rate,
 221};
 222
 223void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
 224                                        void *cb_arg)
 225{
 226        struct clk *clk = __clk_lookup("emc");
 227        struct tegra_clk_emc *emc;
 228        struct clk_hw *hw;
 229
 230        if (clk) {
 231                hw = __clk_get_hw(clk);
 232                emc = to_tegra_clk_emc(hw);
 233
 234                emc->round_cb = round_cb;
 235                emc->cb_arg = cb_arg;
 236        }
 237}
 238
 239bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw)
 240{
 241        return to_tegra_clk_emc(emc_hw)->round_cb != NULL;
 242}
 243
 244struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter)
 245{
 246        struct tegra_clk_emc *emc;
 247        struct clk_init_data init;
 248        struct clk *clk;
 249
 250        emc = kzalloc(sizeof(*emc), GFP_KERNEL);
 251        if (!emc)
 252                return NULL;
 253
 254        /*
 255         * EMC stands for External Memory Controller.
 256         *
 257         * We don't want EMC clock to be disabled ever by gating its
 258         * parent and whatnot because system is busted immediately in that
 259         * case, hence the clock is marked as critical.
 260         */
 261        init.name = "emc";
 262        init.ops = &tegra_clk_emc_ops;
 263        init.flags = CLK_IS_CRITICAL;
 264        init.parent_names = emc_parent_clk_names;
 265        init.num_parents = ARRAY_SIZE(emc_parent_clk_names);
 266
 267        emc->reg = ioaddr;
 268        emc->hw.init = &init;
 269        emc->want_low_jitter = low_jitter;
 270
 271        clk = clk_register(NULL, &emc->hw);
 272        if (IS_ERR(clk)) {
 273                kfree(emc);
 274                return NULL;
 275        }
 276
 277        return clk;
 278}
 279
 280int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same)
 281{
 282        struct tegra_clk_emc *emc;
 283        struct clk_hw *hw;
 284
 285        if (!emc_clk)
 286                return -EINVAL;
 287
 288        hw = __clk_get_hw(emc_clk);
 289        emc = to_tegra_clk_emc(hw);
 290        emc->mc_same_freq = same;
 291
 292        return 0;
 293}
 294