summaryrefslogtreecommitdiff
path: root/drivers/memory/tegra/tegra186-emc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/memory/tegra/tegra186-emc.c')
-rw-r--r--drivers/memory/tegra/tegra186-emc.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index 2a4cb64c4c4c..c9583b66f18d 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -3,15 +3,21 @@
* Copyright (C) 2019-2025 NVIDIA CORPORATION. All rights reserved.
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
+#include <linux/fs.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <soc/tegra/bpmp.h>
#include "mc.h"
+static DEFINE_MUTEX(tegra_emc_debugfs_root_lock);
+static struct dentry *tegra_emc_debugfs_root;
+
struct tegra186_emc_dvfs {
unsigned long latency;
unsigned long rate;
@@ -206,7 +212,17 @@ static int tegra186_emc_get_emc_dvfs_latency(struct tegra186_emc *emc)
return err;
}
- emc->debugfs.root = debugfs_create_dir("emc", NULL);
+ scoped_guard(mutex, &tegra_emc_debugfs_root_lock) {
+ if (!tegra_emc_debugfs_root)
+ tegra_emc_debugfs_root = debugfs_create_dir("emc", NULL);
+
+ if (dev_to_node(emc->dev) == NUMA_NO_NODE)
+ emc->debugfs.root = tegra_emc_debugfs_root;
+ else
+ emc->debugfs.root = debugfs_create_dir(dev_name(emc->dev),
+ tegra_emc_debugfs_root);
+ }
+
debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc,
&tegra186_emc_debug_available_rates_fops);
debugfs_create_file("min_rate", 0644, emc->debugfs.root, emc,
@@ -238,7 +254,7 @@ tegra186_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data)
/* External Memory is the only possible ICC route */
list_for_each_entry(node, &provider->nodes, node_list) {
- if (node->id != TEGRA_ICC_EMEM)
+ if (tegra_mc_client_id_from_node(node) != TEGRA_ICC_EMEM)
continue;
return node;
@@ -257,6 +273,7 @@ static int tegra186_emc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pe
static int tegra186_emc_interconnect_init(struct tegra186_emc *emc)
{
+ int node_id = dev_to_node(emc->dev->parent);
struct icc_node *node;
int err;
@@ -270,26 +287,36 @@ static int tegra186_emc_interconnect_init(struct tegra186_emc *emc)
icc_provider_init(&emc->provider);
/* create External Memory Controller node */
- node = icc_node_create(TEGRA_ICC_EMC);
- if (IS_ERR(node))
- return PTR_ERR(node);
+ node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMC);
+ if (IS_ERR(node)) {
+ err = PTR_ERR(node);
+ goto remove_nodes;
+ }
+
+ if (node_id == NUMA_NO_NODE)
+ node->name = "External Memory Controller";
+ else
+ node->name = dev_name(emc->dev);
- node->name = "External Memory Controller";
icc_node_add(node, &emc->provider);
/* link External Memory Controller to External Memory (DRAM) */
- err = icc_link_create(node, TEGRA_ICC_EMEM);
+ err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_EMEM);
if (err)
goto remove_nodes;
/* create External Memory node */
- node = icc_node_create(TEGRA_ICC_EMEM);
+ node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMEM);
if (IS_ERR(node)) {
err = PTR_ERR(node);
goto remove_nodes;
}
- node->name = "External Memory (DRAM)";
+ if (node_id == NUMA_NO_NODE)
+ node->name = "External Memory (DRAM)";
+ else
+ node->name = devm_kasprintf(emc->dev, GFP_KERNEL, "%d-dram", node_id);
+
icc_node_add(node, &emc->provider);
err = icc_provider_register(&emc->provider);
@@ -382,6 +409,16 @@ static void tegra186_emc_remove(struct platform_device *pdev)
debugfs_remove_recursive(emc->debugfs.root);
+ scoped_guard(mutex, &tegra_emc_debugfs_root_lock) {
+ if (emc->debugfs.root == tegra_emc_debugfs_root) {
+ tegra_emc_debugfs_root = NULL;
+ } else if (tegra_emc_debugfs_root &&
+ simple_empty(tegra_emc_debugfs_root)) {
+ debugfs_remove(tegra_emc_debugfs_root);
+ tegra_emc_debugfs_root = NULL;
+ }
+ }
+
mc->bpmp = NULL;
tegra_bpmp_put(emc->bpmp);
}