Merge tag 'memory-controller-drv-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into soc/drivers

Memory controller drivers for v7.1

1. TegraMC:
 - Few fixes for older issues - missing clock on Tegra264,
   missing enabling of DLL for Tegra30 and Tegra124.
 - Simplify the code in a few places.
 - Rework handling interrupts on different variants and add support for
   error logging on Tegra 264.

2. Drop Baikal SoC bt1-l2-ctl driver, because SoC support is being
   removed tree-wide.

* tag 'memory-controller-drv-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: tegra: Add MC error logging support for Tegra264
  memory: tegra: Prepare for supporting multiple intmask registers
  memory: tegra: Group SoC specific fields
  memory: tegra: Add support for multiple IRQs
  memory: tegra: Group register and fields
  memory: tegra: Group error handling related registers
  memory: tegra-mc: Use %pe format
  memory: tegra-mc: Simplify printing PTR_ERR with dev_err_probe
  memory: tegra-mc: Drop tegra_mc_setup_latency_allowance() return value
  memory: renesas-rpc-if: Simplify printing PTR_ERR with dev_err_probe
  memory: brcmstb_memc: Expand LPDDR4 check to cover for LPDDR5
  dt-bindings: cache: bt1-l2-ctl: Remove unused bindings
  memory: bt1-l2-ctl: Remove not-going-to-be-supported code for Baikal SoC
  memory: tegra30-emc: Fix dll_change check
  memory: tegra124-emc: Fix dll_change check
  memory: tegra: Add support for DBB clock on Tegra264

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann
2026-04-01 23:44:55 +02:00
21 changed files with 809 additions and 565 deletions

View File

@@ -1,63 +0,0 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
%YAML 1.2
---
$id: http://devicetree.org/schemas/cache/baikal,bt1-l2-ctl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Baikal-T1 L2-cache Control Block
maintainers:
- Serge Semin <fancer.lancer@gmail.com>
description: |
By means of the System Controller Baikal-T1 SoC exposes a few settings to
tune the MIPS P5600 CM2 L2 cache performance up. In particular it's possible
to change the Tag, Data and Way-select RAM access latencies. Baikal-T1
L2-cache controller block is responsible for the tuning. Its DT node is
supposed to be a child of the system controller.
properties:
compatible:
const: baikal,bt1-l2-ctl
reg:
maxItems: 1
baikal,l2-ws-latency:
$ref: /schemas/types.yaml#/definitions/uint32
description: Cycles of latency for Way-select RAM accesses
default: 0
minimum: 0
maximum: 3
baikal,l2-tag-latency:
$ref: /schemas/types.yaml#/definitions/uint32
description: Cycles of latency for Tag RAM accesses
default: 0
minimum: 0
maximum: 3
baikal,l2-data-latency:
$ref: /schemas/types.yaml#/definitions/uint32
description: Cycles of latency for Data RAM accesses
default: 1
minimum: 0
maximum: 3
additionalProperties: false
required:
- compatible
examples:
- |
l2@1f04d028 {
compatible = "baikal,bt1-l2-ctl";
reg = <0x1f04d028 0x004>;
baikal,l2-ws-latency = <1>;
baikal,l2-tag-latency = <1>;
baikal,l2-data-latency = <2>;
};
...

View File

@@ -64,17 +64,6 @@ config BRCMSTB_MEMC
controller and specifically control the Self Refresh Power Down
(SRPD) inactivity timeout.
config BT1_L2_CTL
bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
select MFD_SYSCON
help
Baikal-T1 CPU is based on the MIPS P5600 Warrior IP-core. The CPU
resides Coherency Manager v2 with embedded 1MB L2-cache. It's
possible to tune the L2 cache performance up by setting the data,
tags and way-select latencies of RAM access. This driver provides a
dt properties-based and sysfs interface for it.
config TI_AEMIF
tristate "Texas Instruments AEMIF driver"
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST

View File

@@ -11,7 +11,6 @@ obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o
obj-$(CONFIG_BRCMSTB_MEMC) += brcmstb_memc.o
obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o

View File

