diff options
Diffstat (limited to 'drivers/clk/tegra/clk-emc.c')
-rw-r--r-- | drivers/clk/tegra/clk-emc.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c new file mode 100644 index 000000000000..32e5563711ac --- /dev/null +++ b/drivers/clk/tegra/clk-emc.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* | ||
2 | * drivers/clk/tegra/clk-emc.c | ||
3 | * | ||
4 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: | ||
7 | * Mikko Perttunen <mperttunen@nvidia.com> | ||
8 | * | ||
9 | * This software is licensed under the terms of the GNU General Public | ||
10 | * License version 2, as published by the Free Software Foundation, and | ||
11 | * may be copied, distributed, and modified under those terms. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clk-provider.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/clkdev.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of_address.h> | ||
25 | #include <linux/of_platform.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/sort.h> | ||
28 | #include <linux/string.h> | ||
29 | |||
30 | #include <soc/tegra/fuse.h> | ||
31 | #include <soc/tegra/emc.h> | ||
32 | |||
33 | #include "clk.h" | ||
34 | |||
35 | #define CLK_SOURCE_EMC 0x19c | ||
36 | |||
37 | #define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_SHIFT 0 | ||
38 | #define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK 0xff | ||
39 | #define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(x) (((x) & CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK) << \ | ||
40 | CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_SHIFT) | ||
41 | |||
42 | #define CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT 29 | ||
43 | #define CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK 0x7 | ||
44 | #define CLK_SOURCE_EMC_EMC_2X_CLK_SRC(x) (((x) & CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK) << \ | ||
45 | CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT) | ||
46 | |||
47 | static const char * const emc_parent_clk_names[] = { | ||
48 | "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", | ||
49 | "pll_c2", "pll_c3", "pll_c_ud" | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * List of clock sources for various parents the EMC clock can have. | ||
54 | * When we change the timing to a timing with a parent that has the same | ||
55 | * clock source as the current parent, we must first change to a backup | ||
56 | * timing that has a different clock source. | ||
57 | */ | ||
58 | |||
59 | #define EMC_SRC_PLL_M 0 | ||
60 | #define EMC_SRC_PLL_C 1 | ||
61 | #define EMC_SRC_PLL_P 2 | ||
62 | #define EMC_SRC_CLK_M 3 | ||
63 | #define EMC_SRC_PLL_C2 4 | ||
64 | #define EMC_SRC_PLL_C3 5 | ||
65 | |||
66 | static const char emc_parent_clk_sources[] = { | ||
67 | EMC_SRC_PLL_M, EMC_SRC_PLL_C, EMC_SRC_PLL_P, EMC_SRC_CLK_M, | ||
68 | EMC_SRC_PLL_M, EMC_SRC_PLL_C2, EMC_SRC_PLL_C3, EMC_SRC_PLL_C | ||
69 | }; | ||
70 | |||
71 | struct emc_timing { | ||
72 | unsigned long rate, parent_rate; | ||
73 | u8 parent_index; | ||
74 | struct clk *parent; | ||
75 | u32 ram_code; | ||
76 | }; | ||
77 | |||
78 | struct tegra_clk_emc { | ||
79 | struct clk_hw hw; | ||
80 | void __iomem *clk_regs; | ||
81 | struct clk *prev_parent; | ||
82 | bool changing_timing; | ||
83 | |||
84 | struct device_node *emc_node; | ||
85 | struct tegra_emc *emc; | ||
86 | |||
87 | int num_timings; | ||
88 | struct emc_timing *timings; | ||
89 | spinlock_t *lock; | ||
90 | }; | ||
91 | |||
92 | /* Common clock framework callback implementations */ | ||
93 | |||
94 | static unsigned long emc_recalc_rate(struct clk_hw *hw, | ||
95 | unsigned long parent_rate) | ||
96 | { | ||
97 | struct tegra_clk_emc *tegra; | ||
98 | u32 val, div; | ||
99 | |||
100 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
101 | |||
102 | /* | ||
103 | * CCF wrongly assumes that the parent won't change during set_rate, | ||
104 | * so get the parent rate explicitly. | ||
105 | */ | ||
106 | parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); | ||
107 | |||
108 | val = readl(tegra->clk_regs + CLK_SOURCE_EMC); | ||
109 | div = val & CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK; | ||
110 | |||
111 | return parent_rate / (div + 2) * 2; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Rounds up unless no higher rate exists, in which case down. This way is | ||
116 | * safer since things have EMC rate floors. Also don't touch parent_rate | ||
117 | * since we don't want the CCF to play with our parent clocks. | ||
118 | */ | ||
119 | static long emc_round_rate(struct clk_hw *hw, unsigned long rate, | ||
120 | unsigned long *parent_rate) | ||
121 | { | ||
122 | struct tegra_clk_emc *tegra; | ||
123 | u8 ram_code = tegra_read_ram_code(); | ||
124 | struct emc_timing *timing = NULL; | ||
125 | int i; | ||
126 | |||
127 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
128 | |||
129 | for (i = 0; i < tegra->num_timings; i++) { | ||
130 | if (tegra->timings[i].ram_code != ram_code) | ||
131 | continue; | ||
132 | |||
133 | timing = tegra->timings + i; | ||
134 | |||
135 | if (timing->rate >= rate) | ||
136 | return timing->rate; | ||
137 | } | ||
138 | |||
139 | if (timing) | ||
140 | return timing->rate; | ||
141 | |||
142 | return __clk_get_rate(hw->clk); | ||
143 | } | ||
144 | |||
145 | static u8 emc_get_parent(struct clk_hw *hw) | ||
146 | { | ||
147 | struct tegra_clk_emc *tegra; | ||
148 | u32 val; | ||
149 | |||
150 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
151 | |||
152 | val = readl(tegra->clk_regs + CLK_SOURCE_EMC); | ||
153 | |||
154 | return (val >> CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT) | ||
155 | & CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK; | ||
156 | } | ||
157 | |||
158 | static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra) | ||
159 | { | ||
160 | struct platform_device *pdev; | ||
161 | |||
162 | if (tegra->emc) | ||
163 | return tegra->emc; | ||
164 | |||
165 | if (!tegra->emc_node) | ||
166 | return NULL; | ||
167 | |||
168 | pdev = of_find_device_by_node(tegra->emc_node); | ||
169 | if (!pdev) { | ||
170 | pr_err("%s: could not get external memory controller\n", | ||
171 | __func__); | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
175 | of_node_put(tegra->emc_node); | ||
176 | tegra->emc_node = NULL; | ||
177 | |||
178 | tegra->emc = platform_get_drvdata(pdev); | ||
179 | if (!tegra->emc) { | ||
180 | pr_err("%s: cannot find EMC driver\n", __func__); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | return tegra->emc; | ||
185 | } | ||
186 | |||
187 | static int emc_set_timing(struct tegra_clk_emc *tegra, | ||
188 | struct emc_timing *timing) | ||
189 | { | ||
190 | int err; | ||
191 | u8 div; | ||
192 | u32 car_value; | ||
193 | unsigned long flags = 0; | ||
194 | struct tegra_emc *emc = emc_ensure_emc_driver(tegra); | ||
195 | |||
196 | if (!emc) | ||
197 | return -ENOENT; | ||
198 | |||
199 | pr_debug("going to rate %ld prate %ld p %s\n", timing->rate, | ||
200 | timing->parent_rate, __clk_get_name(timing->parent)); | ||
201 | |||
202 | if (emc_get_parent(&tegra->hw) == timing->parent_index && | ||
203 | clk_get_rate(timing->parent) != timing->parent_rate) { | ||
204 | BUG(); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | tegra->changing_timing = true; | ||
209 | |||
210 | err = clk_set_rate(timing->parent, timing->parent_rate); | ||
211 | if (err) { | ||
212 | pr_err("cannot change parent %s rate to %ld: %d\n", | ||
213 | __clk_get_name(timing->parent), timing->parent_rate, | ||
214 | err); | ||
215 | |||
216 | return err; | ||
217 | } | ||
218 | |||
219 | err = clk_prepare_enable(timing->parent); | ||
220 | if (err) { | ||
221 | pr_err("cannot enable parent clock: %d\n", err); | ||
222 | return err; | ||
223 | } | ||
224 | |||
225 | div = timing->parent_rate / (timing->rate / 2) - 2; | ||
226 | |||
227 | err = tegra_emc_prepare_timing_change(emc, timing->rate); | ||
228 | if (err) | ||
229 | return err; | ||
230 | |||
231 | spin_lock_irqsave(tegra->lock, flags); | ||
232 | |||
233 | car_value = readl(tegra->clk_regs + CLK_SOURCE_EMC); | ||
234 | |||
235 | car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_SRC(~0); | ||
236 | car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_SRC(timing->parent_index); | ||
237 | |||
238 | car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(~0); | ||
239 | car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(div); | ||
240 | |||
241 | writel(car_value, tegra->clk_regs + CLK_SOURCE_EMC); | ||
242 | |||
243 | spin_unlock_irqrestore(tegra->lock, flags); | ||
244 | |||
245 | tegra_emc_complete_timing_change(emc, timing->rate); | ||
246 | |||
247 | clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent)); | ||
248 | clk_disable_unprepare(tegra->prev_parent); | ||
249 | |||
250 | tegra->prev_parent = timing->parent; | ||
251 | tegra->changing_timing = false; | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Get backup timing to use as an intermediate step when a change between | ||
258 | * two timings with the same clock source has been requested. First try to | ||
259 | * find a timing with a higher clock rate to avoid a rate below any set rate | ||
260 | * floors. If that is not possible, find a lower rate. | ||
261 | */ | ||
262 | static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, | ||
263 | int timing_index) | ||
264 | { | ||
265 | int i; | ||
266 | u32 ram_code = tegra_read_ram_code(); | ||
267 | struct emc_timing *timing; | ||
268 | |||
269 | for (i = timing_index+1; i < tegra->num_timings; i++) { | ||
270 | timing = tegra->timings + i; | ||
271 | if (timing->ram_code != ram_code) | ||
272 | continue; | ||
273 | |||
274 | if (emc_parent_clk_sources[timing->parent_index] != | ||
275 | emc_parent_clk_sources[ | ||
276 | tegra->timings[timing_index].parent_index]) | ||
277 | return timing; | ||
278 | } | ||
279 | |||
280 | for (i = timing_index-1; i >= 0; --i) { | ||
281 | timing = tegra->timings + i; | ||
282 | if (timing->ram_code != ram_code) | ||
283 | continue; | ||
284 | |||
285 | if (emc_parent_clk_sources[timing->parent_index] != | ||
286 | emc_parent_clk_sources[ | ||
287 | tegra->timings[timing_index].parent_index]) | ||
288 | return timing; | ||
289 | } | ||
290 | |||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | static int emc_set_rate(struct clk_hw *hw, unsigned long rate, | ||
295 | unsigned long parent_rate) | ||
296 | { | ||
297 | struct tegra_clk_emc *tegra; | ||
298 | struct emc_timing *timing = NULL; | ||
299 | int i, err; | ||
300 | u32 ram_code = tegra_read_ram_code(); | ||
301 | |||
302 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
303 | |||
304 | if (__clk_get_rate(hw->clk) == rate) | ||
305 | return 0; | ||
306 | |||
307 | /* | ||
308 | * When emc_set_timing changes the parent rate, CCF will propagate | ||
309 | * that downward to us, so ignore any set_rate calls while a rate | ||
310 | * change is already going on. | ||
311 | */ | ||
312 | if (tegra->changing_timing) | ||
313 | return 0; | ||
314 | |||
315 | for (i = 0; i < tegra->num_timings; i++) { | ||
316 | if (tegra->timings[i].rate == rate && | ||
317 | tegra->timings[i].ram_code == ram_code) { | ||
318 | timing = tegra->timings + i; | ||
319 | break; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | if (!timing) { | ||
324 | pr_err("cannot switch to rate %ld without emc table\n", rate); | ||
325 | return -EINVAL; | ||
326 | } | ||
327 | |||
328 | if (emc_parent_clk_sources[emc_get_parent(hw)] == | ||
329 | emc_parent_clk_sources[timing->parent_index] && | ||
330 | clk_get_rate(timing->parent) != timing->parent_rate) { | ||
331 | /* | ||
332 | * Parent clock source not changed but parent rate has changed, | ||
333 | * need to temporarily switch to another parent | ||
334 | */ | ||
335 | |||
336 | struct emc_timing *backup_timing; | ||
337 | |||
338 | backup_timing = get_backup_timing(tegra, i); | ||
339 | if (!backup_timing) { | ||
340 | pr_err("cannot find backup timing\n"); | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | |||
344 | pr_debug("using %ld as backup rate when going to %ld\n", | ||
345 | backup_timing->rate, rate); | ||
346 | |||
347 | err = emc_set_timing(tegra, backup_timing); | ||
348 | if (err) { | ||
349 | pr_err("cannot set backup timing: %d\n", err); | ||
350 | return err; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | return emc_set_timing(tegra, timing); | ||
355 | } | ||
356 | |||
357 | /* Initialization and deinitialization */ | ||
358 | |||
359 | static int load_one_timing_from_dt(struct tegra_clk_emc *tegra, | ||
360 | struct emc_timing *timing, | ||
361 | struct device_node *node) | ||
362 | { | ||
363 | int err, i; | ||
364 | u32 tmp; | ||
365 | |||
366 | err = of_property_read_u32(node, "clock-frequency", &tmp); | ||
367 | if (err) { | ||
368 | pr_err("timing %s: failed to read rate\n", node->full_name); | ||
369 | return err; | ||
370 | } | ||
371 | |||
372 | timing->rate = tmp; | ||
373 | |||
374 | err = of_property_read_u32(node, "nvidia,parent-clock-frequency", &tmp); | ||
375 | if (err) { | ||
376 | pr_err("timing %s: failed to read parent rate\n", | ||
377 | node->full_name); | ||
378 | return err; | ||
379 | } | ||
380 | |||
381 | timing->parent_rate = tmp; | ||
382 | |||
383 | timing->parent = of_clk_get_by_name(node, "emc-parent"); | ||
384 | if (IS_ERR(timing->parent)) { | ||
385 | pr_err("timing %s: failed to get parent clock\n", | ||
386 | node->full_name); | ||
387 | return PTR_ERR(timing->parent); | ||
388 | } | ||
389 | |||
390 | timing->parent_index = 0xff; | ||
391 | for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) { | ||
392 | if (!strcmp(emc_parent_clk_names[i], | ||
393 | __clk_get_name(timing->parent))) { | ||
394 | timing->parent_index = i; | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | if (timing->parent_index == 0xff) { | ||
399 | pr_err("timing %s: %s is not a valid parent\n", | ||
400 | node->full_name, __clk_get_name(timing->parent)); | ||
401 | clk_put(timing->parent); | ||
402 | return -EINVAL; | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int cmp_timings(const void *_a, const void *_b) | ||
409 | { | ||
410 | const struct emc_timing *a = _a; | ||
411 | const struct emc_timing *b = _b; | ||
412 | |||
413 | if (a->rate < b->rate) | ||
414 | return -1; | ||
415 | else if (a->rate == b->rate) | ||
416 | return 0; | ||
417 | else | ||
418 | return 1; | ||
419 | } | ||
420 | |||
421 | static int load_timings_from_dt(struct tegra_clk_emc *tegra, | ||
422 | struct device_node *node, | ||
423 | u32 ram_code) | ||
424 | { | ||
425 | struct device_node *child; | ||
426 | int child_count = of_get_child_count(node); | ||
427 | int i = 0, err; | ||
428 | |||
429 | tegra->timings = kcalloc(child_count, sizeof(struct emc_timing), | ||
430 | GFP_KERNEL); | ||
431 | if (!tegra->timings) | ||
432 | return -ENOMEM; | ||
433 | |||
434 | tegra->num_timings = child_count; | ||
435 | |||
436 | for_each_child_of_node(node, child) { | ||
437 | struct emc_timing *timing = tegra->timings + (i++); | ||
438 | |||
439 | err = load_one_timing_from_dt(tegra, timing, child); | ||
440 | if (err) | ||
441 | return err; | ||
442 | |||
443 | timing->ram_code = ram_code; | ||
444 | } | ||
445 | |||
446 | sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing), | ||
447 | cmp_timings, NULL); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static const struct clk_ops tegra_clk_emc_ops = { | ||
453 | .recalc_rate = emc_recalc_rate, | ||
454 | .round_rate = emc_round_rate, | ||
455 | .set_rate = emc_set_rate, | ||
456 | .get_parent = emc_get_parent, | ||
457 | }; | ||
458 | |||
459 | struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, | ||
460 | spinlock_t *lock) | ||
461 | { | ||
462 | struct tegra_clk_emc *tegra; | ||
463 | struct clk_init_data init; | ||
464 | struct device_node *node; | ||
465 | u32 node_ram_code; | ||
466 | struct clk *clk; | ||
467 | int err; | ||
468 | |||
469 | tegra = kcalloc(1, sizeof(*tegra), GFP_KERNEL); | ||
470 | if (!tegra) | ||
471 | return ERR_PTR(-ENOMEM); | ||
472 | |||
473 | tegra->clk_regs = base; | ||
474 | tegra->lock = lock; | ||
475 | |||
476 | tegra->num_timings = 0; | ||
477 | |||
478 | for_each_child_of_node(np, node) { | ||
479 | err = of_property_read_u32(node, "nvidia,ram-code", | ||
480 | &node_ram_code); | ||
481 | if (err) { | ||
482 | of_node_put(node); | ||
483 | continue; | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * Store timings for all ram codes as we cannot read the | ||
488 | * fuses until the apbmisc driver is loaded. | ||
489 | */ | ||
490 | err = load_timings_from_dt(tegra, node, node_ram_code); | ||
491 | if (err) | ||
492 | return ERR_PTR(err); | ||
493 | of_node_put(node); | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | if (tegra->num_timings == 0) | ||
498 | pr_warn("%s: no memory timings registered\n", __func__); | ||
499 | |||
500 | tegra->emc_node = of_parse_phandle(np, | ||
501 | "nvidia,external-memory-controller", 0); | ||
502 | if (!tegra->emc_node) | ||
503 | pr_warn("%s: couldn't find node for EMC driver\n", __func__); | ||
504 | |||
505 | init.name = "emc"; | ||
506 | init.ops = &tegra_clk_emc_ops; | ||
507 | init.flags = 0; | ||
508 | init.parent_names = emc_parent_clk_names; | ||
509 | init.num_parents = ARRAY_SIZE(emc_parent_clk_names); | ||
510 | |||
511 | tegra->hw.init = &init; | ||
512 | |||
513 | clk = clk_register(NULL, &tegra->hw); | ||
514 | if (IS_ERR(clk)) | ||
515 | return clk; | ||
516 | |||
517 | tegra->prev_parent = clk_get_parent_by_index( | ||
518 | tegra->hw.clk, emc_get_parent(&tegra->hw)); | ||
519 | tegra->changing_timing = false; | ||
520 | |||
521 | /* Allow debugging tools to see the EMC clock */ | ||
522 | clk_register_clkdev(clk, "emc", "tegra-clk-debug"); | ||
523 | |||
524 | clk_prepare_enable(clk); | ||
525 | |||
526 | return clk; | ||
527 | }; | ||