WIP FPC-III support
[linux/fpc-iii.git] / drivers / clk / tegra / clk-tegra20-emc.c
blobdd74b8543bf1dfdeefd6b296e358c206a5be4c4d
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.
6 * Author: Dmitry Osipenko <digetx@gmail.com>
7 * Copyright (C) 2019 GRATE-DRIVER project
8 */
10 #define pr_fmt(fmt) "tegra-emc-clk: " fmt
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>
21 #include "clk.h"
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
27 #define MC_EMC_SAME_FREQ BIT(16)
28 #define USE_PLLM_UD BIT(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
35 static const char * const emc_parent_clk_names[] = {
36 "pll_m", "pll_c", "pll_p", "clk_m",
39 struct tegra_clk_emc {
40 struct clk_hw hw;
41 void __iomem *reg;
42 bool mc_same_freq;
43 bool want_low_jitter;
45 tegra20_clk_emc_round_cb *round_cb;
46 void *cb_arg;
49 static inline struct tegra_clk_emc *to_tegra_clk_emc(struct clk_hw *hw)
51 return container_of(hw, struct tegra_clk_emc, hw);
54 static unsigned long emc_recalc_rate(struct clk_hw *hw,
55 unsigned long parent_rate)
57 struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
58 u32 val, div;
60 val = readl_relaxed(emc->reg);
61 div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
63 return DIV_ROUND_UP(parent_rate * 2, div + 2);
66 static u8 emc_get_parent(struct clk_hw *hw)
68 struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
70 return readl_relaxed(emc->reg) >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
73 static int emc_set_parent(struct clk_hw *hw, u8 index)
75 struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
76 u32 val, div;
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;
82 div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
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;
89 if (emc->mc_same_freq)
90 val |= MC_EMC_SAME_FREQ;
91 else
92 val &= ~MC_EMC_SAME_FREQ;
94 writel_relaxed(val, emc->reg);
96 fence_udelay(1, emc->reg);
98 return 0;
101 static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
102 unsigned long parent_rate)
104 struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
105 unsigned int index;
106 u32 val, div;
108 div = div_frac_get(rate, parent_rate, 8, 1, 0);
110 val = readl_relaxed(emc->reg);
111 val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
112 val |= div;
114 index = val >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
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;
121 if (emc->mc_same_freq)
122 val |= MC_EMC_SAME_FREQ;
123 else
124 val &= ~MC_EMC_SAME_FREQ;
126 writel_relaxed(val, emc->reg);
128 fence_udelay(1, emc->reg);
130 return 0;
133 static int emc_set_rate_and_parent(struct clk_hw *hw,
134 unsigned long rate,
135 unsigned long parent_rate,
136 u8 index)
138 struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
139 u32 val, div;
141 div = div_frac_get(rate, parent_rate, 8, 1, 0);
143 val = readl_relaxed(emc->reg);
145 val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
146 val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
148 val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
149 val |= div;
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;
156 if (emc->mc_same_freq)
157 val |= MC_EMC_SAME_FREQ;
158 else
159 val &= ~MC_EMC_SAME_FREQ;
161 writel_relaxed(val, emc->reg);
163 fence_udelay(1, emc->reg);
165 return 0;
168 static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
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;
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;
183 for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) {
184 parent_hw = clk_hw_get_parent_by_index(hw, i);
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);
191 if (emc_rate > parent_rate)
192 continue;
194 div = div_frac_get(emc_rate, parent_rate, 8, 1, 0);
195 divided_rate = DIV_ROUND_UP(parent_rate * 2, div + 2);
197 if (divided_rate != emc_rate)
198 continue;
200 req->best_parent_rate = parent_rate;
201 req->best_parent_hw = parent_hw;
202 req->rate = emc_rate;
203 break;
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;
212 return 0;
215 static 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,
224 void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
225 void *cb_arg)
227 struct clk *clk = __clk_lookup("emc");
228 struct tegra_clk_emc *emc;
229 struct clk_hw *hw;
231 if (clk) {
232 hw = __clk_get_hw(clk);
233 emc = to_tegra_clk_emc(hw);
235 emc->round_cb = round_cb;
236 emc->cb_arg = cb_arg;
239 EXPORT_SYMBOL_GPL(tegra20_clk_set_emc_round_callback);
241 bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw)
243 return to_tegra_clk_emc(emc_hw)->round_cb != NULL;
246 struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter)
248 struct tegra_clk_emc *emc;
249 struct clk_init_data init;
250 struct clk *clk;
252 emc = kzalloc(sizeof(*emc), GFP_KERNEL);
253 if (!emc)
254 return NULL;
257 * EMC stands for External Memory Controller.
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.
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);
269 emc->reg = ioaddr;
270 emc->hw.init = &init;
271 emc->want_low_jitter = low_jitter;
273 clk = clk_register(NULL, &emc->hw);
274 if (IS_ERR(clk)) {
275 kfree(emc);
276 return NULL;
279 return clk;
282 int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same)
284 struct tegra_clk_emc *emc;
285 struct clk_hw *hw;
287 if (!emc_clk)
288 return -EINVAL;
290 hw = __clk_get_hw(emc_clk);
291 emc = to_tegra_clk_emc(hw);
292 emc->mc_same_freq = same;
294 return 0;
296 EXPORT_SYMBOL_GPL(tegra20_clk_prepare_emc_mc_same_freq);