diff options
| -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 | ||
