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