Lines Matching +full:emc +full:- +full:configuration
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2015-2020, NVIDIA CORPORATION. All rights reserved.
8 #include <linux/clk-provider.h>
53 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw); in tegra210_clk_emc_get_parent() local
57 value = readl_relaxed(emc->regs + CLK_SOURCE_EMC); in tegra210_clk_emc_get_parent()
66 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw); in tegra210_clk_emc_recalc_rate() local
71 * ->set_rate(), so the parent rate passed in here was cached from the in tegra210_clk_emc_recalc_rate()
72 * parent before the ->set_rate() call. in tegra210_clk_emc_recalc_rate()
74 * This can lead to wrong results being reported for the EMC clock if in tegra210_clk_emc_recalc_rate()
75 * the parent and/or parent rate have changed as part of the EMC rate in tegra210_clk_emc_recalc_rate()
81 value = readl_relaxed(emc->regs + CLK_SOURCE_EMC); in tegra210_clk_emc_recalc_rate()
92 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw); in tegra210_clk_emc_round_rate() local
93 struct tegra210_clk_emc_provider *provider = emc->provider; in tegra210_clk_emc_round_rate()
96 if (!provider || !provider->configs || provider->num_configs == 0) in tegra210_clk_emc_round_rate()
99 for (i = 0; i < provider->num_configs; i++) { in tegra210_clk_emc_round_rate()
100 if (provider->configs[i].rate >= rate) in tegra210_clk_emc_round_rate()
101 return provider->configs[i].rate; in tegra210_clk_emc_round_rate()
104 return provider->configs[i - 1].rate; in tegra210_clk_emc_round_rate()
107 static struct clk *tegra210_clk_emc_find_parent(struct tegra210_clk_emc *emc, in tegra210_clk_emc_find_parent() argument
110 struct clk_hw *parent = clk_hw_get_parent_by_index(&emc->hw, index); in tegra210_clk_emc_find_parent()
121 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw); in tegra210_clk_emc_set_rate() local
122 struct tegra210_clk_emc_provider *provider = emc->provider; in tegra210_clk_emc_set_rate()
124 struct device *dev = provider->dev; in tegra210_clk_emc_set_rate()
131 if (!provider->configs || provider->num_configs == 0) in tegra210_clk_emc_set_rate()
132 return -EINVAL; in tegra210_clk_emc_set_rate()
134 for (i = 0; i < provider->num_configs; i++) { in tegra210_clk_emc_set_rate()
135 if (provider->configs[i].rate >= rate) { in tegra210_clk_emc_set_rate()
136 config = &provider->configs[i]; in tegra210_clk_emc_set_rate()
141 if (i == provider->num_configs) in tegra210_clk_emc_set_rate()
142 config = &provider->configs[i - 1]; in tegra210_clk_emc_set_rate()
145 new_idx = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value); in tegra210_clk_emc_set_rate()
151 if (config->parent_rate != clk_hw_get_rate(old)) { in tegra210_clk_emc_set_rate()
178 return -EINVAL; in tegra210_clk_emc_set_rate()
190 clk = tegra210_clk_emc_find_parent(emc, index); in tegra210_clk_emc_set_rate()
199 if (clk_get_rate(clk) != config->parent_rate) { in tegra210_clk_emc_set_rate()
200 err = clk_set_rate(clk, config->parent_rate); in tegra210_clk_emc_set_rate()
203 config->parent_rate, clk, err); in tegra210_clk_emc_set_rate()
218 /* update the EMC source configuration to reflect the new parent */ in tegra210_clk_emc_set_rate()
219 config->value &= ~CLK_SOURCE_EMC_2X_CLK_SRC; in tegra210_clk_emc_set_rate()
220 config->value |= FIELD_PREP(CLK_SOURCE_EMC_2X_CLK_SRC, index); in tegra210_clk_emc_set_rate()
223 * Finally, switch the EMC programming with both old and new parent in tegra210_clk_emc_set_rate()
226 err = provider->set_rate(dev, config); in tegra210_clk_emc_set_rate()
228 dev_err(dev, "failed to set EMC rate to %lu Hz: %d\n", rate, in tegra210_clk_emc_set_rate()
232 * If we're unable to switch to the new EMC frequency, we no in tegra210_clk_emc_set_rate()
243 clk = tegra210_clk_emc_find_parent(emc, old_idx); in tegra210_clk_emc_set_rate()
269 struct tegra210_clk_emc *emc; in tegra210_clk_register_emc() local
273 emc = kzalloc(sizeof(*emc), GFP_KERNEL); in tegra210_clk_register_emc()
274 if (!emc) in tegra210_clk_register_emc()
275 return ERR_PTR(-ENOMEM); in tegra210_clk_register_emc()
277 emc->regs = regs; in tegra210_clk_register_emc()
279 init.name = "emc"; in tegra210_clk_register_emc()
284 emc->hw.init = &init; in tegra210_clk_register_emc()
286 clk = clk_register(NULL, &emc->hw); in tegra210_clk_register_emc()
288 kfree(emc); in tegra210_clk_register_emc()
299 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(hw); in tegra210_clk_emc_attach() local
300 struct device *dev = provider->dev; in tegra210_clk_emc_attach()
304 if (!try_module_get(provider->owner)) in tegra210_clk_emc_attach()
305 return -ENODEV; in tegra210_clk_emc_attach()
307 for (i = 0; i < provider->num_configs; i++) { in tegra210_clk_emc_attach()
308 struct tegra210_clk_emc_config *config = &provider->configs[i]; in tegra210_clk_emc_attach()
313 div = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_DIVISOR, config->value); in tegra210_clk_emc_attach()
314 src = FIELD_GET(CLK_SOURCE_EMC_2X_CLK_SRC, config->value); in tegra210_clk_emc_attach()
316 /* do basic sanity checking on the EMC timings */ in tegra210_clk_emc_attach()
319 div, config->rate); in tegra210_clk_emc_attach()
320 err = -EINVAL; in tegra210_clk_emc_attach()
324 same_freq = config->value & CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; in tegra210_clk_emc_attach()
326 if (same_freq != config->same_freq) { in tegra210_clk_emc_attach()
328 "ambiguous EMC to MC ratio for rate %lu Hz\n", in tegra210_clk_emc_attach()
329 config->rate); in tegra210_clk_emc_attach()
330 err = -EINVAL; in tegra210_clk_emc_attach()
335 config->parent = src; in tegra210_clk_emc_attach()
338 config->parent_rate = config->rate * (1 + div / 2); in tegra210_clk_emc_attach()
340 unsigned long rate = config->rate * (1 + div / 2); in tegra210_clk_emc_attach()
342 config->parent_rate = clk_hw_get_rate(parent); in tegra210_clk_emc_attach()
344 if (config->parent_rate != rate) { in tegra210_clk_emc_attach()
347 config->rate); in tegra210_clk_emc_attach()
348 err = -EINVAL; in tegra210_clk_emc_attach()
354 emc->provider = provider; in tegra210_clk_emc_attach()
359 module_put(provider->owner); in tegra210_clk_emc_attach()
366 struct tegra210_clk_emc *emc = to_tegra210_clk_emc(__clk_get_hw(clk)); in tegra210_clk_emc_detach() local
368 module_put(emc->provider->owner); in tegra210_clk_emc_detach()
369 emc->provider = NULL; in tegra210_clk_emc_detach()