1
2
3
4
5
6
7
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
256
257
258
259
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