diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2026-04-01 23:44:55 +0200 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2026-04-01 23:44:56 +0200 |
| commit | c7091fd5ebda16a67a121f64cf37014332de965d (patch) | |
| tree | b12fbc8d9dbd2936526b6928d0b8fb755ac4147b | |
| parent | fb5fee1cbc2902981e33a6082de55007531e5b45 (diff) | |
| parent | 82169065ffb07577075a5088b313d78673ded331 (diff) | |
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>
| -rw-r--r-- | Documentation/devicetree/bindings/cache/baikal,bt1-l2-ctl.yaml | 63 | ||||
| -rw-r--r-- | drivers/memory/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/memory/Makefile | 1 | ||||
| -rw-r--r-- | drivers/memory/brcmstb_memc.c | 8 | ||||
| -rw-r--r-- | drivers/memory/bt1-l2-ctl.c | 323 | ||||
| -rw-r--r-- | drivers/memory/renesas-rpc-if.c | 8 | ||||
| -rw-r--r-- | drivers/memory/tegra/mc.c | 135 | ||||
| -rw-r--r-- | drivers/memory/tegra/mc.h | 153 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra114.c | 18 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra124-emc.c | 2 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra124.c | 40 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra186-emc.c | 8 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra186.c | 22 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra194.c | 22 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra20.c | 31 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra210.c | 21 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra234.c | 22 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra264.c | 420 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra30-emc.c | 6 | ||||
| -rw-r--r-- | drivers/memory/tegra/tegra30.c | 18 | ||||
| -rw-r--r-- | include/soc/tegra/mc.h | 40 |
21 files changed, 808 insertions, 564 deletions
diff --git a/Documentation/devicetree/bindings/cache/baikal,bt1-l2-ctl.yaml b/Documentation/devicetree/bindings/cache/baikal,bt1-l2-ctl.yaml deleted file mode 100644 index ec4f367bc0b4..000000000000 --- a/Documentation/devicetree/bindings/cache/baikal,bt1-l2-ctl.yaml +++ /dev/null @@ -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>; - }; -... diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 79df0d22e218..e5527020ff33 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -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 diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index c1959661bf63..3ee883c8759a 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -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 diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c index ba73470b1b13..c28fe9093616 100644 --- a/drivers/memory/brcmstb_memc.c +++ b/drivers/memory/brcmstb_memc.c @@ -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); diff --git a/drivers/memory/bt1-l2-ctl.c b/drivers/memory/bt1-l2-ctl.c deleted file mode 100644 index 0fd96abc172a..000000000000 --- a/drivers/memory/bt1-l2-ctl.c +++ /dev/null @@ -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"); diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 58ccc1c02e90..0fb568456164 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -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); 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 |
