summaryrefslogtreecommitdiff
path: root/drivers/memory/tegra
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/memory/tegra')
-rw-r--r--drivers/memory/tegra/mc.c135
-rw-r--r--drivers/memory/tegra/mc.h153
-rw-r--r--drivers/memory/tegra/tegra114.c18
-rw-r--r--drivers/memory/tegra/tegra124-emc.c2
-rw-r--r--drivers/memory/tegra/tegra124.c40
-rw-r--r--drivers/memory/tegra/tegra186-emc.c8
-rw-r--r--drivers/memory/tegra/tegra186.c22
-rw-r--r--drivers/memory/tegra/tegra194.c22
-rw-r--r--drivers/memory/tegra/tegra20.c31
-rw-r--r--drivers/memory/tegra/tegra210.c21
-rw-r--r--drivers/memory/tegra/tegra234.c22
-rw-r--r--drivers/memory/tegra/tegra264.c420
-rw-r--r--drivers/memory/tegra/tegra30-emc.c6
-rw-r--r--drivers/memory/tegra/tegra30.c18
14 files changed, 765 insertions, 153 deletions
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index 6edb210287dc..d620660da331 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-2025 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/clk.h>
@@ -56,6 +56,23 @@ static const struct of_device_id tegra_mc_of_match[] = {
};
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;
@@ -381,12 +398,16 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
}
EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count);
+const irq_handler_t tegra30_mc_irq_handlers[] = {
+ tegra30_mc_handle_irq
+};
+
#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
defined(CONFIG_ARCH_TEGRA_132_SOC) || \
defined(CONFIG_ARCH_TEGRA_210_SOC)
-static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
+static void tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
{
unsigned long long tick;
unsigned int i;
@@ -414,8 +435,6 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
/* latch new values */
mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
-
- return 0;
}
static int load_one_timing(struct tegra_mc *mc,
@@ -509,32 +528,24 @@ int tegra30_mc_probe(struct tegra_mc *mc)
int err;
mc->clk = devm_clk_get_optional(mc->dev, "mc");
- if (IS_ERR(mc->clk)) {
- dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk));
- return PTR_ERR(mc->clk);
- }
+ if (IS_ERR(mc->clk))
+ return dev_err_probe(mc->dev, PTR_ERR(mc->clk),
+ "failed to get MC clock\n");
/* ensure that debug features are disabled */
mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
- err = tegra_mc_setup_latency_allowance(mc);
- if (err < 0) {
- dev_err(mc->dev, "failed to setup latency allowance: %d\n", err);
- return err;
- }
+ tegra_mc_setup_latency_allowance(mc);
err = tegra_mc_setup_timings(mc);
- if (err < 0) {
- dev_err(mc->dev, "failed to setup timings: %d\n", err);
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(mc->dev, err, "failed to setup timings\n");
return 0;
}
const struct tegra_mc_ops tegra30_mc_ops = {
.probe = tegra30_mc_probe,
- .handle_irq = tegra30_mc_handle_irq,
};
#endif
@@ -575,9 +586,9 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
}
/* mask all interrupts to avoid flooding */
- status = mc_ch_readl(mc, channel, MC_INTSTATUS) & mc->soc->intmask;
+ status = mc_ch_readl(mc, channel, MC_INTSTATUS) & mc->soc->intmasks[0].mask;
} else {
- status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+ status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmasks[0].mask;
}
if (!status)
@@ -600,37 +611,37 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
switch (intmask) {
case MC_INT_DECERR_VPR:
- status_reg = MC_ERR_VPR_STATUS;
- addr_reg = MC_ERR_VPR_ADR;
+ status_reg = mc->soc->regs->err_vpr_status;
+ addr_reg = mc->soc->regs->err_vpr_add;
break;
case MC_INT_SECERR_SEC:
- status_reg = MC_ERR_SEC_STATUS;
- addr_reg = MC_ERR_SEC_ADR;
+ status_reg = mc->soc->regs->err_sec_status;
+ addr_reg = mc->soc->regs->err_sec_add;
break;
case MC_INT_DECERR_MTS:
- status_reg = MC_ERR_MTS_STATUS;
- addr_reg = MC_ERR_MTS_ADR;
+ status_reg = mc->soc->regs->err_mts_status;
+ addr_reg = mc->soc->regs->err_mts_add;
break;
case MC_INT_DECERR_GENERALIZED_CARVEOUT:
- status_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS;
- addr_reg = MC_ERR_GENERALIZED_CARVEOUT_ADR;
+ status_reg = mc->soc->regs->err_gen_co_status;
+ addr_reg = mc->soc->regs->err_gen_co_add;
break;
case MC_INT_DECERR_ROUTE_SANITY:
- status_reg = MC_ERR_ROUTE_SANITY_STATUS;
- addr_reg = MC_ERR_ROUTE_SANITY_ADR;
+ status_reg = mc->soc->regs->err_route_status;
+ addr_reg = mc->soc->regs->err_route_add;
break;
default:
- status_reg = MC_ERR_STATUS;
- addr_reg = MC_ERR_ADR;
+ status_reg = mc->soc->regs->err_status;
+ addr_reg = mc->soc->regs->err_add;
#ifdef CONFIG_PHYS_ADDR_T_64BIT
if (mc->soc->has_addr_hi_reg)
- addr_hi_reg = MC_ERR_ADR_HI;
+ addr_hi_reg = mc->soc->regs->err_add_hi;
#endif
break;
}
@@ -647,9 +658,12 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
addr = mc_ch_readl(mc, channel, addr_hi_reg);
else
addr = mc_readl(mc, addr_hi_reg);
- } else {
+ } else if (mc->soc->mc_addr_hi_mask) {
addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
- MC_ERR_STATUS_ADR_HI_MASK);
+ mc->soc->mc_addr_hi_mask);
+ } else {
+ dev_err_ratelimited(mc->dev, "Unable to determine high address!");
+ return IRQ_NONE;
}
addr <<= 32;
}
@@ -674,11 +688,11 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
}
}
- type = (value & MC_ERR_STATUS_TYPE_MASK) >>
+ type = (value & mc->soc->mc_err_status_type_mask) >>
MC_ERR_STATUS_TYPE_SHIFT;
- desc = tegra_mc_error_names[type];
+ desc = tegra20_mc_error_names[type];
- switch (value & MC_ERR_STATUS_TYPE_MASK) {
+ switch (value & mc->soc->mc_err_status_type_mask) {
case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE:
perm[0] = ' ';
perm[1] = '[';
@@ -744,9 +758,10 @@ const char *const tegra_mc_status_names[32] = {
[16] = "MTS carveout violation",
[17] = "Generalized carveout violation",
[20] = "Route Sanity error",
+ [21] = "GIC_MSI error",
};
-const char *const tegra_mc_error_names[8] = {
+const char *const tegra20_mc_error_names[8] = {
[2] = "EMEM decode error",
[3] = "TrustZone violation",
[4] = "Carveout violation",
@@ -883,7 +898,7 @@ 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);
+ value = mc_ch_readl(mc, 0, mc->soc->regs->cfg_channel_enable);
if (value <= 0) {
mc->num_channels = mc->soc->num_channels;
return;
@@ -935,25 +950,32 @@ static int tegra_mc_probe(struct platform_device *pdev)
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)
- return mc->irq;
+ if (mc->soc->handle_irq) {
+ unsigned int i;
WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
- if (mc->soc->num_channels)
- mc_ch_writel(mc, MC_BROADCAST_CHANNEL, mc->soc->intmask,
- MC_INTMASK);
- else
- mc_writel(mc, mc->soc->intmask, MC_INTMASK);
+ for (i = 0; i < mc->soc->num_interrupts; i++) {
+ int irq;
- err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
- dev_name(&pdev->dev), mc);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
- err);
- return err;
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(&pdev->dev, irq, mc->soc->handle_irq[i], 0,
+ dev_name(&pdev->dev), mc);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", irq, err);
+ return err;
+ }
+ }
+
+ for (i = 0; i < mc->soc->num_intmasks; i++) {
+ if (mc->soc->num_channels)
+ mc_ch_writel(mc, MC_BROADCAST_CHANNEL, mc->soc->intmasks[i].mask,
+ mc->soc->intmasks[i].reg);
+ else
+ mc_writel(mc, mc->soc->intmasks[i].mask, mc->soc->intmasks[i].reg);
}
}
@@ -971,8 +993,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) {
mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
if (IS_ERR(mc->smmu)) {
- dev_err(&pdev->dev, "failed to probe SMMU: %ld\n",
- PTR_ERR(mc->smmu));
+ dev_err(&pdev->dev, "failed to probe SMMU: %pe\n", mc->smmu);
mc->smmu = NULL;
}
}
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index 1d97cf4d3a94..649b54369263 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2014-2025 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#ifndef MEMORY_TEGRA_MC_H
@@ -13,15 +13,36 @@
#include <soc/tegra/mc.h>
#define MC_INTSTATUS 0x00
+/* Bit field of MC_INTSTATUS register */
+#define MC_INT_DECERR_EMEM BIT(6)
+#define MC_INT_INVALID_GART_PAGE BIT(7)
+#define MC_INT_SECURITY_VIOLATION BIT(8)
+#define MC_INT_ARBITRATION_EMEM BIT(9)
+#define MC_INT_INVALID_SMMU_PAGE BIT(10)
+#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
+#define MC_INT_DECERR_VPR BIT(12)
+#define MC_INT_SECERR_SEC BIT(13)
+#define MC_INT_DECERR_MTS BIT(16)
+#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17)
+#define MC_INT_DECERR_ROUTE_SANITY BIT(20)
+#define MC_INT_DECERR_ROUTE_SANITY_GIC_MSI BIT(21)
+
#define MC_INTMASK 0x04
-#define MC_ERR_STATUS 0x08
-#define MC_ERR_ADR 0x0c
#define MC_GART_ERROR_REQ 0x30
#define MC_EMEM_ADR_CFG 0x54
+#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
+
#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
#define MC_SECURITY_VIOLATION_STATUS 0x74
#define MC_EMEM_ARB_CFG 0x90
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) ((x) & 0x1ff)
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
+
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
+#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE BIT(30)
+#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE BIT(31)
+#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK 0x1ff
+
#define MC_EMEM_ARB_TIMING_RCD 0x98
#define MC_EMEM_ARB_TIMING_RP 0x9c
#define MC_EMEM_ARB_TIMING_RC 0xa0
@@ -41,60 +62,97 @@
#define MC_EMEM_ARB_MISC1 0xdc
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
#define MC_EMEM_ARB_OVERRIDE 0xe8
+#define MC_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
+
#define MC_TIMING_CONTROL_DBG 0xf8
#define MC_TIMING_CONTROL 0xfc
-#define MC_ERR_VPR_STATUS 0x654
-#define MC_ERR_VPR_ADR 0x658
-#define MC_ERR_SEC_STATUS 0x67c
-#define MC_ERR_SEC_ADR 0x680
-#define MC_ERR_MTS_STATUS 0x9b0
-#define MC_ERR_MTS_ADR 0x9b4
-#define MC_ERR_ROUTE_SANITY_STATUS 0x9c0
-#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
+#define MC_TIMING_UPDATE BIT(0)
-#define MC_INT_DECERR_ROUTE_SANITY BIT(20)
-#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17)
-#define MC_INT_DECERR_MTS BIT(16)
-#define MC_INT_SECERR_SEC BIT(13)
-#define MC_INT_DECERR_VPR BIT(12)
-#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
-#define MC_INT_INVALID_SMMU_PAGE BIT(10)
-#define MC_INT_ARBITRATION_EMEM BIT(9)
-#define MC_INT_SECURITY_VIOLATION BIT(8)
-#define MC_INT_INVALID_GART_PAGE BIT(7)
-#define MC_INT_DECERR_EMEM BIT(6)
+#define MC_GLOBAL_INTSTATUS 0xf24
-#define MC_ERR_STATUS_TYPE_SHIFT 28
-#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (0x6 << 28)
-#define MC_ERR_STATUS_TYPE_MASK (0x7 << 28)
-#define MC_ERR_STATUS_READABLE BIT(27)
-#define MC_ERR_STATUS_WRITABLE BIT(26)
-#define MC_ERR_STATUS_NONSECURE BIT(25)
-#define MC_ERR_STATUS_ADR_HI_SHIFT 20
-#define MC_ERR_STATUS_ADR_HI_MASK 0x3
-#define MC_ERR_STATUS_SECURITY BIT(17)
+/* Bit field of MC_ERR_STATUS_0 register */
#define MC_ERR_STATUS_RW BIT(16)
+#define MC_ERR_STATUS_SECURITY BIT(17)
+#define MC_ERR_STATUS_NONSECURE BIT(25)
+#define MC_ERR_STATUS_WRITABLE BIT(26)
+#define MC_ERR_STATUS_READABLE BIT(27)
-#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
-
-#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) ((x) & 0x1ff)
-#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
-
-#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK 0x1ff
-#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE BIT(30)
-#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE BIT(31)
+#define MC_ERR_STATUS_GSC_ADR_HI_MASK 0xffff
+#define MC_ERR_STATUS_GSC_ADR_HI_SHIFT 16
+#define MC_ERR_STATUS_RT_ADR_HI_SHIFT 15
-#define MC_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
+#define MC_ERR_STATUS_TYPE_SHIFT 28
+#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (0x6 << 28)
+#define MC_ERR_STATUS_RT_TYPE_MASK (0xf << 28)
+#define MC_ERR_STATUS_RT_TYPE_SHIFT 28
-#define MC_TIMING_UPDATE BIT(0)
+#define MC_ERR_STATUS_ADR_HI_SHIFT 20
#define MC_BROADCAST_CHANNEL ~0
+/* Tegra264 specific registers */
+
+/* Registers for MSS HUB */
+#define MSS_HUB_GLOBAL_INTSTATUS_0 0x6000
+#define MSS_HUBC_INTR BIT(0)
+#define MSS_HUB_GLOBAL_MASK 0x7F00
+#define MSS_HUB_GLOBAL_SHIFT 8
+
+#define MSS_HUB_HUBC_INTSTATUS_0 0x6008
+#define MSS_HUB_INTRSTATUS_0 0x600c
+#define MSS_HUB_HUBC_INTMASK_0 0x6010
+#define MSS_HUB_HUBC_SCRUB_DONE_INTMASK BIT(0)
+
+#define MSS_HUB_HUBC_INTPRIORITY_0 0x6014
+#define MSS_HUB_INTRMASK_0 0x6018
+#define MSS_HUB_COALESCER_ERR_INTMASK BIT(0)
+#define MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK BIT(1)
+#define MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK BIT(2)
+#define MSS_HUB_MSI_ERR_INTMASK BIT(3)
+#define MSS_HUB_POISON_RSP_INTMASK BIT(4)
+#define MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK BIT(5)
+#define MSS_HUB_RESERVED_PA_ERR_INTMASK BIT(6)
+
+#define MSS_HUB_INTRPRIORITY_0 0x601c
+#define MSS_HUB_SMMU_BYPASS_ALLOW_ERR_STATUS_0 0x6020
+#define MSS_HUB_MSI_ERR_STATUS_0 0x6024
+#define MSS_HUB_POISON_RSP_STATUS_0 0x6028
+#define MSS_HUB_COALESCE_ERR_STATUS_0 0x60e0
+#define MSS_HUB_COALESCE_ERR_ADR_HI_0 0x60e4
+#define MSS_HUB_COALESCE_ERR_ADR_0 0x60e8
+#define MSS_HUB_RESTRICTED_ACCESS_ERR_STATUS_0 0x638c
+#define MSS_HUB_RESERVED_PA_ERR_STATUS_0 0x6390
+#define MSS_HUB_ILLEGAL_TBUGRP_ID_ERR_STATUS_0 0x63b0
+
+/* Registers for channels */
+#define MC_CH_INTSTATUS_0 0x82d4
+#define MC_CH_INTMASK_0 0x82d8
+#define WCAM_ERR_INTMASK BIT(19)
+
+#define MC_ERR_GENERALIZED_CARVEOUT_STATUS_1_0 0xbc74
+
+/* Registers for MCF */
+#define MCF_COMMON_INTSTATUS0_0_0 0xce04
+#define MCF_INTSTATUS_0 0xce2c
+#define MCF_INTMASK_0 0xce30
+#define MCF_INTPRIORITY_0 0xce34
+
+/* Registers for SBS */
+#define MSS_SBS_INTSTATUS_0 0xec08
+#define MSS_SBS_INTMASK_0 0xec0c
+#define MSS_SBS_FILL_FIFO_ISO_OVERFLOW_INTMASK BIT(0)
+#define MSS_SBS_FILL_FIFO_SISO_OVERFLOW_INTMASK BIT(1)
+#define MSS_SBS_FILL_FIFO_NISO_OVERFLOW_INTMASK BIT(2)
+
+/* Bit field of MC_ERR_ROUTE_SANITY_STATUS_0 register */
+#define MC_ERR_ROUTE_SANITY_RW BIT(12)
+#define MC_ERR_ROUTE_SANITY_SEC BIT(13)
+
+#define ERR_GENERALIZED_APERTURE_ID_SHIFT 0
+#define ERR_GENERALIZED_APERTURE_ID_MASK 0x1F
+#define ERR_GENERALIZED_CARVEOUT_APERTURE_ID_SHIFT 5
+#define ERR_GENERALIZED_CARVEOUT_APERTURE_ID_MASK 0x1F
+
static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents)
{
val = val * percents;
@@ -203,8 +261,9 @@ extern const struct tegra_mc_ops tegra186_mc_ops;
#endif
irqreturn_t tegra30_mc_handle_irq(int irq, void *data);
+extern const irq_handler_t tegra30_mc_irq_handlers[1];
extern const char * const tegra_mc_status_names[32];
-extern const char * const tegra_mc_error_names[8];
+extern const char * const tegra20_mc_error_names[8];
/*
* These IDs are for internal use of Tegra ICC drivers. The ID numbers are
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 41350570c815..02dd4e26288a 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/of.h>
@@ -1101,6 +1101,14 @@ static const struct tegra_mc_reset tegra114_mc_resets[] = {
TEGRA114_MC_RESET(VI, 0x200, 0x204, 17),
};
+static const struct tegra_mc_intmask tegra114_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra114_mc_soc = {
.clients = tegra114_mc_clients,
.num_clients = ARRAY_SIZE(tegra114_mc_clients),
@@ -1108,10 +1116,14 @@ const struct tegra_mc_soc tegra114_mc_soc = {
.atom_size = 32,
.client_id_mask = 0x7f,
.smmu = &tegra114_smmu_soc,
- .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
- MC_INT_DECERR_EMEM,
+ .intmasks = tegra114_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra114_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra114_mc_resets,
.num_resets = ARRAY_SIZE(tegra114_mc_resets),
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index ff26815e51f1..5cfbc169c5f9 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -608,7 +608,7 @@ static int tegra124_emc_prepare_timing_change(struct tegra_emc *emc,
if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_NONE;
- else if (timing->emc_mode_1 & 0x1)
+ else if (!(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_ON;
else
dll_change = DLL_CHANGE_OFF;
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 991d4f7bc070..df87c5038625 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/of.h>
@@ -1258,6 +1258,15 @@ static const struct tegra_smmu_soc tegra124_smmu_soc = {
.num_asids = 128,
};
+static const struct tegra_mc_intmask tegra124_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra124_mc_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
@@ -1267,14 +1276,18 @@ const struct tegra_mc_soc tegra124_mc_soc = {
.smmu = &tegra124_smmu_soc,
.emem_regs = tegra124_mc_emem_regs,
.num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs),
- .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra124_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra124_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra124_mc_resets,
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
.icc_ops = &tegra124_mc_icc_ops,
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
#endif /* CONFIG_ARCH_TEGRA_124_SOC */
@@ -1292,6 +1305,15 @@ static const struct tegra_smmu_soc tegra132_smmu_soc = {
.num_asids = 128,
};
+static const struct tegra_mc_intmask tegra132_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra132_mc_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
@@ -1299,13 +1321,17 @@ const struct tegra_mc_soc tegra132_mc_soc = {
.atom_size = 32,
.client_id_mask = 0x7f,
.smmu = &tegra132_smmu_soc,
- .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra132_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra132_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra124_mc_resets,
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
.icc_ops = &tegra124_mc_icc_ops,
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
#endif /* CONFIG_ARCH_TEGRA_132_SOC */
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index dfddceecdd1a..03ebab6fbe68 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -22,6 +22,7 @@ struct tegra186_emc {
struct tegra_bpmp *bpmp;
struct device *dev;
struct clk *clk;
+ struct clk *clk_dbb;
struct tegra186_emc_dvfs *dvfs;
unsigned int num_dvfs;
@@ -328,6 +329,13 @@ static int tegra186_emc_probe(struct platform_device *pdev)
goto put_bpmp;
}
+ emc->clk_dbb = devm_clk_get_optional_enabled(&pdev->dev, "dbb");
+ if (IS_ERR(emc->clk_dbb)) {
+ err = dev_err_probe(&pdev->dev, PTR_ERR(emc->clk_dbb),
+ "failed to get DBB clock\n");
+ goto put_bpmp;
+ }
+
platform_set_drvdata(pdev, emc);
emc->dev = &pdev->dev;
diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c
index aee11457bf8e..91d56165605f 100644
--- a/drivers/memory/tegra/tegra186.c
+++ b/drivers/memory/tegra/tegra186.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2017-2025 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2017-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/io.h>
@@ -174,7 +174,6 @@ const struct tegra_mc_ops tegra186_mc_ops = {
.remove = tegra186_mc_remove,
.resume = tegra186_mc_resume,
.probe_device = tegra186_mc_probe_device,
- .handle_irq = tegra30_mc_handle_irq,
};
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
@@ -902,17 +901,30 @@ static const struct tegra_mc_client tegra186_mc_clients[] = {
},
};
+static const struct tegra_mc_intmask tegra186_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
+ MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra186_mc_soc = {
.num_clients = ARRAY_SIZE(tegra186_mc_clients),
.clients = tegra186_mc_clients,
.num_address_bits = 40,
.num_channels = 4,
.client_id_mask = 0xff,
- .intmask = MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra186_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra186_mc_intmasks),
.ops = &tegra186_mc_ops,
.ch_intmask = 0x0000000f,
.global_intstatus_channel_shift = 0,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
#endif
diff --git a/drivers/memory/tegra/tegra194.c b/drivers/memory/tegra/tegra194.c
index 26035ac3a1eb..a8cc57690696 100644
--- a/drivers/memory/tegra/tegra194.c
+++ b/drivers/memory/tegra/tegra194.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2017-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <soc/tegra/mc.h>
@@ -1343,19 +1343,31 @@ static const struct tegra_mc_client tegra194_mc_clients[] = {
},
};
+static const struct tegra_mc_intmask tegra194_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_ROUTE_SANITY | MC_INT_DECERR_GENERALIZED_CARVEOUT |
+ MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra194_mc_soc = {
.num_clients = ARRAY_SIZE(tegra194_mc_clients),
.clients = tegra194_mc_clients,
.num_address_bits = 40,
.num_channels = 16,
.client_id_mask = 0xff,
- .intmask = MC_INT_DECERR_ROUTE_SANITY |
- MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra194_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra194_mc_intmasks),
.has_addr_hi_reg = true,
.ops = &tegra186_mc_ops,
.icc_ops = &tegra_mc_icc_ops,
.ch_intmask = 0x00000f00,
.global_intstatus_channel_shift = 8,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
index 4748113bfe9d..27dd6886f86e 100644
--- a/drivers/memory/tegra/tegra20.c
+++ b/drivers/memory/tegra/tegra20.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2012-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/bitfield.h>
@@ -695,7 +695,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
unsigned int bit;
/* mask all interrupts to avoid flooding */
- status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+ status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmasks[0].mask;
if (!status)
return IRQ_NONE;
@@ -713,7 +713,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
value = mc_readl(mc, reg);
id = value & mc->soc->client_id_mask;
- desc = tegra_mc_error_names[2];
+ desc = tegra20_mc_error_names[2];
if (value & BIT(31))
direction = "write";
@@ -724,7 +724,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
value = mc_readl(mc, reg);
id = (value >> 1) & mc->soc->client_id_mask;
- desc = tegra_mc_error_names[2];
+ desc = tegra20_mc_error_names[2];
if (value & BIT(0))
direction = "write";
@@ -736,7 +736,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
id = value & mc->soc->client_id_mask;
type = (value & BIT(30)) ? 4 : 3;
- desc = tegra_mc_error_names[type];
+ desc = tegra20_mc_error_names[type];
secure = "secure ";
if (value & BIT(31))
@@ -761,9 +761,20 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static const irq_handler_t tegra20_mc_irq_handlers[] = {
+ tegra20_mc_handle_irq
+};
+
static const struct tegra_mc_ops tegra20_mc_ops = {
.probe = tegra20_mc_probe,
- .handle_irq = tegra20_mc_handle_irq,
+};
+
+static const struct tegra_mc_intmask tegra20_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
+ MC_INT_DECERR_EMEM,
+ },
};
const struct tegra_mc_soc tegra20_mc_soc = {
@@ -771,11 +782,15 @@ const struct tegra_mc_soc tegra20_mc_soc = {
.num_clients = ARRAY_SIZE(tegra20_mc_clients),
.num_address_bits = 32,
.client_id_mask = 0x3f,
- .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
- MC_INT_DECERR_EMEM,
+ .intmasks = tegra20_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra20_mc_intmasks),
.reset_ops = &tegra20_mc_reset_ops,
.resets = tegra20_mc_resets,
.num_resets = ARRAY_SIZE(tegra20_mc_resets),
.icc_ops = &tegra20_mc_icc_ops,
.ops = &tegra20_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra20_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra20_mc_irq_handlers),
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index 3c2949c16fde..f58f3ef6f681 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2015 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2015-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <dt-bindings/memory/tegra210-mc.h>
@@ -1273,6 +1273,15 @@ static const struct tegra_mc_reset tegra210_mc_resets[] = {
TEGRA210_MC_RESET(TSECB, 0x970, 0x974, 13),
};
+static const struct tegra_mc_intmask tegra210_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra210_mc_soc = {
.clients = tegra210_mc_clients,
.num_clients = ARRAY_SIZE(tegra210_mc_clients),
@@ -1280,11 +1289,15 @@ const struct tegra_mc_soc tegra210_mc_soc = {
.atom_size = 64,
.client_id_mask = 0xff,
.smmu = &tegra210_smmu_soc,
- .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra210_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra210_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra210_mc_resets,
.num_resets = ARRAY_SIZE(tegra210_mc_resets),
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c
index 5f57cea48b62..87b22038a5fb 100644
--- a/drivers/memory/tegra/tegra234.c
+++ b/drivers/memory/tegra/tegra234.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2022-2023, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2022-2026, NVIDIA CORPORATION. All rights reserved.
*/
#include <soc/tegra/mc.h>
@@ -1132,16 +1132,23 @@ static const struct tegra_mc_icc_ops tegra234_mc_icc_ops = {
.set = tegra234_mc_icc_set,
};
+static const struct tegra_mc_intmask tegra234_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_ROUTE_SANITY | MC_INT_DECERR_GENERALIZED_CARVEOUT |
+ MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra234_mc_soc = {
.num_clients = ARRAY_SIZE(tegra234_mc_clients),
.clients = tegra234_mc_clients,
.num_address_bits = 40,
.num_channels = 16,
.client_id_mask = 0x1ff,
- .intmask = MC_INT_DECERR_ROUTE_SANITY |
- MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra234_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra234_mc_intmasks),
.has_addr_hi_reg = true,
.ops = &tegra186_mc_ops,
.icc_ops = &tegra234_mc_icc_ops,
@@ -1152,4 +1159,9 @@ const struct tegra_mc_soc tegra234_mc_soc = {
* supported.
*/
.num_carveouts = 32,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra264.c b/drivers/memory/tegra/tegra264.c
index 5203e6c11372..e43ef14da1ee 100644
--- a/drivers/memory/tegra/tegra264.c
+++ b/drivers/memory/tegra/tegra264.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2025, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2025-2026, NVIDIA CORPORATION. All rights reserved.
*/
#include <dt-bindings/memory/nvidia,tegra264.h>
@@ -188,6 +188,41 @@ static const struct tegra_mc_client tegra264_mc_clients[] = {
},
};
+static const char *const tegra264_hub_error_names[32] = {
+ [0] = "coalescer error",
+ [1] = "SMMU BYPASS ALLOW error",
+ [2] = "Illegal tbugrp_id error",
+ [3] = "Malformed MSI request error",
+ [4] = "Read response with poison bit error",
+ [5] = "Restricted access violation error",
+ [6] = "Reserved PA error",
+};
+
+static const char *const tegra264_mc_error_names[4] = {
+ [1] = "EMEM decode error",
+ [2] = "TrustZone violation",
+ [3] = "Carveout violation",
+};
+
+static const char *const tegra264_rt_error_names[16] = {
+ [1] = "DECERR_PARTIAL_POPULATED",
+ [2] = "DECERR_SMMU_BYPASS",
+ [3] = "DECERR_INVALID_MMIO",
+ [4] = "DECERR_INVALID_GIC_MSI",
+ [5] = "DECERR_ATOMIC_SYSRAM",
+ [9] = "DECERR_REMOTE_REQ_PRE_BOOT",
+ [10] = "DECERR_ISO_OVER_C2C",
+ [11] = "DECERR_UNSUPPORTED_SBS_OPCODE",
+ [12] = "DECERR_SBS_REQ_OVER_SISO_LL",
+};
+
+/*
+ * MC instance aperture mapping for hubc registers
+ */
+static const int mc_hubc_aperture_number[5] = {
+ 7, 8, 9, 10, 11
+};
+
/*
* tegra264_mc_icc_set() - Pass MC client info to the BPMP-FW
* @src: ICC node for Memory Controller's (MC) Client
@@ -283,6 +318,312 @@ static int tegra264_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pea
return 0;
}
+static void mcf_log_fault(struct tegra_mc *mc, u32 channel, unsigned long mcf_ch_intstatus)
+{
+ unsigned int bit;
+
+ for_each_set_bit(bit, &mcf_ch_intstatus, 32) {
+ const char *client = "unknown", *desc = "NA";
+ u32 status_reg, status1_reg = 0, addr_reg, addr_hi_reg = 0, err_type_mask = 0;
+ u32 value, client_id, i, addr_hi_shift = 0, addr_hi_mask = 0, status1;
+ u32 mc_rw_bit = MC_ERR_STATUS_RW, mc_sec_bit = MC_ERR_STATUS_SECURITY;
+ phys_addr_t addr = 0;
+ u8 type;
+
+ switch (BIT(bit)) {
+ case MC_INT_DECERR_EMEM:
+ case MC_INT_SECURITY_VIOLATION:
+ status_reg = mc->soc->regs->err_status;
+ addr_reg = mc->soc->regs->err_add;
+ addr_hi_reg = mc->soc->regs->err_add_hi;
+ err_type_mask = mc->soc->mc_err_status_type_mask;
+ break;
+
+ case MC_INT_DECERR_VPR:
+ status_reg = mc->soc->regs->err_vpr_status;
+ addr_reg = mc->soc->regs->err_vpr_add;
+ addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ break;
+
+ case MC_INT_SECERR_SEC:
+ status_reg = mc->soc->regs->err_sec_status;
+ addr_reg = mc->soc->regs->err_sec_add;
+ addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ break;
+
+ case MC_INT_DECERR_MTS:
+ status_reg = mc->soc->regs->err_mts_status;
+ addr_reg = mc->soc->regs->err_mts_add;
+ addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ break;
+
+ case MC_INT_DECERR_GENERALIZED_CARVEOUT:
+ status_reg = mc->soc->regs->err_gen_co_status;
+ status1_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS_1_0;
+ addr_reg = mc->soc->regs->err_gen_co_add;
+ addr_hi_shift = MC_ERR_STATUS_GSC_ADR_HI_SHIFT;
+ addr_hi_mask = MC_ERR_STATUS_GSC_ADR_HI_MASK;
+ break;
+
+ case MC_INT_DECERR_ROUTE_SANITY:
+ case MC_INT_DECERR_ROUTE_SANITY_GIC_MSI:
+ status_reg = mc->soc->regs->err_route_status;
+ addr_reg = mc->soc->regs->err_route_add;
+ addr_hi_shift = MC_ERR_STATUS_RT_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ mc_sec_bit = MC_ERR_ROUTE_SANITY_SEC;
+ mc_rw_bit = MC_ERR_ROUTE_SANITY_RW;
+ err_type_mask = MC_ERR_STATUS_RT_TYPE_MASK;
+ break;
+
+ default:
+ dev_err_ratelimited(mc->dev, "Incorrect MC interrupt mask\n");
+ return;
+ }
+
+ value = mc_ch_readl(mc, channel, status_reg);
+ if (addr_hi_reg) {
+ addr = mc_ch_readl(mc, channel, addr_hi_reg);
+ } else {
+ if (!status1_reg) {
+ addr = ((value >> addr_hi_shift) & addr_hi_mask);
+ } else {
+ status1 = mc_ch_readl(mc, channel, status1_reg);
+ addr = ((status1 >> addr_hi_shift) & addr_hi_mask);
+ }
+ }
+
+ addr <<= 32;
+ addr |= mc_ch_readl(mc, channel, addr_reg);
+
+ client_id = value & mc->soc->client_id_mask;
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ if (mc->soc->clients[i].id == client_id) {
+ client = mc->soc->clients[i].name;
+ break;
+ }
+ }
+
+ if (err_type_mask == MC_ERR_STATUS_RT_TYPE_MASK) {
+ type = (value & err_type_mask) >>
+ MC_ERR_STATUS_RT_TYPE_SHIFT;
+ desc = tegra264_rt_error_names[type];
+ } else if (err_type_mask) {
+ type = (value & err_type_mask) >>
+ MC_ERR_STATUS_TYPE_SHIFT;
+ desc = tegra264_mc_error_names[type];
+ }
+
+ dev_err_ratelimited(mc->dev, "%s: %s %s @%pa: %s (%s)\n",
+ client, value & mc_sec_bit ? "secure" : "non-secure",
+ value & mc_rw_bit ? "write" : "read", &addr,
+ tegra_mc_status_names[bit] ?: "unknown", desc);
+ if (status1_reg)
+ dev_err_ratelimited(mc->dev, "gsc_apr_id=%u gsc_co_apr_id=%u\n",
+ ((status1 >> ERR_GENERALIZED_APERTURE_ID_SHIFT)
+ & ERR_GENERALIZED_APERTURE_ID_MASK),
+ ((status1 >> ERR_GENERALIZED_CARVEOUT_APERTURE_ID_SHIFT)
+ & ERR_GENERALIZED_CARVEOUT_APERTURE_ID_MASK));
+ }
+
+ /* clear interrupts */
+ mc_ch_writel(mc, channel, mcf_ch_intstatus, MCF_INTSTATUS_0);
+}
+
+static irqreturn_t handle_mcf_irq(int irq, void *data)
+{
+ struct tegra_mc *mc = data;
+ unsigned long common_intstat, intstatus;
+ u32 slice;
+
+ /* Read MCF_COMMON_INTSTATUS0_0_0 from MCB block */
+ common_intstat = mc_ch_readl(mc, MC_BROADCAST_CHANNEL, MCF_COMMON_INTSTATUS0_0_0);
+ if (common_intstat == 0) {
+ dev_warn(mc->dev, "No interrupt in MCF\n");
+ return IRQ_NONE;
+ }
+
+ for_each_set_bit(slice, &common_intstat, 32) {
+ /* Find out the slice number on which interrupt occurred */
+ if (slice > 4) {
+ dev_err(mc->dev, "Slice index out of bounds: %u\n", slice);
+ return IRQ_NONE;
+ }
+
+ intstatus = mc_ch_readl(mc, slice, MCF_INTSTATUS_0);
+ if (intstatus != 0)
+ mcf_log_fault(mc, slice, intstatus);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hub_log_fault(struct tegra_mc *mc, u32 hub, unsigned long hub_intstat)
+{
+ unsigned int bit;
+
+ for_each_set_bit(bit, &hub_intstat, 32) {
+ const char *client = "unknown";
+ u32 client_id, status_reg, value, i;
+ phys_addr_t addr = 0;
+
+ switch (BIT(bit)) {
+ case MSS_HUB_COALESCER_ERR_INTMASK:
+ status_reg = MSS_HUB_COALESCE_ERR_STATUS_0;
+ addr = mc_ch_readl(mc, hub, MSS_HUB_COALESCE_ERR_ADR_HI_0);
+ addr <<= 32;
+ addr |= mc_ch_readl(mc, hub, MSS_HUB_COALESCE_ERR_ADR_0);
+ break;
+
+ case MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK:
+ status_reg = MSS_HUB_SMMU_BYPASS_ALLOW_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK:
+ status_reg = MSS_HUB_ILLEGAL_TBUGRP_ID_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_MSI_ERR_INTMASK:
+ status_reg = MSS_HUB_MSI_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_POISON_RSP_INTMASK:
+ status_reg = MSS_HUB_POISON_RSP_STATUS_0;
+ break;
+
+ case MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK:
+ status_reg = MSS_HUB_RESTRICTED_ACCESS_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_RESERVED_PA_ERR_INTMASK:
+ status_reg = MSS_HUB_RESERVED_PA_ERR_STATUS_0;
+ break;
+
+ default:
+ dev_err_ratelimited(mc->dev, "Incorrect HUB interrupt mask\n");
+ return;
+ }
+
+ value = mc_ch_readl(mc, hub, status_reg);
+
+ client_id = value & mc->soc->client_id_mask;
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ if (mc->soc->clients[i].id == client_id) {
+ client = mc->soc->clients[i].name;
+ break;
+ }
+ }
+
+ dev_err_ratelimited(mc->dev, "%s: @%pa: %s status: 0x%x\n",
+ client, &addr, tegra264_hub_error_names[bit] ?: "unknown",
+ value);
+ }
+
+ /* clear interrupts */
+ mc_ch_writel(mc, hub, hub_intstat, MSS_HUB_INTRSTATUS_0);
+}
+
+static irqreturn_t handle_hub_irq(int irq, void *data, int mc_hubc_aperture_number)
+{
+ struct tegra_mc *mc = data;
+ u32 global_intstat;
+ unsigned long hub_interrupt, intstat, hub;
+
+ /* Read MSS_HUB_GLOBAL_INTSTATUS_0 from mc_hubc_aperture_number block */
+ global_intstat = mc_ch_readl(mc, mc_hubc_aperture_number, MSS_HUB_GLOBAL_INTSTATUS_0);
+ if (global_intstat == 0) {
+ dev_warn(mc->dev, "No interrupt in HUB/HUBC\n");
+ return IRQ_NONE;
+ }
+
+ /* Handle interrupt from hubc */
+ if (global_intstat & MSS_HUBC_INTR) {
+ /* Read MSS_HUB_HUBC_INTSTATUS_0 from block mc_hubc_aperture_number */
+ intstat = mc_ch_readl(mc, mc_hubc_aperture_number, MSS_HUB_HUBC_INTSTATUS_0);
+ if (intstat != 0) {
+ dev_err_ratelimited(mc->dev, "Scrubber operation status: 0x%lx\n",
+ intstat);
+ /* Clear hubc interrupt */
+ mc_ch_writel(mc, mc_hubc_aperture_number, intstat,
+ MSS_HUB_HUBC_INTSTATUS_0);
+ }
+ }
+
+ hub_interrupt = (global_intstat & MSS_HUB_GLOBAL_MASK) >> MSS_HUB_GLOBAL_SHIFT;
+ /* Handle interrupt from hub */
+ for_each_set_bit(hub, &hub_interrupt, 32) {
+ /* Read MSS_HUB_INTRSTATUS_0 from block MCi */
+ intstat = mc_ch_readl(mc, hub, MSS_HUB_INTRSTATUS_0);
+ if (intstat != 0)
+ hub_log_fault(mc, hub, intstat);
+ }
+
+ /* Clear global interrupt status register */
+ mc_ch_writel(mc, mc_hubc_aperture_number, global_intstat, MSS_HUB_GLOBAL_INTSTATUS_0);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_disp_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[0]);
+}
+
+static irqreturn_t handle_system_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[1]);
+}
+
+static irqreturn_t handle_vision_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[2]);
+}
+
+static irqreturn_t handle_uphy_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[3]);
+}
+
+static irqreturn_t handle_top_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[4]);
+}
+
+static irqreturn_t handle_generic_irq(struct tegra_mc *mc, unsigned long intstat_reg)
+{
+ u32 intstat, i;
+
+ /* Iterate over all MC blocks to read INTSTATUS */
+ for (i = 0; i < mc->num_channels; i++) {
+ intstat = mc_ch_readl(mc, i, intstat_reg);
+ if (intstat) {
+ dev_err_ratelimited(mc->dev, "channel: %i status: 0x%x\n", i, intstat);
+ /* Clear interrupt */
+ mc_ch_writel(mc, i, intstat, intstat_reg);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_sbs_irq(int irq, void *data)
+{
+ return handle_generic_irq((struct tegra_mc *)data, MSS_SBS_INTSTATUS_0);
+}
+
+static irqreturn_t handle_channel_irq(int irq, void *data)
+{
+ return handle_generic_irq((struct tegra_mc *)data, MC_CH_INTSTATUS_0);
+}
+
+static const irq_handler_t tegra264_mc_irq_handlers[8] = {
+ handle_mcf_irq, handle_disp_hub_irq, handle_vision_hub_irq,
+ handle_system_hub_irq, handle_uphy_hub_irq, handle_top_hub_irq,
+ handle_sbs_irq, handle_channel_irq
+};
+
static const struct tegra_mc_icc_ops tegra264_mc_icc_ops = {
.xlate = tegra_mc_icc_xlate,
.aggregate = tegra264_mc_icc_aggregate,
@@ -290,16 +631,80 @@ static const struct tegra_mc_icc_ops tegra264_mc_icc_ops = {
.set = tegra264_mc_icc_set,
};
+static const struct tegra_mc_regs tegra264_mc_regs = {
+ .cfg_channel_enable = 0x8870,
+ .err_status = 0xbc00,
+ .err_add = 0xbc04,
+ .err_add_hi = 0xbc08,
+ .err_vpr_status = 0xbc20,
+ .err_vpr_add = 0xbc24,
+ .err_sec_status = 0xbc3c,
+ .err_sec_add = 0xbc40,
+ .err_mts_status = 0xbc5c,
+ .err_mts_add = 0xbc60,
+ .err_gen_co_status = 0xbc78,
+ .err_gen_co_add = 0xbc7c,
+ .err_route_status = 0xbc64,
+ .err_route_add = 0xbc68,
+};
+
+static const struct tegra_mc_intmask tegra264_mc_intmasks[] = {
+ {
+ .reg = MCF_INTMASK_0,
+ .mask = MC_INT_DECERR_ROUTE_SANITY_GIC_MSI | MC_INT_DECERR_ROUTE_SANITY |
+ MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
+ MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+ {
+ .reg = MCF_INTPRIORITY_0,
+ .mask = MC_INT_DECERR_ROUTE_SANITY_GIC_MSI | MC_INT_DECERR_ROUTE_SANITY |
+ MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
+ MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+ {
+ .reg = MSS_HUB_INTRMASK_0,
+ .mask = MSS_HUB_COALESCER_ERR_INTMASK | MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK |
+ MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK | MSS_HUB_MSI_ERR_INTMASK |
+ MSS_HUB_POISON_RSP_INTMASK | MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK |
+ MSS_HUB_RESERVED_PA_ERR_INTMASK,
+ },
+ {
+ .reg = MSS_HUB_INTRPRIORITY_0,
+ .mask = MSS_HUB_COALESCER_ERR_INTMASK | MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK |
+ MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK | MSS_HUB_MSI_ERR_INTMASK |
+ MSS_HUB_POISON_RSP_INTMASK | MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK |
+ MSS_HUB_RESERVED_PA_ERR_INTMASK,
+ },
+ {
+ .reg = MSS_HUB_HUBC_INTMASK_0,
+ .mask = MSS_HUB_HUBC_SCRUB_DONE_INTMASK,
+ },
+ {
+ .reg = MSS_HUB_HUBC_INTPRIORITY_0,
+ .mask = MSS_HUB_HUBC_SCRUB_DONE_INTMASK,
+ },
+ {
+ .reg = MSS_SBS_INTMASK_0,
+ .mask = MSS_SBS_FILL_FIFO_ISO_OVERFLOW_INTMASK |
+ MSS_SBS_FILL_FIFO_SISO_OVERFLOW_INTMASK |
+ MSS_SBS_FILL_FIFO_NISO_OVERFLOW_INTMASK,
+ },
+ {
+ .reg = MC_CH_INTMASK_0,
+ .mask = WCAM_ERR_INTMASK,
+ }
+};
+
const struct tegra_mc_soc tegra264_mc_soc = {
.num_clients = ARRAY_SIZE(tegra264_mc_clients),
.clients = tegra264_mc_clients,
.num_address_bits = 40,
.num_channels = 16,
.client_id_mask = 0x1ff,
- .intmask = MC_INT_DECERR_ROUTE_SANITY |
- MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra264_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra264_mc_intmasks),
.has_addr_hi_reg = true,
.ops = &tegra186_mc_ops,
.icc_ops = &tegra264_mc_icc_ops,
@@ -310,4 +715,9 @@ const struct tegra_mc_soc tegra264_mc_soc = {
* supported.
*/
.num_carveouts = 32,
+ .mc_addr_hi_mask = 0xff,
+ .mc_err_status_type_mask = (0x3 << 28),
+ .regs = &tegra264_mc_regs,
+ .handle_irq = tegra264_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra264_mc_irq_handlers),
};
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 606106dd2b32..5812c8cd6ce4 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG);
emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1))
+ if (emc->dll_on == !(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_NONE;
- else if (timing->emc_mode_1 & 0x1)
+ else if (!(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_ON;
else
dll_change = DLL_CHANGE_OFF;
- emc->dll_on = !!(timing->emc_mode_1 & 0x1);
+ emc->dll_on = !(timing->emc_mode_1 & 0x1);
if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL))
emc->zcal_long = true;
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index a6bcde4b92c0..8389e3af0121 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/device.h>
@@ -1384,6 +1384,14 @@ static const struct tegra_mc_icc_ops tegra30_mc_icc_ops = {
.set = tegra30_mc_icc_set,
};
+static const struct tegra_mc_intmask tegra30_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra30_mc_soc = {
.clients = tegra30_mc_clients,
.num_clients = ARRAY_SIZE(tegra30_mc_clients),
@@ -1393,11 +1401,15 @@ const struct tegra_mc_soc tegra30_mc_soc = {
.smmu = &tegra30_smmu_soc,
.emem_regs = tegra30_mc_emem_regs,
.num_emem_regs = ARRAY_SIZE(tegra30_mc_emem_regs),
- .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
- MC_INT_DECERR_EMEM,
+ .intmasks = tegra30_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra30_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra30_mc_resets,
.num_resets = ARRAY_SIZE(tegra30_mc_resets),
.icc_ops = &tegra30_mc_icc_ops,
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_err_status_type_mask = (0x7 << 28),
};