diff options
Diffstat (limited to 'drivers/memory/tegra/mc.c')
| -rw-r--r-- | drivers/memory/tegra/mc.c | 130 |
1 files changed, 76 insertions, 54 deletions
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 592907546ee6..6edb210287dc 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2014-2025 NVIDIA CORPORATION. All rights reserved. */ #include <linux/clk.h> @@ -11,10 +11,11 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/sort.h> +#include <linux/tegra-icc.h> #include <soc/tegra/fuse.h> @@ -48,6 +49,9 @@ static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_234_SOC { .compatible = "nvidia,tegra234-mc", .data = &tegra234_mc_soc }, #endif +#ifdef CONFIG_ARCH_TEGRA_264_SOC + { .compatible = "nvidia,tegra264-mc", .data = &tegra264_mc_soc }, +#endif { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tegra_mc_of_match); @@ -449,7 +453,6 @@ static int load_one_timing(struct tegra_mc *mc, static int load_timings(struct tegra_mc *mc, struct device_node *node) { - struct device_node *child; struct tegra_mc_timing *timing; int child_count = of_get_child_count(node); int i = 0, err; @@ -461,14 +464,12 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) mc->num_timings = child_count; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { timing = &mc->timings[i++]; err = load_one_timing(mc, timing, child); - if (err) { - of_node_put(child); + if (err) return err; - } } return 0; @@ -476,7 +477,6 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) static int tegra_mc_setup_timings(struct tegra_mc *mc) { - struct device_node *node; u32 ram_code, node_ram_code; int err; @@ -484,14 +484,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) mc->num_timings = 0; - for_each_child_of_node(mc->dev->of_node, node) { + for_each_child_of_node_scoped(mc->dev->of_node, node) { err = of_property_read_u32(node, "nvidia,ram-code", &node_ram_code); if (err || (node_ram_code != ram_code)) continue; err = load_timings(mc, node); - of_node_put(node); if (err) return err; break; @@ -754,6 +753,43 @@ const char *const tegra_mc_error_names[8] = { [6] = "SMMU translation error", }; +struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *data) +{ + struct tegra_mc *mc = icc_provider_to_tegra_mc(data); + struct icc_node *node; + + list_for_each_entry(node, &mc->provider.nodes, node_list) { + if (node->id == spec->args[0]) + return node; + } + + /* + * If a client driver calls devm_of_icc_get() before the MC driver + * is probed, then return EPROBE_DEFER to the client driver. + */ + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra_mc_icc_get(struct icc_node *node, u32 *average, u32 *peak) +{ + *average = 0; + *peak = 0; + + return 0; +} + +static int tegra_mc_icc_set(struct icc_node *src, struct icc_node *dst) +{ + return 0; +} + +const struct tegra_mc_icc_ops tegra_mc_icc_ops = { + .xlate = tegra_mc_icc_xlate, + .aggregate = icc_std_aggregate, + .get_bw = tegra_mc_icc_get, + .set = tegra_mc_icc_set, +}; + /* * Memory Controller (MC) has few Memory Clients that are issuing memory * bandwidth allocation requests to the MC interconnect provider. The MC @@ -792,18 +828,16 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc) mc->provider.data = &mc->provider; mc->provider.set = mc->soc->icc_ops->set; mc->provider.aggregate = mc->soc->icc_ops->aggregate; + mc->provider.get_bw = mc->soc->icc_ops->get_bw; + mc->provider.xlate = mc->soc->icc_ops->xlate; mc->provider.xlate_extended = mc->soc->icc_ops->xlate_extended; - err = icc_provider_add(&mc->provider); - if (err) - return err; + icc_provider_init(&mc->provider); /* create Memory Controller node */ node = icc_node_create(TEGRA_ICC_MC); - if (IS_ERR(node)) { - err = PTR_ERR(node); - goto del_provider; - } + if (IS_ERR(node)) + return PTR_ERR(node); node->name = "Memory Controller"; icc_node_add(node, &mc->provider); @@ -828,18 +862,39 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc) err = icc_link_create(node, TEGRA_ICC_MC); if (err) goto remove_nodes; + + node->data = (struct tegra_mc_client *)&(mc->soc->clients[i]); } + err = icc_provider_register(&mc->provider); + if (err) + goto remove_nodes; + return 0; remove_nodes: icc_nodes_remove(&mc->provider); -del_provider: - icc_provider_del(&mc->provider); return err; } +static void tegra_mc_num_channel_enabled(struct tegra_mc *mc) +{ + unsigned int i; + u32 value; + + value = mc_ch_readl(mc, 0, MC_EMEM_ADR_CFG_CHANNEL_ENABLE); + if (value <= 0) { + mc->num_channels = mc->soc->num_channels; + return; + } + + for (i = 0; i < 32; i++) { + if (value & BIT(i)) + mc->num_channels++; + } +} + static int tegra_mc_probe(struct platform_device *pdev) { struct tegra_mc *mc; @@ -878,6 +933,8 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } + tegra_mc_num_channel_enabled(mc); + if (mc->soc->ops && mc->soc->ops->handle_irq) { mc->irq = platform_get_irq(pdev, 0); if (mc->irq < 0) @@ -920,35 +977,6 @@ static int tegra_mc_probe(struct platform_device *pdev) } } - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { - mc->gart = tegra_gart_probe(&pdev->dev, mc); - if (IS_ERR(mc->gart)) { - dev_err(&pdev->dev, "failed to probe GART: %ld\n", - PTR_ERR(mc->gart)); - mc->gart = NULL; - } - } - - return 0; -} - -static int __maybe_unused tegra_mc_suspend(struct device *dev) -{ - struct tegra_mc *mc = dev_get_drvdata(dev); - - if (mc->soc->ops && mc->soc->ops->suspend) - return mc->soc->ops->suspend(mc); - - return 0; -} - -static int __maybe_unused tegra_mc_resume(struct device *dev) -{ - struct tegra_mc *mc = dev_get_drvdata(dev); - - if (mc->soc->ops && mc->soc->ops->resume) - return mc->soc->ops->resume(mc); - return 0; } @@ -961,15 +989,10 @@ static void tegra_mc_sync_state(struct device *dev) icc_sync_state(dev); } -static const struct dev_pm_ops tegra_mc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume) -}; - static struct platform_driver tegra_mc_driver = { .driver = { .name = "tegra-mc", .of_match_table = tegra_mc_of_match, - .pm = &tegra_mc_pm_ops, .suppress_bind_attrs = true, .sync_state = tegra_mc_sync_state, }, @@ -985,4 +1008,3 @@ arch_initcall(tegra_mc_init); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); -MODULE_LICENSE("GPL v2"); |
