Unverified Commit 095ee35a authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'tegra-for-6.5-memory' of...

Merge tag 'tegra-for-6.5-memory' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into soc/drivers

memory: tegra: Changes for v6.5-rc1

This introduces an interconnect provider for the memory controller and
external memory controller found on Tegra234 chips that will eventually
be used to dynamically scale the EMC frequency based on a device's
bandwidth needs.

* tag 'tegra-for-6.5-memory' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  memory: tegra: Make CPU cluster BW request a multiple of MC channels
  memory: tegra: Add software memory clients in Tegra234
  memory: tegra: Add memory clients for Tegra234
  memory: tegra: Add interconnect support for DRAM scaling in Tegra234
  dt-bindings: tegra: Add ICC IDs for dummy memory clients
  dt-bindings: tegra: Document compatible for IGX

Link: https://lore.kernel.org/r/20230609193620.2275240-4-thierry.reding@gmail.com


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents b161ec3d e852af72
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -167,6 +167,11 @@ properties:
          - const: nvidia,p3737-0000+p3701-0000
          - const: nvidia,p3701-0000
          - const: nvidia,tegra234
      - description: NVIDIA IGX Orin Development Kit
        items:
          - const: nvidia,p3740-0002+p3701-0008
          - const: nvidia,p3701-0008
          - const: nvidia,tegra234
      - description: Jetson Orin NX
        items:
          - const: nvidia,p3767-0000
+24 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/tegra-icc.h>

#include <soc/tegra/fuse.h>

@@ -792,6 +793,8 @@ 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;

	icc_provider_init(&mc->provider);
@@ -824,6 +827,8 @@ 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);
@@ -838,6 +843,23 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
	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;
@@ -876,6 +898,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)
+1 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@
#define MC_ERR_ROUTE_SANITY_ADR				0x9c4
#define MC_ERR_GENERALIZED_CARVEOUT_STATUS		0xc00
#define MC_ERR_GENERALIZED_CARVEOUT_ADR			0xc04
#define MC_EMEM_ADR_CFG_CHANNEL_ENABLE			0xdf8
#define MC_GLOBAL_INTSTATUS				0xf24
#define MC_ERR_ADR_HI					0x11fc

+133 −0
Original line number Diff line number Diff line
@@ -7,9 +7,11 @@
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>

#include <soc/tegra/bpmp.h>
#include "mc.h"

struct tegra186_emc_dvfs {
	unsigned long latency;
@@ -29,8 +31,15 @@ struct tegra186_emc {
		unsigned long min_rate;
		unsigned long max_rate;
	} debugfs;

	struct icc_provider provider;
};

static inline struct tegra186_emc *to_tegra186_emc(struct icc_provider *provider)
{
	return container_of(provider, struct tegra186_emc, provider);
}

/*
 * debugfs interface
 *
@@ -146,8 +155,102 @@ DEFINE_DEBUGFS_ATTRIBUTE(tegra186_emc_debug_max_rate_fops,
			  tegra186_emc_debug_max_rate_get,
			  tegra186_emc_debug_max_rate_set, "%llu\n");

/*
 * tegra_emc_icc_set_bw() - Set BW api for EMC provider
 * @src: ICC node for External Memory Controller (EMC)
 * @dst: ICC node for External Memory (DRAM)
 *
 * Do nothing here as info to BPMP-FW is now passed in the BW set function
 * of the MC driver. BPMP-FW sets the final Freq based on the passed values.
 */
static int tegra_emc_icc_set_bw(struct icc_node *src, struct icc_node *dst)
{
	return 0;
}

static struct icc_node *
tegra_emc_of_icc_xlate(struct of_phandle_args *spec, void *data)
{
	struct icc_provider *provider = data;
	struct icc_node *node;

	/* External Memory is the only possible ICC route */
	list_for_each_entry(node, &provider->nodes, node_list) {
		if (node->id != TEGRA_ICC_EMEM)
			continue;

		return node;
	}

	return ERR_PTR(-EPROBE_DEFER);
}

