diff options
Diffstat (limited to 'drivers/soc/tegra')
| -rw-r--r-- | drivers/soc/tegra/Kconfig | 29 | ||||
| -rw-r--r-- | drivers/soc/tegra/Makefile | 1 | ||||
| -rw-r--r-- | drivers/soc/tegra/cbb/tegra-cbb.c | 33 | ||||
| -rw-r--r-- | drivers/soc/tegra/cbb/tegra194-cbb.c | 50 | ||||
| -rw-r--r-- | drivers/soc/tegra/cbb/tegra234-cbb.c | 771 | ||||
| -rw-r--r-- | drivers/soc/tegra/common.c | 12 | ||||
| -rw-r--r-- | drivers/soc/tegra/flowctrl.c | 4 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra.c | 129 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra20.c | 2 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra30.c | 166 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/fuse.h | 8 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/speedo-tegra210.c | 63 | ||||
| -rw-r--r-- | drivers/soc/tegra/fuse/tegra-apbmisc.c | 116 | ||||
| -rw-r--r-- | drivers/soc/tegra/pmc.c | 405 | ||||
| -rw-r--r-- | drivers/soc/tegra/powergate-bpmp.c | 361 |
15 files changed, 1302 insertions, 848 deletions
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 3658fb0f0c5b..c0fc54c3cd35 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -96,10 +96,8 @@ config ARCH_TEGRA_210_SOC config ARCH_TEGRA_186_SOC bool "NVIDIA Tegra186 SoC" depends on !CPU_BIG_ENDIAN + select PINCTRL_TEGRA186 select MAILBOX - select TEGRA_BPMP - select TEGRA_HSP_MBOX - select TEGRA_IVC select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a @@ -114,9 +112,6 @@ config ARCH_TEGRA_194_SOC depends on !CPU_BIG_ENDIAN select MAILBOX select PINCTRL_TEGRA194 - select TEGRA_BPMP - select TEGRA_HSP_MBOX - select TEGRA_IVC select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegra194 SoC. @@ -125,13 +120,24 @@ config ARCH_TEGRA_234_SOC bool "NVIDIA Tegra234 SoC" depends on !CPU_BIG_ENDIAN select MAILBOX - select TEGRA_BPMP - select TEGRA_HSP_MBOX - select TEGRA_IVC + select PINCTRL_TEGRA234 select SOC_TEGRA_PMC help Enable support for the NVIDIA Tegra234 SoC. +config ARCH_TEGRA_241_SOC + bool "NVIDIA Tegra241 SoC" + help + Enable support for the NVIDIA Tegra241 SoC. + +config ARCH_TEGRA_264_SOC + bool "NVIDIA Tegra264 SoC" + depends on !CPU_BIG_ENDIAN + select MAILBOX + select SOC_TEGRA_PMC + help + Enable support for the NVIDIA Tegra264 SoC. + endif endif @@ -151,11 +157,6 @@ config SOC_TEGRA_PMC select PM_GENERIC_DOMAINS select REGMAP -config SOC_TEGRA_POWERGATE_BPMP - def_bool y - depends on PM_GENERIC_DOMAINS - depends on TEGRA_BPMP - config SOC_TEGRA20_VOLTAGE_COUPLER bool "Voltage scaling support for Tegra20 SoCs" depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile index d722f512dc9d..01059619e764 100644 --- a/drivers/soc/tegra/Makefile +++ b/drivers/soc/tegra/Makefile @@ -5,7 +5,6 @@ obj-y += cbb/ obj-y += common.o obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o -obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o obj-$(CONFIG_ARCH_TEGRA_186_SOC) += ari-tegra186.o diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c index a8566b9dd8de..6215c6a84fbe 100644 --- a/drivers/soc/tegra/cbb/tegra-cbb.c +++ b/drivers/soc/tegra/cbb/tegra-cbb.c @@ -7,16 +7,11 @@ #include <linux/cpufeature.h> #include <linux/debugfs.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/io.h> -#include <linux/of_irq.h> -#include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/version.h> #include <soc/tegra/fuse.h> #include <soc/tegra/tegra-cbb.h> @@ -74,19 +69,12 @@ static int tegra_cbb_err_show(struct seq_file *file, void *data) } DEFINE_SHOW_ATTRIBUTE(tegra_cbb_err); -static int tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb) +static void tegra_cbb_err_debugfs_init(struct tegra_cbb *cbb) { static struct dentry *root; - if (!root) { + if (!root) root = debugfs_create_file("tegra_cbb_err", 0444, NULL, cbb, &tegra_cbb_err_fops); - if (IS_ERR_OR_NULL(root)) { - pr_err("%s(): could not create debugfs node\n", __func__); - return PTR_ERR(root); - } - } - - return 0; } void tegra_cbb_stall_enable(struct tegra_cbb *cbb) @@ -127,20 +115,16 @@ int tegra_cbb_get_irq(struct platform_device *pdev, unsigned int *nonsec_irq, if (num_intr == 2) { irq = platform_get_irq(pdev, index); - if (irq <= 0) { - dev_err(&pdev->dev, "failed to get non-secure IRQ: %d\n", irq); + if (irq <= 0) return -ENOENT; - } *nonsec_irq = irq; index++; } irq = platform_get_irq(pdev, index); - if (irq <= 0) { - dev_err(&pdev->dev, "failed to get secure IRQ: %d\n", irq); + if (irq <= 0) return -ENOENT; - } *sec_irq = irq; @@ -157,13 +141,8 @@ int tegra_cbb_register(struct tegra_cbb *cbb) { int ret; - if (IS_ENABLED(CONFIG_DEBUG_FS)) { - ret = tegra_cbb_err_debugfs_init(cbb); - if (ret) { - dev_err(cbb->dev, "failed to create debugfs\n"); - return ret; - } - } + if (IS_ENABLED(CONFIG_DEBUG_FS)) + tegra_cbb_err_debugfs_init(cbb); /* register interrupt handler for errors due to different initiators */ ret = cbb->ops->interrupt_enable(cbb); diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index d4112b683f00..ab75d50cc85c 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved + * Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved * * The driver handles Error's from Control Backbone(CBB) generated due to * illegal accesses. When an error is reported from a NOC within CBB, @@ -15,15 +15,12 @@ #include <linux/debugfs.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/io.h> -#include <linux/of_irq.h> -#include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/version.h> #include <soc/tegra/fuse.h> #include <soc/tegra/tegra-cbb.h> @@ -141,7 +138,7 @@ struct tegra194_cbb_userbits { struct tegra194_cbb_noc_data { const char *name; bool erd_mask_inband_err; - const char * const *master_id; + const char * const *initiator_id; unsigned int max_aperture; const struct tegra194_cbb_aperture *noc_aperture; const char * const *routeid_initflow; @@ -219,7 +216,7 @@ static const char * const tegra194_axi2apb_error[] = { "CH2RFIFOF - Ch2 Request FIFO Full interrupt" }; -static const char * const tegra194_master_id[] = { +static const char * const tegra194_initiator_id[] = { [0x0] = "CCPLEX", [0x1] = "CCPLEX_DPMU", [0x2] = "BPMP", @@ -241,7 +238,7 @@ static const struct tegra_cbb_error tegra194_cbb_errors[] = { { .code = "SLV", .source = "Target", - .desc = "Target error detected by CBB slave" + .desc = "Target error detected by CBB target" }, { .code = "DEC", .source = "Initiator NIU", @@ -1777,8 +1774,8 @@ static void print_errlog5(struct seq_file *file, struct tegra194_cbb *cbb) tegra_cbb_print_err(file, "\t AXI ID\t\t: %#x\n", userbits.axi_id); } - tegra_cbb_print_err(file, "\t Master ID\t\t: %s\n", - cbb->noc->master_id[userbits.mstr_id]); + tegra_cbb_print_err(file, "\t Initiator ID\t\t: %s\n", + cbb->noc->initiator_id[userbits.mstr_id]); tegra_cbb_print_err(file, "\t Security Group(GRPSEC): %#x\n", userbits.grpsec); tegra_cbb_print_cache(file, userbits.axcache); tegra_cbb_print_prot(file, userbits.axprot); @@ -1839,15 +1836,15 @@ print_errlog1_2(struct seq_file *file, struct tegra194_cbb *cbb, } /* - * Print transcation type, error code and description from ErrLog0 for all - * errors. For NOC slave errors, all relevant error info is printed using + * Print transaction type, error code and description from ErrLog0 for all + * errors. For NOC target errors, all relevant error info is printed using * ErrLog0 only. But additional information is printed for errors from - * APB slaves because for them: - * - All errors are logged as SLV(slave) errors due to APB having only single + * APB targets because for them: + * - All errors are logged as SLV(target) errors due to APB having only single * bit pslverr to report all errors. * - Exact cause is printed by reading DMAAPB_X_RAW_INTERRUPT_STATUS register. * - The driver prints information showing AXI2APB bridge and exact error - * only if there is error in any AXI2APB slave. + * only if there is error in any AXI2APB target. * - There is still no way to disambiguate a DEC error from SLV error type. */ static bool print_errlog0(struct seq_file *file, struct tegra194_cbb *cbb) @@ -1887,8 +1884,8 @@ static bool print_errlog0(struct seq_file *file, struct tegra194_cbb *cbb) /* For all SLV errors, read DMAAPB_X_RAW_INTERRUPT_STATUS * register to get error status for all AXI2APB bridges. * Print bridge details if a bit is set in a bridge's - * status register due to error in a APB slave connected - * to that bridge. For other NOC slaves, none of the status + * status register due to error in a APB target connected + * to that bridge. For other NOC targets, none of the status * register will be set. */ @@ -2121,7 +2118,7 @@ static const struct tegra_cbb_ops tegra194_cbb_ops = { static struct tegra194_cbb_noc_data tegra194_cbb_central_noc_data = { .name = "cbb-noc", .erd_mask_inband_err = true, - .master_id = tegra194_master_id, + .initiator_id = tegra194_initiator_id, .noc_aperture = tegra194_cbbcentralnoc_apert_lookup, .max_aperture = ARRAY_SIZE(tegra194_cbbcentralnoc_apert_lookup), .routeid_initflow = tegra194_cbbcentralnoc_routeid_initflow, @@ -2133,7 +2130,7 @@ static struct tegra194_cbb_noc_data tegra194_cbb_central_noc_data = { static struct tegra194_cbb_noc_data tegra194_aon_noc_data = { .name = "aon-noc", .erd_mask_inband_err = false, - .master_id = tegra194_master_id, + .initiator_id = tegra194_initiator_id, .noc_aperture = tegra194_aonnoc_aperture_lookup, .max_aperture = ARRAY_SIZE(tegra194_aonnoc_aperture_lookup), .routeid_initflow = tegra194_aonnoc_routeid_initflow, @@ -2145,7 +2142,7 @@ static struct tegra194_cbb_noc_data tegra194_aon_noc_data = { static struct tegra194_cbb_noc_data tegra194_bpmp_noc_data = { .name = "bpmp-noc", .erd_mask_inband_err = false, - .master_id = tegra194_master_id, + .initiator_id = tegra194_initiator_id, .noc_aperture = tegra194_bpmpnoc_apert_lookup, .max_aperture = ARRAY_SIZE(tegra194_bpmpnoc_apert_lookup), .routeid_initflow = tegra194_bpmpnoc_routeid_initflow, @@ -2157,7 +2154,7 @@ static struct tegra194_cbb_noc_data tegra194_bpmp_noc_data = { static struct tegra194_cbb_noc_data tegra194_rce_noc_data = { .name = "rce-noc", .erd_mask_inband_err = false, - .master_id = tegra194_master_id, + .initiator_id = tegra194_initiator_id, .noc_aperture = tegra194_scenoc_apert_lookup, .max_aperture = ARRAY_SIZE(tegra194_scenoc_apert_lookup), .routeid_initflow = tegra194_scenoc_routeid_initflow, @@ -2169,7 +2166,7 @@ static struct tegra194_cbb_noc_data tegra194_rce_noc_data = { static struct tegra194_cbb_noc_data tegra194_sce_noc_data = { .name = "sce-noc", .erd_mask_inband_err = false, - .master_id = tegra194_master_id, + .initiator_id = tegra194_initiator_id, .noc_aperture = tegra194_scenoc_apert_lookup, .max_aperture = ARRAY_SIZE(tegra194_scenoc_apert_lookup), .routeid_initflow = tegra194_scenoc_routeid_initflow, @@ -2191,7 +2188,6 @@ MODULE_DEVICE_TABLE(of, tegra194_cbb_match); static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node *np) { struct tegra_cbb *entry; - struct resource res; unsigned long flags; unsigned int i; int err; @@ -2211,8 +2207,7 @@ static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node spin_unlock_irqrestore(&cbb_lock, flags); if (!cbb->bridges) { - while (of_address_to_resource(np, cbb->num_bridges, &res) == 0) - cbb->num_bridges++; + cbb->num_bridges = of_address_count(np); cbb->bridges = devm_kcalloc(cbb->base.dev, cbb->num_bridges, sizeof(*cbb->bridges), GFP_KERNEL); @@ -2298,7 +2293,7 @@ static int tegra194_cbb_probe(struct platform_device *pdev) return tegra_cbb_register(&cbb->base); } -static int tegra194_cbb_remove(struct platform_device *pdev) +static void tegra194_cbb_remove(struct platform_device *pdev) { struct tegra194_cbb *cbb = platform_get_drvdata(pdev); struct tegra_cbb *noc, *tmp; @@ -2316,8 +2311,6 @@ static int tegra194_cbb_remove(struct platform_device *pdev) } spin_unlock_irqrestore(&cbb_lock, flags); - - return 0; } static int __maybe_unused tegra194_cbb_resume_noirq(struct device *dev) @@ -2359,4 +2352,3 @@ module_exit(tegra194_cbb_exit); MODULE_AUTHOR("Sumit Gupta <sumitg@nvidia.com>"); MODULE_DESCRIPTION("Control Backbone error handling driver for Tegra194"); -MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c index f33d094e5ea6..a9adbcecd47c 100644 --- a/drivers/soc/tegra/cbb/tegra234-cbb.c +++ b/drivers/soc/tegra/cbb/tegra234-cbb.c @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved + * Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved * * The driver handles Error's from Control Backbone(CBB) version 2.0. * generated due to illegal accesses. The driver prints debug information * about failed transaction on receiving interrupt from Error Notifier. * Error types supported by CBB2.0 are: * UNSUPPORTED_ERR, PWRDOWN_ERR, TIMEOUT_ERR, FIREWALL_ERR, DECODE_ERR, - * SLAVE_ERR + * TARGET_ERR */ #include <linux/acpi.h> @@ -16,15 +16,11 @@ #include <linux/debugfs.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/io.h> -#include <linux/of_irq.h> -#include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/version.h> #include <soc/tegra/fuse.h> #include <soc/tegra/tegra-cbb.h> @@ -34,18 +30,22 @@ #define FABRIC_EN_CFG_ADDR_LOW_0 0x80 #define FABRIC_EN_CFG_ADDR_HI_0 0x84 -#define FABRIC_MN_MASTER_ERR_EN_0 0x200 -#define FABRIC_MN_MASTER_ERR_FORCE_0 0x204 -#define FABRIC_MN_MASTER_ERR_STATUS_0 0x208 -#define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0 0x20c +#define FABRIC_EN_CFG_TARGET_NODE_ADDR_INDEX_0_0 0x100 +#define FABRIC_EN_CFG_TARGET_NODE_ADDR_LOW_0 0x140 +#define FABRIC_EN_CFG_TARGET_NODE_ADDR_HI_0 0x144 -#define FABRIC_MN_MASTER_LOG_ERR_STATUS_0 0x300 -#define FABRIC_MN_MASTER_LOG_ADDR_LOW_0 0x304 -#define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0 0x308 -#define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0 0x30c -#define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0 0x310 -#define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0 0x314 -#define FABRIC_MN_MASTER_LOG_USER_BITS0_0 0x318 +#define FABRIC_MN_INITIATOR_ERR_EN_0 0x200 +#define FABRIC_MN_INITIATOR_ERR_FORCE_0 0x204 +#define FABRIC_MN_INITIATOR_ERR_STATUS_0 0x208 +#define FABRIC_MN_INITIATOR_ERR_OVERFLOW_STATUS_0 0x20c + +#define FABRIC_MN_INITIATOR_LOG_ERR_STATUS_0 0x300 +#define FABRIC_MN_INITIATOR_LOG_ADDR_LOW_0 0x304 +#define FABRIC_MN_INITIATOR_LOG_ADDR_HIGH_0 0x308 +#define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES0_0 0x30c +#define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES1_0 0x310 +#define FABRIC_MN_INITIATOR_LOG_ATTRIBUTES2_0 0x314 +#define FABRIC_MN_INITIATOR_LOG_USER_BITS0_0 0x318 #define AXI_SLV_TIMEOUT_STATUS_0_0 0x8 #define APB_BLOCK_TMO_STATUS_0 0xc00 @@ -57,7 +57,7 @@ #define FAB_EM_EL_FALCONSEC GENMASK(1, 0) #define FAB_EM_EL_FABID GENMASK(20, 16) -#define FAB_EM_EL_SLAVEID GENMASK(7, 0) +#define FAB_EM_EL_TARGETID GENMASK(7, 0) #define FAB_EM_EL_ACCESSID GENMASK(7, 0) @@ -78,34 +78,79 @@ #define WEN 0x20000 enum tegra234_cbb_fabric_ids { - CBB_FAB_ID, - SCE_FAB_ID, - RCE_FAB_ID, - DCE_FAB_ID, - AON_FAB_ID, - PSC_FAB_ID, - BPMP_FAB_ID, - FSI_FAB_ID, - MAX_FAB_ID, + T234_CBB_FABRIC_ID, + T234_SCE_FABRIC_ID, + T234_RCE_FABRIC_ID, + T234_DCE_FABRIC_ID, + T234_AON_FABRIC_ID, + T234_PSC_FABRIC_ID, + T234_BPMP_FABRIC_ID, + T234_FSI_FABRIC_ID, + T234_MAX_FABRIC_ID, +}; + +enum tegra264_cbb_fabric_ids { + T264_SYSTEM_CBB_FABRIC_ID, + T264_TOP_0_CBB_FABRIC_ID, + T264_VISION_CBB_FABRIC_ID, + T264_DISP_USB_CBB_FABRIC_ID, + T264_UPHY0_CBB_FABRIC_ID, + T264_RSVD0_FABRIC_ID, + T264_RSVD1_FABRIC_ID, + T264_RSVD2_FABRIC_ID, + T264_RSVD3_FABRIC_ID, + T264_RSVD4_FABRIC_ID, + T264_RSVD5_FABRIC_ID, + T264_AON_FABRIC_ID, + T264_PSC_FABRIC_ID, + T264_OESP_FABRIC_ID, + T264_APE_FABRIC_ID, + T264_BPMP_FABRIC_ID, + T264_RCE_0_FABRIC_ID, + T264_RCE_1_FABRIC_ID, + T264_RSVD6_FABRIC_ID, + T264_DCE_FABRIC_ID, + T264_FSI_FABRIC_ID, + T264_ISC_FABRIC_ID, + T264_SB_FABRIC_ID, + T264_ISC_CPU_FABRIC_ID, + T264_RSVD7_FABRIC_ID, +}; + +enum t254_cbb_fabric_ids { + T254_DCE_FABRIC_ID = 19, + T254_DISP_CLUSTER_FABRIC_ID = 25, + T254_C2C_FABRIC_ID = 26, + T254_GPU_FABRIC_ID = 27, + T254_DISP_CLUSTER_1_FABRIC_ID = 28, + T254_MAX_FABRIC_ID, }; -struct tegra234_slave_lookup { +struct tegra234_target_lookup { const char *name; unsigned int offset; }; -struct tegra234_cbb_fabric { +struct tegra234_fabric_lookup { const char *name; + bool is_lookup; + const struct tegra234_target_lookup *target_map; + const int max_targets; +}; + +struct tegra234_cbb_fabric { + int fab_id; phys_addr_t off_mask_erd; phys_addr_t firewall_base; unsigned int firewall_ctl; unsigned int firewall_wr_ctl; - const char * const *master_id; + const char * const *initiator_id; unsigned int notifier_offset; const struct tegra_cbb_error *errors; const int max_errors; - const struct tegra234_slave_lookup *slave_map; - const int max_slaves; + const struct tegra234_fabric_lookup *fab_list; + const u32 err_intr_enbl; + const u32 err_status_clr; }; struct tegra234_cbb { @@ -181,7 +226,7 @@ static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb) void __iomem *addr; addr = priv->regs + priv->fabric->notifier_offset; - writel(0x1ff, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0); + writel(priv->fabric->err_intr_enbl, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0); dsb(sy); } @@ -189,7 +234,9 @@ static void tegra234_cbb_error_clear(struct tegra_cbb *cbb) { struct tegra234_cbb *priv = to_tegra234_cbb(cbb); - writel(0x3f, priv->mon + FABRIC_MN_MASTER_ERR_STATUS_0); + writel(0, priv->mon + FABRIC_MN_INITIATOR_ERR_FORCE_0); + + writel(priv->fabric->err_status_clr, priv->mon + FABRIC_MN_INITIATOR_ERR_STATUS_0); dsb(sy); } @@ -220,13 +267,13 @@ static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr) return timeout; } -static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *slave, void __iomem *addr, +static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *target, void __iomem *addr, u32 status) { - tegra_cbb_print_err(file, "\t %s : %#x\n", slave, status); + tegra_cbb_print_err(file, "\t %s : %#x\n", target, status); } -static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave, +static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target, void __iomem *base) { unsigned int block = 0; @@ -236,7 +283,7 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave, status = tegra234_cbb_get_tmo_slv(base); if (status) - tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", slave, status); + tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", target, status); while (status) { if (status & BIT(0)) { @@ -251,7 +298,7 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave, if (clients != 0xffffffff) clients &= BIT(client); - sprintf(name, "%s_BLOCK%d_TMO", slave, block); + sprintf(name, "%s_BLOCK%d_TMO", target, block); tegra234_cbb_tmo_slv(file, name, addr, clients); } @@ -266,22 +313,27 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave, } } -static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234_cbb *cbb, - u8 slave_id, u8 fab_id) +static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb, + u8 target_id, u8 fab_id) { - const struct tegra234_slave_lookup *map = cbb->fabric->slave_map; + const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map; void __iomem *addr; + if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) { + tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id); + return; + } + /* - * 1) Get slave node name and address mapping using slave_id. - * 2) Check if the timed out slave node is APB or AXI. - * 3) If AXI, then print timeout register and reset axi slave + * 1) Get target node name and address mapping using target_id. + * 2) Check if the timed out target node is APB or AXI. + * 3) If AXI, then print timeout register and reset axi target * using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register. * 4) If APB, then perform an additional lookup to find the client * which timed out. * a) Get block number from the index of set bit in * <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register. - * b) Get address of register repective to block number i.e. + * b) Get address of register respective to block number i.e. * <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0. * c) Read the register in above step to get client_id which * timed out as per the set bits. @@ -289,12 +341,12 @@ static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234 * e) Goto step-a till all bits are set. */ - addr = cbb->regs + map[slave_id].offset; + addr = cbb->regs + map[target_id].offset; - if (strstr(map[slave_id].name, "AXI2APB")) { + if (strstr(map[target_id].name, "AXI2APB")) { addr += APB_BLOCK_TMO_STATUS_0; - tegra234_cbb_lookup_apbslv(file, map[slave_id].name, addr); + tegra234_cbb_lookup_apbslv(file, map[target_id].name, addr); } else { char name[64]; u32 status; @@ -303,12 +355,29 @@ static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234 status = tegra234_cbb_get_tmo_slv(addr); if (status) { - sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[slave_id].name); + sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[target_id].name); tegra234_cbb_tmo_slv(file, name, addr, status); } } } +static void tegra234_hw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb, + u8 target_id, u8 fab_id) +{ + unsigned int notifier = cbb->fabric->notifier_offset; + u32 hi, lo; + u64 addr; + + writel(target_id, cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_INDEX_0_0); + + hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_HI_0); + lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_TARGET_NODE_ADDR_LOW_0); + + addr = (u64)hi << 32 | lo; + + tegra_cbb_print_err(file, "\t Target Node Addr : %#llx\n", addr); +} + static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status, u32 overflow) { @@ -353,8 +422,7 @@ static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) { u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size; - u8 access_type, access_id, requester_socket_id, local_socket_id, slave_id, fab_id; - char fabric_name[20]; + u8 access_type, access_id, requester_socket_id, local_socket_id, target_id, fab_id; bool is_numa = false; u8 burst_type; @@ -368,7 +436,7 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) /* * For SOC with multiple NUMA nodes, print cross socket access - * errors only if initiator/master_id is CCPLEX, CPMU or GPU. + * errors only if initiator_id is CCPLEX, CPMU or GPU. */ if (is_numa) { local_socket_id = numa_node_id(); @@ -381,7 +449,7 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) } fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2); - slave_id = FIELD_GET(FAB_EM_EL_SLAVEID, cbb->mn_attr2); + target_id = FIELD_GET(FAB_EM_EL_TARGETID, cbb->mn_attr2); access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1); @@ -399,21 +467,18 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) else tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type); - tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]); + tegra_cbb_print_err(file, "\t Initiator_Id\t\t: %#x\n", mstr_id); + if (cbb->fabric->initiator_id) + tegra_cbb_print_err(file, "\t Initiator\t\t: %s\n", + cbb->fabric->initiator_id[mstr_id]); + tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access); tegra_cbb_print_cache(file, cache_type); tegra_cbb_print_prot(file, prot_type); tegra_cbb_print_err(file, "\t Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n"); - tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x", access_id); - - if (fab_id == PSC_FAB_ID) - strcpy(fabric_name, "psc-fabric"); - else if (fab_id == FSI_FAB_ID) - strcpy(fabric_name, "fsi-fabric"); - else - strcpy(fabric_name, cbb->fabric->name); + tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x\n", access_id); if (is_numa) { tegra_cbb_print_err(file, "\t Requester_Socket_Id\t: %#x\n", @@ -424,8 +489,21 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) num_possible_nodes()); } - tegra_cbb_print_err(file, "\t Fabric\t\t: %s\n", fabric_name); - tegra_cbb_print_err(file, "\t Slave_Id\t\t: %#x\n", slave_id); + tegra_cbb_print_err(file, "\t Fabric\t\t: %s (id:%#x)\n", + cbb->fabric->fab_list[fab_id].name, fab_id); + + if (of_machine_is_compatible("nvidia,tegra264") && fab_id == T264_UPHY0_CBB_FABRIC_ID) { + /* + * In T264, AON Fabric ID value is incorrectly same as UPHY0 fabric ID. + * For 'ID = 0x4', we must check for the address which caused the error + * to find the correct fabric which returned error. + */ + tegra_cbb_print_err(file, "\t or Fabric\t\t: %s\n", + cbb->fabric->fab_list[T264_AON_FABRIC_ID].name); + tegra_cbb_print_err(file, "\t Please use Address to determine correct fabric.\n"); + } + + tegra_cbb_print_err(file, "\t Target_Id\t\t: %#x\n", target_id); tegra_cbb_print_err(file, "\t Burst_length\t\t: %#x\n", burst_length); tegra_cbb_print_err(file, "\t Burst_type\t\t: %#x\n", burst_type); tegra_cbb_print_err(file, "\t Beat_size\t\t: %#x\n", beat_size); @@ -433,27 +511,30 @@ static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) tegra_cbb_print_err(file, "\t GRPSEC\t\t: %#x\n", grpsec); tegra_cbb_print_err(file, "\t FALCONSEC\t\t: %#x\n", falconsec); - if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID)) + if (!cbb->fabric->fab_list[fab_id].is_lookup) return; - if (slave_id >= cbb->fabric->max_slaves) { - tegra_cbb_print_err(file, "\t Invalid slave_id:%d\n", slave_id); - return; - } - + /* + * If is_lookup field is set in fabric_lookup table of soc data, it + * means that address lookup of target is supported for Timeout errors. + * If is_lookup is set and the target_map is not populated making + * max_targets as zero, then it means HW lookup is to be performed. + */ if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) { - tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id); - return; + if (cbb->fabric->fab_list[fab_id].max_targets) + tegra234_sw_lookup_target_timeout(file, cbb, target_id, fab_id); + else + tegra234_hw_lookup_target_timeout(file, cbb, target_id, fab_id); } - tegra_cbb_print_err(file, "\t Slave\t\t\t: %s\n", cbb->fabric->slave_map[slave_id].name); + return; } static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb) { u32 overflow, status, error; - status = readl(cbb->mon + FABRIC_MN_MASTER_ERR_STATUS_0); + status = readl(cbb->mon + FABRIC_MN_INITIATOR_ERR_STATUS_0); if (!status) { pr_err("Error Notifier received a spurious notification\n"); return -ENODATA; @@ -464,11 +545,11 @@ static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb) return -EINVAL; } - overflow = readl(cbb->mon + FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0); + overflow = readl(cbb->mon + FABRIC_MN_INITIATOR_ERR_OVERFLOW_STATUS_0); tegra234_cbb_print_error(file, cbb, status, overflow); - error = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ERR_STATUS_0); + error = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ERR_STATUS_0); if (!error) { pr_info("Error Monitor doesn't have Error Logger\n"); return -EINVAL; @@ -480,15 +561,15 @@ static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb) if (error & BIT(0)) { u32 hi, lo; - hi = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_HIGH_0); - lo = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_LOW_0); + hi = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ADDR_HIGH_0); + lo = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ADDR_LOW_0); cbb->access = (u64)hi << 32 | lo; - cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0); - cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0); - cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0); - cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_MASTER_LOG_USER_BITS0_0); + cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES0_0); + cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES1_0); + cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_ATTRIBUTES2_0); + cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_INITIATOR_LOG_USER_BITS0_0); print_errlog_err(file, cbb); } @@ -507,7 +588,7 @@ static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u pr_crit("**************************************\n"); pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(), - cbb->fabric->name, status); + cbb->fabric->fab_list[cbb->fabric->fab_id].name, status); while (status) { if (status & BIT(0)) { @@ -530,13 +611,13 @@ static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u tegra234_cbb_error_clear(&cbb->base); if (err) return err; + tegra_cbb_print_err(file, "\t**************************************\n"); } status >>= 1; index++; } - tegra_cbb_print_err(file, "\t**************************************\n"); return 0; } @@ -585,7 +666,8 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data) if (status && (irq == priv->sec_irq)) { tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n", - smp_processor_id(), priv->fabric->name, + smp_processor_id(), + priv->fabric->fab_list[priv->fabric->fab_id].name, priv->res->start, irq); err = print_err_notifier(NULL, priv, status); @@ -593,7 +675,7 @@ static irqreturn_t tegra234_cbb_isr(int irq, void *data) goto unlock; /* - * If illegal request is from CCPLEX(id:0x1) master then call WARN() + * If illegal request is from CCPLEX(id:0x1) initiator then call WARN() */ if (priv->fabric->off_mask_erd) { mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits); @@ -645,7 +727,7 @@ static const struct tegra_cbb_ops tegra234_cbb_ops = { #endif }; -static const char * const tegra234_master_id[] = { +static const char * const tegra234_initiator_id[] = { [0x00] = "TZ", [0x01] = "CCPLEX", [0x02] = "CCPMU", @@ -676,8 +758,8 @@ static const char * const tegra234_master_id[] = { static const struct tegra_cbb_error tegra234_cbb_errors[] = { { - .code = "SLAVE_ERR", - .desc = "Slave being accessed responded with an error" + .code = "TARGET_ERR", + .desc = "Target being accessed responded with an error" }, { .code = "DECODE_ERR", .desc = "Attempt to access an address hole" @@ -686,37 +768,24 @@ static const struct tegra_cbb_error tegra234_cbb_errors[] = { .desc = "Attempt to access a region which is firewall protected" }, { .code = "TIMEOUT_ERR", - .desc = "No response returned by slave" + .desc = "No response returned by target" }, { .code = "PWRDOWN_ERR", .desc = "Attempt to access a portion of fabric that is powered down" }, { .code = "UNSUPPORTED_ERR", - .desc = "Attempt to access a slave through an unsupported access" + .desc = "Attempt to access a target through an unsupported access" } }; -static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = { +static const struct tegra234_target_lookup tegra234_aon_target_map[] = { { "AXI2APB", 0x00000 }, { "AST", 0x14000 }, { "CBB", 0x15000 }, { "CPU", 0x16000 }, }; -static const struct tegra234_cbb_fabric tegra234_aon_fabric = { - .name = "aon-fabric", - .master_id = tegra234_master_id, - .slave_map = tegra234_aon_slave_map, - .max_slaves = ARRAY_SIZE(tegra234_aon_slave_map), - .errors = tegra234_cbb_errors, - .max_errors = ARRAY_SIZE(tegra234_cbb_errors), - .notifier_offset = 0x17000, - .firewall_base = 0x30000, - .firewall_ctl = 0x8d0, - .firewall_wr_ctl = 0x8c8, -}; - -static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = { +static const struct tegra234_target_lookup tegra234_bpmp_target_map[] = { { "AXI2APB", 0x00000 }, { "AST0", 0x15000 }, { "AST1", 0x16000 }, @@ -724,20 +793,16 @@ static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = { { "CPU", 0x18000 }, }; -static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = { - .name = "bpmp-fabric", - .master_id = tegra234_master_id, - .slave_map = tegra234_bpmp_slave_map, - .max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map), - .errors = tegra234_cbb_errors, - .max_errors = ARRAY_SIZE(tegra234_cbb_errors), - .notifier_offset = 0x19000, - .firewall_base = 0x30000, - .firewall_ctl = 0x8f0, - .firewall_wr_ctl = 0x8e8, +static const struct tegra234_target_lookup tegra234_common_target_map[] = { + { "AXI2APB", 0x00000 }, + { "AST0", 0x15000 }, + { "AST1", 0x16000 }, + { "CBB", 0x17000 }, + { "RSVD", 0x00000 }, + { "CPU", 0x18000 }, }; -static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = { +static const struct tegra234_target_lookup tegra234_cbb_target_map[] = { { "AON", 0x40000 }, { "BPMP", 0x41000 }, { "CBB", 0x42000 }, @@ -801,13 +866,65 @@ static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = { { "AXI2APB_3", 0x91000 }, }; +static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = { + [T234_CBB_FABRIC_ID] = { "cbb-fabric", true, + tegra234_cbb_target_map, + ARRAY_SIZE(tegra234_cbb_target_map) }, + [T234_SCE_FABRIC_ID] = { "sce-fabric", true, + tegra234_common_target_map, + ARRAY_SIZE(tegra234_common_target_map) }, + [T234_RCE_FABRIC_ID] = { "rce-fabric", true, + tegra234_common_target_map, + ARRAY_SIZE(tegra234_common_target_map) }, + [T234_DCE_FABRIC_ID] = { "dce-fabric", true, + tegra234_common_target_map, + ARRAY_SIZE(tegra234_common_target_map) }, + [T234_AON_FABRIC_ID] = { "aon-fabric", true, + tegra234_aon_target_map, + ARRAY_SIZE(tegra234_bpmp_target_map) }, + [T234_PSC_FABRIC_ID] = { "psc-fabric" }, + [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true, + tegra234_bpmp_target_map, + ARRAY_SIZE(tegra234_bpmp_target_map) }, + [T234_FSI_FABRIC_ID] = { "fsi-fabric" }, +}; + +static const struct tegra234_cbb_fabric tegra234_aon_fabric = { + .fab_id = T234_AON_FABRIC_ID, + .fab_list = tegra234_cbb_fab_list, + .initiator_id = tegra234_initiator_id, + .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), + .err_intr_enbl = 0x7, + .err_status_clr = 0x3f, + .notifier_offset = 0x17000, + .firewall_base = 0x30000, + .firewall_ctl = 0x8d0, + .firewall_wr_ctl = 0x8c8, +}; + +static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = { + .fab_id = T234_BPMP_FABRIC_ID, + .fab_list = tegra234_cbb_fab_list, + .initiator_id = tegra234_initiator_id, + .errors = tegra234_cbb_errors, + .max_errors = ARRAY_SIZE(tegra234_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x3f, + .notifier_offset = 0x19000, + .firewall_base = 0x30000, + .firewall_ctl = 0x8f0, + .firewall_wr_ctl = 0x8e8, +}; + static const struct tegra234_cbb_fabric tegra234_cbb_fabric = { - .name = "cbb-fabric", - .master_id = tegra234_master_id, - .slave_map = tegra234_cbb_slave_map, - .max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map), + .fab_id = T234_CBB_FABRIC_ID, + .fab_list = tegra234_cbb_fab_list, + .initiator_id = tegra234_initiator_id, .errors = tegra234_cbb_errors, .max_errors = ARRAY_SIZE(tegra234_cbb_errors), + .err_intr_enbl = 0x7f, + .err_status_clr = 0x3f, .notifier_offset = 0x60000, .off_mask_erd = 0x3a004, .firewall_base = 0x10000, @@ -815,22 +932,14 @@ static const struct tegra234_cbb_fabric tegra234_cbb_fabric = { .firewall_wr_ctl = 0x23e8, }; -static const struct tegra234_slave_lookup tegra234_common_slave_map[] = { - { "AXI2APB", 0x00000 }, - { "AST0", 0x15000 }, - { "AST1", 0x16000 }, - { "CBB", 0x17000 }, - { "RSVD", 0x00000 }, - { "CPU", 0x18000 }, -}; - static const struct tegra234_cbb_fabric tegra234_dce_fabric = { - .name = "dce-fabric", - .master_id = tegra234_master_id, - .slave_map = tegra234_common_slave_map, - .max_slaves = ARRAY_SIZE(tegra234_common_slave_map), + .fab_id = T234_DCE_FABRIC_ID, + .fab_list = tegra234_cbb_fab_list, + .initiator_id = tegra234_initiator_id, .errors = tegra234_cbb_errors, .max_errors = ARRAY_SIZE(tegra234_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x3f, .notifier_offset = 0x19000, .firewall_base = 0x30000, .firewall_ctl = 0x290, @@ -838,12 +947,13 @@ static const struct tegra234_cbb_fabric tegra234_dce_fabric = { }; static const struct tegra234_cbb_fabric tegra234_rce_fabric = { - .name = "rce-fabric", - .master_id = tegra234_master_id, - .slave_map = tegra234_common_slave_map, - .max_slaves = ARRAY_SIZE(tegra234_common_slave_map), + .fab_id = T234_RCE_FABRIC_ID, + .fab_list = tegra234_cbb_fab_list, + .initiator_id = tegra234_initiator_id, .errors = tegra234_cbb_errors, .max_errors = ARRAY_SIZE(tegra234_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x3f, .notifier_offset = 0x19000, .firewall_base = 0x30000, .firewall_ctl = 0x290, @@ -851,19 +961,20 @@ static const struct tegra234_cbb_fabric tegra234_rce_fabric = { }; static const struct tegra234_cbb_fabric tegra234_sce_fabric = { - .name = "sce-fabric", - .master_id = tegra234_master_id, - .slave_map = tegra234_common_slave_map, - .max_slaves = ARRAY_SIZE(tegra234_common_slave_map), + .fab_id = T234_SCE_FABRIC_ID, + .fab_list = tegra234_cbb_fab_list, + .initiator_id = tegra234_initiator_id, .errors = tegra234_cbb_errors, .max_errors = ARRAY_SIZE(tegra234_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x3f, .notifier_offset = 0x19000, .firewall_base = 0x30000, .firewall_ctl = 0x290, .firewall_wr_ctl = 0x288, }; -static const char * const tegra241_master_id[] = { +static const char * const tegra241_initiator_id[] = { [0x0] = "TZ", [0x1] = "CCPLEX", [0x2] = "CCPMU", @@ -881,22 +992,22 @@ static const char * const tegra241_master_id[] = { }; /* - * Possible causes for Slave and Timeout errors. - * SLAVE_ERR: - * Slave being accessed responded with an error. Slave could return + * Possible causes for Target and Timeout errors. + * TARGET_ERR: + * Target being accessed responded with an error. Target could return * an error for various cases : * Unsupported access, clamp setting when power gated, register - * level firewall(SCR), address hole within the slave, etc + * level firewall(SCR), address hole within the target, etc * * TIMEOUT_ERR: - * No response returned by slave. Can be due to slave being clock - * gated, under reset, powered down or slave inability to respond - * for an internal slave issue + * No response returned by target. Can be due to target being clock + * gated, under reset, powered down or target inability to respond + * for an internal target issue */ static const struct tegra_cbb_error tegra241_cbb_errors[] = { { - .code = "SLAVE_ERR", - .desc = "Slave being accessed responded with an error." + .code = "TARGET_ERR", + .desc = "Target being accessed responded with an error." }, { .code = "DECODE_ERR", .desc = "Attempt to access an address hole or Reserved region of memory." @@ -905,16 +1016,16 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = { .desc = "Attempt to access a region which is firewalled." }, { .code = "TIMEOUT_ERR", - .desc = "No response returned by slave." + .desc = "No response returned by target." }, { .code = "PWRDOWN_ERR", .desc = "Attempt to access a portion of the fabric that is powered down." }, { .code = "UNSUPPORTED_ERR", - .desc = "Attempt to access a slave through an unsupported access." + .desc = "Attempt to access a target through an unsupported access." }, { .code = "POISON_ERR", - .desc = "Slave responds with poison error to indicate error in data." + .desc = "Target responds with poison error to indicate error in data." }, { .code = "RSVD" }, { @@ -972,7 +1083,18 @@ static const struct tegra_cbb_error tegra241_cbb_errors[] = { }, }; -static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = { +static const struct tegra234_target_lookup tegra241_bpmp_target_map[] = { + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "CBB", 0x15000 }, + { "CPU", 0x16000 }, + { "AXI2APB", 0x00000 }, + { "DBB0", 0x17000 }, + { "DBB1", 0x18000 }, +}; + +static const struct tegra234_target_lookup tegra241_cbb_target_map[] = { { "RSVD", 0x00000 }, { "PCIE_C8", 0x51000 }, { "PCIE_C9", 0x52000 }, @@ -1034,13 +1156,20 @@ static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = { { "AXI2APB_32", 0x8F000 }, }; +static const struct tegra234_fabric_lookup tegra241_cbb_fab_list[] = { + [T234_CBB_FABRIC_ID] = { "cbb-fabric", true, + tegra241_cbb_target_map, ARRAY_SIZE(tegra241_cbb_target_map) }, + [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true, + tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_cbb_target_map) }, +}; static const struct tegra234_cbb_fabric tegra241_cbb_fabric = { - .name = "cbb-fabric", - .master_id = tegra241_master_id, - .slave_map = tegra241_cbb_slave_map, - .max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map), + .fab_id = T234_CBB_FABRIC_ID, + .fab_list = tegra241_cbb_fab_list, + .initiator_id = tegra241_initiator_id, .errors = tegra241_cbb_errors, .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0x7, + .err_status_clr = 0x1ff007f, .notifier_offset = 0x60000, .off_mask_erd = 0x40004, .firewall_base = 0x20000, @@ -1048,30 +1177,302 @@ static const struct tegra234_cbb_fabric tegra241_cbb_fabric = { .firewall_wr_ctl = 0x2368, }; -static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = { - { "RSVD", 0x00000 }, - { "RSVD", 0x00000 }, - { "RSVD", 0x00000 }, - { "CBB", 0x15000 }, - { "CPU", 0x16000 }, - { "AXI2APB", 0x00000 }, - { "DBB0", 0x17000 }, - { "DBB1", 0x18000 }, -}; - static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = { - .name = "bpmp-fabric", - .master_id = tegra241_master_id, - .slave_map = tegra241_bpmp_slave_map, - .max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map), + .fab_id = T234_BPMP_FABRIC_ID, + .fab_list = tegra241_cbb_fab_list, + .initiator_id = tegra241_initiator_id, .errors = tegra241_cbb_errors, .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x1ff007f, .notifier_offset = 0x19000, .firewall_base = 0x30000, .firewall_ctl = 0x8f0, .firewall_wr_ctl = 0x8e8, }; +static const char * const tegra264_initiator_id[] = { + [0x0] = "TZ", + [0x1] = "CCPLEX", + [0x2] = "ISC", + [0x3] = "BPMP_FW", + [0x4] = "AON", + [0x5] = "MSS_SEQ", + [0x6] = "GPCDMA_P", + [0x7] = "TSECA_NONSECURE", + [0x8] = "TSECA_LIGHTSECURE", + [0x9] = "TSECA_HEAVYSECURE", + [0xa] = "CORESIGHT", + [0xb] = "APE_0", + [0xc] = "APE_1", + [0xd] = "PEATRANS", + [0xe] = "JTAGM_DFT", + [0xf] = "RCE", + [0x10] = "DCE", + [0x11] = "PSC_FW_USER", + [0x12] = "PSC_FW_SUPERVISOR", + [0x13] = "PSC_FW_MACHINE", + [0x14] = "PSC_BOOT", + [0x15] = "BPMP_BOOT", + [0x16] = "GPU_0", + [0x17] = "GPU_1", + [0x18] = "GPU_2", + [0x19] = "GPU_3", + [0x1a] = "GPU_4", + [0x1b] = "PSC_EXT_BOOT", + [0x1c] = "PSC_EXT_RUNTIME", + [0x1d] = "OESP_EXT", + [0x1e] = "SB_EXT", + [0x1f] = "FSI_SAFETY_0", + [0x20] = "FSI_SAFETY_1", + [0x21] = "FSI_SAFETY_2", + [0x22] = "FSI_SAFETY_3", + [0x23] = "FSI_CHSM", + [0x24] = "RCE_1", + [0x25] = "BPMP_OEM_FW", + [0x26 ... 0x3d] = "RSVD", + [0x3e] = "CBB_SMN", + [0x3f] = "CBB_RSVD" +}; + +static const struct tegra234_target_lookup tegra264_top0_cbb_target_map[] = { + { "RSVD", 0x000000 }, + { "CBB_CENTRAL", 0xC020000 }, + { "AXI2APB_1", 0x80000 }, + { "AXI2APB_10", 0x81000 }, + { "AXI2APB_11", 0x82000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_14", 0x83000 }, + { "AXI2APB_15", 0x84000 }, + { "AXI2APB_16", 0x85000 }, + { "AXI2APB_17", 0x86000 }, + { "AXI2APB_2", 0x87000 }, + { "AXI2APB_3", 0x88000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_5", 0x8A000 }, + { "AXI2APB_6", 0x8B000 }, + { "AXI2APB_7", 0x8C000 }, + { "AXI2APB_8", 0x8D000 }, + { "AXI2APB_9", 0x8E000 }, + { "FSI_SLAVE", 0x64000 }, + { "DISP_USB_CBB_T", 0x65000 }, + { "SYSTEM_CBB_T", 0x66000 }, + { "UPHY0_CBB_T", 0x67000 }, + { "VISION_CBB_T", 0x68000 }, + { "CCPLEX_SLAVE", 0x69000 }, + { "PCIE_C0", 0x6A000 }, + { "SMN_UCF_RX_0", 0x6B000 }, + { "SMN_UCF_RX_1", 0x6C000 }, + { "AXI2APB_4", 0x89000 }, +}; + +static const struct tegra234_target_lookup tegra264_sys_cbb_target_map[] = { + { "RSVD", 0x00000 }, + { "AXI2APB_1", 0xE1000 }, + { "RSVD", 0x00000 }, + { "AON_SLAVE", 0x79000 }, + { "APE_SLAVE", 0x73000 }, + { "BPMP_SLAVE", 0x74000 }, + { "OESP_SLAVE", 0x75000 }, + { "PSC_SLAVE", 0x76000 }, + { "SB_SLAVE", 0x7A000 }, + { "SMN_SYSTEM_RX", 0x7B000 }, + { "STM", 0x77000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_3", 0xE3000 }, + { "TOP_CBB_T", 0x7C000 }, + { "AXI2APB_2", 0xE4000 }, + { "AXI2APB_4", 0xE5000 }, + { "AXI2APB_5", 0xE6000 }, +}; + +static const struct tegra234_target_lookup tegra264_uphy0_cbb_target_map[] = { + [0 ... 20] = { "RSVD", 0x00000 }, + { "AXI2APB_1", 0x71000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_3", 0x75000 }, + { "SMN_UPHY0_RX", 0x53000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "PCIE_C4", 0x4B000 }, + { "AXI2APB_2", 0x74000 }, + { "AXI2APB_4", 0x76000 }, + { "AXI2APB_5", 0x77000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_7", 0x79000 }, + { "PCIE_C2", 0x56000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "PCIE_C1", 0x55000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_10", 0x72000 }, + { "AXI2APB_11", 0x7C000 }, + { "AXI2APB_8", 0x7A000 }, + { "AXI2APB_9", 0x7B000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "PCIE_C5", 0x4E000 }, + { "PCIE_C3", 0x58000 }, + { "RSVD", 0x00000 }, + { "ISC_SLAVE", 0x54000 }, + { "TOP_CBB_T", 0x57000 }, + { "AXI2APB_12", 0x7D000 }, + { "AXI2APB_13", 0x70000 }, + { "AXI2APB_6", 0x7E000 }, +}; + +static const struct tegra234_target_lookup tegra264_vision_cbb_target_map[] = { + [0 ... 5] = { "RSVD", 0x0 }, + { "HOST1X", 0x45000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "AXI2APB_2", 0x71000 }, + { "RSVD", 0x00000 }, + { "RSVD", 0x00000 }, + { "SMN_VISION_RX", 0x47000 }, + [13 ... 19] = { "RSVD", 0x0 }, + { "RCE_0_SLAVE", 0x4B000 }, + { "RCE_1_SLAVE", 0x4C000 }, + { "AXI2APB_1", 0x72000 }, + { "AXI2APB_3", 0x73000 }, + { "TOP_CBB_T", 0x4D000 }, + +}; + +static const struct tegra234_fabric_lookup tegra264_cbb_fab_list[] = { + [T264_SYSTEM_CBB_FABRIC_ID] = { "system-cbb-fabric", true, + tegra264_sys_cbb_target_map, + ARRAY_SIZE(tegra264_sys_cbb_target_map) }, + [T264_TOP_0_CBB_FABRIC_ID] = { "top0-cbb-fabric", true, + tegra264_top0_cbb_target_map, + ARRAY_SIZE(tegra264_top0_cbb_target_map) }, + [T264_VISION_CBB_FABRIC_ID] = { "vision-cbb-fabric", true, + tegra264_vision_cbb_target_map, + ARRAY_SIZE(tegra264_vision_cbb_target_map) }, + [T264_DISP_USB_CBB_FABRIC_ID] = { "disp-usb-cbb-fabric" }, + [T264_UPHY0_CBB_FABRIC_ID] = { "uphy0-cbb-fabric", true, + tegra264_uphy0_cbb_target_map, + ARRAY_SIZE(tegra264_uphy0_cbb_target_map) }, + [T264_AON_FABRIC_ID] = { "aon-fabric" }, + [T264_PSC_FABRIC_ID] = { "psc-fabric" }, + [T264_OESP_FABRIC_ID] = { "oesp-fabric" }, + [T264_APE_FABRIC_ID] = { "ape-fabirc" }, + [T264_BPMP_FABRIC_ID] = { "bpmp-fabric" }, + [T264_RCE_0_FABRIC_ID] = { "rce0-fabric" }, + [T264_RCE_1_FABRIC_ID] = { "rce1-fabric" }, + [T264_DCE_FABRIC_ID] = { "dce-fabric" }, + [T264_FSI_FABRIC_ID] = { "fsi-fabric" }, + [T264_ISC_FABRIC_ID] = { "isc-fabric" }, + [T264_SB_FABRIC_ID] = { "sb-fabric" }, + [T264_ISC_CPU_FABRIC_ID] = { "isc-cpu-fabric" }, +}; + +static const struct tegra234_cbb_fabric tegra264_top0_cbb_fabric = { + .fab_id = T264_TOP_0_CBB_FABRIC_ID, + .fab_list = tegra264_cbb_fab_list, + .initiator_id = tegra264_initiator_id, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0x7, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x90000, + .off_mask_erd = 0x4a004, + .firewall_base = 0x3c0000, + .firewall_ctl = 0x5b0, + .firewall_wr_ctl = 0x5a8, +}; + +static const struct tegra234_cbb_fabric tegra264_sys_cbb_fabric = { + .fab_id = T264_SYSTEM_CBB_FABRIC_ID, + .fab_list = tegra264_cbb_fab_list, + .initiator_id = tegra264_initiator_id, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x40000, + .firewall_base = 0x29c000, + .firewall_ctl = 0x170, + .firewall_wr_ctl = 0x168, +}; + +static const struct tegra234_cbb_fabric tegra264_uphy0_cbb_fabric = { + .fab_id = T264_UPHY0_CBB_FABRIC_ID, + .fab_list = tegra264_cbb_fab_list, + .initiator_id = tegra264_initiator_id, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0x1, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x80000, + .firewall_base = 0x360000, + .firewall_ctl = 0x590, + .firewall_wr_ctl = 0x588, +}; + +static const struct tegra234_cbb_fabric tegra264_vision_cbb_fabric = { + .fab_id = T264_VISION_CBB_FABRIC_ID, + .fab_list = tegra264_cbb_fab_list, + .initiator_id = tegra264_initiator_id, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0x1, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x80000, + .firewall_base = 0x290000, + .firewall_ctl = 0x5d0, + .firewall_wr_ctl = 0x5c8, +}; + +static const struct tegra234_fabric_lookup t254_cbb_fab_list[] = { + [T254_C2C_FABRIC_ID] = { "c2c-fabric", true }, + [T254_DISP_CLUSTER_FABRIC_ID] = { "display-cluster-fabric", true }, + [T254_GPU_FABRIC_ID] = { "gpu-fabric", true }, +}; + +static const struct tegra234_cbb_fabric t254_c2c_fabric = { + .fab_id = T254_C2C_FABRIC_ID, + .fab_list = t254_cbb_fab_list, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0xf, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x50000, + .off_mask_erd = 0x14004, + .firewall_base = 0x40000, + .firewall_ctl = 0x9b0, + .firewall_wr_ctl = 0x9a8, +}; + +static const struct tegra234_cbb_fabric t254_disp_fabric = { + .fab_id = T254_DISP_CLUSTER_FABRIC_ID, + .fab_list = t254_cbb_fab_list, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0x1, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x50000, + .firewall_base = 0x30000, + .firewall_ctl = 0x810, + .firewall_wr_ctl = 0x808, +}; + +static const struct tegra234_cbb_fabric t254_gpu_fabric = { + .fab_id = T254_GPU_FABRIC_ID, + .fab_list = t254_cbb_fab_list, + .errors = tegra241_cbb_errors, + .max_errors = ARRAY_SIZE(tegra241_cbb_errors), + .err_intr_enbl = 0x1f, + .err_status_clr = 0x1ff007f, + .notifier_offset = 0x50000, + .firewall_base = 0x30000, + .firewall_ctl = 0x930, + .firewall_wr_ctl = 0x928, +}; + static const struct of_device_id tegra234_cbb_dt_ids[] = { { .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric }, { .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric }, @@ -1079,6 +1480,10 @@ static const struct of_device_id tegra234_cbb_dt_ids[] = { { .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric }, { .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric }, { .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric }, + { .compatible = "nvidia,tegra264-sys-cbb-fabric", .data = &tegra264_sys_cbb_fabric }, + { .compatible = "nvidia,tegra264-top0-cbb-fabric", .data = &tegra264_top0_cbb_fabric }, + { .compatible = "nvidia,tegra264-uphy0-cbb-fabric", .data = &tegra264_uphy0_cbb_fabric }, + { .compatible = "nvidia,tegra264-vision-cbb-fabric", .data = &tegra264_vision_cbb_fabric }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids); @@ -1092,6 +1497,9 @@ struct tegra234_cbb_acpi_uid { static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids[] = { { "NVDA1070", "1", &tegra241_cbb_fabric }, { "NVDA1070", "2", &tegra241_bpmp_fabric }, + { "NVDA1070", "3", &t254_c2c_fabric }, + { "NVDA1070", "4", &t254_disp_fabric }, + { "NVDA1070", "5", &t254_gpu_fabric }, { }, }; @@ -1174,18 +1582,13 @@ static int tegra234_cbb_probe(struct platform_device *pdev) return tegra_cbb_register(&cbb->base); } -static int tegra234_cbb_remove(struct platform_device *pdev) -{ - return 0; -} - static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) { struct tegra234_cbb *cbb = dev_get_drvdata(dev); tegra234_cbb_error_enable(&cbb->base); - dev_dbg(dev, "%s resumed\n", cbb->fabric->name); + dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name); return 0; } @@ -1196,7 +1599,6 @@ static const struct dev_pm_ops tegra234_cbb_pm = { static struct platform_driver tegra234_cbb_driver = { .probe = tegra234_cbb_probe, - .remove = tegra234_cbb_remove, .driver = { .name = "tegra234-cbb", .of_match_table = tegra234_cbb_dt_ids, @@ -1218,4 +1620,3 @@ static void __exit tegra234_cbb_exit(void) module_exit(tegra234_cbb_exit); MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234"); -MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index dff6d5ef4e46..d82b7670abb7 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -27,17 +27,7 @@ static const struct of_device_id tegra_machine_match[] = { bool soc_is_tegra(void) { - const struct of_device_id *match; - struct device_node *root; - - root = of_find_node_by_path("/"); - if (!root) - return false; - - match = of_match_node(tegra_machine_match, root); - of_node_put(root); - - return match != NULL; + return of_machine_device_match(tegra_machine_match); } static int tegra_core_dev_init_opp_state(struct device *dev) diff --git a/drivers/soc/tegra/flowctrl.c b/drivers/soc/tegra/flowctrl.c index 5db919d96aba..221202db3313 100644 --- a/drivers/soc/tegra/flowctrl.c +++ b/drivers/soc/tegra/flowctrl.c @@ -156,10 +156,8 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid) static int tegra_flowctrl_probe(struct platform_device *pdev) { void __iomem *base = tegra_flowctrl_base; - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res); + tegra_flowctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(tegra_flowctrl_base)) return PTR_ERR(tegra_flowctrl_base); diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index f02953f793e9..74d2fedea71c 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -1,13 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved. */ +#include <linux/acpi.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/kobject.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/mod_devicetable.h> #include <linux/nvmem-consumer.h> #include <linux/nvmem-provider.h> #include <linux/of.h> @@ -113,6 +115,28 @@ static void tegra_fuse_restore(void *base) fuse->clk = NULL; } +static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info) +{ + pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n", + tegra_revision_name[tegra_sku_info->revision], + tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id, + tegra_sku_info->soc_process_id); + pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n", + tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id); +} + +static int tegra_fuse_add_lookups(struct tegra_fuse *fuse) +{ + fuse->lookups = kmemdup_array(fuse->soc->lookups, fuse->soc->num_lookups, + sizeof(*fuse->lookups), GFP_KERNEL); + if (!fuse->lookups) + return -ENOMEM; + + nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups); + + return 0; +} + static int tegra_fuse_probe(struct platform_device *pdev) { void __iomem *base = fuse->base; @@ -125,23 +149,49 @@ static int tegra_fuse_probe(struct platform_device *pdev) return err; /* take over the memory region from the early initialization */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fuse->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(fuse->base)) + return PTR_ERR(fuse->base); fuse->phys = res->start; - fuse->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(fuse->base)) { - err = PTR_ERR(fuse->base); - return err; - } - fuse->clk = devm_clk_get(&pdev->dev, "fuse"); - if (IS_ERR(fuse->clk)) { - if (PTR_ERR(fuse->clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get FUSE clock: %ld", - PTR_ERR(fuse->clk)); + /* Initialize the soc data and lookups if using ACPI boot. */ + if (is_acpi_node(dev_fwnode(&pdev->dev)) && !fuse->soc) { + u8 chip; - return PTR_ERR(fuse->clk); + tegra_acpi_init_apbmisc(); + + chip = tegra_get_chip_id(); + switch (chip) { +#if defined(CONFIG_ARCH_TEGRA_194_SOC) + case TEGRA194: + fuse->soc = &tegra194_fuse_soc; + break; +#endif +#if defined(CONFIG_ARCH_TEGRA_234_SOC) + case TEGRA234: + fuse->soc = &tegra234_fuse_soc; + break; +#endif +#if defined(CONFIG_ARCH_TEGRA_241_SOC) + case TEGRA241: + fuse->soc = &tegra241_fuse_soc; + break; +#endif + default: + return dev_err_probe(&pdev->dev, -EINVAL, "Unsupported SoC: %02x\n", chip); + } + + fuse->soc->init(fuse); + + err = tegra_fuse_add_lookups(fuse); + if (err) + return dev_err_probe(&pdev->dev, err, "failed to add FUSE lookups\n"); } + fuse->clk = devm_clk_get_optional(&pdev->dev, "fuse"); + if (IS_ERR(fuse->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(fuse->clk), "failed to get FUSE clock\n"); + platform_set_drvdata(pdev, fuse); fuse->dev = &pdev->dev; @@ -166,7 +216,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) nvmem.nkeepout = fuse->soc->num_keepouts; nvmem.type = NVMEM_TYPE_OTP; nvmem.read_only = true; - nvmem.root_only = true; + nvmem.root_only = false; nvmem.reg_read = tegra_fuse_read; nvmem.size = fuse->soc->info->size; nvmem.word_size = 4; @@ -182,12 +232,8 @@ static int tegra_fuse_probe(struct platform_device *pdev) } fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse"); - if (IS_ERR(fuse->rst)) { - err = PTR_ERR(fuse->rst); - dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n", - fuse->rst); - return err; - } + if (IS_ERR(fuse->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(fuse->rst), "failed to get FUSE reset\n"); /* * FUSE clock is enabled at a boot time, hence this resume/suspend @@ -265,10 +311,17 @@ static const struct dev_pm_ops tegra_fuse_pm = { SET_SYSTEM_SLEEP_PM_OPS(tegra_fuse_suspend, tegra_fuse_resume) }; +static const struct acpi_device_id tegra_fuse_acpi_match[] = { + { "NVDA200F" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, tegra_fuse_acpi_match); + static struct platform_driver tegra_fuse_driver = { .driver = { .name = "tegra-fuse", .of_match_table = tegra_fuse_match, + .acpi_match_table = tegra_fuse_acpi_match, .pm = &tegra_fuse_pm, .suppress_bind_attrs = true, }, @@ -290,7 +343,16 @@ u32 __init tegra_fuse_read_early(unsigned int offset) int tegra_fuse_readl(unsigned long offset, u32 *value) { - if (!fuse->read || !fuse->clk) + if (!fuse->dev) + return -EPROBE_DEFER; + + /* + * Wait for fuse->clk to be initialized if device-tree boot is used. + */ + if (is_of_node(dev_fwnode(fuse->dev)) && !fuse->clk) + return -EPROBE_DEFER; + + if (!fuse->read) return -EPROBE_DEFER; if (IS_ERR(fuse->clk)) @@ -346,7 +408,8 @@ const struct attribute_group tegra_soc_attr_group = { }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC) static ssize_t platform_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -373,7 +436,7 @@ const struct attribute_group tegra194_soc_attr_group = { }; #endif -struct device * __init tegra_soc_device_register(void) +struct device *tegra_soc_device_register(void) { struct soc_device_attribute *attr; struct soc_device *dev; @@ -410,6 +473,7 @@ static int __init tegra_init_fuse(void) const struct of_device_id *match; struct device_node *np; struct resource regs; + int err; tegra_init_apbmisc(); @@ -500,22 +564,13 @@ static int __init tegra_init_fuse(void) fuse->soc->init(fuse); - pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n", - tegra_revision_name[tegra_sku_info.revision], - tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, - tegra_sku_info.soc_process_id); - pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n", - tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); - - if (fuse->soc->lookups) { - size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups; + tegra_fuse_print_sku_info(&tegra_sku_info); - fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL); - if (fuse->lookups) - nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups); - } + err = tegra_fuse_add_lookups(fuse); + if (err) + pr_err("failed to add FUSE lookups\n"); - return 0; + return err; } early_initcall(tegra_init_fuse); diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 12503f563e36..fdecf7b7c246 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -14,7 +14,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/kobject.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/random.h> diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 932a03c64534..524fa1b0cd3d 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -10,8 +10,6 @@ #include <linux/kernel.h> #include <linux/nvmem-consumer.h> #include <linux/nvmem-provider.h> -#include <linux/of_device.h> -#include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/random.h> @@ -40,7 +38,8 @@ defined(CONFIG_ARCH_TEGRA_210_SOC) || \ defined(CONFIG_ARCH_TEGRA_186_SOC) || \ defined(CONFIG_ARCH_TEGRA_194_SOC) || \ - defined(CONFIG_ARCH_TEGRA_234_SOC) + defined(CONFIG_ARCH_TEGRA_234_SOC) || \ + defined(CONFIG_ARCH_TEGRA_241_SOC) static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { if (WARN_ON(!fuse->base)) @@ -118,6 +117,124 @@ const struct tegra_fuse_soc tegra30_fuse_soc = { #endif #ifdef CONFIG_ARCH_TEGRA_114_SOC +static const struct nvmem_cell_info tegra114_fuse_cells[] = { + { + .name = "tsensor-cpu1", + .offset = 0x084, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-cpu2", + .offset = 0x088, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-common", + .offset = 0x08c, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-cpu0", + .offset = 0x098, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "xusb-pad-calibration", + .offset = 0x0f0, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-cpu3", + .offset = 0x12c, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-gpu", + .offset = 0x154, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-mem0", + .offset = 0x158, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-mem1", + .offset = 0x15c, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, { + .name = "tsensor-pllx", + .offset = 0x160, + .bytes = 4, + .bit_offset = 0, + .nbits = 32, + }, +}; + +static const struct nvmem_cell_lookup tegra114_fuse_lookups[] = { + { + .nvmem_name = "fuse", + .cell_name = "xusb-pad-calibration", + .dev_id = "7009f000.padctl", + .con_id = "calibration", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-common", + .dev_id = "700e2000.thermal-sensor", + .con_id = "common", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-cpu0", + .dev_id = "700e2000.thermal-sensor", + .con_id = "cpu0", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-cpu1", + .dev_id = "700e2000.thermal-sensor", + .con_id = "cpu1", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-cpu2", + .dev_id = "700e2000.thermal-sensor", + .con_id = "cpu2", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-cpu3", + .dev_id = "700e2000.thermal-sensor", + .con_id = "cpu3", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-mem0", + .dev_id = "700e2000.thermal-sensor", + .con_id = "mem0", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-mem1", + .dev_id = "700e2000.thermal-sensor", + .con_id = "mem1", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-gpu", + .dev_id = "700e2000.thermal-sensor", + .con_id = "gpu", + }, { + .nvmem_name = "fuse", + .cell_name = "tsensor-pllx", + .dev_id = "700e2000.thermal-sensor", + .con_id = "pllx", + }, +}; + static const struct tegra_fuse_info tegra114_fuse_info = { .read = tegra30_fuse_read, .size = 0x2a0, @@ -128,6 +245,10 @@ const struct tegra_fuse_soc tegra114_fuse_soc = { .init = tegra30_fuse_init, .speedo_init = tegra114_init_speedo_data, .info = &tegra114_fuse_info, + .lookups = tegra114_fuse_lookups, + .num_lookups = ARRAY_SIZE(tegra114_fuse_lookups), + .cells = tegra114_fuse_cells, + .num_cells = ARRAY_SIZE(tegra114_fuse_cells), .soc_attr_group = &tegra_soc_attr_group, .clk_suspend_on = false, }; @@ -648,22 +769,27 @@ static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = { }; static const struct nvmem_keepout tegra234_fuse_keepouts[] = { - { .start = 0x01c, .end = 0x0c8 }, - { .start = 0x12c, .end = 0x184 }, + { .start = 0x01c, .end = 0x064 }, + { .start = 0x084, .end = 0x0a0 }, + { .start = 0x0a4, .end = 0x0c8 }, + { .start = 0x12c, .end = 0x164 }, + { .start = 0x16c, .end = 0x184 }, { .start = 0x190, .end = 0x198 }, { .start = 0x1a0, .end = 0x204 }, - { .start = 0x21c, .end = 0x250 }, - { .start = 0x25c, .end = 0x2f0 }, + { .start = 0x21c, .end = 0x2f0 }, { .start = 0x310, .end = 0x3d8 }, - { .start = 0x400, .end = 0x4f0 }, - { .start = 0x4f8, .end = 0x7e8 }, + { .start = 0x400, .end = 0x420 }, + { .start = 0x444, .end = 0x490 }, + { .start = 0x4bc, .end = 0x4f0 }, + { .start = 0x4f8, .end = 0x54c }, + { .start = 0x57c, .end = 0x7e8 }, { .start = 0x8d0, .end = 0x8d8 }, { .start = 0xacc, .end = 0xf00 } }; static const struct tegra_fuse_info tegra234_fuse_info = { .read = tegra30_fuse_read, - .size = 0x98c, + .size = 0xf90, .spare = 0x280, }; @@ -680,3 +806,23 @@ const struct tegra_fuse_soc tegra234_fuse_soc = { .clk_suspend_on = false, }; #endif + +#if defined(CONFIG_ARCH_TEGRA_241_SOC) +static const struct tegra_fuse_info tegra241_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x16008, + .spare = 0xcf0, +}; + +static const struct nvmem_keepout tegra241_fuse_keepouts[] = { + { .start = 0xc, .end = 0x1600c } +}; + +const struct tegra_fuse_soc tegra241_fuse_soc = { + .init = tegra30_fuse_init, + .info = &tegra241_fuse_info, + .keepouts = tegra241_fuse_keepouts, + .num_keepouts = ARRAY_SIZE(tegra241_fuse_keepouts), + .soc_attr_group = &tegra194_soc_attr_group, +}; +#endif diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 90f23be73894..9fee6ad6ad9e 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -69,6 +69,7 @@ struct tegra_fuse { void tegra_init_revision(void); void tegra_init_apbmisc(void); +void tegra_acpi_init_apbmisc(void); u32 __init tegra_fuse_read_spare(unsigned int spare); u32 __init tegra_fuse_read_early(unsigned int offset); @@ -123,7 +124,8 @@ extern const struct tegra_fuse_soc tegra186_fuse_soc; #endif #if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_241_SOC) extern const struct attribute_group tegra194_soc_attr_group; #endif @@ -135,4 +137,8 @@ extern const struct tegra_fuse_soc tegra194_fuse_soc; extern const struct tegra_fuse_soc tegra234_fuse_soc; #endif +#ifdef CONFIG_ARCH_TEGRA_241_SOC +extern const struct tegra_fuse_soc tegra241_fuse_soc; +#endif + #endif diff --git a/drivers/soc/tegra/fuse/speedo-tegra210.c b/drivers/soc/tegra/fuse/speedo-tegra210.c index 695d0b7f9a8a..06c2bcbee573 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra210.c +++ b/drivers/soc/tegra/fuse/speedo-tegra210.c @@ -65,27 +65,52 @@ static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, sku_info->gpu_speedo_id = 0; *threshold = THRESHOLD_INDEX_0; - switch (sku) { - case 0x00: /* Engineering SKU */ - case 0x01: /* Engineering SKU */ - case 0x07: - case 0x17: - case 0x27: - if (speedo_rev >= 2) + if (sku_info->revision >= TEGRA_REVISION_A02) { + switch (sku) { + case 0x00: /* Engineering SKU */ + case 0x01: /* Engineering SKU */ + case 0x13: + sku_info->cpu_speedo_id = 5; + sku_info->gpu_speedo_id = 2; + break; + + case 0x07: + case 0x17: + case 0x1F: + sku_info->cpu_speedo_id = 7; + sku_info->gpu_speedo_id = 2; + break; + + case 0x27: + sku_info->cpu_speedo_id = 1; + sku_info->gpu_speedo_id = 2; + break; + + case 0x83: + sku_info->cpu_speedo_id = 3; + sku_info->gpu_speedo_id = 3; + break; + + case 0x87: + sku_info->cpu_speedo_id = 2; sku_info->gpu_speedo_id = 1; - break; - - case 0x13: - if (speedo_rev >= 2) - sku_info->gpu_speedo_id = 1; - - sku_info->cpu_speedo_id = 1; - break; - - default: + break; + + case 0x8F: + sku_info->soc_speedo_id = 2; + sku_info->cpu_speedo_id = 9; + sku_info->gpu_speedo_id = 2; + break; + + default: + pr_err("Tegra210: unknown revision 2 or newer SKU %#04x\n", sku); + /* Using the default for the error case */ + break; + } + } else if (sku == 0x00 || sku == 0x01 || sku == 0x07 || sku == 0x13 || sku == 0x17) { + sku_info->gpu_speedo_id = 1; + } else { pr_err("Tegra210: unknown SKU %#04x\n", sku); - /* Using the default for the error case */ - break; } } diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 4591c5bcb690..0ce94fdc536f 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -1,16 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. */ +#include <linux/acpi.h> #include <linux/export.h> +#include <linux/io.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/io.h> -#include <soc/tegra/fuse.h> #include <soc/tegra/common.h> +#include <soc/tegra/fuse.h> #include "fuse.h" @@ -62,6 +64,8 @@ bool tegra_is_silicon(void) switch (tegra_get_chip_id()) { case TEGRA194: case TEGRA234: + case TEGRA241: + case TEGRA264: if (tegra_get_platform() == 0) return true; @@ -124,6 +128,7 @@ static const struct of_device_id apbmisc_match[] __initconst = { { .compatible = "nvidia,tegra186-misc", }, { .compatible = "nvidia,tegra194-misc", }, { .compatible = "nvidia,tegra234-misc", }, + { .compatible = "nvidia,tegra264-misc", }, {}, }; @@ -159,9 +164,34 @@ void __init tegra_init_revision(void) tegra_sku_info.platform = tegra_get_platform(); } -void __init tegra_init_apbmisc(void) +static void tegra_init_apbmisc_resources(struct resource *apbmisc, + struct resource *straps) { void __iomem *strapping_base; + + apbmisc_base = ioremap(apbmisc->start, resource_size(apbmisc)); + if (apbmisc_base) + chipid = readl_relaxed(apbmisc_base + 4); + else + pr_err("failed to map APBMISC registers\n"); + + strapping_base = ioremap(straps->start, resource_size(straps)); + if (strapping_base) { + strapping = readl_relaxed(strapping_base); + iounmap(strapping_base); + } else { + pr_err("failed to map strapping options registers\n"); + } +} + +/** + * tegra_init_apbmisc - Initializes Tegra APBMISC and Strapping registers. + * + * This is called during early init as some of the old 32-bit ARM code needs + * information from the APBMISC registers very early during boot. + */ +void __init tegra_init_apbmisc(void) +{ struct resource apbmisc, straps; struct device_node *np; @@ -218,23 +248,73 @@ void __init tegra_init_apbmisc(void) } } - apbmisc_base = ioremap(apbmisc.start, resource_size(&apbmisc)); - if (!apbmisc_base) { - pr_err("failed to map APBMISC registers\n"); - } else { - chipid = readl_relaxed(apbmisc_base + 4); + tegra_init_apbmisc_resources(&apbmisc, &straps); + long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code"); + +put: + of_node_put(np); +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id apbmisc_acpi_match[] = { + { "NVDA2010" }, + { /* sentinel */ } +}; + +void tegra_acpi_init_apbmisc(void) +{ + struct resource *resources[2] = { NULL }; + struct resource_entry *rentry; + struct acpi_device *adev = NULL; + struct list_head resource_list; + int rcount = 0; + int ret; + + adev = acpi_dev_get_first_match_dev(apbmisc_acpi_match[0].id, NULL, -1); + if (!adev) + return; + + INIT_LIST_HEAD(&resource_list); + + ret = acpi_dev_get_memory_resources(adev, &resource_list); + if (ret < 0) { + pr_err("failed to get APBMISC memory resources"); + goto out_put_acpi_dev; } - strapping_base = ioremap(straps.start, resource_size(&straps)); - if (!strapping_base) { - pr_err("failed to map strapping options registers\n"); - } else { - strapping = readl_relaxed(strapping_base); - iounmap(strapping_base); + /* + * Get required memory resources. + * + * resources[0]: apbmisc. + * resources[1]: straps. + */ + resource_list_for_each_entry(rentry, &resource_list) { + if (rcount >= ARRAY_SIZE(resources)) + break; + + resources[rcount++] = rentry->res; } - long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code"); + if (!resources[0]) { + pr_err("failed to get APBMISC registers\n"); + goto out_free_resource_list; + } -put: - of_node_put(np); + if (!resources[1]) { + pr_err("failed to get strapping options registers\n"); + goto out_free_resource_list; + } + + tegra_init_apbmisc_resources(resources[0], resources[1]); + +out_free_resource_list: + acpi_dev_free_resource_list(&resource_list); + +out_put_acpi_dev: + acpi_dev_put(adev); +} +#else +void tegra_acpi_init_apbmisc(void) +{ } +#endif diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index cf4cfbf9f7c5..f3760a3b3026 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3,7 +3,7 @@ * drivers/soc/tegra/pmc.c * * Copyright (c) 2010 Google, Inc - * Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -47,6 +47,7 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/string_choices.h> #include <linux/syscore_ops.h> #include <soc/tegra/common.h> @@ -177,6 +178,7 @@ /* Tegra186 and later */ #define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) #define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) +#define WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN (1 << 1) #define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) #define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) #define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) @@ -191,6 +193,8 @@ #define WAKE_AOWAKE_CTRL 0x4f4 #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) +#define SW_WAKE_ID 83 /* wake83 */ + /* for secure PMC */ #define TEGRA_SMC_PMC 0xc2fffe00 #define TEGRA_SMC_PMC_READ 0xaa @@ -355,6 +359,7 @@ struct tegra_pmc_soc { void (*setup_irq_polarity)(struct tegra_pmc *pmc, struct device_node *np, bool invert); + void (*set_wake_filters)(struct tegra_pmc *pmc); int (*irq_set_wake)(struct irq_data *data, unsigned int on); int (*irq_set_type)(struct irq_data *data, unsigned int type); int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id, @@ -380,6 +385,7 @@ struct tegra_pmc_soc { bool has_blink_output; bool has_usb_sleepwalk; bool supports_core_domain; + bool has_single_mmio_aperture; }; /** @@ -392,7 +398,6 @@ struct tegra_pmc_soc { * @clk: pointer to pclk clock * @soc: pointer to SoC data structure * @tz_only: flag specifying if the PMC can only be accessed via TrustZone - * @debugfs: pointer to debugfs entry * @rate: currently configured rate of pclk * @suspend_mode: lowest suspend mode available * @cpu_good_time: CPU power good time (in microseconds) @@ -413,12 +418,12 @@ struct tegra_pmc_soc { * @irq: chip implementation for the IRQ domain * @clk_nb: pclk clock changes handler * @core_domain_state_synced: flag marking the core domain's state as synced - * @core_domain_registered: flag marking the core domain as registered * @wake_type_level_map: Bitmap indicating level type for non-dual edge wakes * @wake_type_dual_edge_map: Bitmap indicating if a wake is dual-edge or not * @wake_sw_status_map: Bitmap to hold raw status of wakes without mask * @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in * cntrl register associated with each wake during system suspend. + * @syscore: syscore suspend/resume callbacks */ struct tegra_pmc { struct device *dev; @@ -427,7 +432,6 @@ struct tegra_pmc { void __iomem *aotag; void __iomem *scratch; struct clk *clk; - struct dentry *debugfs; const struct tegra_pmc_soc *soc; bool tz_only; @@ -458,13 +462,12 @@ struct tegra_pmc { struct notifier_block clk_nb; bool core_domain_state_synced; - bool core_domain_registered; unsigned long *wake_type_level_map; unsigned long *wake_type_dual_edge_map; unsigned long *wake_sw_status_map; unsigned long *wake_cntrl_level_map; - struct syscore_ops syscore; + struct syscore syscore; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1178,7 +1181,7 @@ static int powergate_show(struct seq_file *s, void *data) continue; seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], - status ? "yes" : "no"); + str_yes_no(status)); } return 0; @@ -1186,16 +1189,6 @@ static int powergate_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(powergate); -static int tegra_powergate_debugfs_init(void) -{ - pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, - &powergate_fops); - if (!pmc->debugfs) - return -ENOMEM; - - return 0; -} - static int tegra_powergate_of_get_clks(struct tegra_powergate *pg, struct device_node *np) { @@ -1240,7 +1233,7 @@ err: } static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, - struct device_node *np, bool off) + struct device_node *np) { struct device *dev = pg->pmc->dev; int err; @@ -1255,22 +1248,6 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, err = reset_control_acquire(pg->reset); if (err < 0) { pr_err("failed to acquire resets: %d\n", err); - goto out; - } - - if (off) { - err = reset_control_assert(pg->reset); - } else { - err = reset_control_deassert(pg->reset); - if (err < 0) - goto out; - - reset_control_release(pg->reset); - } - -out: - if (err) { - reset_control_release(pg->reset); reset_control_put(pg->reset); } @@ -1303,6 +1280,7 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) pg->id = id; pg->genpd.name = np->name; + pg->genpd.flags = GENPD_FLAG_NO_SYNC_STATE; pg->genpd.power_off = tegra_genpd_power_off; pg->genpd.power_on = tegra_genpd_power_on; pg->pmc = pmc; @@ -1315,20 +1293,43 @@ static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) goto set_available; } - err = tegra_powergate_of_get_resets(pg, np, off); + err = tegra_powergate_of_get_resets(pg, np); if (err < 0) { dev_err(dev, "failed to get resets for %pOFn: %d\n", np, err); goto remove_clks; } - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { - if (off) - WARN_ON(tegra_powergate_power_up(pg, true)); + /* + * If the power-domain is off, then ensure the resets are asserted. + * If the power-domain is on, then power down to ensure that when is + * it turned on the power-domain, clocks and resets are all in the + * expected state. + */ + if (off) { + err = reset_control_assert(pg->reset); + if (err) { + pr_err("failed to assert resets: %d\n", err); + goto remove_resets; + } + } else { + err = tegra_powergate_power_down(pg); + if (err) { + dev_err(dev, "failed to turn off PM domain %s: %d\n", + pg->genpd.name, err); + goto remove_resets; + } + } + /* + * If PM_GENERIC_DOMAINS is not enabled, power-on + * the domain and skip the genpd registration. + */ + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + WARN_ON(tegra_powergate_power_up(pg, true)); goto remove_resets; } - err = pm_genpd_init(&pg->genpd, NULL, off); + err = pm_genpd_init(&pg->genpd, NULL, true); if (err < 0) { dev_err(dev, "failed to initialise PM domain %pOFn: %d\n", np, err); @@ -1401,13 +1402,6 @@ tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd, return 0; } -static unsigned int -tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd, - struct dev_pm_opp *opp) -{ - return dev_pm_opp_get_level(opp); -} - static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) { struct generic_pm_domain *genpd; @@ -1419,8 +1413,8 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) return -ENOMEM; genpd->name = "core"; + genpd->flags = GENPD_FLAG_NO_SYNC_STATE; genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; - genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; err = devm_pm_opp_set_regulators(pmc->dev, rname); if (err) @@ -1439,8 +1433,6 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) goto remove_genpd; } - pmc->core_domain_registered = true; - return 0; remove_genpd: @@ -1453,7 +1445,7 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, struct device_node *parent) { struct of_phandle_args child_args, parent_args; - struct device_node *np, *child; + struct device_node *np; int err = 0; /* @@ -1472,12 +1464,10 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, if (!np) return 0; - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { err = tegra_powergate_add(pmc, child); - if (err < 0) { - of_node_put(child); + if (err < 0) break; - } if (of_parse_phandle_with_args(child, "power-domains", "#power-domain-cells", @@ -1489,10 +1479,8 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, err = of_genpd_add_subdomain(&parent_args, &child_args); of_node_put(parent_args.np); - if (err) { - of_node_put(child); + if (err) break; - } } of_node_put(np); @@ -1793,30 +1781,6 @@ static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id) return TEGRA_IO_PAD_VOLTAGE_3V3; } -/** - * tegra_io_rail_power_on() - enable power to I/O rail - * @id: Tegra I/O pad ID for which to enable power - * - * See also: tegra_io_pad_power_enable() - */ -int tegra_io_rail_power_on(unsigned int id) -{ - return tegra_io_pad_power_enable(id); -} -EXPORT_SYMBOL(tegra_io_rail_power_on); - -/** - * tegra_io_rail_power_off() - disable power to I/O rail - * @id: Tegra I/O pad ID for which to disable power - * - * See also: tegra_io_pad_power_disable() - */ -int tegra_io_rail_power_off(unsigned int id) -{ - return tegra_io_pad_power_disable(id); -} -EXPORT_SYMBOL(tegra_io_rail_power_off); - #ifdef CONFIG_PM_SLEEP enum tegra_suspend_mode tegra_pmc_get_suspend_mode(void) { @@ -2416,6 +2380,17 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type) return 0; } +static void tegra186_pmc_set_wake_filters(struct tegra_pmc *pmc) +{ + u32 value; + + /* SW Wake (wake83) needs SR_CAPTURE filter to be enabled */ + value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID)); + value |= WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN; + writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID)); + dev_dbg(pmc->dev, "WAKE_AOWAKE_CNTRL_83 = 0x%x\n", value); +} + static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on) { struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); @@ -2531,8 +2506,8 @@ static int tegra_pmc_irq_init(struct tegra_pmc *pmc) pmc->irq.irq_set_type = pmc->soc->irq_set_type; pmc->irq.irq_set_wake = pmc->soc->irq_set_wake; - pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node, - &tegra_pmc_irq_domain_ops, pmc); + pmc->domain = irq_domain_create_hierarchy(parent, 0, 96, dev_fwnode(pmc->dev), + &tegra_pmc_irq_domain_ops, pmc); if (!pmc->domain) { dev_err(pmc->dev, "failed to allocate domain\n"); return -ENOMEM; @@ -2914,31 +2889,36 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wake"); - if (res) { - pmc->wake = devm_ioremap_resource(&pdev->dev, res); + if (pmc->soc->has_single_mmio_aperture) { + pmc->wake = base; + pmc->aotag = base; + pmc->scratch = base; + } else { + pmc->wake = devm_platform_ioremap_resource_byname(pdev, "wake"); if (IS_ERR(pmc->wake)) return PTR_ERR(pmc->wake); - } else { - pmc->wake = base; - } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aotag"); - if (res) { - pmc->aotag = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->aotag)) - return PTR_ERR(pmc->aotag); - } else { - pmc->aotag = base; - } + /* "aotag" is an optional aperture */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "aotag"); + if (res) { + pmc->aotag = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->aotag)) + return PTR_ERR(pmc->aotag); + } else { + pmc->aotag = NULL; + } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scratch"); - if (res) { - pmc->scratch = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->scratch)) - return PTR_ERR(pmc->scratch); - } else { - pmc->scratch = base; + /* "scratch" is an optional aperture */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "scratch"); + if (res) { + pmc->scratch = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmc->scratch)) + return PTR_ERR(pmc->scratch); + } else { + pmc->scratch = NULL; + } } pmc->clk = devm_clk_get_optional(&pdev->dev, "pclk"); @@ -2950,12 +2930,15 @@ static int tegra_pmc_probe(struct platform_device *pdev) * PMC should be last resort for restarting since it soft-resets * CPU without resetting everything else. */ - err = devm_register_reboot_notifier(&pdev->dev, - &tegra_pmc_reboot_notifier); - if (err) { - dev_err(&pdev->dev, "unable to register reboot notifier, %d\n", - err); - return err; + if (pmc->scratch) { + err = devm_register_reboot_notifier(&pdev->dev, + &tegra_pmc_reboot_notifier); + if (err) { + dev_err(&pdev->dev, + "unable to register reboot notifier, %d\n", + err); + return err; + } } err = devm_register_sys_off_handler(&pdev->dev, @@ -2989,7 +2972,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) */ if (pmc->clk) { pmc->clk_nb.notifier_call = tegra_pmc_clk_notify_cb; - err = clk_notifier_register(pmc->clk, &pmc->clk_nb); + err = devm_clk_notifier_register(&pdev->dev, pmc->clk, + &pmc->clk_nb); if (err) { dev_err(&pdev->dev, "failed to register clk notifier\n"); @@ -3011,19 +2995,13 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_reset_sysfs_init(pmc); - if (IS_ENABLED(CONFIG_DEBUG_FS)) { - err = tegra_powergate_debugfs_init(); - if (err < 0) - goto cleanup_sysfs; - } - err = tegra_pmc_pinctrl_init(pmc); if (err) - goto cleanup_debugfs; + goto cleanup_sysfs; err = tegra_pmc_regmap_init(pmc); if (err < 0) - goto cleanup_debugfs; + goto cleanup_sysfs; err = tegra_powergate_init(pmc, pdev->dev.of_node); if (err < 0) @@ -3042,16 +3020,19 @@ static int tegra_pmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmc); tegra_pm_init_suspend(); + /* Some wakes require specific filter configuration */ + if (pmc->soc->set_wake_filters) + pmc->soc->set_wake_filters(pmc); + + debugfs_create_file("powergate", 0444, NULL, NULL, &powergate_fops); + return 0; cleanup_powergates: tegra_powergate_remove_all(pdev->dev.of_node); -cleanup_debugfs: - debugfs_remove(pmc->debugfs); cleanup_sysfs: device_remove_file(&pdev->dev, &dev_attr_reset_reason); device_remove_file(&pdev->dev, &dev_attr_reset_level); - clk_notifier_unregister(pmc->clk, &pmc->clk_nb); return err; } @@ -3174,7 +3155,7 @@ static void tegra186_pmc_process_wake_events(struct tegra_pmc *pmc, unsigned int } } -static void tegra186_pmc_wake_syscore_resume(void) +static void tegra186_pmc_wake_syscore_resume(void *data) { u32 status, mask; unsigned int i; @@ -3187,7 +3168,7 @@ static void tegra186_pmc_wake_syscore_resume(void) } } -static int tegra186_pmc_wake_syscore_suspend(void) +static int tegra186_pmc_wake_syscore_suspend(void *data) { wke_read_sw_wake_status(pmc); @@ -3206,6 +3187,11 @@ static int tegra186_pmc_wake_syscore_suspend(void) return 0; } +static const struct syscore_ops tegra186_pmc_wake_syscore_ops = { + .suspend = tegra186_pmc_wake_syscore_suspend, + .resume = tegra186_pmc_wake_syscore_resume, +}; + #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) static int tegra_pmc_suspend(struct device *dev) { @@ -3331,6 +3317,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .num_pmc_clks = 0, .has_blink_output = true, .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra30_powergates[] = { @@ -3392,6 +3379,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra114_powergates[] = { @@ -3449,6 +3437,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra124_powergates[] = { @@ -3593,6 +3582,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const char * const tegra210_powergates[] = { @@ -3756,6 +3746,7 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .num_pmc_clks = ARRAY_SIZE(tegra_pmc_clks_data), .has_blink_output = true, .has_usb_sleepwalk = true, + .has_single_mmio_aperture = true, }; static const struct tegra_io_pad_soc tegra186_io_pads[] = { @@ -3851,10 +3842,8 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = { static void tegra186_pmc_init(struct tegra_pmc *pmc) { - pmc->syscore.suspend = tegra186_pmc_wake_syscore_suspend; - pmc->syscore.resume = tegra186_pmc_wake_syscore_resume; - - register_syscore_ops(&pmc->syscore); + pmc->syscore.ops = &tegra186_pmc_wake_syscore_ops; + register_syscore(&pmc->syscore); } static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, @@ -3938,6 +3927,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .regs = &tegra186_pmc_regs, .init = tegra186_pmc_init, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, .irq_set_wake = tegra186_pmc_irq_set_wake, .irq_set_type = tegra186_pmc_irq_set_type, .reset_sources = tegra186_reset_sources, @@ -3952,6 +3942,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_pmc_clks = 0, .has_blink_output = false, .has_usb_sleepwalk = false, + .has_single_mmio_aperture = false, }; static const struct tegra_io_pad_soc tegra194_io_pads[] = { @@ -4092,6 +4083,7 @@ static const char * const tegra194_reset_sources[] = { }; static const struct tegra_wake_event tegra194_wake_events[] = { + TEGRA_WAKE_GPIO("eqos", 20, 0, TEGRA194_MAIN_GPIO(G, 4)), TEGRA_WAKE_IRQ("pmu", 24, 209), TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)), TEGRA_WAKE_IRQ("rtc", 73, 10), @@ -4122,6 +4114,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .regs = &tegra194_pmc_regs, .init = tegra186_pmc_init, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, .irq_set_wake = tegra186_pmc_irq_set_wake, .irq_set_type = tegra186_pmc_irq_set_type, .reset_sources = tegra194_reset_sources, @@ -4136,6 +4129,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .num_pmc_clks = 0, .has_blink_output = false, .has_usb_sleepwalk = false, + .has_single_mmio_aperture = false, }; static const struct tegra_io_pad_soc tegra234_io_pads[] = { @@ -4225,8 +4219,20 @@ static const char * const tegra234_reset_sources[] = { }; static const struct tegra_wake_event tegra234_wake_events[] = { + TEGRA_WAKE_GPIO("sd-wake", 8, 0, TEGRA234_MAIN_GPIO(G, 7)), + TEGRA_WAKE_GPIO("eqos", 20, 0, TEGRA234_MAIN_GPIO(G, 4)), + TEGRA_WAKE_IRQ("pmu", 24, 209), TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)), + TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)), TEGRA_WAKE_IRQ("rtc", 73, 10), + TEGRA_WAKE_IRQ("usb3-port-0", 76, 167), + TEGRA_WAKE_IRQ("usb3-port-1", 77, 167), + TEGRA_WAKE_IRQ("usb3-port-2-3", 78, 167), + TEGRA_WAKE_IRQ("usb2-port-0", 79, 167), + TEGRA_WAKE_IRQ("usb2-port-1", 80, 167), + TEGRA_WAKE_IRQ("usb2-port-2", 81, 167), + TEGRA_WAKE_IRQ("usb2-port-3", 82, 167), + TEGRA_WAKE_IRQ("sw-wake", SW_WAKE_ID, 179), }; static const struct tegra_pmc_soc tegra234_pmc_soc = { @@ -4247,6 +4253,7 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = { .regs = &tegra234_pmc_regs, .init = tegra186_pmc_init, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, .irq_set_wake = tegra186_pmc_irq_set_wake, .irq_set_type = tegra186_pmc_irq_set_type, .reset_sources = tegra234_reset_sources, @@ -4260,9 +4267,131 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = { .pmc_clks_data = NULL, .num_pmc_clks = 0, .has_blink_output = false, + .has_single_mmio_aperture = false, +}; + +static const struct tegra_pmc_regs tegra264_pmc_regs = { + .scratch0 = 0x684, + .rst_status = 0x4, + .rst_source_shift = 0x2, + .rst_source_mask = 0x1fc, + .rst_level_shift = 0x0, + .rst_level_mask = 0x3, +}; + +static const char * const tegra264_reset_sources[] = { + "SYS_RESET_N", /* 0x0 */ + "CSDC_RTC_XTAL", + "VREFRO_POWER_BAD", + "SCPM_SOC_XTAL", + "SCPM_RTC_XTAL", + "FMON_32K", + "FMON_OSC", + "POD_RTC", + "POD_IO", /* 0x8 */ + "POD_PLUS_IO_SPLL", + "POD_PLUS_SOC", + "VMON_PLUS_UV", + "VMON_PLUS_OV", + "FUSECRC_FAULT", + "OSC_FAULT", + "BPMP_BOOT_FAULT", + "SCPM_BPMP_CORE_CLK", /* 0x10 */ + "SCPM_PSC_SE_CLK", + "VMON_SOC_MIN", + "VMON_SOC_MAX", + "VMON_MSS_MIN", + "VMON_MSS_MAX", + "POD_PLUS_IO_VMON", + "NVJTAG_SEL_MONITOR", + "NV_THERM_FAULT", /* 0x18 */ + "FSI_THERM_FAULT", + "PSC_SW", + "SCPM_OESP_SE_CLK", + "SCPM_SB_SE_CLK", + "POD_CPU", + "POD_GPU", + "DCLS_GPU", + "POD_MSS", /* 0x20 */ + "FMON_FSI", + "POD_FSI", + "VMON_FSI_MIN", + "VMON_FSI_MAX", + "VMON_CPU0_MIN", + "VMON_CPU0_MAX", + "BPMP_FMON", + "AO_WDT_POR", /* 0x28 */ + "BPMP_WDT_POR", + "AO_TKE_WDT_POR", + "RCE0_WDT_POR", + "RCE1_WDT_POR", + "DCE_WDT_POR", + "FSI_R5_WDT_POR", + "FSI_R52_0_WDT_POR", + "FSI_R52_1_WDT_POR", /* 0x30 */ + "FSI_R52_2_WDT_POR", + "FSI_R52_3_WDT_POR", + "TOP_0_WDT_POR", + "TOP_1_WDT_POR", + "TOP_2_WDT_POR", + "APE_C0_WDT_POR", + "APE_C1_WDT_POR", + "GPU_TKE_WDT_POR", /* 0x38 */ + "PSC_WDT_POR", + "OESP_WDT_POR", + "SB_WDT_POR", + "SW_MAIN", + "L0L1_RST_OUT_N", + "FSI_HSM", + "CSITE_SW", + "AO_WDT_DBG", /* 0x40 */ + "BPMP_WDT_DBG", + "AO_TKE_WDT_DBG", + "RCE0_WDT_DBG", + "RCE1_WDT_DBG", + "DCE_WDT_DBG", + "FSI_R5_WDT_DBG", + "FSI_R52_0_WDT_DBG", + "FSI_R52_1_WDT_DBG", /* 0x48 */ + "FSI_R52_2_WDT_DBG", + "FSI_R52_3_WDT_DBG", + "TOP_0_WDT_DBG", + "TOP_1_WDT_DBG", + "TOP_2_WDT_DBG", + "APE_C0_WDT_DBG", + "APE_C1_WDT_DBG", + "PSC_WDT_DBG", /* 0x50 */ + "OESP_WDT_DBG", + "SB_WDT_DBG", + "TSC_0_WDT_DBG", + "TSC_1_WDT_DBG", + "L2_RST_OUT_N", + "SC7" +}; + +static const struct tegra_wake_event tegra264_wake_events[] = { +}; + +static const struct tegra_pmc_soc tegra264_pmc_soc = { + .has_impl_33v_pwr = true, + .regs = &tegra264_pmc_regs, + .init = tegra186_pmc_init, + .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, + .irq_set_wake = tegra186_pmc_irq_set_wake, + .irq_set_type = tegra186_pmc_irq_set_type, + .reset_sources = tegra264_reset_sources, + .num_reset_sources = ARRAY_SIZE(tegra264_reset_sources), + .reset_levels = tegra186_reset_levels, + .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), + .wake_events = tegra264_wake_events, + .num_wake_events = ARRAY_SIZE(tegra264_wake_events), + .max_wake_events = 128, + .max_wake_vectors = 4, }; static const struct of_device_id tegra_pmc_match[] = { + { .compatible = "nvidia,tegra264-pmc", .data = &tegra264_pmc_soc }, { .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc }, { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, @@ -4277,8 +4406,25 @@ static const struct of_device_id tegra_pmc_match[] = { static void tegra_pmc_sync_state(struct device *dev) { + struct device_node *np, *child; int err; + np = of_get_child_by_name(dev->of_node, "powergates"); + if (!np) + return; + + for_each_child_of_node(np, child) + of_genpd_sync_state(child); + + of_node_put(np); + + np = of_get_child_by_name(dev->of_node, "core-domain"); + if (!np) + return; + + of_genpd_sync_state(np); + of_node_put(np); + /* * Newer device-trees have power domains, but we need to prepare all * device drivers with runtime PM and OPP support first, otherwise @@ -4292,9 +4438,6 @@ static void tegra_pmc_sync_state(struct device *dev) * no dependencies that will block the state syncing. We shouldn't * mark the domain as synced in this case. */ - if (!pmc->core_domain_registered) - return; - pmc->core_domain_state_synced = true; /* this is a no-op if core regulator isn't used */ diff --git a/drivers/soc/tegra/powergate-bpmp.c b/drivers/soc/tegra/powergate-bpmp.c deleted file mode 100644 index 8eaf50d0b6af..000000000000 --- a/drivers/soc/tegra/powergate-bpmp.c +++ /dev/null @@ -1,361 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved - */ - -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/pm_domain.h> -#include <linux/slab.h> - -#include <soc/tegra/bpmp.h> -#include <soc/tegra/bpmp-abi.h> - -struct tegra_powergate_info { - unsigned int id; - char *name; -}; - -struct tegra_powergate { - struct generic_pm_domain genpd; - struct tegra_bpmp *bpmp; - unsigned int id; -}; - -static inline struct tegra_powergate * -to_tegra_powergate(struct generic_pm_domain *genpd) -{ - return container_of(genpd, struct tegra_powergate, genpd); -} - -static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp, - unsigned int id, u32 state) -{ - struct mrq_pg_request request; - struct tegra_bpmp_message msg; - int err; - - memset(&request, 0, sizeof(request)); - request.cmd = CMD_PG_SET_STATE; - request.id = id; - request.set_state.state = state; - - memset(&msg, 0, sizeof(msg)); - msg.mrq = MRQ_PG; - msg.tx.data = &request; - msg.tx.size = sizeof(request); - - err = tegra_bpmp_transfer(bpmp, &msg); - if (err < 0) - return err; - else if (msg.rx.ret < 0) - return -EINVAL; - - return 0; -} - -static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp, - unsigned int id) -{ - struct mrq_pg_response response; - struct mrq_pg_request request; - struct tegra_bpmp_message msg; - int err; - - memset(&request, 0, sizeof(request)); - request.cmd = CMD_PG_GET_STATE; - request.id = id; - - memset(&response, 0, sizeof(response)); - - memset(&msg, 0, sizeof(msg)); - msg.mrq = MRQ_PG; - msg.tx.data = &request; - msg.tx.size = sizeof(request); - msg.rx.data = &response; - msg.rx.size = sizeof(response); - - err = tegra_bpmp_transfer(bpmp, &msg); - if (err < 0) - return PG_STATE_OFF; - else if (msg.rx.ret < 0) - return -EINVAL; - - return response.get_state.state; -} - -static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp) -{ - struct mrq_pg_response response; - struct mrq_pg_request request; - struct tegra_bpmp_message msg; - int err; - - memset(&request, 0, sizeof(request)); - request.cmd = CMD_PG_GET_MAX_ID; - - memset(&response, 0, sizeof(response)); - - memset(&msg, 0, sizeof(msg)); - msg.mrq = MRQ_PG; - msg.tx.data = &request; - msg.tx.size = sizeof(request); - msg.rx.data = &response; - msg.rx.size = sizeof(response); - - err = tegra_bpmp_transfer(bpmp, &msg); - if (err < 0) - return err; - else if (msg.rx.ret < 0) - return -EINVAL; - - return response.get_max_id.max_id; -} - -static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp, - unsigned int id) -{ - struct mrq_pg_response response; - struct mrq_pg_request request; - struct tegra_bpmp_message msg; - int err; - - memset(&request, 0, sizeof(request)); - request.cmd = CMD_PG_GET_NAME; - request.id = id; - - memset(&response, 0, sizeof(response)); - - memset(&msg, 0, sizeof(msg)); - msg.mrq = MRQ_PG; - msg.tx.data = &request; - msg.tx.size = sizeof(request); - msg.rx.data = &response; - msg.rx.size = sizeof(response); - - err = tegra_bpmp_transfer(bpmp, &msg); - if (err < 0 || msg.rx.ret < 0) - return NULL; - - return kstrdup(response.get_name.name, GFP_KERNEL); -} - -static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp, - unsigned int id) -{ - return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF; -} - -static int tegra_powergate_power_on(struct generic_pm_domain *domain) -{ - struct tegra_powergate *powergate = to_tegra_powergate(domain); - struct tegra_bpmp *bpmp = powergate->bpmp; - - return tegra_bpmp_powergate_set_state(bpmp, powergate->id, - PG_STATE_ON); -} - -static int tegra_powergate_power_off(struct generic_pm_domain *domain) -{ - struct tegra_powergate *powergate = to_tegra_powergate(domain); - struct tegra_bpmp *bpmp = powergate->bpmp; - - return tegra_bpmp_powergate_set_state(bpmp, powergate->id, - PG_STATE_OFF); -} - -static struct tegra_powergate * -tegra_powergate_add(struct tegra_bpmp *bpmp, - const struct tegra_powergate_info *info) -{ - struct tegra_powergate *powergate; - bool off; - int err; - - off = !tegra_bpmp_powergate_is_powered(bpmp, info->id); - - powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL); - if (!powergate) - return ERR_PTR(-ENOMEM); - - powergate->id = info->id; - powergate->bpmp = bpmp; - - powergate->genpd.name = kstrdup(info->name, GFP_KERNEL); - powergate->genpd.power_on = tegra_powergate_power_on; - powergate->genpd.power_off = tegra_powergate_power_off; - - err = pm_genpd_init(&powergate->genpd, NULL, off); - if (err < 0) { - kfree(powergate->genpd.name); - return ERR_PTR(err); - } - - return powergate; -} - -static void tegra_powergate_remove(struct tegra_powergate *powergate) -{ - struct generic_pm_domain *genpd = &powergate->genpd; - struct tegra_bpmp *bpmp = powergate->bpmp; - int err; - - err = pm_genpd_remove(genpd); - if (err < 0) - dev_err(bpmp->dev, "failed to remove power domain %s: %d\n", - genpd->name, err); - - kfree(genpd->name); -} - -static int -tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp, - struct tegra_powergate_info **powergatesp) -{ - struct tegra_powergate_info *powergates; - unsigned int max_id, id, count = 0; - unsigned int num_holes = 0; - int err; - - err = tegra_bpmp_powergate_get_max_id(bpmp); - if (err < 0) - return err; - - max_id = err; - - dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id); - - powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL); - if (!powergates) - return -ENOMEM; - - for (id = 0; id <= max_id; id++) { - struct tegra_powergate_info *info = &powergates[count]; - - info->name = tegra_bpmp_powergate_get_name(bpmp, id); - if (!info->name || info->name[0] == '\0') { - num_holes++; - continue; - } - - info->id = id; - count++; - } - - dev_dbg(bpmp->dev, "holes: %u\n", num_holes); - - *powergatesp = powergates; - - return count; -} - -static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp, - struct tegra_powergate_info *powergates, - unsigned int count) -{ - struct genpd_onecell_data *genpd = &bpmp->genpd; - struct generic_pm_domain **domains; - struct tegra_powergate *powergate; - unsigned int i; - int err; - - domains = kcalloc(count, sizeof(*domains), GFP_KERNEL); - if (!domains) - return -ENOMEM; - - for (i = 0; i < count; i++) { - powergate = tegra_powergate_add(bpmp, &powergates[i]); - if (IS_ERR(powergate)) { - err = PTR_ERR(powergate); - goto remove; - } - - dev_dbg(bpmp->dev, "added power domain %s\n", - powergate->genpd.name); - domains[i] = &powergate->genpd; - } - - genpd->num_domains = count; - genpd->domains = domains; - - return 0; - -remove: - while (i--) { - powergate = to_tegra_powergate(domains[i]); - tegra_powergate_remove(powergate); - } - - kfree(genpd->domains); - return err; -} - -static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp) -{ - struct genpd_onecell_data *genpd = &bpmp->genpd; - unsigned int i = genpd->num_domains; - struct tegra_powergate *powergate; - - while (i--) { - dev_dbg(bpmp->dev, "removing power domain %s\n", - genpd->domains[i]->name); - powergate = to_tegra_powergate(genpd->domains[i]); - tegra_powergate_remove(powergate); - } -} - -static struct generic_pm_domain * -tegra_powergate_xlate(struct of_phandle_args *spec, void *data) -{ - struct generic_pm_domain *domain = ERR_PTR(-ENOENT); - struct genpd_onecell_data *genpd = data; - unsigned int i; - - for (i = 0; i < genpd->num_domains; i++) { - struct tegra_powergate *powergate; - - powergate = to_tegra_powergate(genpd->domains[i]); - if (powergate->id == spec->args[0]) { - domain = &powergate->genpd; - break; - } - } - - return domain; -} - -int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp) -{ - struct device_node *np = bpmp->dev->of_node; - struct tegra_powergate_info *powergates; - struct device *dev = bpmp->dev; - unsigned int count, i; - int err; - - err = tegra_bpmp_probe_powergates(bpmp, &powergates); - if (err < 0) - return err; - - count = err; - - dev_dbg(dev, "%u power domains probed\n", count); - - err = tegra_bpmp_add_powergates(bpmp, powergates, count); - if (err < 0) - goto free; - - bpmp->genpd.xlate = tegra_powergate_xlate; - - err = of_genpd_add_provider_onecell(np, &bpmp->genpd); - if (err < 0) { - dev_err(dev, "failed to add power domain provider: %d\n", err); - tegra_bpmp_remove_powergates(bpmp); - } - -free: - for (i = 0; i < count; i++) - kfree(powergates[i].name); - - kfree(powergates); - return err; -} |
