diff options
author | Michael Turquette <mturquette@baylibre.com> | 2015-06-20 16:29:48 -0400 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2015-06-20 16:29:48 -0400 |
commit | 2cd7b0432888ef2e1f8b54c1c6f8751e1e0e9b5e (patch) | |
tree | 8ecab6ac6ef54b4ccc7b93a6a079e72a6ff7d640 | |
parent | 85e88fab134d8896cf4d8be0aac10cc54018ee63 (diff) | |
parent | 36b7be6d3ea8f434f1e0723f3fb0e85c3e00ebc2 (diff) |
Merge tag 'tegra-for-4.2-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into clk-next
clk: tegra: Changes for v4.2-rc1
This contains the EMC clock driver that's been exhaustively reviewed and
tested. It also includes a change to the clock core that allows a clock
provider to perform low-level reparenting of clocks. This is required by
the EMC clock driver because the reparenting needs to be done at a very
specific point in time during the EMC frequency switch.
-rw-r--r-- | Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt | 44 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt | 2 | ||||
-rw-r--r-- | drivers/clk/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clk/clk.c | 8 | ||||
-rw-r--r-- | drivers/clk/tegra/Kconfig | 3 | ||||
-rw-r--r-- | drivers/clk/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-emc.c | 538 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra124.c | 19 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra30.c | 2 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.h | 12 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/tegra-apbmisc.c | 21 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 1 | ||||
-rw-r--r-- | include/soc/tegra/fuse.h | 1 |
13 files changed, 637 insertions, 16 deletions
diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt index c6620bc96703..7f02fb4ca4ad 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt | |||
@@ -20,15 +20,38 @@ Required properties : | |||
20 | - #reset-cells : Should be 1. | 20 | - #reset-cells : Should be 1. |
21 | In clock consumers, this cell represents the bit number in the CAR's | 21 | In clock consumers, this cell represents the bit number in the CAR's |
22 | array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. | 22 | array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. |
23 | - nvidia,external-memory-controller : phandle of the EMC driver. | ||
24 | |||
25 | The node should contain a "emc-timings" subnode for each supported RAM type (see | ||
26 | field RAM_CODE in register PMC_STRAPPING_OPT_A). | ||
27 | |||
28 | Required properties for "emc-timings" nodes : | ||
29 | - nvidia,ram-code : Should contain the value of RAM_CODE this timing set | ||
30 | is used for. | ||
31 | |||
32 | Each "emc-timings" node should contain a "timing" subnode for every supported | ||
33 | EMC clock rate. | ||
34 | |||
35 | Required properties for "timing" nodes : | ||
36 | - clock-frequency : Should contain the memory clock rate to which this timing | ||
37 | relates. | ||
38 | - nvidia,parent-clock-frequency : Should contain the rate at which the current | ||
39 | parent of the EMC clock should be running at this timing. | ||
40 | - clocks : Must contain an entry for each entry in clock-names. | ||
41 | See ../clocks/clock-bindings.txt for details. | ||
42 | - clock-names : Must include the following entries: | ||
43 | - emc-parent : the clock that should be the parent of the EMC clock at this | ||
44 | timing. | ||
23 | 45 | ||
24 | Example SoC include file: | 46 | Example SoC include file: |
25 | 47 | ||
26 | / { | 48 | / { |
27 | tegra_car: clock { | 49 | tegra_car: clock@60006000 { |
28 | compatible = "nvidia,tegra124-car"; | 50 | compatible = "nvidia,tegra124-car"; |
29 | reg = <0x60006000 0x1000>; | 51 | reg = <0x60006000 0x1000>; |
30 | #clock-cells = <1>; | 52 | #clock-cells = <1>; |
31 | #reset-cells = <1>; | 53 | #reset-cells = <1>; |
54 | nvidia,external-memory-controller = <&emc>; | ||
32 | }; | 55 | }; |
33 | 56 | ||
34 | usb@c5004000 { | 57 | usb@c5004000 { |
@@ -62,4 +85,23 @@ Example board file: | |||
62 | &tegra_car { | 85 | &tegra_car { |
63 | clocks = <&clk_32k> <&osc>; | 86 | clocks = <&clk_32k> <&osc>; |
64 | }; | 87 | }; |
88 | |||
89 | clock@60006000 { | ||
90 | emc-timings-3 { | ||
91 | nvidia,ram-code = <3>; | ||
92 | |||
93 | timing-12750000 { | ||
94 | clock-frequency = <12750000>; | ||
95 | nvidia,parent-clock-frequency = <408000000>; | ||
96 | clocks = <&tegra_car TEGRA124_CLK_PLL_P>; | ||
97 | clock-names = "emc-parent"; | ||
98 | }; | ||
99 | timing-20400000 { | ||
100 | clock-frequency = <20400000>; | ||
101 | nvidia,parent-clock-frequency = <408000000>; | ||
102 | clocks = <&tegra_car TEGRA124_CLK_PLL_P>; | ||
103 | clock-names = "emc-parent"; | ||
104 | }; | ||
105 | }; | ||
106 | }; | ||
65 | }; | 107 | }; |
diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt index 47b205cc9cc7..4556359c5876 100644 --- a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt +++ b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt | |||
@@ -10,3 +10,5 @@ Required properties: | |||
10 | The second entry gives the physical address and length of the | 10 | The second entry gives the physical address and length of the |
11 | registers indicating the strapping options. | 11 | registers indicating the strapping options. |
12 | 12 | ||
13 | Optional properties: | ||
14 | - nvidia,long-ram-code: If present, the RAM code is long (4 bit). If not, short (2 bit). | ||
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1dd4f9d8bcb6..42f7120ca9ce 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -176,3 +176,4 @@ endmenu | |||
176 | source "drivers/clk/mvebu/Kconfig" | 176 | source "drivers/clk/mvebu/Kconfig" |
177 | 177 | ||
178 | source "drivers/clk/samsung/Kconfig" | 178 | source "drivers/clk/samsung/Kconfig" |
179 | source "drivers/clk/tegra/Kconfig" | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 059e5d25c9ba..ddb4b541016f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -1660,6 +1660,14 @@ static void clk_core_reparent(struct clk_core *core, | |||
1660 | __clk_recalc_rates(core, POST_RATE_CHANGE); | 1660 | __clk_recalc_rates(core, POST_RATE_CHANGE); |
1661 | } | 1661 | } |
1662 | 1662 | ||
1663 | void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent) | ||
1664 | { | ||
1665 | if (!hw) | ||
1666 | return; | ||
1667 | |||
1668 | clk_core_reparent(hw->core, !new_parent ? NULL : new_parent->core); | ||
1669 | } | ||
1670 | |||
1663 | /** | 1671 | /** |
1664 | * clk_has_parent - check if a clock is a possible parent for another | 1672 | * clk_has_parent - check if a clock is a possible parent for another |
1665 | * @clk: clock source | 1673 | * @clk: clock source |
diff --git a/drivers/clk/tegra/Kconfig b/drivers/clk/tegra/Kconfig new file mode 100644 index 000000000000..1ba30d1e14f2 --- /dev/null +++ b/drivers/clk/tegra/Kconfig | |||
@@ -0,0 +1,3 @@ | |||
1 | config TEGRA_CLK_EMC | ||
2 | def_bool y | ||
3 | depends on TEGRA124_EMC | ||
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index edb8358fa6ce..aec862ba7a17 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile | |||
@@ -11,6 +11,7 @@ obj-y += clk-tegra-periph.o | |||
11 | obj-y += clk-tegra-pmc.o | 11 | obj-y += clk-tegra-pmc.o |
12 | obj-y += clk-tegra-fixed.o | 12 | obj-y += clk-tegra-fixed.o |
13 | obj-y += clk-tegra-super-gen4.o | 13 | obj-y += clk-tegra-super-gen4.o |
14 | obj-$(CONFIG_TEGRA_CLK_EMC) += clk-emc.o | ||
14 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o | 15 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o |
15 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o | 16 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o |
16 | obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o | 17 | obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o |
diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c new file mode 100644 index 000000000000..7649685c86bc --- /dev/null +++ b/drivers/clk/tegra/clk-emc.c | |||
@@ -0,0 +1,538 @@ | |||
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_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
120 | unsigned long min_rate, | ||
121 | unsigned long max_rate, | ||
122 | unsigned long *best_parent_rate, | ||
123 | struct clk_hw **best_parent_hw) | ||
124 | { | ||
125 | struct tegra_clk_emc *tegra; | ||
126 | u8 ram_code = tegra_read_ram_code(); | ||
127 | struct emc_timing *timing = NULL; | ||
128 | int i; | ||
129 | |||
130 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
131 | |||
132 | for (i = 0; i < tegra->num_timings; i++) { | ||
133 | if (tegra->timings[i].ram_code != ram_code) | ||
134 | continue; | ||
135 | |||
136 | timing = tegra->timings + i; | ||
137 | |||
138 | if (timing->rate > max_rate) { | ||
139 | i = min(i, 1); | ||
140 | return tegra->timings[i - 1].rate; | ||
141 | } | ||
142 | |||
143 | if (timing->rate < min_rate) | ||
144 | continue; | ||
145 | |||
146 | if (timing->rate >= rate) | ||
147 | return timing->rate; | ||
148 | } | ||
149 | |||
150 | if (timing) | ||
151 | return timing->rate; | ||
152 | |||
153 | return __clk_get_rate(hw->clk); | ||
154 | } | ||
155 | |||
156 | static u8 emc_get_parent(struct clk_hw *hw) | ||
157 | { | ||
158 | struct tegra_clk_emc *tegra; | ||
159 | u32 val; | ||
160 | |||
161 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
162 | |||
163 | val = readl(tegra->clk_regs + CLK_SOURCE_EMC); | ||
164 | |||
165 | return (val >> CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT) | ||
166 | & CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK; | ||
167 | } | ||
168 | |||
169 | static struct tegra_emc *emc_ensure_emc_driver(struct tegra_clk_emc *tegra) | ||
170 | { | ||
171 | struct platform_device *pdev; | ||
172 | |||
173 | if (tegra->emc) | ||
174 | return tegra->emc; | ||
175 | |||
176 | if (!tegra->emc_node) | ||
177 | return NULL; | ||
178 | |||
179 | pdev = of_find_device_by_node(tegra->emc_node); | ||
180 | if (!pdev) { | ||
181 | pr_err("%s: could not get external memory controller\n", | ||
182 | __func__); | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | of_node_put(tegra->emc_node); | ||
187 | tegra->emc_node = NULL; | ||
188 | |||
189 | tegra->emc = platform_get_drvdata(pdev); | ||
190 | if (!tegra->emc) { | ||
191 | pr_err("%s: cannot find EMC driver\n", __func__); | ||
192 | return NULL; | ||
193 | } | ||
194 | |||
195 | return tegra->emc; | ||
196 | } | ||
197 | |||
198 | static int emc_set_timing(struct tegra_clk_emc *tegra, | ||
199 | struct emc_timing *timing) | ||
200 | { | ||
201 | int err; | ||
202 | u8 div; | ||
203 | u32 car_value; | ||
204 | unsigned long flags = 0; | ||
205 | struct tegra_emc *emc = emc_ensure_emc_driver(tegra); | ||
206 | |||
207 | if (!emc) | ||
208 | return -ENOENT; | ||
209 | |||
210 | pr_debug("going to rate %ld prate %ld p %s\n", timing->rate, | ||
211 | timing->parent_rate, __clk_get_name(timing->parent)); | ||
212 | |||
213 | if (emc_get_parent(&tegra->hw) == timing->parent_index && | ||
214 | clk_get_rate(timing->parent) != timing->parent_rate) { | ||
215 | BUG(); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | tegra->changing_timing = true; | ||
220 | |||
221 | err = clk_set_rate(timing->parent, timing->parent_rate); | ||
222 | if (err) { | ||
223 | pr_err("cannot change parent %s rate to %ld: %d\n", | ||
224 | __clk_get_name(timing->parent), timing->parent_rate, | ||
225 | err); | ||
226 | |||
227 | return err; | ||
228 | } | ||
229 | |||
230 | err = clk_prepare_enable(timing->parent); | ||
231 | if (err) { | ||
232 | pr_err("cannot enable parent clock: %d\n", err); | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | div = timing->parent_rate / (timing->rate / 2) - 2; | ||
237 | |||
238 | err = tegra_emc_prepare_timing_change(emc, timing->rate); | ||
239 | if (err) | ||
240 | return err; | ||
241 | |||
242 | spin_lock_irqsave(tegra->lock, flags); | ||
243 | |||
244 | car_value = readl(tegra->clk_regs + CLK_SOURCE_EMC); | ||
245 | |||
246 | car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_SRC(~0); | ||
247 | car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_SRC(timing->parent_index); | ||
248 | |||
249 | car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(~0); | ||
250 | car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(div); | ||
251 | |||
252 | writel(car_value, tegra->clk_regs + CLK_SOURCE_EMC); | ||
253 | |||
254 | spin_unlock_irqrestore(tegra->lock, flags); | ||
255 | |||
256 | tegra_emc_complete_timing_change(emc, timing->rate); | ||
257 | |||
258 | clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent)); | ||
259 | clk_disable_unprepare(tegra->prev_parent); | ||
260 | |||
261 | tegra->prev_parent = timing->parent; | ||
262 | tegra->changing_timing = false; | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Get backup timing to use as an intermediate step when a change between | ||
269 | * two timings with the same clock source has been requested. First try to | ||
270 | * find a timing with a higher clock rate to avoid a rate below any set rate | ||
271 | * floors. If that is not possible, find a lower rate. | ||
272 | */ | ||
273 | static struct emc_timing *get_backup_timing(struct tegra_clk_emc *tegra, | ||
274 | int timing_index) | ||
275 | { | ||
276 | int i; | ||
277 | u32 ram_code = tegra_read_ram_code(); | ||
278 | struct emc_timing *timing; | ||
279 | |||
280 | for (i = timing_index+1; i < tegra->num_timings; 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 | for (i = timing_index-1; i >= 0; --i) { | ||
292 | timing = tegra->timings + i; | ||
293 | if (timing->ram_code != ram_code) | ||
294 | continue; | ||
295 | |||
296 | if (emc_parent_clk_sources[timing->parent_index] != | ||
297 | emc_parent_clk_sources[ | ||
298 | tegra->timings[timing_index].parent_index]) | ||
299 | return timing; | ||
300 | } | ||
301 | |||
302 | return NULL; | ||
303 | } | ||
304 | |||
305 | static int emc_set_rate(struct clk_hw *hw, unsigned long rate, | ||
306 | unsigned long parent_rate) | ||
307 | { | ||
308 | struct tegra_clk_emc *tegra; | ||
309 | struct emc_timing *timing = NULL; | ||
310 | int i, err; | ||
311 | u32 ram_code = tegra_read_ram_code(); | ||
312 | |||
313 | tegra = container_of(hw, struct tegra_clk_emc, hw); | ||
314 | |||
315 | if (__clk_get_rate(hw->clk) == rate) | ||
316 | return 0; | ||
317 | |||
318 | /* | ||
319 | * When emc_set_timing changes the parent rate, CCF will propagate | ||
320 | * that downward to us, so ignore any set_rate calls while a rate | ||
321 | * change is already going on. | ||
322 | */ | ||
323 | if (tegra->changing_timing) | ||
324 | return 0; | ||
325 | |||
326 | for (i = 0; i < tegra->num_timings; i++) { | ||
327 | if (tegra->timings[i].rate == rate && | ||
328 | tegra->timings[i].ram_code == ram_code) { | ||
329 | timing = tegra->timings + i; | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | if (!timing) { | ||
335 | pr_err("cannot switch to rate %ld without emc table\n", rate); | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | |||
339 | if (emc_parent_clk_sources[emc_get_parent(hw)] == | ||
340 | emc_parent_clk_sources[timing->parent_index] && | ||
341 | clk_get_rate(timing->parent) != timing->parent_rate) { | ||
342 | /* | ||
343 | * Parent clock source not changed but parent rate has changed, | ||
344 | * need to temporarily switch to another parent | ||
345 | */ | ||
346 | |||
347 | struct emc_timing *backup_timing; | ||
348 | |||
349 | backup_timing = get_backup_timing(tegra, i); | ||
350 | if (!backup_timing) { | ||
351 | pr_err("cannot find backup timing\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | pr_debug("using %ld as backup rate when going to %ld\n", | ||
356 | backup_timing->rate, rate); | ||
357 | |||
358 | err = emc_set_timing(tegra, backup_timing); | ||
359 | if (err) { | ||
360 | pr_err("cannot set backup timing: %d\n", err); | ||
361 | return err; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | return emc_set_timing(tegra, timing); | ||
366 | } | ||
367 | |||
368 | /* Initialization and deinitialization */ | ||
369 | |||
370 | static int load_one_timing_from_dt(struct tegra_clk_emc *tegra, | ||
371 | struct emc_timing *timing, | ||
372 | struct device_node *node) | ||
373 | { | ||
374 | int err, i; | ||
375 | u32 tmp; | ||
376 | |||
377 | err = of_property_read_u32(node, "clock-frequency", &tmp); | ||
378 | if (err) { | ||
379 | pr_err("timing %s: failed to read rate\n", node->full_name); | ||
380 | return err; | ||
381 | } | ||
382 | |||
383 | timing->rate = tmp; | ||
384 | |||
385 | err = of_property_read_u32(node, "nvidia,parent-clock-frequency", &tmp); | ||
386 | if (err) { | ||
387 | pr_err("timing %s: failed to read parent rate\n", | ||
388 | node->full_name); | ||
389 | return err; | ||
390 | } | ||
391 | |||
392 | timing->parent_rate = tmp; | ||
393 | |||
394 | timing->parent = of_clk_get_by_name(node, "emc-parent"); | ||
395 | if (IS_ERR(timing->parent)) { | ||
396 | pr_err("timing %s: failed to get parent clock\n", | ||
397 | node->full_name); | ||
398 | return PTR_ERR(timing->parent); | ||
399 | } | ||
400 | |||
401 | timing->parent_index = 0xff; | ||
402 | for (i = 0; i < ARRAY_SIZE(emc_parent_clk_names); i++) { | ||
403 | if (!strcmp(emc_parent_clk_names[i], | ||
404 | __clk_get_name(timing->parent))) { | ||
405 | timing->parent_index = i; | ||
406 | break; | ||
407 | } | ||
408 | } | ||
409 | if (timing->parent_index == 0xff) { | ||
410 | pr_err("timing %s: %s is not a valid parent\n", | ||
411 | node->full_name, __clk_get_name(timing->parent)); | ||
412 | clk_put(timing->parent); | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int cmp_timings(const void *_a, const void *_b) | ||
420 | { | ||
421 | const struct emc_timing *a = _a; | ||
422 | const struct emc_timing *b = _b; | ||
423 | |||
424 | if (a->rate < b->rate) | ||
425 | return -1; | ||
426 | else if (a->rate == b->rate) | ||
427 | return 0; | ||
428 | else | ||
429 | return 1; | ||
430 | } | ||
431 | |||
432 | static int load_timings_from_dt(struct tegra_clk_emc *tegra, | ||
433 | struct device_node *node, | ||
434 | u32 ram_code) | ||
435 | { | ||
436 | struct device_node *child; | ||
437 | int child_count = of_get_child_count(node); | ||
438 | int i = 0, err; | ||
439 | |||
440 | tegra->timings = kcalloc(child_count, sizeof(struct emc_timing), | ||
441 | GFP_KERNEL); | ||
442 | if (!tegra->timings) | ||
443 | return -ENOMEM; | ||
444 | |||
445 | tegra->num_timings = child_count; | ||
446 | |||
447 | for_each_child_of_node(node, child) { | ||
448 | struct emc_timing *timing = tegra->timings + (i++); | ||
449 | |||
450 | err = load_one_timing_from_dt(tegra, timing, child); | ||
451 | if (err) | ||
452 | return err; | ||
453 | |||
454 | timing->ram_code = ram_code; | ||
455 | } | ||
456 | |||
457 | sort(tegra->timings, tegra->num_timings, sizeof(struct emc_timing), | ||
458 | cmp_timings, NULL); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static const struct clk_ops tegra_clk_emc_ops = { | ||
464 | .recalc_rate = emc_recalc_rate, | ||
465 | .determine_rate = emc_determine_rate, | ||
466 | .set_rate = emc_set_rate, | ||
467 | .get_parent = emc_get_parent, | ||
468 | }; | ||
469 | |||
470 | struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, | ||
471 | spinlock_t *lock) | ||
472 | { | ||
473 | struct tegra_clk_emc *tegra; | ||
474 | struct clk_init_data init; | ||
475 | struct device_node *node; | ||
476 | u32 node_ram_code; | ||
477 | struct clk *clk; | ||
478 | int err; | ||
479 | |||
480 | tegra = kcalloc(1, sizeof(*tegra), GFP_KERNEL); | ||
481 | if (!tegra) | ||
482 | return ERR_PTR(-ENOMEM); | ||
483 | |||
484 | tegra->clk_regs = base; | ||
485 | tegra->lock = lock; | ||
486 | |||
487 | tegra->num_timings = 0; | ||
488 | |||
489 | for_each_child_of_node(np, node) { | ||
490 | err = of_property_read_u32(node, "nvidia,ram-code", | ||
491 | &node_ram_code); | ||
492 | if (err) { | ||
493 | of_node_put(node); | ||
494 | continue; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * Store timings for all ram codes as we cannot read the | ||
499 | * fuses until the apbmisc driver is loaded. | ||
500 | */ | ||
501 | err = load_timings_from_dt(tegra, node, node_ram_code); | ||
502 | if (err) | ||
503 | return ERR_PTR(err); | ||
504 | of_node_put(node); | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | if (tegra->num_timings == 0) | ||
509 | pr_warn("%s: no memory timings registered\n", __func__); | ||
510 | |||
511 | tegra->emc_node = of_parse_phandle(np, | ||
512 | "nvidia,external-memory-controller", 0); | ||
513 | if (!tegra->emc_node) | ||
514 | pr_warn("%s: couldn't find node for EMC driver\n", __func__); | ||
515 | |||
516 | init.name = "emc"; | ||
517 | init.ops = &tegra_clk_emc_ops; | ||
518 | init.flags = 0; | ||
519 | init.parent_names = emc_parent_clk_names; | ||
520 | init.num_parents = ARRAY_SIZE(emc_parent_clk_names); | ||
521 | |||
522 | tegra->hw.init = &init; | ||
523 | |||
524 | clk = clk_register(NULL, &tegra->hw); | ||
525 | if (IS_ERR(clk)) | ||
526 | return clk; | ||
527 | |||
528 | tegra->prev_parent = clk_get_parent_by_index( | ||
529 | tegra->hw.clk, emc_get_parent(&tegra->hw)); | ||
530 | tegra->changing_timing = false; | ||
531 | |||
532 | /* Allow debugging tools to see the EMC clock */ | ||
533 | clk_register_clkdev(clk, "emc", "tegra-clk-debug"); | ||
534 | |||
535 | clk_prepare_enable(clk); | ||
536 | |||
537 | return clk; | ||
538 | }; | ||
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 11f857cd5f6a..e8cca3eac007 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c | |||
@@ -152,11 +152,6 @@ static unsigned long tegra124_input_freq[] = { | |||
152 | [12] = 260000000, | 152 | [12] = 260000000, |
153 | }; | 153 | }; |
154 | 154 | ||
155 | static const char *mux_pllmcp_clkm[] = { | ||
156 | "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3", | ||
157 | }; | ||
158 | #define mux_pllmcp_clkm_idx NULL | ||
159 | |||
160 | static struct div_nmp pllxc_nmp = { | 155 | static struct div_nmp pllxc_nmp = { |
161 | .divm_shift = 0, | 156 | .divm_shift = 0, |
162 | .divm_width = 8, | 157 | .divm_width = 8, |
@@ -791,7 +786,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { | |||
791 | [tegra_clk_i2c2] = { .dt_id = TEGRA124_CLK_I2C2, .present = true }, | 786 | [tegra_clk_i2c2] = { .dt_id = TEGRA124_CLK_I2C2, .present = true }, |
792 | [tegra_clk_uartc] = { .dt_id = TEGRA124_CLK_UARTC, .present = true }, | 787 | [tegra_clk_uartc] = { .dt_id = TEGRA124_CLK_UARTC, .present = true }, |
793 | [tegra_clk_mipi_cal] = { .dt_id = TEGRA124_CLK_MIPI_CAL, .present = true }, | 788 | [tegra_clk_mipi_cal] = { .dt_id = TEGRA124_CLK_MIPI_CAL, .present = true }, |
794 | [tegra_clk_emc] = { .dt_id = TEGRA124_CLK_EMC, .present = true }, | ||
795 | [tegra_clk_usb2] = { .dt_id = TEGRA124_CLK_USB2, .present = true }, | 789 | [tegra_clk_usb2] = { .dt_id = TEGRA124_CLK_USB2, .present = true }, |
796 | [tegra_clk_usb3] = { .dt_id = TEGRA124_CLK_USB3, .present = true }, | 790 | [tegra_clk_usb3] = { .dt_id = TEGRA124_CLK_USB3, .present = true }, |
797 | [tegra_clk_vde_8] = { .dt_id = TEGRA124_CLK_VDE, .present = true }, | 791 | [tegra_clk_vde_8] = { .dt_id = TEGRA124_CLK_VDE, .present = true }, |
@@ -1127,13 +1121,7 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, | |||
1127 | periph_clk_enb_refcnt); | 1121 | periph_clk_enb_refcnt); |
1128 | clks[TEGRA124_CLK_DSIB] = clk; | 1122 | clks[TEGRA124_CLK_DSIB] = clk; |
1129 | 1123 | ||
1130 | /* emc mux */ | 1124 | clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC, |
1131 | clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, | ||
1132 | ARRAY_SIZE(mux_pllmcp_clkm), 0, | ||
1133 | clk_base + CLK_SOURCE_EMC, | ||
1134 | 29, 3, 0, &emc_lock); | ||
1135 | |||
1136 | clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, | ||
1137 | &emc_lock); | 1125 | &emc_lock); |
1138 | clks[TEGRA124_CLK_MC] = clk; | 1126 | clks[TEGRA124_CLK_MC] = clk; |
1139 | 1127 | ||
@@ -1389,7 +1377,6 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { | |||
1389 | {TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0}, | 1377 | {TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0}, |
1390 | {TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0}, | 1378 | {TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0}, |
1391 | {TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0}, | 1379 | {TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0}, |
1392 | {TEGRA124_CLK_EMC, TEGRA124_CLK_CLK_MAX, 0, 1}, | ||
1393 | {TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1}, | 1380 | {TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1}, |
1394 | {TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1}, | 1381 | {TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1}, |
1395 | {TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0}, | 1382 | {TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0}, |
@@ -1513,6 +1500,10 @@ static void __init tegra124_132_clock_init_post(struct device_node *np) | |||
1513 | tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, | 1500 | tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, |
1514 | &pll_x_params); | 1501 | &pll_x_params); |
1515 | tegra_add_of_provider(np); | 1502 | tegra_add_of_provider(np); |
1503 | |||
1504 | clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np, | ||
1505 | &emc_lock); | ||
1506 | |||
1516 | tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); | 1507 | tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); |
1517 | 1508 | ||
1518 | tegra_cpu_car_ops = &tegra124_cpu_car_ops; | 1509 | tegra_cpu_car_ops = &tegra124_cpu_car_ops; |
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 4b26509fc218..0af3e834dd24 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c | |||
@@ -679,7 +679,7 @@ static struct tegra_devclk devclks[] __initdata = { | |||
679 | { .dev_id = "tegra30-dam.1", .dt_id = TEGRA30_CLK_DAM1 }, | 679 | { .dev_id = "tegra30-dam.1", .dt_id = TEGRA30_CLK_DAM1 }, |
680 | { .dev_id = "tegra30-dam.2", .dt_id = TEGRA30_CLK_DAM2 }, | 680 | { .dev_id = "tegra30-dam.2", .dt_id = TEGRA30_CLK_DAM2 }, |
681 | { .con_id = "hda", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA }, | 681 | { .con_id = "hda", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA }, |
682 | { .con_id = "hda2codec", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA2CODEC_2X }, | 682 | { .con_id = "hda2codec_2x", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA2CODEC_2X }, |
683 | { .dev_id = "spi_tegra.0", .dt_id = TEGRA30_CLK_SBC1 }, | 683 | { .dev_id = "spi_tegra.0", .dt_id = TEGRA30_CLK_SBC1 }, |
684 | { .dev_id = "spi_tegra.1", .dt_id = TEGRA30_CLK_SBC2 }, | 684 | { .dev_id = "spi_tegra.1", .dt_id = TEGRA30_CLK_SBC2 }, |
685 | { .dev_id = "spi_tegra.2", .dt_id = TEGRA30_CLK_SBC3 }, | 685 | { .dev_id = "spi_tegra.2", .dt_id = TEGRA30_CLK_SBC3 }, |
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index d6ac00647faf..75ddc8ff8bd4 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h | |||
@@ -623,6 +623,18 @@ void tegra_super_clk_gen4_init(void __iomem *clk_base, | |||
623 | void __iomem *pmc_base, struct tegra_clk *tegra_clks, | 623 | void __iomem *pmc_base, struct tegra_clk *tegra_clks, |
624 | struct tegra_clk_pll_params *pll_params); | 624 | struct tegra_clk_pll_params *pll_params); |
625 | 625 | ||
626 | #ifdef CONFIG_TEGRA_CLK_EMC | ||
627 | struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, | ||
628 | spinlock_t *lock); | ||
629 | #else | ||
630 | static inline struct clk *tegra_clk_register_emc(void __iomem *base, | ||
631 | struct device_node *np, | ||
632 | spinlock_t *lock) | ||
633 | { | ||
634 | return NULL; | ||
635 | } | ||
636 | #endif | ||
637 | |||
626 | void tegra114_clock_tune_cpu_trimmers_high(void); | 638 | void tegra114_clock_tune_cpu_trimmers_high(void); |
627 | void tegra114_clock_tune_cpu_trimmers_low(void); | 639 | void tegra114_clock_tune_cpu_trimmers_low(void); |
628 | void tegra114_clock_tune_cpu_trimmers_init(void); | 640 | void tegra114_clock_tune_cpu_trimmers_init(void); |
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 3bf5aba4caaa..73fad05d8f2c 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c | |||
@@ -28,8 +28,15 @@ | |||
28 | #define APBMISC_SIZE 0x64 | 28 | #define APBMISC_SIZE 0x64 |
29 | #define FUSE_SKU_INFO 0x10 | 29 | #define FUSE_SKU_INFO 0x10 |
30 | 30 | ||
31 | #define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT 4 | ||
32 | #define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG \ | ||
33 | (0xf << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT) | ||
34 | #define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \ | ||
35 | (0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT) | ||
36 | |||
31 | static void __iomem *apbmisc_base; | 37 | static void __iomem *apbmisc_base; |
32 | static void __iomem *strapping_base; | 38 | static void __iomem *strapping_base; |
39 | static bool long_ram_code; | ||
33 | 40 | ||
34 | u32 tegra_read_chipid(void) | 41 | u32 tegra_read_chipid(void) |
35 | { | 42 | { |
@@ -54,6 +61,18 @@ u32 tegra_read_straps(void) | |||
54 | return 0; | 61 | return 0; |
55 | } | 62 | } |
56 | 63 | ||
64 | u32 tegra_read_ram_code(void) | ||
65 | { | ||
66 | u32 straps = tegra_read_straps(); | ||
67 | |||
68 | if (long_ram_code) | ||
69 | straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG; | ||
70 | else | ||
71 | straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT; | ||
72 | |||
73 | return straps >> PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT; | ||
74 | } | ||
75 | |||
57 | static const struct of_device_id apbmisc_match[] __initconst = { | 76 | static const struct of_device_id apbmisc_match[] __initconst = { |
58 | { .compatible = "nvidia,tegra20-apbmisc", }, | 77 | { .compatible = "nvidia,tegra20-apbmisc", }, |
59 | {}, | 78 | {}, |
@@ -112,4 +131,6 @@ void __init tegra_init_apbmisc(void) | |||
112 | strapping_base = of_iomap(np, 1); | 131 | strapping_base = of_iomap(np, 1); |
113 | if (!strapping_base) | 132 | if (!strapping_base) |
114 | pr_err("ioremap tegra strapping_base failed\n"); | 133 | pr_err("ioremap tegra strapping_base failed\n"); |
134 | |||
135 | long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code"); | ||
115 | } | 136 | } |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 6a24df64b0a0..78842f46f152 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -592,6 +592,7 @@ long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, | |||
592 | unsigned long max_rate, | 592 | unsigned long max_rate, |
593 | unsigned long *best_parent_rate, | 593 | unsigned long *best_parent_rate, |
594 | struct clk_hw **best_parent_p); | 594 | struct clk_hw **best_parent_p); |
595 | void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); | ||
595 | 596 | ||
596 | static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) | 597 | static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) |
597 | { | 598 | { |
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index b5f7b5f8d008..b019e3465f11 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h | |||
@@ -56,6 +56,7 @@ struct tegra_sku_info { | |||
56 | }; | 56 | }; |
57 | 57 | ||
58 | u32 tegra_read_straps(void); | 58 | u32 tegra_read_straps(void); |
59 | u32 tegra_read_ram_code(void); | ||
59 | u32 tegra_read_chipid(void); | 60 | u32 tegra_read_chipid(void); |
60 | int tegra_fuse_readl(unsigned long offset, u32 *value); | 61 | int tegra_fuse_readl(unsigned long offset, u32 *value); |
61 | 62 | ||