@@ -14,6 +14,7 @@
#define REG_MEMC_CNTRLR_CONFIG 0x00
#define CNTRLR_CONFIG_LPDDR4_SHIFT 5
#define CNTRLR_CONFIG_LPDDR5_SHIFT 6
#define CNTRLR_CONFIG_MASK 0xf
#define REG_MEMC_SRPD_CFG_21 0x20
#define REG_MEMC_SRPD_CFG_20 0x34
@@ -34,14 +35,15 @@ struct brcmstb_memc {
u32 srpd_offset;
};
static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc)
static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc)
{
void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG;
u32 reg;
reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK;
return reg == CNTRLR_CONFIG_LPDDR4_SHIFT;
return reg == CNTRLR_CONFIG_LPDDR4_SHIFT ||
reg == CNTRLR_CONFIG_LPDDR5_SHIFT;
}
static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc,
@@ -95,7 +97,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr,
* dynamic tuning process will also get affected by the inactivity
* timeout, thus making it non functional.
*/
if (brcmstb_memc_uses_lpddr4(memc))
if (brcmstb_memc_uses_lpddr45(memc))
return -EOPNOTSUPP;
ret = kstrtouint(buf, 10, &val);

View File

@@ -1,323 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
*
* Authors:
* Serge Semin <Sergey.Semin@baikalelectronics.ru>
*
* Baikal-T1 CM2 L2-cache Control Block driver.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bitfield.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/sysfs.h>
#include <linux/of.h>
#define L2_CTL_REG 0x028
#define L2_CTL_DATA_STALL_FLD 0
#define L2_CTL_DATA_STALL_MASK GENMASK(1, L2_CTL_DATA_STALL_FLD)
#define L2_CTL_TAG_STALL_FLD 2
#define L2_CTL_TAG_STALL_MASK GENMASK(3, L2_CTL_TAG_STALL_FLD)
#define L2_CTL_WS_STALL_FLD 4
#define L2_CTL_WS_STALL_MASK GENMASK(5, L2_CTL_WS_STALL_FLD)
#define L2_CTL_SET_CLKRATIO BIT(13)
#define L2_CTL_CLKRATIO_LOCK BIT(31)
#define L2_CTL_STALL_MIN 0
#define L2_CTL_STALL_MAX 3
#define L2_CTL_STALL_SET_DELAY_US 1
#define L2_CTL_STALL_SET_TOUT_US 1000
/*
* struct l2_ctl - Baikal-T1 L2 Control block private data.
* @dev: Pointer to the device structure.
* @sys_regs: Baikal-T1 System Controller registers map.
*/
struct l2_ctl {
struct device *dev;
struct regmap *sys_regs;
};
/*
* enum l2_ctl_stall - Baikal-T1 L2-cache-RAM stall identifier.
* @L2_WSSTALL: Way-select latency.
* @L2_TAGSTALL: Tag latency.
* @L2_DATASTALL: Data latency.
*/
enum l2_ctl_stall {
L2_WS_STALL,
L2_TAG_STALL,
L2_DATA_STALL
};
/*
* struct l2_ctl_device_attribute - Baikal-T1 L2-cache device attribute.
* @dev_attr: Actual sysfs device attribute.
* @id: L2-cache stall field identifier.
*/
struct l2_ctl_device_attribute {
struct device_attribute dev_attr;
enum l2_ctl_stall id;
};
#define to_l2_ctl_dev_attr(_dev_attr) \
container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr)
#define L2_CTL_ATTR_RW(_name, _prefix, _id) \
struct l2_ctl_device_attribute l2_ctl_attr_##_name = \
{ __ATTR(_name, 0644, _prefix##_show, _prefix##_store), _id }
static int l2_ctl_get_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 *val)
{
u32 data = 0;
int ret;
ret = regmap_read(l2->sys_regs, L2_CTL_REG, &data);
if (ret)
return ret;
switch (id) {
case L2_WS_STALL:
*val = FIELD_GET(L2_CTL_WS_STALL_MASK, data);
break;
case L2_TAG_STALL:
*val = FIELD_GET(L2_CTL_TAG_STALL_MASK, data);
break;
case L2_DATA_STALL:
*val = FIELD_GET(L2_CTL_DATA_STALL_MASK, data);
break;
default:
return -EINVAL;
}
return 0;
}
static int l2_ctl_set_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 val)
{
u32 mask = 0, data = 0;
int ret;
val = clamp_val(val, L2_CTL_STALL_MIN, L2_CTL_STALL_MAX);
switch (id) {
case L2_WS_STALL:
data = FIELD_PREP(L2_CTL_WS_STALL_MASK, val);
mask = L2_CTL_WS_STALL_MASK;
break;
case L2_TAG_STALL:
data = FIELD_PREP(L2_CTL_TAG_STALL_MASK, val);
mask = L2_CTL_TAG_STALL_MASK;
break;
case L2_DATA_STALL:
data = FIELD_PREP(L2_CTL_DATA_STALL_MASK, val);
mask = L2_CTL_DATA_STALL_MASK;
break;
default:
return -EINVAL;
}
data |= L2_CTL_SET_CLKRATIO;
mask |= L2_CTL_SET_CLKRATIO;
ret = regmap_update_bits(l2->sys_regs, L2_CTL_REG, mask, data);
if (ret)
return ret;
return regmap_read_poll_timeout(l2->sys_regs, L2_CTL_REG, data,
data & L2_CTL_CLKRATIO_LOCK,
L2_CTL_STALL_SET_DELAY_US,
L2_CTL_STALL_SET_TOUT_US);
}
static void l2_ctl_clear_data(void *data)
{
struct l2_ctl *l2 = data;
struct platform_device *pdev = to_platform_device(l2->dev);
platform_set_drvdata(pdev, NULL);
}
static struct l2_ctl *l2_ctl_create_data(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct l2_ctl *l2;
int ret;
l2 = devm_kzalloc(dev, sizeof(*l2), GFP_KERNEL);
if (!l2)
return ERR_PTR(-ENOMEM);
ret = devm_add_action(dev, l2_ctl_clear_data, l2);
if (ret) {
dev_err(dev, "Can't add L2 CTL data clear action\n");
return ERR_PTR(ret);
}
l2->dev = dev;
platform_set_drvdata(pdev, l2);
return l2;
}
static int l2_ctl_find_sys_regs(struct l2_ctl *l2)
{
l2->sys_regs = syscon_node_to_regmap(l2->dev->of_node->parent);
if (IS_ERR(l2->sys_regs)) {
dev_err(l2->dev, "Couldn't get L2 CTL register map\n");
return PTR_ERR(l2->sys_regs);
}
return 0;
}
static int l2_ctl_of_parse_property(struct l2_ctl *l2, enum l2_ctl_stall id,
const char *propname)
{
int ret = 0;
u32 data;
if (!of_property_read_u32(l2->dev->of_node, propname, &data)) {
ret = l2_ctl_set_latency(l2, id, data);
if (ret)
dev_err(l2->dev, "Invalid value of '%s'\n", propname);
}
return ret;
}
static int l2_ctl_of_parse(struct l2_ctl *l2)
{
int ret;
ret = l2_ctl_of_parse_property(l2, L2_WS_STALL, "baikal,l2-ws-latency");
if (ret)
return ret;
ret = l2_ctl_of_parse_property(l2, L2_TAG_STALL, "baikal,l2-tag-latency");
if (ret)
return ret;
return l2_ctl_of_parse_property(l2, L2_DATA_STALL,
"baikal,l2-data-latency");
}
static ssize_t l2_ctl_latency_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
struct l2_ctl *l2 = dev_get_drvdata(dev);
u32 data;
int ret;
ret = l2_ctl_get_latency(l2, devattr->id, &data);
if (ret)
return ret;
return sysfs_emit(buf, "%u\n", data);
}
static ssize_t l2_ctl_latency_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
struct l2_ctl *l2 = dev_get_drvdata(dev);
u32 data;
int ret;
if (kstrtouint(buf, 0, &data) < 0)
return -EINVAL;
ret = l2_ctl_set_latency(l2, devattr->id, data);
if (ret)
return ret;
return count;
}
static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL);
static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL);
static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL);
static struct attribute *l2_ctl_sysfs_attrs[] = {
&l2_ctl_attr_l2_ws_latency.dev_attr.attr,
&l2_ctl_attr_l2_tag_latency.dev_attr.attr,
&l2_ctl_attr_l2_data_latency.dev_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(l2_ctl_sysfs);
static void l2_ctl_remove_sysfs(void *data)
{
struct l2_ctl *l2 = data;
device_remove_groups(l2->dev, l2_ctl_sysfs_groups);
}
static int l2_ctl_init_sysfs(struct l2_ctl *l2)
{
int ret;
ret = device_add_groups(l2->dev, l2_ctl_sysfs_groups);
if (ret) {
dev_err(l2->dev, "Failed to create L2 CTL sysfs nodes\n");
return ret;
}
ret = devm_add_action_or_reset(l2->dev, l2_ctl_remove_sysfs, l2);
if (ret)
dev_err(l2->dev, "Can't add L2 CTL sysfs remove action\n");
return ret;
}
static int l2_ctl_probe(struct platform_device *pdev)
{
struct l2_ctl *l2;
int ret;
l2 = l2_ctl_create_data(pdev);
if (IS_ERR(l2))
return PTR_ERR(l2);
ret = l2_ctl_find_sys_regs(l2);
if (ret)
return ret;
ret = l2_ctl_of_parse(l2);
if (ret)
return ret;
ret = l2_ctl_init_sysfs(l2);
if (ret)
return ret;
return 0;
}
static const struct of_device_id l2_ctl_of_match[] = {
{ .compatible = "baikal,bt1-l2-ctl" },
{ }
};
MODULE_DEVICE_TABLE(of, l2_ctl_of_match);
static struct platform_driver l2_ctl_driver = {
.probe = l2_ctl_probe,
.driver = {
.name = "bt1-l2-ctl",
.of_match_table = l2_ctl_of_match
}
};
module_platform_driver(l2_ctl_driver);
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
MODULE_DESCRIPTION("Baikal-T1 L2-cache driver");

View File

@@ -1005,11 +1005,9 @@ static int rpcif_probe(struct platform_device *pdev)
return PTR_ERR(rpc->base);
rpc->info = of_device_get_match_data(dev);
rpc->regmap = devm_regmap_init(dev, NULL, rpc, rpc->info->regmap_config);
if (IS_ERR(rpc->regmap)) {
dev_err(dev, "failed to init regmap for rpcif, error %ld\n",
PTR_ERR(rpc->regmap));
return PTR_ERR(rpc->regmap);
}
if (IS_ERR(rpc->regmap))
return dev_err_probe(dev, PTR_ERR(rpc->regmap),
"failed to init regmap for rpcif\n");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
rpc->dirmap = devm_ioremap_resource(dev, res);

View File

@@ -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;
}
}