static int tegra_emc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *peak)
{
	*avg = 0;
	*peak = 0;

	return 0;
}

static int tegra_emc_interconnect_init(struct tegra186_emc *emc)
{
	struct tegra_mc *mc = dev_get_drvdata(emc->dev->parent);
	const struct tegra_mc_soc *soc = mc->soc;
	struct icc_node *node;
	int err;

	emc->provider.dev = emc->dev;
	emc->provider.set = tegra_emc_icc_set_bw;
	emc->provider.data = &emc->provider;
	emc->provider.aggregate = soc->icc_ops->aggregate;
	emc->provider.xlate = tegra_emc_of_icc_xlate;
	emc->provider.get_bw = tegra_emc_icc_get_init_bw;

	icc_provider_init(&emc->provider);

	/* create External Memory Controller node */
	node = icc_node_create(TEGRA_ICC_EMC);
	if (IS_ERR(node)) {
		err = PTR_ERR(node);
		goto err_msg;
	}

	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);
	if (err)
		goto remove_nodes;

	/* create External Memory node */
	node = icc_node_create(TEGRA_ICC_EMEM);
	if (IS_ERR(node)) {
		err = PTR_ERR(node);
		goto remove_nodes;
	}

	node->name = "External Memory (DRAM)";
	icc_node_add(node, &emc->provider);

	err = icc_provider_register(&emc->provider);
	if (err)
		goto remove_nodes;

	return 0;

remove_nodes:
	icc_nodes_remove(&emc->provider);
err_msg:
	dev_err(emc->dev, "failed to initialize ICC: %d\n", err);

	return err;
}

static int tegra186_emc_probe(struct platform_device *pdev)
{
	struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent);
	struct mrq_emc_dvfs_latency_response response;
	struct tegra_bpmp_message msg;
	struct tegra186_emc *emc;
@@ -236,6 +339,32 @@ static int tegra186_emc_probe(struct platform_device *pdev)
	debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
			    emc, &tegra186_emc_debug_max_rate_fops);

	if (mc && mc->soc->icc_ops) {
		if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_BWMGR_INT)) {
			mc->bwmgr_mrq_supported = true;

			/*
			 * MC driver probe can't get BPMP reference as it gets probed
			 * earlier than BPMP. So, save the BPMP ref got from the EMC
			 * DT node in the mc->bpmp and use it in MC's icc_set hook.
			 */
			mc->bpmp = emc->bpmp;
			barrier();
		}

		/*
		 * Initialize the ICC even if BPMP-FW doesn't support 'MRQ_BWMGR_INT'.
		 * Use the flag 'mc->bwmgr_mrq_supported' within MC driver and return
		 * EINVAL instead of passing the request to BPMP-FW later when the BW
		 * request is made by client with 'icc_set_bw()' call.
		 */
		err = tegra_emc_interconnect_init(emc);
		if (err) {
			mc->bpmp = NULL;
			goto put_bpmp;
		}
	}

	return 0;

put_bpmp:
@@ -245,9 +374,12 @@ static int tegra186_emc_probe(struct platform_device *pdev)

static int tegra186_emc_remove(struct platform_device *pdev)
{
	struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent);
	struct tegra186_emc *emc = platform_get_drvdata(pdev);

	debugfs_remove_recursive(emc->debugfs.root);

	mc->bpmp = NULL;
	tegra_bpmp_put(emc->bpmp);

	return 0;
@@ -272,6 +404,7 @@ static struct platform_driver tegra186_emc_driver = {
		.name = "tegra186-emc",
		.of_match_table = tegra186_emc_of_match,
		.suppress_bind_attrs = true,
		.sync_state = icc_sync_state,
	},
	.probe = tegra186_emc_probe,
	.remove = tegra186_emc_remove,
+594 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
 * Copyright (C) 2022-2023, NVIDIA CORPORATION.  All rights reserved.
 */

