// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/tegra-icc.h>
#include <soc/tegra/fuse.h>
#include "mc.h"
static const struct of_device_id tegra_mc_of_match[] = {
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
{ .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_114_SOC
{ .compatible = "nvidia,tegra114-mc", .data = &tegra114_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_124_SOC
{ .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_132_SOC
{ .compatible = "nvidia,tegra132-mc", .data = &tegra132_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_210_SOC
{ .compatible = "nvidia,tegra210-mc", .data = &tegra210_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_186_SOC
{ .compatible = "nvidia,tegra186-mc", .data = &tegra186_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_194_SOC
{ .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_234_SOC
{ .compatible = "nvidia,tegra234-mc", .data = &tegra234_mc_soc },
#endif
#ifdef CONFIG_ARCH_TEGRA_238_SOC
{ .compatible = "nvidia,tegra238-mc", .data = &tegra238_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);
const struct tegra_mc_regs tegra20_mc_regs = {
.cfg_channel_enable = 0xdf8,
.err_status = 0x08,
.err_add = 0x0c,
.err_add_hi = 0x11fc,
.err_vpr_status = 0x654,
.err_vpr_add = 0x658,
.err_sec_status = 0x67c,
.err_sec_add = 0x680,
.err_mts_status = 0x9b0,
.err_mts_add = 0x9b4,
.err_gen_co_status = 0xc00,
.err_gen_co_add = 0xc04,
.err_route_status = 0x9c0,
.err_route_add = 0x9c4,
};
static void tegra_mc_devm_action_put_device(void *data)
{
struct tegra_mc *mc = data;
put_device(mc->dev);
}
/**
* devm_tegra_memory_controller_get() - get Tegra Memory Controller handle
* @dev: device pointer for the consumer device
*
* This function will search for the Memory Controller node in a device-tree
* and retrieve the Memory Controller handle.
*
* Return: ERR_PTR() on error or a valid pointer to a struct tegra_mc.
*/
struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev)
{
struct platform_device *pdev;
struct device_node *np;
struct tegra_mc *mc;
int err;
np = of_parse_phandle(dev->of_node, "nvidia,memory-controller", 0);
if (!np)
return ERR_PTR(-ENOENT);
pdev = of_find_device_by_node(np);
of_node_put(np);
if (!pdev)
return ERR_PTR(-ENODEV);
mc = platform_get_drvdata(pdev);
if (!mc) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
err = devm_add_action_or_reset(dev, tegra_mc_devm_action_put_device, mc);
if (err)
return ERR_PTR(err);
return mc;
}
EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get);
int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev)
{
if (mc->soc->ops && mc->soc->ops->probe_device)
return mc->soc->