View File

@@ -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
/* 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_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_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_RT_TYPE_MASK (0xf << 28)
#define MC_ERR_STATUS_RT_TYPE_SHIFT 28
#define MC_ERR_STATUS_ADR_HI_SHIFT 20
#define MC_ERR_STATUS_ADR_HI_MASK 0x3
#define MC_ERR_STATUS_SECURITY BIT(17)
#define MC_ERR_STATUS_RW BIT(16)
#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_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
#define MC_TIMING_UPDATE BIT(0)
#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

View File

@@ -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),
};

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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

View File

@@ -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),
};

View File

@@ -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),
};

View File

@@ -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),
};

View File

@@ -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),
};

View File

@@ -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),
};

View File

@@ -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;

View File

@@ -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),
};

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2014 NVIDIA Corporation
* Copyright (C) 2014-2026 NVIDIA Corporation
*/
#ifndef __SOC_TEGRA_MC_H__
@@ -10,10 +10,11 @@
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/interconnect-provider.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/reset-controller.h>
#include <linux/types.h>
#include <linux/tegra-icc.h>
#include <linux/types.h>
struct clk;
struct device;
@@ -164,10 +165,31 @@ struct tegra_mc_ops {
int (*probe)(struct tegra_mc *mc);
void (*remove)(struct tegra_mc *mc);
int (*resume)(struct tegra_mc *mc);
irqreturn_t (*handle_irq)(int irq, void *data);
int (*probe_device)(struct tegra_mc *mc, struct device *dev);
};
struct tegra_mc_regs {
unsigned int cfg_channel_enable;
unsigned int err_status;
unsigned int err_add;
unsigned int err_add_hi;
unsigned int err_vpr_status;
unsigned int err_vpr_add;
unsigned int err_sec_status;
unsigned int err_sec_add;
unsigned int err_mts_status;
unsigned int err_mts_add;
unsigned int err_gen_co_status;
unsigned int err_gen_co_add;
unsigned int err_route_status;
unsigned int err_route_add;
};
struct tegra_mc_intmask {
u32 reg;
u32 mask;
};
struct tegra_mc_soc {
const struct tegra_mc_client *clients;
unsigned int num_clients;
@@ -185,7 +207,6 @@ struct tegra_mc_soc {
const struct tegra_smmu_soc *smmu;
u32 intmask;
u32 ch_intmask;
u32 global_intstatus_channel_shift;
bool has_addr_hi_reg;
@@ -196,6 +217,14 @@ struct tegra_mc_soc {
const struct tegra_mc_icc_ops *icc_ops;
const struct tegra_mc_ops *ops;
const struct tegra_mc_regs *regs;
const irq_handler_t *handle_irq;
unsigned int num_interrupts;
unsigned int mc_addr_hi_mask;
unsigned int mc_err_status_type_mask;
const struct tegra_mc_intmask *intmasks;
unsigned int num_intmasks;
};
struct tegra_mc {
@@ -206,7 +235,6 @@ struct tegra_mc {
void __iomem *bcast_ch_regs;
void __iomem **ch_regs;
struct clk *clk;
int irq;
const struct tegra_mc_soc *soc;
unsigned long tick;
@@ -256,4 +284,6 @@ tegra_mc_get_carveout_info(struct tegra_mc *mc, unsigned int id,
}
#endif
extern const struct tegra_mc_regs tegra20_mc_regs;
#endif /* __SOC_TEGRA_MC_H__ */