#include <soc/tegra/mc.h>

#include <dt-bindings/memory/tegra234-mc.h>
#include <linux/interconnect.h>
#include <linux/tegra-icc.h>

#include <soc/tegra/bpmp.h>
#include "mc.h"

static const struct tegra_mc_client tegra234_mc_clients[] = {
	{
		.id = TEGRA234_MEMORY_CLIENT_HDAR,
		.name = "hdar",
		.bpmp_id = TEGRA_ICC_BPMP_HDA,
		.type = TEGRA_ICC_ISO_AUDIO,
		.sid = TEGRA234_SID_HDA,
		.regs = {
			.sid = {
				.override = 0xa8,
				.security = 0xac,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_HDAW,
		.name = "hdaw",
		.bpmp_id = TEGRA_ICC_BPMP_HDA,
		.type = TEGRA_ICC_ISO_AUDIO,
		.sid = TEGRA234_SID_HDA,
		.regs = {
			.sid = {
				.override = 0x1a8,
				.security = 0x1ac,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBEARD,
		.name = "mgbeard",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE,
		.regs = {
			.sid = {
@@ -23,6 +52,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBEBRD,
		.name = "mgbebrd",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE_VF1,
		.regs = {
			.sid = {
@@ -33,6 +64,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBECRD,
		.name = "mgbecrd",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE_VF2,
		.regs = {
			.sid = {
@@ -43,6 +76,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBEDRD,
		.name = "mgbedrd",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE_VF3,
		.regs = {
			.sid = {
@@ -52,6 +87,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBEAWR,
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.name = "mgbeawr",
		.sid = TEGRA234_SID_MGBE,
		.regs = {
@@ -63,6 +100,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBEBWR,
		.name = "mgbebwr",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE_VF1,
		.regs = {
			.sid = {
@@ -73,6 +112,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBECWR,
		.name = "mgbecwr",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE_VF2,
		.regs = {
			.sid = {
@@ -83,6 +124,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_SDMMCRAB,
		.name = "sdmmcrab",
		.bpmp_id = TEGRA_ICC_BPMP_SDMMC_4,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_SDMMC4,
		.regs = {
			.sid = {
@@ -93,6 +136,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_MGBEDWR,
		.name = "mgbedwr",
		.bpmp_id = TEGRA_ICC_BPMP_EQOS,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_MGBE_VF3,
		.regs = {
			.sid = {
@@ -103,6 +148,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_SDMMCWAB,
		.name = "sdmmcwab",
		.bpmp_id = TEGRA_ICC_BPMP_SDMMC_4,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_SDMMC4,
		.regs = {
			.sid = {
@@ -110,6 +157,90 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
				.security = 0x33c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_VI2W,
		.name = "vi2w",
		.bpmp_id = TEGRA_ICC_BPMP_VI2,
		.type = TEGRA_ICC_ISO_VI,
		.sid = TEGRA234_SID_ISO_VI2,
		.regs = {
			.sid = {
				.override = 0x380,
				.security = 0x384,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_VI2FALR,
		.name = "vi2falr",
		.bpmp_id = TEGRA_ICC_BPMP_VI2FAL,
		.type = TEGRA_ICC_ISO_VIFAL,
		.sid = TEGRA234_SID_ISO_VI2FALC,
		.regs = {
			.sid = {
				.override = 0x388,
				.security = 0x38c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_VI2FALW,
		.name = "vi2falw",
		.bpmp_id = TEGRA_ICC_BPMP_VI2FAL,
		.type = TEGRA_ICC_ISO_VIFAL,
		.sid = TEGRA234_SID_ISO_VI2FALC,
		.regs = {
			.sid = {
				.override = 0x3e0,
				.security = 0x3e4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_APER,
		.name = "aper",
		.bpmp_id = TEGRA_ICC_BPMP_APE,
		.type = TEGRA_ICC_ISO_AUDIO,
		.sid = TEGRA234_SID_APE,
		.regs = {
			.sid = {
				.override = 0x3d0,
				.security = 0x3d4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_APEW,
		.name = "apew",
		.bpmp_id = TEGRA_ICC_BPMP_APE,
		.type = TEGRA_ICC_ISO_AUDIO,
		.sid = TEGRA234_SID_APE,
		.regs = {
			.sid = {
				.override = 0x3d8,
				.security = 0x3dc,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR,
		.name = "nvdisplayr",
		.bpmp_id = TEGRA_ICC_BPMP_DISPLAY,
		.type = TEGRA_ICC_ISO_DISPLAY,
		.sid = TEGRA234_SID_ISO_NVDISPLAY,
		.regs = {
			.sid = {
				.override = 0x490,
				.security = 0x494,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR1,
		.name = "nvdisplayr1",
		.bpmp_id = TEGRA_ICC_BPMP_DISPLAY,
		.type = TEGRA_ICC_ISO_DISPLAY,
		.sid = TEGRA234_SID_ISO_NVDISPLAY,
		.regs = {
			.sid = {
				.override = 0x508,
				.security = 0x50c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_BPMPR,
		.name = "bpmpr",
@@ -153,6 +284,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_APEDMAR,
		.name = "apedmar",
		.bpmp_id = TEGRA_ICC_BPMP_APEDMA,
		.type = TEGRA_ICC_ISO_AUDIO,
		.sid = TEGRA234_SID_APE,
		.regs = {
			.sid = {
@@ -163,6 +296,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
	}, {
		.id = TEGRA234_MEMORY_CLIENT_APEDMAW,
		.name = "apedmaw",
		.bpmp_id = TEGRA_ICC_BPMP_APEDMA,
		.type = TEGRA_ICC_ISO_AUDIO,
		.sid = TEGRA234_SID_APE,
		.regs = {
			.sid = {
@@ -330,7 +465,464 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
				.security = 0x37c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE0R,
		.name = "pcie0r",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_0,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE0,
		.regs = {
			.sid = {
				.override = 0x6c0,
				.security = 0x6c4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE0W,
		.name = "pcie0w",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_0,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE0,
		.regs = {
			.sid = {
				.override = 0x6c8,
				.security = 0x6cc,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE1R,
		.name = "pcie1r",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_1,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE1,
		.regs = {
			.sid = {
				.override = 0x6d0,
				.security = 0x6d4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE1W,
		.name = "pcie1w",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_1,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE1,
		.regs = {
			.sid = {
				.override = 0x6d8,
				.security = 0x6dc,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE2AR,
		.name = "pcie2ar",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_2,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE2,
		.regs = {
			.sid = {
				.override = 0x6e0,
				.security = 0x6e4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE2AW,
		.name = "pcie2aw",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_2,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE2,
		.regs = {
			.sid = {
				.override = 0x6e8,
				.security = 0x6ec,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE3R,
		.name = "pcie3r",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_3,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE3,
		.regs = {
			.sid = {
				.override = 0x6f0,
				.security = 0x6f4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE3W,
		.name = "pcie3w",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_3,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE3,
		.regs = {
			.sid = {
				.override = 0x6f8,
				.security = 0x6fc,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE4R,
		.name = "pcie4r",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_4,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE4,
		.regs = {
			.sid = {
				.override = 0x700,
				.security = 0x704,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE4W,
		.name = "pcie4w",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_4,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE4,
		.regs = {
			.sid = {
				.override = 0x708,
				.security = 0x70c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE5R,
		.name = "pcie5r",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_5,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE5,
		.regs = {
			.sid = {
				.override = 0x710,
				.security = 0x714,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE5W,
		.name = "pcie5w",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_5,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE5,
		.regs = {
			.sid = {
				.override = 0x718,
				.security = 0x71c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE5R1,
		.name = "pcie5r1",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_5,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE5,
		.regs = {
			.sid = {
				.override = 0x778,
				.security = 0x77c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE6AR,
		.name = "pcie6ar",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_6,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE6,
		.regs = {
			.sid = {
				.override = 0x140,
				.security = 0x144,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE6AW,
		.name = "pcie6aw",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_6,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE6,
		.regs = {
			.sid = {
				.override = 0x148,
				.security = 0x14c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE6AR1,
		.name = "pcie6ar1",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_6,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE6,
		.regs = {
			.sid = {
				.override = 0x1e8,
				.security = 0x1ec,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE7AR,
		.name = "pcie7ar",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_7,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE7,
		.regs = {
			.sid = {
				.override = 0x150,
				.security = 0x154,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE7AW,
		.name = "pcie7aw",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_7,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE7,
		.regs = {
			.sid = {
				.override = 0x180,
				.security = 0x184,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE7AR1,
		.name = "pcie7ar1",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_7,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE7,
		.regs = {
			.sid = {
				.override = 0x248,
				.security = 0x24c,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE8AR,
		.name = "pcie8ar",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_8,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE8,
		.regs = {
			.sid = {
				.override = 0x190,
				.security = 0x194,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE8AW,
		.name = "pcie8aw",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_8,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE8,
		.regs = {
			.sid = {
				.override = 0x1d8,
				.security = 0x1dc,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE9AR,
		.name = "pcie9ar",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_9,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE9,
		.regs = {
			.sid = {
				.override = 0x1e0,
				.security = 0x1e4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE9AW,
		.name = "pcie9aw",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_9,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE9,
		.regs = {
			.sid = {
				.override = 0x1f0,
				.security = 0x1f4,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE10AR,
		.name = "pcie10ar",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_10,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE10,
		.regs = {
			.sid = {
				.override = 0x1f8,
				.security = 0x1fc,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE10AW,
		.name = "pcie10aw",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_10,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE10,
		.regs = {
			.sid = {
				.override = 0x200,
				.security = 0x204,
			},
		},
	}, {
		.id = TEGRA234_MEMORY_CLIENT_PCIE10AR1,
		.name = "pcie10ar1",
		.bpmp_id = TEGRA_ICC_BPMP_PCIE_10,
		.type = TEGRA_ICC_NISO,
		.sid = TEGRA234_SID_PCIE10,
		.regs = {
			.sid = {
				.override = 0x240,
				.security = 0x244,
			},
		},
	}, {
		.id = TEGRA_ICC_MC_CPU_CLUSTER0,
		.name = "sw_cluster0",
		.bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER0,
		.type = TEGRA_ICC_NISO,
	}, {
		.id = TEGRA_ICC_MC_CPU_CLUSTER1,
		.name = "sw_cluster1",
		.bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER1,
		.type = TEGRA_ICC_NISO,
	}, {
		.id = TEGRA_ICC_MC_CPU_CLUSTER2,
		.name = "sw_cluster2",
		.bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER2,
		.type = TEGRA_ICC_NISO,
	},
};

/*
 * tegra234_mc_icc_set() - Pass MC client info to the BPMP-FW
 * @src: ICC node for Memory Controller's (MC) Client
 * @dst: ICC node for Memory Controller (MC)
 *
 * Passing the current request info from the MC to the BPMP-FW where
 * LA and PTSA registers are accessed and the final EMC freq is set
 * based on client_id, type, latency and bandwidth.
 * icc_set_bw() makes set_bw calls for both MC and EMC providers in
 * sequence. Both the calls are protected by 'mutex_lock(&icc_lock)'.
 * So, the data passed won't be updated by concurrent set calls from
 * other clients.
 */
static int tegra234_mc_icc_set(struct icc_node *src, struct icc_node *dst)
{
	struct tegra_mc *mc = icc_provider_to_tegra_mc(dst->provider);
	struct mrq_bwmgr_int_request bwmgr_req = { 0 };
	struct mrq_bwmgr_int_response bwmgr_resp = { 0 };
	const struct tegra_mc_client *pclient = src->data;
	struct tegra_bpmp_message msg;
	int ret;

	/*
	 * Same Src and Dst node will happen during boot from icc_node_add().
	 * This can be used to pre-initialize and set bandwidth for all clients
	 * before their drivers are loaded. We are skipping this case as for us,
	 * the pre-initialization already happened in Bootloader(MB2) and BPMP-FW.
	 */
	if (src->id == dst->id)
		return 0;

	if (!mc->bwmgr_mrq_supported)
		return -EINVAL;

	if (!mc->bpmp) {
		dev_err(mc->dev, "BPMP reference NULL\n");
		return -ENOENT;
	}

	if (pclient->type == TEGRA_ICC_NISO)
		bwmgr_req.bwmgr_calc_set_req.niso_bw = src->avg_bw;
	else
		bwmgr_req.bwmgr_calc_set_req.iso_bw = src->avg_bw;

	bwmgr_req.bwmgr_calc_set_req.client_id = pclient->bpmp_id;

	bwmgr_req.cmd = CMD_BWMGR_INT_CALC_AND_SET;
	bwmgr_req.bwmgr_calc_set_req.mc_floor = src->peak_bw;
	bwmgr_req.bwmgr_calc_set_req.floor_unit = BWMGR_INT_UNIT_KBPS;

	memset(&msg, 0, sizeof(msg));
	msg.mrq = MRQ_BWMGR_INT;
	msg.tx.data = &bwmgr_req;
	msg.tx.size = sizeof(bwmgr_req);
	msg.rx.data = &bwmgr_resp;
	msg.rx.size = sizeof(bwmgr_resp);

	ret = tegra_bpmp_transfer(mc->bpmp, &msg);
	if (ret < 0) {
		dev_err(mc->dev, "BPMP transfer failed: %d\n", ret);
		goto error;
	}
	if (msg.rx.ret < 0) {
		pr_err("failed to set bandwidth for %u: %d\n",
		       bwmgr_req.bwmgr_calc_set_req.client_id, msg.rx.ret);
		ret = -EINVAL;
	}

error:
	return ret;
}

static int tegra234_mc_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
				     u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
{
	struct icc_provider *p = node->provider;
	struct tegra_mc *mc = icc_provider_to_tegra_mc(p);

	if (!mc->bwmgr_mrq_supported)
		return -EINVAL;

	if (node->id == TEGRA_ICC_MC_CPU_CLUSTER0 ||
	    node->id == TEGRA_ICC_MC_CPU_CLUSTER1 ||
	    node->id == TEGRA_ICC_MC_CPU_CLUSTER2) {
		if (mc)
			peak_bw = peak_bw * mc->num_channels;
	}

	*agg_avg += avg_bw;
	*agg_peak = max(*agg_peak, peak_bw);

	return 0;
}

static struct icc_node*
tegra234_mc_of_icc_xlate(struct of_phandle_args *spec, void *data)
{
	struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
	unsigned int cl_id = spec->args[0];
	struct icc_node *node;

	list_for_each_entry(node, &mc->provider.nodes, node_list) {
		if (node->id != cl_id)
			continue;

		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 tegra234_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *peak)
{
	*avg = 0;
	*peak = 0;

	return 0;
}

static const struct tegra_mc_icc_ops tegra234_mc_icc_ops = {
	.xlate = tegra234_mc_of_icc_xlate,
	.aggregate = tegra234_mc_icc_aggregate,
	.get_bw = tegra234_mc_icc_get_init_bw,
	.set = tegra234_mc_icc_set,
};

const struct tegra_mc_soc tegra234_mc_soc = {
@@ -345,6 +937,7 @@ const struct tegra_mc_soc tegra234_mc_soc = {
		   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
	.has_addr_hi_reg = true,
	.ops = &tegra186_mc_ops,
	.icc_ops = &tegra234_mc_icc_ops,
	.ch_intmask = 0x0000ff00,
	.global_intstatus_channel_shift = 8,
	/*
Loading