summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-16 20:34:34 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-16 20:34:34 -0700
commit31b43c079f9aa55754c20404a42bca9a49e01f60 (patch)
tree5c05933f3546f52ff9adab5c10a65599e6b62293 /drivers
parente65f4718a577fcc84d40431f022985898b6dbf2e (diff)
parent33a20cdaf41d08a66581cc01a60c1a3d596ba9cd (diff)
Merge tag 'soc-drivers-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann: "The driver updates again are all over the place with many minor fixes going into platform specific code. The most notable changes are: - Support for Microchip pic64gx system controllers - Work on cleaning up devicetree bindings for SoC drivers, and converting them into the new format - Lots of smaller changes for Qualcomm SoC drivers, including support for a number of newly supported chips - reset controller API cleanups and a new driver for Cix Sky1 - Reworks of the Tegra PMC and CBB drivers, along with a change to how individual Tegra SoCs get selected in Kconfig and BPMP firmware driver updates including a refresh of the ABI header to match the version used by firmware - STM32 updates to the firewall bus driver and support for the debug bus through OP-TEE - SCMI firmware driver improvements for reliability, in particular for dealing with broken firmware interrupts - Memory driver updates for Tegra, and a patch to remove the unused Baikal T1 driver" * tag 'soc-drivers-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (193 commits) firmware: arm_ffa: Use the correct buffer size during RXTX_MAP firmware: qcom: scm: Allow QSEECOM on Lenovo IdeaCentre Mini X clk: spear: fix resource leak in clk_register_vco_pll() reset: rzv2h-usb2phy: Add support for VBUS mux controller registration reset: rzv2h-usb2phy: Convert to regmap API dt-bindings: reset: renesas,rzv2h-usb2phy: Document RZ/G3E USB2PHY reset dt-bindings: reset: renesas,rzv2h-usb2phy: Add '#mux-state-cells' property soc: microchip: add mpfs gpio interrupt mux driver dt-bindings: soc: microchip: document PolarFire SoC's gpio interrupt mux gpio: mpfs: Add interrupt support soc: qcom: ubwc: add helpers to get programmable values soc: qcom: ubwc: add helper to get min_acc length firmware: qcom: scm: Register gunyah watchdog device soc: qcom: socinfo: Add SoC ID for SA8650P dt-bindings: arm: qcom,ids: Add SoC ID for SA8650P firmware: qcom: scm: Allow QSEECOM on Mahua CRD soc: qcom: wcnss: simplify allocation of req soc: qcom: pd-mapper: Add support for Eliza soc: qcom: aoss: compare against normalized cooling state soc: qcom: llcc: fix v1 SB syndrome register offset ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/Kconfig10
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/imx-aipstz.c15
-rw-r--r--drivers/bus/stm32_dbg_bus.c250
-rw-r--r--drivers/bus/stm32_etzpc.c3
-rw-r--r--drivers/bus/stm32_firewall.c59
-rw-r--r--drivers/bus/stm32_firewall.h83
-rw-r--r--drivers/bus/stm32_rifsc.c61
-rw-r--r--drivers/clk/samsung/clk-acpm.c4
-rw-r--r--drivers/clk/spear/clk-vco-pll.c4
-rw-r--r--drivers/firmware/arm_ffa/driver.c2
-rw-r--r--drivers/firmware/arm_scmi/base.c4
-rw-r--r--drivers/firmware/arm_scmi/common.h4
-rw-r--r--drivers/firmware/arm_scmi/driver.c4
-rw-r--r--drivers/firmware/arm_scmi/quirks.h8
-rw-r--r--drivers/firmware/qcom/qcom_qseecom_uefisecapp.c9
-rw-r--r--drivers/firmware/qcom/qcom_scm.c71
-rw-r--r--drivers/firmware/samsung/exynos-acpm-dvfs.c13
-rw-r--r--drivers/firmware/samsung/exynos-acpm-dvfs.h4
-rw-r--r--drivers/firmware/samsung/exynos-acpm-pmic.c26
-rw-r--r--drivers/firmware/samsung/exynos-acpm-pmic.h10
-rw-r--r--drivers/firmware/samsung/exynos-acpm.c30
-rw-r--r--drivers/firmware/samsung/exynos-acpm.h10
-rw-r--r--drivers/firmware/tegra/bpmp.c34
-rw-r--r--drivers/gpio/Kconfig1
-rw-r--r--drivers/gpio/gpio-mpfs.c122
-rw-r--r--drivers/memory/Kconfig11
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/brcmstb_memc.c8
-rw-r--r--drivers/memory/bt1-l2-ctl.c323
-rw-r--r--drivers/memory/renesas-rpc-if.c8
-rw-r--r--drivers/memory/tegra/mc.c135
-rw-r--r--drivers/memory/tegra/mc.h153
-rw-r--r--drivers/memory/tegra/tegra114.c18
-rw-r--r--drivers/memory/tegra/tegra124-emc.c2
-rw-r--r--drivers/memory/tegra/tegra124.c40
-rw-r--r--drivers/memory/tegra/tegra186-emc.c8
-rw-r--r--drivers/memory/tegra/tegra186.c22
-rw-r--r--drivers/memory/tegra/tegra194.c22
-rw-r--r--drivers/memory/tegra/tegra20.c31
-rw-r--r--drivers/memory/tegra/tegra210.c21
-rw-r--r--drivers/memory/tegra/tegra234.c22
-rw-r--r--drivers/memory/tegra/tegra264.c420
-rw-r--r--drivers/memory/tegra/tegra30-emc.c6
-rw-r--r--drivers/memory/tegra/tegra30.c18
-rw-r--r--drivers/mfd/sec-acpm.c10
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32-hdp.c14
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c505
-rw-r--r--drivers/reset/reset-ath79.c12
-rw-r--r--drivers/reset/reset-gpio.c27
-rw-r--r--drivers/reset/reset-intel-gw.c11
-rw-r--r--drivers/reset/reset-lpc18xx.c12
-rw-r--r--drivers/reset/reset-ma35d1.c11
-rw-r--r--drivers/reset/reset-npcm.c12
-rw-r--r--drivers/reset/reset-rzv2h-usb2phy.c197
-rw-r--r--drivers/reset/reset-sky1.c367
-rw-r--r--drivers/reset/reset-sunplus.c12
-rw-r--r--drivers/reset/sti/reset-syscfg.c9
-rw-r--r--drivers/soc/hisilicon/kunpeng_hccs.c7
-rw-r--r--drivers/soc/microchip/Kconfig11
-rw-r--r--drivers/soc/microchip/Makefile1
-rw-r--r--drivers/soc/microchip/mpfs-irqmux.c181
-rw-r--r--drivers/soc/microchip/mpfs-sys-controller.c74
-rw-r--r--drivers/soc/qcom/llcc-qcom.c188
-rw-r--r--drivers/soc/qcom/ocmem.c17
-rw-r--r--drivers/soc/qcom/pdr_interface.c4
-rw-r--r--drivers/soc/qcom/pdr_internal.h3
-rw-r--r--drivers/soc/qcom/pmic_glink.c66
-rw-r--r--drivers/soc/qcom/qcom_aoss.c2
-rw-r--r--drivers/soc/qcom/qcom_pd_mapper.c33
-rw-r--r--drivers/soc/qcom/smp2p.c103
-rw-r--r--drivers/soc/qcom/socinfo.c11
-rw-r--r--drivers/soc/qcom/ubwc_config.c31
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c17
-rw-r--r--drivers/soc/renesas/Kconfig12
-rw-r--r--drivers/soc/renesas/Makefile1
-rw-r--r--drivers/soc/renesas/r9a08g046-sysc.c91
-rw-r--r--drivers/soc/renesas/r9a09g047-sys.c2
-rw-r--r--drivers/soc/renesas/r9a09g056-sys.c2
-rw-r--r--drivers/soc/renesas/r9a09g057-sys.c2
-rw-r--r--drivers/soc/renesas/rz-sysc.c3
-rw-r--r--drivers/soc/renesas/rz-sysc.h1
-rw-r--r--drivers/soc/tegra/Kconfig20
-rw-r--r--drivers/soc/tegra/cbb/tegra234-cbb.c169
-rw-r--r--drivers/soc/tegra/common.c5
-rw-r--r--drivers/soc/tegra/pmc.c664
-rw-r--r--drivers/tee/optee/device.c5
89 files changed, 3592 insertions, 1454 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 2a1b46f07080..7a1b04007efb 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -169,6 +169,16 @@ config QCOM_SSC_BLOCK_BUS
i2c/spi/uart controllers, a hexagon core, and a clock controller
which provides clocks for the above.
+config STM32_DBG_BUS
+ tristate "OP-TEE based debug access bus"
+ depends on OPTEE && STM32_FIREWALL
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ Select this to get the support for the OP-TEE based STM32 debug bus
+ driver that is used to handle debug-related peripherals on STM32
+ platforms when the debug configuration is not accessible by the
+ normal world.
+
config STM32_FIREWALL
bool "STM32 Firewall framework"
depends on (ARCH_STM32 || COMPILE_TEST) && OF
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 8e693fe8a03a..799724cfc2df 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
obj-$(CONFIG_QCOM_SSC_BLOCK_BUS) += qcom-ssc-block-bus.o
+obj-$(CONFIG_STM32_DBG_BUS) += stm32_dbg_bus.o
obj-$(CONFIG_STM32_FIREWALL) += stm32_firewall.o stm32_rifsc.o stm32_etzpc.o
obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
diff --git a/drivers/bus/imx-aipstz.c b/drivers/bus/imx-aipstz.c
index 5fdf377f5d06..83371e5b35a2 100644
--- a/drivers/bus/imx-aipstz.c
+++ b/drivers/bus/imx-aipstz.c
@@ -11,9 +11,19 @@
#include <linux/regmap.h>
#define IMX_AIPSTZ_MPR0 0x0
+#define IMX_AIPSTZ_OPACR0 0x40
+#define IMX_AIPSTZ_OPACR1 0x44
+#define IMX_AIPSTZ_OPACR2 0x48
+#define IMX_AIPSTZ_OPACR3 0x4c
+#define IMX_AIPSTZ_OPACR4 0x50
struct imx_aipstz_config {
u32 mpr0;
+ u32 opacr0;
+ u32 opacr1;
+ u32 opacr2;
+ u32 opacr3;
+ u32 opacr4;
};
struct imx_aipstz_data {
@@ -24,6 +34,11 @@ struct imx_aipstz_data {
static void imx_aipstz_apply_default(struct imx_aipstz_data *data)
{
writel(data->default_cfg->mpr0, data->base + IMX_AIPSTZ_MPR0);
+ writel(data->default_cfg->opacr0, data->base + IMX_AIPSTZ_OPACR0);
+ writel(data->default_cfg->opacr1, data->base + IMX_AIPSTZ_OPACR1);
+ writel(data->default_cfg->opacr2, data->base + IMX_AIPSTZ_OPACR2);
+ writel(data->default_cfg->opacr3, data->base + IMX_AIPSTZ_OPACR3);
+ writel(data->default_cfg->opacr4, data->base + IMX_AIPSTZ_OPACR4);
}
static const struct of_device_id imx_aipstz_match_table[] = {
diff --git a/drivers/bus/stm32_dbg_bus.c b/drivers/bus/stm32_dbg_bus.c
new file mode 100644
index 000000000000..e30ef3465609
--- /dev/null
+++ b/drivers/bus/stm32_dbg_bus.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/bus/stm32_firewall.h>
+#include <linux/bus/stm32_firewall_device.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+
+enum stm32_dbg_profile {
+ PERIPHERAL_DBG_PROFILE = 0,
+ HDP_DBG_PROFILE = 1,
+};
+
+enum stm32_dbg_pta_command {
+ /*
+ * PTA_CMD_GRANT_DBG_ACCESS - Verify the debug configuration against the given debug profile
+ * and grant access or not
+ *
+ * [in] value[0].a Debug profile to grant access to.
+ */
+ PTA_CMD_GRANT_DBG_ACCESS,
+};
+
+/**
+ * struct stm32_dbg_bus - OP-TEE based STM32 debug bus private data
+ * @dev: STM32 debug bus device.
+ * @ctx: OP-TEE context handler.
+ */
+struct stm32_dbg_bus {
+ struct device *dev;
+ struct tee_context *ctx;
+};
+
+/* Expect at most 1 instance of this driver */
+static struct stm32_dbg_bus *stm32_dbg_bus_priv;
+
+static int stm32_dbg_pta_open_session(u32 *id)
+{
+ struct tee_client_device *dbg_bus_dev = to_tee_client_device(stm32_dbg_bus_priv->dev);
+ struct tee_ioctl_open_session_arg sess_arg;
+ int ret;
+
+ memset(&sess_arg, 0, sizeof(sess_arg));
+ export_uuid(sess_arg.uuid, &dbg_bus_dev->id.uuid);
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+
+ ret = tee_client_open_session(stm32_dbg_bus_priv->ctx, &sess_arg, NULL);
+ if (ret < 0 || sess_arg.ret) {
+ dev_err(stm32_dbg_bus_priv->dev, "Failed opening tee session, err: %#x\n",
+ sess_arg.ret);
+ return -EOPNOTSUPP;
+ }
+
+ *id = sess_arg.session;
+
+ return 0;
+}
+
+static void stm32_dbg_pta_close_session(u32 id)
+{
+ tee_client_close_session(stm32_dbg_bus_priv->ctx, id);
+}
+
+static int stm32_dbg_bus_grant_access(struct stm32_firewall_controller *ctrl, u32 dbg_profile)
+{
+ struct tee_ioctl_invoke_arg inv_arg = {0};
+ struct tee_param param[1] = {0};
+ u32 session_id;
+ int ret;
+
+ if (dbg_profile != PERIPHERAL_DBG_PROFILE && dbg_profile != HDP_DBG_PROFILE)
+ return -EOPNOTSUPP;
+
+ ret = stm32_dbg_pta_open_session(&session_id);
+ if (ret)
+ return ret;
+
+ inv_arg.func = PTA_CMD_GRANT_DBG_ACCESS;
+ inv_arg.session = session_id;
+ inv_arg.num_params = 1;
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = dbg_profile;
+
+ ret = tee_client_invoke_func(stm32_dbg_bus_priv->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_dbg(stm32_dbg_bus_priv->dev,
+ "When invoking function, err %x, TEE returns: %x\n", ret, inv_arg.ret);
+ if (!ret)
+ ret = -EACCES;
+ }
+
+ stm32_dbg_pta_close_session(session_id);
+
+ return ret;
+}
+
+/* Implement mandatory release_access ops even if it does nothing*/
+static void stm32_dbg_bus_release_access(struct stm32_firewall_controller *ctrl, u32 dbg_profile)
+{
+}
+
+static int stm32_dbg_bus_plat_probe(struct platform_device *pdev)
+{
+ struct stm32_firewall_controller *dbg_controller;
+ int ret;
+
+ /* Defer if OP-TEE service is not yet available */
+ if (!stm32_dbg_bus_priv)
+ return -EPROBE_DEFER;
+
+ dbg_controller = devm_kzalloc(&pdev->dev, sizeof(*dbg_controller), GFP_KERNEL);
+ if (!dbg_controller)
+ return dev_err_probe(&pdev->dev, -ENOMEM, "Couldn't allocate debug controller\n");
+
+ dbg_controller->dev = &pdev->dev;
+ dbg_controller->mmio = NULL;
+ dbg_controller->name = dev_driver_string(dbg_controller->dev);
+ dbg_controller->type = STM32_PERIPHERAL_FIREWALL;
+ dbg_controller->grant_access = stm32_dbg_bus_grant_access;
+ dbg_controller->release_access = stm32_dbg_bus_release_access;
+
+ ret = stm32_firewall_controller_register(dbg_controller);
+ if (ret) {
+ dev_err(dbg_controller->dev, "Couldn't register as a firewall controller: %d", ret);
+ return ret;
+ }
+
+ ret = stm32_firewall_populate_bus(dbg_controller);
+ if (ret) {
+ dev_err(dbg_controller->dev, "Couldn't populate debug bus: %d", ret);
+ stm32_firewall_controller_unregister(dbg_controller);
+ return ret;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ dev_err(dbg_controller->dev, "Couldn't populate the node: %d", ret);
+ stm32_firewall_controller_unregister(dbg_controller);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id stm32_dbg_bus_of_match[] = {
+ { .compatible = "st,stm32mp131-dbg-bus", },
+ { .compatible = "st,stm32mp151-dbg-bus", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, stm32_dbg_bus_of_match);
+
+static struct platform_driver stm32_dbg_bus_driver = {
+ .probe = stm32_dbg_bus_plat_probe,
+ .driver = {
+ .name = "stm32-dbg-bus",
+ .of_match_table = stm32_dbg_bus_of_match,
+ },
+};
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+ return (ver->impl_id == TEE_IMPL_ID_OPTEE);
+}
+
+static void stm32_dbg_bus_remove(struct tee_client_device *tee_dev)
+{
+ tee_client_close_context(stm32_dbg_bus_priv->ctx);
+ stm32_dbg_bus_priv = NULL;
+
+ of_platform_depopulate(&tee_dev->dev);
+}
+
+static int stm32_dbg_bus_probe(struct tee_client_device *tee_dev)
+{
+ struct device *dev = &tee_dev->dev;
+ struct stm32_dbg_bus *priv;
+ int ret = 0;
+
+ if (stm32_dbg_bus_priv)
+ return dev_err_probe(dev, -EBUSY,
+ "A STM32 debug bus device is already initialized\n");
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Open context with TEE driver */
+ priv->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+ if (IS_ERR_OR_NULL(priv->ctx))
+ return dev_err_probe(dev, PTR_ERR_OR_ZERO(priv->ctx), "Cannot open TEE context\n");
+
+ stm32_dbg_bus_priv = priv;
+ stm32_dbg_bus_priv->dev = dev;
+
+ return ret;
+}
+
+static const struct tee_client_device_id optee_dbg_bus_id_table[] = {
+ {UUID_INIT(0xdd05bc8b, 0x9f3b, 0x49f0,
+ 0xb6, 0x49, 0x01, 0xaa, 0x10, 0xc1, 0xc2, 0x10)},
+ {}
+};
+
+static struct tee_client_driver stm32_optee_dbg_bus_driver = {
+ .id_table = optee_dbg_bus_id_table,
+ .probe = stm32_dbg_bus_probe,
+ .remove = stm32_dbg_bus_remove,
+ .driver = {
+ .name = "optee_dbg_bus",
+ },
+};
+
+static void __exit stm32_optee_dbg_bus_driver_exit(void)
+{
+ platform_driver_unregister(&stm32_dbg_bus_driver);
+ tee_client_driver_unregister(&stm32_optee_dbg_bus_driver);
+}
+module_exit(stm32_optee_dbg_bus_driver_exit);
+
+static int __init stm32_optee_dbg_bus_driver_init(void)
+{
+ int err;
+
+ err = tee_client_driver_register(&stm32_optee_dbg_bus_driver);
+ if (err)
+ return err;
+
+ err = platform_driver_register(&stm32_dbg_bus_driver);
+ if (err)
+ tee_client_driver_unregister(&stm32_optee_dbg_bus_driver);
+
+ return err;
+}
+module_init(stm32_optee_dbg_bus_driver_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gatien Chevallier <gatien.chevallier@foss.st.com>");
+MODULE_DESCRIPTION("OP-TEE based STM32 debug access bus driver");
diff --git a/drivers/bus/stm32_etzpc.c b/drivers/bus/stm32_etzpc.c
index 7fc0f16960be..4918a14e507e 100644
--- a/drivers/bus/stm32_etzpc.c
+++ b/drivers/bus/stm32_etzpc.c
@@ -5,6 +5,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/bus/stm32_firewall.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -16,8 +17,6 @@
#include <linux/platform_device.h>
#include <linux/types.h>
-#include "stm32_firewall.h"
-
/*
* ETZPC registers
*/
diff --git a/drivers/bus/stm32_firewall.c b/drivers/bus/stm32_firewall.c
index 7e7afe8007db..e3619dba8b06 100644
--- a/drivers/bus/stm32_firewall.c
+++ b/drivers/bus/stm32_firewall.c
@@ -5,6 +5,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/bus/stm32_firewall.h>
#include <linux/bus/stm32_firewall_device.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -18,8 +19,6 @@
#include <linux/types.h>
#include <linux/slab.h>
-#include "stm32_firewall.h"
-
/* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */
#define STM32_FIREWALL_MAX_ARGS (STM32_FIREWALL_MAX_EXTRA_ARGS + 1)
@@ -185,6 +184,48 @@ void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 su
}
EXPORT_SYMBOL_GPL(stm32_firewall_release_access_by_id);
+int stm32_firewall_get_grant_all_access(struct device *dev, struct stm32_firewall **firewall,
+ int *nb_firewall)
+{
+ struct stm32_firewall *loc_firewall;
+ int err;
+ int i;
+
+ *nb_firewall = of_count_phandle_with_args(dev->of_node, "access-controllers",
+ "#access-controller-cells");
+ if (*nb_firewall < 0)
+ return *nb_firewall;
+
+ if (!*nb_firewall) {
+ *firewall = NULL;
+ return 0;
+ }
+
+ loc_firewall = devm_kcalloc(dev, *nb_firewall, sizeof(*loc_firewall), GFP_KERNEL);
+ if (!loc_firewall)
+ return -ENOMEM;
+
+ /* Get stm32 firewall information */
+ err = stm32_firewall_get_firewall(dev->of_node, loc_firewall, *nb_firewall);
+ if (err)
+ return err;
+
+ for (i = 0; i < *nb_firewall; i++) {
+ err = stm32_firewall_grant_access(&loc_firewall[i]);
+ if (err) {
+ while (i--)
+ stm32_firewall_release_access(&loc_firewall[i]);
+
+ return err;
+ }
+ }
+
+ *firewall = loc_firewall;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(stm32_firewall_get_grant_all_access);
+
/* Firewall controller API */
int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller)
@@ -241,7 +282,6 @@ EXPORT_SYMBOL_GPL(stm32_firewall_controller_unregister);
int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller)
{
struct stm32_firewall *firewalls;
- struct device_node *child;
struct device *parent;
unsigned int i;
int len;
@@ -251,30 +291,25 @@ int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_contr
dev_dbg(parent, "Populating %s system bus\n", dev_name(firewall_controller->dev));
- for_each_available_child_of_node(dev_of_node(parent), child) {
+ for_each_available_child_of_node_scoped(dev_of_node(parent), child) {
/* The access-controllers property is mandatory for firewall bus devices */
len = of_count_phandle_with_args(child, "access-controllers",
"#access-controller-cells");
- if (len <= 0) {
- of_node_put(child);
+ if (len <= 0)
return -EINVAL;
- }
firewalls = kzalloc_objs(*firewalls, len);
- if (!firewalls) {
- of_node_put(child);
+ if (!firewalls)
return -ENOMEM;
- }
err = stm32_firewall_get_firewall(child, firewalls, (unsigned int)len);
if (err) {
kfree(firewalls);
- of_node_put(child);
return err;
}
for (i = 0; i < len; i++) {
- if (firewall_controller->grant_access(firewall_controller,
+ if (firewall_controller->grant_access(firewalls[i].firewall_ctrl,
firewalls[i].firewall_id)) {
/*
* Peripheral access not allowed or not defined.
diff --git a/drivers/bus/stm32_firewall.h b/drivers/bus/stm32_firewall.h
deleted file mode 100644
index e5fac85fe346..000000000000
--- a/drivers/bus/stm32_firewall.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) 2023, STMicroelectronics - All Rights Reserved
- */
-
-#ifndef _STM32_FIREWALL_H
-#define _STM32_FIREWALL_H
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/types.h>
-
-/**
- * STM32_PERIPHERAL_FIREWALL: This type of firewall protects peripherals
- * STM32_MEMORY_FIREWALL: This type of firewall protects memories/subsets of memory
- * zones
- * STM32_NOTYPE_FIREWALL: Undefined firewall type
- */
-
-#define STM32_PERIPHERAL_FIREWALL BIT(1)
-#define STM32_MEMORY_FIREWALL BIT(2)
-#define STM32_NOTYPE_FIREWALL BIT(3)
-
-/**
- * struct stm32_firewall_controller - Information on firewall controller supplying services
- *
- * @name: Name of the firewall controller
- * @dev: Device reference of the firewall controller
- * @mmio: Base address of the firewall controller
- * @entry: List entry of the firewall controller list
- * @type: Type of firewall
- * @max_entries: Number of entries covered by the firewall
- * @grant_access: Callback used to grant access for a device access against a
- * firewall controller
- * @release_access: Callback used to release resources taken by a device when access was
- * granted
- * @grant_memory_range_access: Callback used to grant access for a device to a given memory region
- */
-struct stm32_firewall_controller {
- const char *name;
- struct device *dev;
- void __iomem *mmio;
- struct list_head entry;
- unsigned int type;
- unsigned int max_entries;
-
- int (*grant_access)(struct stm32_firewall_controller *ctrl, u32 id);
- void (*release_access)(struct stm32_firewall_controller *ctrl, u32 id);
- int (*grant_memory_range_access)(struct stm32_firewall_controller *ctrl, phys_addr_t paddr,
- size_t size);
-};
-
-/**
- * stm32_firewall_controller_register - Register a firewall controller to the STM32 firewall
- * framework
- * @firewall_controller: Firewall controller to register
- *
- * Returns 0 in case of success or -ENODEV if no controller was given.
- */
-int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller);
-
-/**
- * stm32_firewall_controller_unregister - Unregister a firewall controller from the STM32
- * firewall framework
- * @firewall_controller: Firewall controller to unregister
- */
-void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller);
-
-/**
- * stm32_firewall_populate_bus - Populate device tree nodes that have a correct firewall
- * configuration. This is used at boot-time only, as a sanity check
- * between device tree and firewalls hardware configurations to
- * prevent a kernel crash when a device driver is not granted access
- *
- * @firewall_controller: Firewall controller which nodes will be populated or not
- *
- * Returns 0 in case of success or appropriate errno code if error occurred.
- */
-int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller);
-
-#endif /* _STM32_FIREWALL_H */
diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c
index debeaf8ea1bd..19d10379dcef 100644
--- a/drivers/bus/stm32_rifsc.c
+++ b/drivers/bus/stm32_rifsc.c
@@ -5,6 +5,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/bus/stm32_firewall.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -15,10 +16,9 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/string.h>
#include <linux/types.h>
-#include "stm32_firewall.h"
-
/*
* RIFSC offset register
*/
@@ -450,7 +450,7 @@ static void stm32_rifsc_fill_rimu_dbg_entry(struct rifsc_dbg_private *rifsc,
const struct stm32_rifsc_resources_names *dbg_names = rifsc->res_names;
u32 rimc_attr = readl_relaxed(rifsc->mmio + RIFSC_RIMC_ATTR0 + 0x4 * i);
- snprintf(dbg_entry->m_name, sizeof(dbg_entry->m_name), "%s", dbg_names->initiator_names[i]);
+ strscpy(dbg_entry->m_name, dbg_names->initiator_names[i]);
dbg_entry->m_cid = FIELD_GET(RIFSC_RIMC_MCID_MASK, rimc_attr);
dbg_entry->cidsel = rimc_attr & RIFSC_RIMC_CIDSEL;
dbg_entry->m_sec = rimc_attr & RIFSC_RIMC_MSEC;
@@ -469,8 +469,7 @@ static void stm32_rifsc_fill_dev_dbg_entry(struct rifsc_dbg_private *rifsc,
sec_cfgr = readl_relaxed(rifsc->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);
priv_cfgr = readl_relaxed(rifsc->mmio + RIFSC_RISC_PRIVCFGR0 + 0x4 * reg_id);
- snprintf(dbg_entry->dev_name, sizeof(dbg_entry->dev_name), "%s",
- dbg_names->device_names[i]);
+ strscpy(dbg_entry->dev_name, dbg_names->device_names[i]);
dbg_entry->dev_id = i;
dbg_entry->dev_cid_filt_en = cid_cfgr & CIDCFGR_CFEN;
dbg_entry->dev_sem_en = cid_cfgr & CIDCFGR_SEMEN;
@@ -688,34 +687,6 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32
sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id);
cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id);
- /* First check conditions for semaphore mode, which doesn't take into account static CID. */
- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {
- if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) {
- /* Static CID is irrelevant if semaphore mode */
- goto skip_cid_check;
- } else {
- dev_dbg(rifsc_controller->dev,
- "Invalid bus semaphore configuration: index %d\n", firewall_id);
- return -EACCES;
- }
- }
-
- /*
- * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which
- * corresponds to whatever CID.
- */
- if (!(cid_reg_value & CIDCFGR_CFEN) ||
- FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0)
- goto skip_cid_check;
-
- /* Coherency check with the CID configuration */
- if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) {
- dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n",
- firewall_id);
- return -EACCES;
- }
-
-skip_cid_check:
/* Check security configuration */
if (sec_reg_value & BIT(reg_offset)) {
dev_dbg(rifsc_controller->dev,
@@ -723,19 +694,31 @@ skip_cid_check:
return -EACCES;
}
- /*
- * If the peripheral is in semaphore mode, take the semaphore so that
- * the CID1 has the ownership.
- */
- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) {
+ /* Skip CID check if CID filtering isn't enabled */
+ if (!(cid_reg_value & CIDCFGR_CFEN))
+ goto skip_cid_check;
+
+ /* First check conditions for semaphore mode, which doesn't take into account static CID. */
+ if (cid_reg_value & CIDCFGR_SEMEN) {
+ if (!(cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT))) {
+ dev_dbg(rifsc_controller->dev,
+ "Invalid bus semaphore configuration: index %d\n", firewall_id);
+ return -EACCES;
+ }
+
rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id);
if (rc) {
- dev_err(rifsc_controller->dev,
+ dev_dbg(rifsc_controller->dev,
"Couldn't acquire semaphore for peripheral: %d\n", firewall_id);
return rc;
}
+ } else if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) {
+ dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n",
+ firewall_id);
+ return -EACCES;
}
+skip_cid_check:
return 0;
}
diff --git a/drivers/clk/samsung/clk-acpm.c b/drivers/clk/samsung/clk-acpm.c
index b90809ce3f88..d8944160793a 100644
--- a/drivers/clk/samsung/clk-acpm.c
+++ b/drivers/clk/samsung/clk-acpm.c
@@ -20,7 +20,7 @@ struct acpm_clk {
u32 id;
struct clk_hw hw;
unsigned int mbox_chan_id;
- const struct acpm_handle *handle;
+ struct acpm_handle *handle;
};
struct acpm_clk_variant {
@@ -113,7 +113,7 @@ static int acpm_clk_register(struct device *dev, struct acpm_clk *aclk,
static int acpm_clk_probe(struct platform_device *pdev)
{
- const struct acpm_handle *acpm_handle;
+ struct acpm_handle *acpm_handle;
struct clk_hw_onecell_data *clk_data;
struct clk_hw **hws;
struct device *dev = &pdev->dev;
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c
index 601e123f5c4b..faba727e2f84 100644
--- a/drivers/clk/spear/clk-vco-pll.c
+++ b/drivers/clk/spear/clk-vco-pll.c
@@ -343,13 +343,15 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name,
tpll_clk = clk_register(NULL, &pll->hw);
if (IS_ERR_OR_NULL(tpll_clk))
- goto free_pll;
+ goto unregister_clk;
if (pll_clk)
*pll_clk = tpll_clk;
return vco_clk;
+unregister_clk:
+ clk_unregister(vco_clk);
free_pll:
kfree(pll);
free_vco:
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index f2f94d4d533e..eb2782848283 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -2078,7 +2078,7 @@ static int __init ffa_init(void)
ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer),
virt_to_phys(drv_info->rx_buffer),
- rxtx_bufsz / FFA_PAGE_SIZE);
+ PAGE_ALIGN(rxtx_bufsz) / FFA_PAGE_SIZE);
if (ret) {
pr_err("failed to register FFA RxTx buffers\n");
goto free_pages;
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 22267bbd0f4d..cd1331c2fc40 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -7,6 +7,7 @@
#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/scmi_protocol.h>
@@ -219,8 +220,7 @@ scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
}
real_list_sz = t->rx.len - sizeof(u32);
- calc_list_sz = (1 + (loop_num_ret - 1) / sizeof(u32)) *
- sizeof(u32);
+ calc_list_sz = round_up(loop_num_ret, sizeof(u32));
if (calc_list_sz != real_list_sz) {
dev_warn(dev,
"Malformed reply - real_sz:%zd calc_sz:%u (loop_num_ret:%d)\n",
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index 7c35c95fddba..7c9617d080a0 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -235,6 +235,9 @@ struct scmi_transport_ops {
* to have an execution latency lesser-equal to the threshold
* should be considered for atomic mode operation: such
* decision is finally left up to the SCMI drivers.
+ * @no_completion_irq: Flag to indicate that this transport has no completion
+ * interrupt and has to be polled. This is similar to the
+ * force_polling below, except this is set via DT property.
* @force_polling: Flag to force this whole transport to use SCMI core polling
* mechanism instead of completion interrupts even if available.
* @sync_cmds_completed_on_ret: Flag to indicate that the transport assures
@@ -254,6 +257,7 @@ struct scmi_desc {
int max_msg;
int max_msg_size;
unsigned int atomic_threshold;
+ bool no_completion_irq;
const bool force_polling;
const bool sync_cmds_completed_on_ret;
const bool atomic_enabled;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 3e76a3204ba4..f167194f7cf6 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2735,6 +2735,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
cinfo->is_p2a = !tx;
cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms;
cinfo->max_msg_size = info->desc->max_msg_size;
+ cinfo->no_completion_irq = info->desc->no_completion_irq;
/* Create a unique name for this transport device */
snprintf(name, 32, "__scmi_transport_device_%s_%02X",
@@ -3150,6 +3151,9 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev)
if (ret && ret != -EINVAL)
dev_err(dev, "Malformed arm,max-msg DT property.\n");
+ trans->desc.no_completion_irq = of_property_read_bool(dev->of_node,
+ "arm,no-completion-irq");
+
dev_info(dev,
"SCMI max-rx-timeout: %dms / max-msg-size: %dbytes / max-msg: %d\n",
trans->desc.max_rx_timeout_ms, trans->desc.max_msg_size,
diff --git a/drivers/firmware/arm_scmi/quirks.h b/drivers/firmware/arm_scmi/quirks.h
index a71fde85a527..d8ba60b95652 100644
--- a/drivers/firmware/arm_scmi/quirks.h
+++ b/drivers/firmware/arm_scmi/quirks.h
@@ -20,10 +20,10 @@
* named as _qn.
*/
#define SCMI_QUIRK(_qn, _blk) \
- do { \
+ ({ \
if (static_branch_unlikely(&(scmi_quirk_ ## _qn))) \
(_blk); \
- } while (0)
+ })
void scmi_quirks_initialize(void);
void scmi_quirks_enable(struct device *dev, const char *vend,
@@ -34,10 +34,10 @@ void scmi_quirks_enable(struct device *dev, const char *vend,
#define DECLARE_SCMI_QUIRK(_qn)
/* Force quirks compilation even when SCMI Quirks are disabled */
#define SCMI_QUIRK(_qn, _blk) \
- do { \
+ ({ \
if (0) \
(_blk); \
- } while (0)
+ })
static inline void scmi_quirks_initialize(void) { }
static inline void scmi_quirks_enable(struct device *dev, const char *vend,
diff --git a/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c b/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
index 98a463e9774b..befa68d1dcaf 100644
--- a/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
+++ b/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
@@ -699,20 +699,18 @@ static DEFINE_MUTEX(__qcuefi_lock);
static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
{
- mutex_lock(&__qcuefi_lock);
+ guard(mutex)(&__qcuefi_lock);
- if (qcuefi && __qcuefi) {
- mutex_unlock(&__qcuefi_lock);
+ if (qcuefi && __qcuefi)
return -EEXIST;
- }
__qcuefi = qcuefi;
- mutex_unlock(&__qcuefi_lock);
return 0;
}
static struct qcuefi_client *qcuefi_acquire(void)
+ __acquires(__qcuefi_lock)
{
mutex_lock(&__qcuefi_lock);
if (!__qcuefi) {
@@ -723,6 +721,7 @@ static struct qcuefi_client *qcuefi_acquire(void)
}
static void qcuefi_release(void)
+ __releases(__qcuefi_lock)
{
mutex_unlock(&__qcuefi_lock);
}
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 8fbc96693a55..9b06a69d3a6d 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -199,19 +199,18 @@ static int qcom_scm_bw_enable(void)
if (!__scm->path)
return 0;
- mutex_lock(&__scm->scm_bw_lock);
+ guard(mutex)(&__scm->scm_bw_lock);
+
if (!__scm->scm_vote_count) {
ret = icc_set_bw(__scm->path, 0, UINT_MAX);
if (ret < 0) {
dev_err(__scm->dev, "failed to set bandwidth request\n");
- goto err_bw;
+ return ret;
}
}
__scm->scm_vote_count++;
-err_bw:
- mutex_unlock(&__scm->scm_bw_lock);
- return ret;
+ return 0;
}
static void qcom_scm_bw_disable(void)
@@ -923,14 +922,13 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
goto free_input_rt;
}
- tbl_ptr = kzalloc(size, GFP_KERNEL);
+ tbl_ptr = kmemdup(output_rt_tzm, size, GFP_KERNEL);
if (!tbl_ptr) {
qcom_tzmem_free(output_rt_tzm);
ret = -ENOMEM;
goto free_input_rt;
}
- memcpy(tbl_ptr, output_rt_tzm, size);
*output_rt_size = size;
qcom_tzmem_free(output_rt_tzm);
@@ -2290,15 +2288,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
*/
static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = {
{ .compatible = "asus,vivobook-s15" },
+ { .compatible = "asus,vivobook-s15-x1p4" },
{ .compatible = "asus,zenbook-a14-ux3407qa" },
{ .compatible = "asus,zenbook-a14-ux3407ra" },
{ .compatible = "dell,inspiron-14-plus-7441" },
{ .compatible = "dell,latitude-7455" },
{ .compatible = "dell,xps13-9345" },
+ { .compatible = "ecs,liva-qc710" },
{ .compatible = "hp,elitebook-ultra-g1q" },
{ .compatible = "hp,omnibook-x14" },
{ .compatible = "huawei,gaokun3" },
{ .compatible = "lenovo,flex-5g" },
+ { .compatible = "lenovo,ideacentre-mini-01q8x10" },
{ .compatible = "lenovo,thinkbook-16" },
{ .compatible = "lenovo,thinkpad-t14s" },
{ .compatible = "lenovo,thinkpad-x13s", },
@@ -2309,7 +2310,10 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = {
{ .compatible = "microsoft,denali", },
{ .compatible = "microsoft,romulus13", },
{ .compatible = "microsoft,romulus15", },
+ { .compatible = "qcom,glymur-crd" },
{ .compatible = "qcom,hamoa-iot-evk" },
+ { .compatible = "qcom,mahua-crd" },
+ { .compatible = "qcom,purwa-iot-evk" },
{ .compatible = "qcom,sc8180x-primus" },
{ .compatible = "qcom,x1e001de-devkit" },
{ .compatible = "qcom,x1e80100-crd" },
@@ -2467,6 +2471,56 @@ int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size,
}
EXPORT_SYMBOL(qcom_scm_qtee_callback_response);
+static void qcom_scm_gunyah_wdt_free(void *data)
+{
+ struct platform_device *gunyah_wdt_dev = data;
+
+ platform_device_unregister(gunyah_wdt_dev);
+}
+
+static void qcom_scm_gunyah_wdt_init(struct qcom_scm *scm)
+{
+ struct platform_device *gunyah_wdt_dev;
+ struct device_node *np;
+ bool of_wdt_available;
+ int i;
+ static const uuid_t gunyah_uuid = UUID_INIT(0xc1d58fcd, 0xa453, 0x5fdb,
+ 0x92, 0x65, 0xce, 0x36,
+ 0x67, 0x3d, 0x5f, 0x14);
+ static const char * const of_wdt_compatible[] = {
+ "qcom,kpss-wdt",
+ "arm,sbsa-gwdt",
+ };
+
+ /* Bail out if we are not running under Gunyah */
+ if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) ||
+ !arm_smccc_hypervisor_has_uuid(&gunyah_uuid))
+ return;
+
+ /*
+ * Gunyah emulates either of Qualcomm watchdog or ARM SBSA watchdog on
+ * newer platforms. Bail out if we find them in the devicetree.
+ */
+ for (i = 0; i < ARRAY_SIZE(of_wdt_compatible); i++) {
+ np = of_find_compatible_node(NULL, NULL, of_wdt_compatible[i]);
+ of_wdt_available = of_device_is_available(np);
+ of_node_put(np);
+ if (of_wdt_available)
+ return;
+ }
+
+ gunyah_wdt_dev = platform_device_register_simple("gunyah-wdt", -1,
+ NULL, 0);
+ if (IS_ERR(gunyah_wdt_dev)) {
+ dev_err(scm->dev, "Failed to register Gunyah watchdog device: %ld\n",
+ PTR_ERR(gunyah_wdt_dev));
+ return;
+ }
+
+ devm_add_action_or_reset(scm->dev, qcom_scm_gunyah_wdt_free,
+ gunyah_wdt_dev);
+}
+
static void qcom_scm_qtee_free(void *data)
{
struct platform_device *qtee_dev = data;
@@ -2811,6 +2865,9 @@ static int qcom_scm_probe(struct platform_device *pdev)
/* Initialize the QTEE object interface. */
qcom_scm_qtee_init(scm);
+ /* Initialize the Gunyah watchdog platform device. */
+ qcom_scm_gunyah_wdt_init(scm);
+
return 0;
}
diff --git a/drivers/firmware/samsung/exynos-acpm-dvfs.c b/drivers/firmware/samsung/exynos-acpm-dvfs.c
index 1c5b2b143bcc..06bdf62dea1f 100644
--- a/drivers/firmware/samsung/exynos-acpm-dvfs.c
+++ b/drivers/firmware/samsung/exynos-acpm-dvfs.c
@@ -5,6 +5,7 @@
* Copyright 2025 Linaro Ltd.
*/
+#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
#include <linux/ktime.h>
@@ -24,12 +25,12 @@ static void acpm_dvfs_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
unsigned int acpm_chan_id, bool response)
{
xfer->acpm_chan_id = acpm_chan_id;
+ xfer->txcnt = cmdlen;
xfer->txd = cmd;
- xfer->txlen = cmdlen;
if (response) {
+ xfer->rxcnt = cmdlen;
xfer->rxd = cmd;
- xfer->rxlen = cmdlen;
}
}
@@ -42,7 +43,7 @@ static void acpm_dvfs_init_set_rate_cmd(u32 cmd[4], unsigned int clk_id,
cmd[3] = ktime_to_ms(ktime_get());
}
-int acpm_dvfs_set_rate(const struct acpm_handle *handle,
+int acpm_dvfs_set_rate(struct acpm_handle *handle,
unsigned int acpm_chan_id, unsigned int clk_id,
unsigned long rate)
{
@@ -50,7 +51,7 @@ int acpm_dvfs_set_rate(const struct acpm_handle *handle,
u32 cmd[4];
acpm_dvfs_init_set_rate_cmd(cmd, clk_id, rate);
- acpm_dvfs_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id, false);
+ acpm_dvfs_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id, false);
return acpm_do_xfer(handle, &xfer);
}
@@ -62,7 +63,7 @@ static void acpm_dvfs_init_get_rate_cmd(u32 cmd[4], unsigned int clk_id)
cmd[3] = ktime_to_ms(ktime_get());
}
-unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
+unsigned long acpm_dvfs_get_rate(struct acpm_handle *handle,
unsigned int acpm_chan_id, unsigned int clk_id)
{
struct acpm_xfer xfer;
@@ -70,7 +71,7 @@ unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
int ret;
acpm_dvfs_init_get_rate_cmd(cmd, clk_id);
- acpm_dvfs_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id, true);
+ acpm_dvfs_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id, true);
ret = acpm_do_xfer(handle, &xfer);
if (ret)
diff --git a/drivers/firmware/samsung/exynos-acpm-dvfs.h b/drivers/firmware/samsung/exynos-acpm-dvfs.h
index 9f2778e649c9..b37b15426102 100644
--- a/drivers/firmware/samsung/exynos-acpm-dvfs.h
+++ b/drivers/firmware/samsung/exynos-acpm-dvfs.h
@@ -11,10 +11,10 @@
struct acpm_handle;
-int acpm_dvfs_set_rate(const struct acpm_handle *handle,
+int acpm_dvfs_set_rate(struct acpm_handle *handle,
unsigned int acpm_chan_id, unsigned int id,
unsigned long rate);
-unsigned long acpm_dvfs_get_rate(const struct acpm_handle *handle,
+unsigned long acpm_dvfs_get_rate(struct acpm_handle *handle,
unsigned int acpm_chan_id,
unsigned int clk_id);
diff --git a/drivers/firmware/samsung/exynos-acpm-pmic.c b/drivers/firmware/samsung/exynos-acpm-pmic.c
index 961d7599e422..0c50993cc9a8 100644
--- a/drivers/firmware/samsung/exynos-acpm-pmic.c
+++ b/drivers/firmware/samsung/exynos-acpm-pmic.c
@@ -41,7 +41,7 @@ static const int acpm_pmic_linux_errmap[] = {
[2] = -EACCES, /* Write register can't be accessed or issues to access it. */
};
-static int acpm_pmic_to_linux_err(int err)
+static int acpm_pmic_to_linux_err(unsigned int err)
{
if (err >= 0 && err < ARRAY_SIZE(acpm_pmic_linux_errmap))
return acpm_pmic_linux_errmap[err];
@@ -63,8 +63,8 @@ static void acpm_pmic_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
{
xfer->txd = cmd;
xfer->rxd = cmd;
- xfer->txlen = cmdlen;
- xfer->rxlen = cmdlen;
+ xfer->txcnt = cmdlen;
+ xfer->rxcnt = cmdlen;
xfer->acpm_chan_id = acpm_chan_id;
}
@@ -77,7 +77,7 @@ static void acpm_pmic_init_read_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan)
cmd[3] = ktime_to_ms(ktime_get());
}
-int acpm_pmic_read_reg(const struct acpm_handle *handle,
+int acpm_pmic_read_reg(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 *buf)
{
@@ -86,7 +86,7 @@ int acpm_pmic_read_reg(const struct acpm_handle *handle,
int ret;
acpm_pmic_init_read_cmd(cmd, type, reg, chan);
- acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
+ acpm_pmic_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id);
ret = acpm_do_xfer(handle, &xfer);
if (ret)
@@ -107,7 +107,7 @@ static void acpm_pmic_init_bulk_read_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
FIELD_PREP(ACPM_PMIC_VALUE, count);
}
-int acpm_pmic_bulk_read(const struct acpm_handle *handle,
+int acpm_pmic_bulk_read(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 count, u8 *buf)
{
@@ -119,7 +119,7 @@ int acpm_pmic_bulk_read(const struct acpm_handle *handle,
return -EINVAL;
acpm_pmic_init_bulk_read_cmd(cmd, type, reg, chan, count);
- acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
+ acpm_pmic_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id);
ret = acpm_do_xfer(handle, &xfer);
if (ret)
@@ -150,7 +150,7 @@ static void acpm_pmic_init_write_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
cmd[3] = ktime_to_ms(ktime_get());
}
-int acpm_pmic_write_reg(const struct acpm_handle *handle,
+int acpm_pmic_write_reg(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 value)
{
@@ -159,7 +159,7 @@ int acpm_pmic_write_reg(const struct acpm_handle *handle,
int ret;
acpm_pmic_init_write_cmd(cmd, type, reg, chan, value);
- acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
+ acpm_pmic_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id);
ret = acpm_do_xfer(handle, &xfer);
if (ret)
@@ -187,7 +187,7 @@ static void acpm_pmic_init_bulk_write_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
}
}
-int acpm_pmic_bulk_write(const struct acpm_handle *handle,
+int acpm_pmic_bulk_write(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 count, const u8 *buf)
{
@@ -199,7 +199,7 @@ int acpm_pmic_bulk_write(const struct acpm_handle *handle,
return -EINVAL;
acpm_pmic_init_bulk_write_cmd(cmd, type, reg, chan, count, buf);
- acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
+ acpm_pmic_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id);
ret = acpm_do_xfer(handle, &xfer);
if (ret)
@@ -220,7 +220,7 @@ static void acpm_pmic_init_update_cmd(u32 cmd[4], u8 type, u8 reg, u8 chan,
cmd[3] = ktime_to_ms(ktime_get());
}
-int acpm_pmic_update_reg(const struct acpm_handle *handle,
+int acpm_pmic_update_reg(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 value, u8 mask)
{
@@ -229,7 +229,7 @@ int acpm_pmic_update_reg(const struct acpm_handle *handle,
int ret;
acpm_pmic_init_update_cmd(cmd, type, reg, chan, value, mask);
- acpm_pmic_set_xfer(&xfer, cmd, sizeof(cmd), acpm_chan_id);
+ acpm_pmic_set_xfer(&xfer, cmd, ARRAY_SIZE(cmd), acpm_chan_id);
ret = acpm_do_xfer(handle, &xfer);
if (ret)
diff --git a/drivers/firmware/samsung/exynos-acpm-pmic.h b/drivers/firmware/samsung/exynos-acpm-pmic.h
index 078421888a14..88ae9aada2ae 100644
--- a/drivers/firmware/samsung/exynos-acpm-pmic.h
+++ b/drivers/firmware/samsung/exynos-acpm-pmic.h
@@ -11,19 +11,19 @@
struct acpm_handle;
-int acpm_pmic_read_reg(const struct acpm_handle *handle,
+int acpm_pmic_read_reg(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 *buf);
-int acpm_pmic_bulk_read(const struct acpm_handle *handle,
+int acpm_pmic_bulk_read(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 count, u8 *buf);
-int acpm_pmic_write_reg(const struct acpm_handle *handle,
+int acpm_pmic_write_reg(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 value);
-int acpm_pmic_bulk_write(const struct acpm_handle *handle,
+int acpm_pmic_bulk_write(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 count, const u8 *buf);
-int acpm_pmic_update_reg(const struct acpm_handle *handle,
+int acpm_pmic_update_reg(struct acpm_handle *handle,
unsigned int acpm_chan_id, u8 type, u8 reg, u8 chan,
u8 value, u8 mask);
#endif /* __EXYNOS_ACPM_PMIC_H__ */
diff --git a/drivers/firmware/samsung/exynos-acpm.c b/drivers/firmware/samsung/exynos-acpm.c
index 0cb269c70460..16c46ed60837 100644
--- a/drivers/firmware/samsung/exynos-acpm.c
+++ b/drivers/firmware/samsung/exynos-acpm.c
@@ -205,7 +205,7 @@ static void acpm_get_saved_rx(struct acpm_chan *achan,
rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
if (rx_seqnum == tx_seqnum) {
- memcpy(xfer->rxd, rx_data->cmd, xfer->rxlen);
+ memcpy(xfer->rxd, rx_data->cmd, xfer->rxcnt * sizeof(*xfer->rxd));
clear_bit(rx_seqnum - 1, achan->bitmap_seqnum);
}
}
@@ -258,8 +258,7 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
if (rx_data->response) {
if (rx_seqnum == tx_seqnum) {
- __ioread32_copy(xfer->rxd, addr,
- xfer->rxlen / 4);
+ __ioread32_copy(xfer->rxd, addr, xfer->rxcnt);
rx_set = true;
clear_bit(seqnum, achan->bitmap_seqnum);
} else {
@@ -269,8 +268,7 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
* clear yet the bitmap. It will be cleared
* after the response is copied to the request.
*/
- __ioread32_copy(rx_data->cmd, addr,
- xfer->rxlen / 4);
+ __ioread32_copy(rx_data->cmd, addr, xfer->rxcnt);
}
} else {
clear_bit(seqnum, achan->bitmap_seqnum);
@@ -412,7 +410,7 @@ static int acpm_wait_for_message_response(struct acpm_chan *achan,
*
* Return: 0 on success, -errno otherwise.
*/
-int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer)
+int acpm_do_xfer(struct acpm_handle *handle, const struct acpm_xfer *xfer)
{
struct acpm_info *acpm = handle_to_acpm_info(handle);
struct exynos_mbox_msg msg;
@@ -425,7 +423,9 @@ int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer)
achan = &acpm->chans[xfer->acpm_chan_id];
- if (!xfer->txd || xfer->txlen > achan->mlen || xfer->rxlen > achan->mlen)
+ if (!xfer->txd ||
+ (xfer->txcnt * sizeof(*xfer->txd) > achan->mlen) ||
+ (xfer->rxcnt * sizeof(*xfer->rxd) > achan->mlen))
return -EINVAL;
if (!achan->poll_completion) {
@@ -448,7 +448,7 @@ int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer)
/* Write TX command. */
__iowrite32_copy(achan->tx.base + achan->mlen * tx_front,
- xfer->txd, xfer->txlen / 4);
+ xfer->txd, xfer->txcnt);
/* Advance TX front. */
writel(idx, achan->tx.front);
@@ -674,7 +674,7 @@ static int acpm_probe(struct platform_device *pdev)
* acpm_handle_put() - release the handle acquired by acpm_get_by_phandle.
* @handle: Handle acquired by acpm_get_by_phandle.
*/
-static void acpm_handle_put(const struct acpm_handle *handle)
+static void acpm_handle_put(struct acpm_handle *handle)
{
struct acpm_info *acpm = handle_to_acpm_info(handle);
struct device *dev = acpm->dev;
@@ -700,9 +700,11 @@ static void devm_acpm_release(struct device *dev, void *res)
* @np: ACPM device tree node.
*
* Return: pointer to handle on success, ERR_PTR(-errno) otherwise.
+ *
+ * Note: handle CANNOT be pointer to const
*/
-static const struct acpm_handle *acpm_get_by_node(struct device *dev,
- struct device_node *np)
+static struct acpm_handle *acpm_get_by_node(struct device *dev,
+ struct device_node *np)
{
struct platform_device *pdev;
struct device_link *link;
@@ -743,10 +745,10 @@ static const struct acpm_handle *acpm_get_by_node(struct device *dev,
*
* Return: pointer to handle on success, ERR_PTR(-errno) otherwise.
*/
-const struct acpm_handle *devm_acpm_get_by_node(struct device *dev,
- struct device_node *np)
+struct acpm_handle *devm_acpm_get_by_node(struct device *dev,
+ struct device_node *np)
{
- const struct acpm_handle **ptr, *handle;
+ struct acpm_handle **ptr, *handle;
ptr = devres_alloc(devm_acpm_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
diff --git a/drivers/firmware/samsung/exynos-acpm.h b/drivers/firmware/samsung/exynos-acpm.h
index 2d14cb58f98c..5df8354dc96c 100644
--- a/drivers/firmware/samsung/exynos-acpm.h
+++ b/drivers/firmware/samsung/exynos-acpm.h
@@ -8,16 +8,16 @@
#define __EXYNOS_ACPM_H__
struct acpm_xfer {
- const u32 *txd;
- u32 *rxd;
- size_t txlen;
- size_t rxlen;
+ const u32 *txd __counted_by_ptr(txcnt);
+ u32 *rxd __counted_by_ptr(rxcnt);
+ size_t txcnt;
+ size_t rxcnt;
unsigned int acpm_chan_id;
};
struct acpm_handle;
-int acpm_do_xfer(const struct acpm_handle *handle,
+int acpm_do_xfer(struct acpm_handle *handle,
const struct acpm_xfer *xfer);
#endif /* __EXYNOS_ACPM_H__ */
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index e74bba7ccc44..753472b53bd8 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -32,6 +32,40 @@ channel_to_ops(struct tegra_bpmp_channel *channel)
return bpmp->soc->ops;
}
+struct tegra_bpmp *tegra_bpmp_get_with_id(struct device *dev, unsigned int *id)
+{
+ struct platform_device *pdev;
+ struct of_phandle_args args;
+ struct tegra_bpmp *bpmp;
+ int err;
+
+ err = __of_parse_phandle_with_args(dev->of_node, "nvidia,bpmp", NULL,
+ 1, 0, &args);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ pdev = of_find_device_by_node(args.np);
+ if (!pdev) {
+ bpmp = ERR_PTR(-ENODEV);
+ goto put;
+ }
+
+ bpmp = platform_get_drvdata(pdev);
+ if (!bpmp) {
+ bpmp = ERR_PTR(-EPROBE_DEFER);
+ put_device(&pdev->dev);
+ goto put;
+ }
+
+ if (id)
+ *id = args.args[0];
+
+put:
+ of_node_put(args.np);
+ return bpmp;
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_get_with_id);
+
struct tegra_bpmp *tegra_bpmp_get(struct device *dev)
{
struct platform_device *pdev;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c5ede0e4a32a..020e51e30317 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -580,6 +580,7 @@ config GPIO_PL061
config GPIO_POLARFIRE_SOC
bool "Microchip FPGA GPIO support"
select REGMAP_MMIO
+ select GPIOLIB_IRQCHIP
help
Say yes here to support the GPIO controllers on Microchip FPGAs.
diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c
index 9468795b9634..1a4cf213c723 100644
--- a/drivers/gpio/gpio-mpfs.c
+++ b/drivers/gpio/gpio-mpfs.c
@@ -9,8 +9,9 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
-#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -18,7 +19,7 @@
#define MPFS_GPIO_CTRL(i) (0x4 * (i))
#define MPFS_MAX_NUM_GPIO 32
-#define MPFS_GPIO_EN_INT 3
+#define MPFS_GPIO_EN_INT BIT(3)
#define MPFS_GPIO_EN_OUT_BUF BIT(2)
#define MPFS_GPIO_EN_IN BIT(1)
#define MPFS_GPIO_EN_OUT BIT(0)
@@ -52,6 +53,7 @@ static const struct regmap_config mpfs_gpio_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
+ .use_raw_spinlock = true,
};
static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index)
@@ -114,13 +116,98 @@ static int mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int valu
return ret;
}
+static int mpfs_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ int gpio_index = irqd_to_hwirq(data) % 32;
+ u32 interrupt_type;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_BOTH;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_NEG;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_POS;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_LOW;
+ break;
+ }
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_TYPE_INT_MASK, interrupt_type);
+
+ return 0;
+}
+
+static void mpfs_gpio_irq_unmask(struct irq_data *data)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ int gpio_index = irqd_to_hwirq(data) % 32;
+
+ gpiochip_enable_irq(gc, gpio_index);
+ mpfs_gpio_direction_input(gc, gpio_index);
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_EN_INT, MPFS_GPIO_EN_INT);
+}
+
+static void mpfs_gpio_irq_mask(struct irq_data *data)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ int gpio_index = irqd_to_hwirq(data) % 32;
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_EN_INT, 0);
+ gpiochip_disable_irq(gc, gpio_index);
+}
+
+static const struct irq_chip mpfs_gpio_irqchip = {
+ .name = "MPFS GPIO",
+ .irq_set_type = mpfs_gpio_irq_set_type,
+ .irq_mask = mpfs_gpio_irq_mask,
+ .irq_unmask = mpfs_gpio_irq_unmask,
+ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static void mpfs_gpio_irq_handler(struct irq_desc *desc)
+{
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ struct mpfs_gpio_chip *mpfs_gpio = irq_desc_get_handler_data(desc);
+ unsigned long status;
+ u32 val;
+ int i;
+
+ chained_irq_enter(irqchip, desc);
+
+ regmap_read(mpfs_gpio->regs, MPFS_IRQ_REG, &val);
+ status = val;
+ for_each_set_bit(i, &status, MPFS_MAX_NUM_GPIO) {
+ regmap_write(mpfs_gpio->regs, MPFS_IRQ_REG, BIT(i));
+ generic_handle_domain_irq(mpfs_gpio->gc.irq.domain, i);
+ }
+
+ chained_irq_exit(irqchip, desc);
+}
+
static int mpfs_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
struct mpfs_gpio_chip *mpfs_gpio;
+ struct gpio_irq_chip *girq;
struct clk *clk;
void __iomem *base;
- int ngpios;
+ int ngpios, nirqs, ret;
mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL);
if (!mpfs_gpio)
@@ -157,6 +244,35 @@ static int mpfs_gpio_probe(struct platform_device *pdev)
mpfs_gpio->gc.parent = dev;
mpfs_gpio->gc.owner = THIS_MODULE;
+ nirqs = of_irq_count(node);
+ if (nirqs > MPFS_MAX_NUM_GPIO)
+ return -ENXIO;
+
+ if (nirqs) {
+ girq = &mpfs_gpio->gc.irq;
+
+ gpio_irq_chip_set_chip(girq, &mpfs_gpio_irqchip);
+
+ girq->num_parents = nirqs;
+ girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
+ sizeof(*girq->parents), GFP_KERNEL);
+ if (!girq->parents)
+ return -ENOMEM;
+
+ for (int i = 0; i < nirqs; i++) {
+ ret = platform_get_irq(pdev, i);
+ if (ret < 0)
+ return ret;
+
+ girq->parents[i] = ret;
+ girq->parent_handler_data = mpfs_gpio;
+ girq->parent_handler = mpfs_gpio_irq_handler;
+ }
+
+ girq->handler = handle_level_irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ }
+
return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio);
}
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 79df0d22e218..e5527020ff33 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -64,17 +64,6 @@ config BRCMSTB_MEMC
controller and specifically control the Self Refresh Power Down
(SRPD) inactivity timeout.
-config BT1_L2_CTL
- bool "Baikal-T1 CM2 L2-RAM Cache Control Block"
- depends on MIPS_BAIKAL_T1 || COMPILE_TEST
- select MFD_SYSCON
- help
- Baikal-T1 CPU is based on the MIPS P5600 Warrior IP-core. The CPU
- resides Coherency Manager v2 with embedded 1MB L2-cache. It's
- possible to tune the L2 cache performance up by setting the data,
- tags and way-select latencies of RAM access. This driver provides a
- dt properties-based and sysfs interface for it.
-
config TI_AEMIF
tristate "Texas Instruments AEMIF driver"
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index c1959661bf63..3ee883c8759a 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o
obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o
obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o
obj-$(CONFIG_BRCMSTB_MEMC) += brcmstb_memc.o
-obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o
diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c
index ba73470b1b13..c28fe9093616 100644
--- a/drivers/memory/brcmstb_memc.c
+++ b/drivers/memory/brcmstb_memc.c
@@ -14,6 +14,7 @@
#define REG_MEMC_CNTRLR_CONFIG 0x00
#define CNTRLR_CONFIG_LPDDR4_SHIFT 5
+#define CNTRLR_CONFIG_LPDDR5_SHIFT 6
#define CNTRLR_CONFIG_MASK 0xf
#define REG_MEMC_SRPD_CFG_21 0x20
#define REG_MEMC_SRPD_CFG_20 0x34
@@ -34,14 +35,15 @@ struct brcmstb_memc {
u32 srpd_offset;
};
-static int brcmstb_memc_uses_lpddr4(struct brcmstb_memc *memc)
+static int brcmstb_memc_uses_lpddr45(struct brcmstb_memc *memc)
{
void __iomem *config = memc->ddr_ctrl + REG_MEMC_CNTRLR_CONFIG;
u32 reg;
reg = readl_relaxed(config) & CNTRLR_CONFIG_MASK;
- return reg == CNTRLR_CONFIG_LPDDR4_SHIFT;
+ return reg == CNTRLR_CONFIG_LPDDR4_SHIFT ||
+ reg == CNTRLR_CONFIG_LPDDR5_SHIFT;
}
static int brcmstb_memc_srpd_config(struct brcmstb_memc *memc,
@@ -95,7 +97,7 @@ static ssize_t srpd_store(struct device *dev, struct device_attribute *attr,
* dynamic tuning process will also get affected by the inactivity
* timeout, thus making it non functional.
*/
- if (brcmstb_memc_uses_lpddr4(memc))
+ if (brcmstb_memc_uses_lpddr45(memc))
return -EOPNOTSUPP;
ret = kstrtouint(buf, 10, &val);
diff --git a/drivers/memory/bt1-l2-ctl.c b/drivers/memory/bt1-l2-ctl.c
deleted file mode 100644
index 0fd96abc172a..000000000000
--- a/drivers/memory/bt1-l2-ctl.c
+++ /dev/null
@@ -1,323 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
- *
- * Authors:
- * Serge Semin <Sergey.Semin@baikalelectronics.ru>
- *
- * Baikal-T1 CM2 L2-cache Control Block driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/bitfield.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/sysfs.h>
-#include <linux/of.h>
-
-#define L2_CTL_REG 0x028
-#define L2_CTL_DATA_STALL_FLD 0
-#define L2_CTL_DATA_STALL_MASK GENMASK(1, L2_CTL_DATA_STALL_FLD)
-#define L2_CTL_TAG_STALL_FLD 2
-#define L2_CTL_TAG_STALL_MASK GENMASK(3, L2_CTL_TAG_STALL_FLD)
-#define L2_CTL_WS_STALL_FLD 4
-#define L2_CTL_WS_STALL_MASK GENMASK(5, L2_CTL_WS_STALL_FLD)
-#define L2_CTL_SET_CLKRATIO BIT(13)
-#define L2_CTL_CLKRATIO_LOCK BIT(31)
-
-#define L2_CTL_STALL_MIN 0
-#define L2_CTL_STALL_MAX 3
-#define L2_CTL_STALL_SET_DELAY_US 1
-#define L2_CTL_STALL_SET_TOUT_US 1000
-
-/*
- * struct l2_ctl - Baikal-T1 L2 Control block private data.
- * @dev: Pointer to the device structure.
- * @sys_regs: Baikal-T1 System Controller registers map.
- */
-struct l2_ctl {
- struct device *dev;
-
- struct regmap *sys_regs;
-};
-
-/*
- * enum l2_ctl_stall - Baikal-T1 L2-cache-RAM stall identifier.
- * @L2_WSSTALL: Way-select latency.
- * @L2_TAGSTALL: Tag latency.
- * @L2_DATASTALL: Data latency.
- */
-enum l2_ctl_stall {
- L2_WS_STALL,
- L2_TAG_STALL,
- L2_DATA_STALL
-};
-
-/*
- * struct l2_ctl_device_attribute - Baikal-T1 L2-cache device attribute.
- * @dev_attr: Actual sysfs device attribute.
- * @id: L2-cache stall field identifier.
- */
-struct l2_ctl_device_attribute {
- struct device_attribute dev_attr;
- enum l2_ctl_stall id;
-};
-
-#define to_l2_ctl_dev_attr(_dev_attr) \
- container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr)
-
-#define L2_CTL_ATTR_RW(_name, _prefix, _id) \
- struct l2_ctl_device_attribute l2_ctl_attr_##_name = \
- { __ATTR(_name, 0644, _prefix##_show, _prefix##_store), _id }
-
-static int l2_ctl_get_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 *val)
-{
- u32 data = 0;
- int ret;
-
- ret = regmap_read(l2->sys_regs, L2_CTL_REG, &data);
- if (ret)
- return ret;
-
- switch (id) {
- case L2_WS_STALL:
- *val = FIELD_GET(L2_CTL_WS_STALL_MASK, data);
- break;
- case L2_TAG_STALL:
- *val = FIELD_GET(L2_CTL_TAG_STALL_MASK, data);
- break;
- case L2_DATA_STALL:
- *val = FIELD_GET(L2_CTL_DATA_STALL_MASK, data);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int l2_ctl_set_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 val)
-{
- u32 mask = 0, data = 0;
- int ret;
-
- val = clamp_val(val, L2_CTL_STALL_MIN, L2_CTL_STALL_MAX);
-
- switch (id) {
- case L2_WS_STALL:
- data = FIELD_PREP(L2_CTL_WS_STALL_MASK, val);
- mask = L2_CTL_WS_STALL_MASK;
- break;
- case L2_TAG_STALL:
- data = FIELD_PREP(L2_CTL_TAG_STALL_MASK, val);
- mask = L2_CTL_TAG_STALL_MASK;
- break;
- case L2_DATA_STALL:
- data = FIELD_PREP(L2_CTL_DATA_STALL_MASK, val);
- mask = L2_CTL_DATA_STALL_MASK;
- break;
- default:
- return -EINVAL;
- }
-
- data |= L2_CTL_SET_CLKRATIO;
- mask |= L2_CTL_SET_CLKRATIO;
-
- ret = regmap_update_bits(l2->sys_regs, L2_CTL_REG, mask, data);
- if (ret)
- return ret;
-
- return regmap_read_poll_timeout(l2->sys_regs, L2_CTL_REG, data,
- data & L2_CTL_CLKRATIO_LOCK,
- L2_CTL_STALL_SET_DELAY_US,
- L2_CTL_STALL_SET_TOUT_US);
-}
-
-static void l2_ctl_clear_data(void *data)
-{
- struct l2_ctl *l2 = data;
- struct platform_device *pdev = to_platform_device(l2->dev);
-
- platform_set_drvdata(pdev, NULL);
-}
-
-static struct l2_ctl *l2_ctl_create_data(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct l2_ctl *l2;
- int ret;
-
- l2 = devm_kzalloc(dev, sizeof(*l2), GFP_KERNEL);
- if (!l2)
- return ERR_PTR(-ENOMEM);
-
- ret = devm_add_action(dev, l2_ctl_clear_data, l2);
- if (ret) {
- dev_err(dev, "Can't add L2 CTL data clear action\n");
- return ERR_PTR(ret);
- }
-
- l2->dev = dev;
- platform_set_drvdata(pdev, l2);
-
- return l2;
-}
-
-static int l2_ctl_find_sys_regs(struct l2_ctl *l2)
-{
- l2->sys_regs = syscon_node_to_regmap(l2->dev->of_node->parent);
- if (IS_ERR(l2->sys_regs)) {
- dev_err(l2->dev, "Couldn't get L2 CTL register map\n");
- return PTR_ERR(l2->sys_regs);
- }
-
- return 0;
-}
-
-static int l2_ctl_of_parse_property(struct l2_ctl *l2, enum l2_ctl_stall id,
- const char *propname)
-{
- int ret = 0;
- u32 data;
-
- if (!of_property_read_u32(l2->dev->of_node, propname, &data)) {
- ret = l2_ctl_set_latency(l2, id, data);
- if (ret)
- dev_err(l2->dev, "Invalid value of '%s'\n", propname);
- }
-
- return ret;
-}
-
-static int l2_ctl_of_parse(struct l2_ctl *l2)
-{
- int ret;
-
- ret = l2_ctl_of_parse_property(l2, L2_WS_STALL, "baikal,l2-ws-latency");
- if (ret)
- return ret;
-
- ret = l2_ctl_of_parse_property(l2, L2_TAG_STALL, "baikal,l2-tag-latency");
- if (ret)
- return ret;
-
- return l2_ctl_of_parse_property(l2, L2_DATA_STALL,
- "baikal,l2-data-latency");
-}
-
-static ssize_t l2_ctl_latency_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
- struct l2_ctl *l2 = dev_get_drvdata(dev);
- u32 data;
- int ret;
-
- ret = l2_ctl_get_latency(l2, devattr->id, &data);
- if (ret)
- return ret;
-
- return sysfs_emit(buf, "%u\n", data);
-}
-
-static ssize_t l2_ctl_latency_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr);
- struct l2_ctl *l2 = dev_get_drvdata(dev);
- u32 data;
- int ret;
-
- if (kstrtouint(buf, 0, &data) < 0)
- return -EINVAL;
-
- ret = l2_ctl_set_latency(l2, devattr->id, data);
- if (ret)
- return ret;
-
- return count;
-}
-
-static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL);
-static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL);
-static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL);
-
-static struct attribute *l2_ctl_sysfs_attrs[] = {
- &l2_ctl_attr_l2_ws_latency.dev_attr.attr,
- &l2_ctl_attr_l2_tag_latency.dev_attr.attr,
- &l2_ctl_attr_l2_data_latency.dev_attr.attr,
- NULL
-};
-ATTRIBUTE_GROUPS(l2_ctl_sysfs);
-
-static void l2_ctl_remove_sysfs(void *data)
-{
- struct l2_ctl *l2 = data;
-
- device_remove_groups(l2->dev, l2_ctl_sysfs_groups);
-}
-
-static int l2_ctl_init_sysfs(struct l2_ctl *l2)
-{
- int ret;
-
- ret = device_add_groups(l2->dev, l2_ctl_sysfs_groups);
- if (ret) {
- dev_err(l2->dev, "Failed to create L2 CTL sysfs nodes\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(l2->dev, l2_ctl_remove_sysfs, l2);
- if (ret)
- dev_err(l2->dev, "Can't add L2 CTL sysfs remove action\n");
-
- return ret;
-}
-
-static int l2_ctl_probe(struct platform_device *pdev)
-{
- struct l2_ctl *l2;
- int ret;
-
- l2 = l2_ctl_create_data(pdev);
- if (IS_ERR(l2))
- return PTR_ERR(l2);
-
- ret = l2_ctl_find_sys_regs(l2);
- if (ret)
- return ret;
-
- ret = l2_ctl_of_parse(l2);
- if (ret)
- return ret;
-
- ret = l2_ctl_init_sysfs(l2);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static const struct of_device_id l2_ctl_of_match[] = {
- { .compatible = "baikal,bt1-l2-ctl" },
- { }
-};
-MODULE_DEVICE_TABLE(of, l2_ctl_of_match);
-
-static struct platform_driver l2_ctl_driver = {
- .probe = l2_ctl_probe,
- .driver = {
- .name = "bt1-l2-ctl",
- .of_match_table = l2_ctl_of_match
- }
-};
-module_platform_driver(l2_ctl_driver);
-
-MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
-MODULE_DESCRIPTION("Baikal-T1 L2-cache driver");
diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
index 58ccc1c02e90..0fb568456164 100644
--- a/drivers/memory/renesas-rpc-if.c
+++ b/drivers/memory/renesas-rpc-if.c
@@ -1005,11 +1005,9 @@ static int rpcif_probe(struct platform_device *pdev)
return PTR_ERR(rpc->base);
rpc->info = of_device_get_match_data(dev);
rpc->regmap = devm_regmap_init(dev, NULL, rpc, rpc->info->regmap_config);
- if (IS_ERR(rpc->regmap)) {
- dev_err(dev, "failed to init regmap for rpcif, error %ld\n",
- PTR_ERR(rpc->regmap));
- return PTR_ERR(rpc->regmap);
- }
+ if (IS_ERR(rpc->regmap))
+ return dev_err_probe(dev, PTR_ERR(rpc->regmap),
+ "failed to init regmap for rpcif\n");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
rpc->dirmap = devm_ioremap_resource(dev, res);
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index 6edb210287dc..d620660da331 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014-2025 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/clk.h>
@@ -56,6 +56,23 @@ static const struct of_device_id tegra_mc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
+const struct tegra_mc_regs tegra20_mc_regs = {
+ .cfg_channel_enable = 0xdf8,
+ .err_status = 0x08,
+ .err_add = 0x0c,
+ .err_add_hi = 0x11fc,
+ .err_vpr_status = 0x654,
+ .err_vpr_add = 0x658,
+ .err_sec_status = 0x67c,
+ .err_sec_add = 0x680,
+ .err_mts_status = 0x9b0,
+ .err_mts_add = 0x9b4,
+ .err_gen_co_status = 0xc00,
+ .err_gen_co_add = 0xc04,
+ .err_route_status = 0x9c0,
+ .err_route_add = 0x9c4,
+};
+
static void tegra_mc_devm_action_put_device(void *data)
{
struct tegra_mc *mc = data;
@@ -381,12 +398,16 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
}
EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count);
+const irq_handler_t tegra30_mc_irq_handlers[] = {
+ tegra30_mc_handle_irq
+};
+
#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
defined(CONFIG_ARCH_TEGRA_132_SOC) || \
defined(CONFIG_ARCH_TEGRA_210_SOC)
-static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
+static void tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
{
unsigned long long tick;
unsigned int i;
@@ -414,8 +435,6 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
/* latch new values */
mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
-
- return 0;
}
static int load_one_timing(struct tegra_mc *mc,
@@ -509,32 +528,24 @@ int tegra30_mc_probe(struct tegra_mc *mc)
int err;
mc->clk = devm_clk_get_optional(mc->dev, "mc");
- if (IS_ERR(mc->clk)) {
- dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk));
- return PTR_ERR(mc->clk);
- }
+ if (IS_ERR(mc->clk))
+ return dev_err_probe(mc->dev, PTR_ERR(mc->clk),
+ "failed to get MC clock\n");
/* ensure that debug features are disabled */
mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
- err = tegra_mc_setup_latency_allowance(mc);
- if (err < 0) {
- dev_err(mc->dev, "failed to setup latency allowance: %d\n", err);
- return err;
- }
+ tegra_mc_setup_latency_allowance(mc);
err = tegra_mc_setup_timings(mc);
- if (err < 0) {
- dev_err(mc->dev, "failed to setup timings: %d\n", err);
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(mc->dev, err, "failed to setup timings\n");
return 0;
}
const struct tegra_mc_ops tegra30_mc_ops = {
.probe = tegra30_mc_probe,
- .handle_irq = tegra30_mc_handle_irq,
};
#endif
@@ -575,9 +586,9 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
}
/* mask all interrupts to avoid flooding */
- status = mc_ch_readl(mc, channel, MC_INTSTATUS) & mc->soc->intmask;
+ status = mc_ch_readl(mc, channel, MC_INTSTATUS) & mc->soc->intmasks[0].mask;
} else {
- status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+ status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmasks[0].mask;
}
if (!status)
@@ -600,37 +611,37 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
switch (intmask) {
case MC_INT_DECERR_VPR:
- status_reg = MC_ERR_VPR_STATUS;
- addr_reg = MC_ERR_VPR_ADR;
+ status_reg = mc->soc->regs->err_vpr_status;
+ addr_reg = mc->soc->regs->err_vpr_add;
break;
case MC_INT_SECERR_SEC:
- status_reg = MC_ERR_SEC_STATUS;
- addr_reg = MC_ERR_SEC_ADR;
+ status_reg = mc->soc->regs->err_sec_status;
+ addr_reg = mc->soc->regs->err_sec_add;
break;
case MC_INT_DECERR_MTS:
- status_reg = MC_ERR_MTS_STATUS;
- addr_reg = MC_ERR_MTS_ADR;
+ status_reg = mc->soc->regs->err_mts_status;
+ addr_reg = mc->soc->regs->err_mts_add;
break;
case MC_INT_DECERR_GENERALIZED_CARVEOUT:
- status_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS;
- addr_reg = MC_ERR_GENERALIZED_CARVEOUT_ADR;
+ status_reg = mc->soc->regs->err_gen_co_status;
+ addr_reg = mc->soc->regs->err_gen_co_add;
break;
case MC_INT_DECERR_ROUTE_SANITY:
- status_reg = MC_ERR_ROUTE_SANITY_STATUS;
- addr_reg = MC_ERR_ROUTE_SANITY_ADR;
+ status_reg = mc->soc->regs->err_route_status;
+ addr_reg = mc->soc->regs->err_route_add;
break;
default:
- status_reg = MC_ERR_STATUS;
- addr_reg = MC_ERR_ADR;
+ status_reg = mc->soc->regs->err_status;
+ addr_reg = mc->soc->regs->err_add;
#ifdef CONFIG_PHYS_ADDR_T_64BIT
if (mc->soc->has_addr_hi_reg)
- addr_hi_reg = MC_ERR_ADR_HI;
+ addr_hi_reg = mc->soc->regs->err_add_hi;
#endif
break;
}
@@ -647,9 +658,12 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
addr = mc_ch_readl(mc, channel, addr_hi_reg);
else
addr = mc_readl(mc, addr_hi_reg);
- } else {
+ } else if (mc->soc->mc_addr_hi_mask) {
addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
- MC_ERR_STATUS_ADR_HI_MASK);
+ mc->soc->mc_addr_hi_mask);
+ } else {
+ dev_err_ratelimited(mc->dev, "Unable to determine high address!");
+ return IRQ_NONE;
}
addr <<= 32;
}
@@ -674,11 +688,11 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data)
}
}
- type = (value & MC_ERR_STATUS_TYPE_MASK) >>
+ type = (value & mc->soc->mc_err_status_type_mask) >>
MC_ERR_STATUS_TYPE_SHIFT;
- desc = tegra_mc_error_names[type];
+ desc = tegra20_mc_error_names[type];
- switch (value & MC_ERR_STATUS_TYPE_MASK) {
+ switch (value & mc->soc->mc_err_status_type_mask) {
case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE:
perm[0] = ' ';
perm[1] = '[';
@@ -744,9 +758,10 @@ const char *const tegra_mc_status_names[32] = {
[16] = "MTS carveout violation",
[17] = "Generalized carveout violation",
[20] = "Route Sanity error",
+ [21] = "GIC_MSI error",
};
-const char *const tegra_mc_error_names[8] = {
+const char *const tegra20_mc_error_names[8] = {
[2] = "EMEM decode error",
[3] = "TrustZone violation",
[4] = "Carveout violation",
@@ -883,7 +898,7 @@ static void tegra_mc_num_channel_enabled(struct tegra_mc *mc)
unsigned int i;
u32 value;
- value = mc_ch_readl(mc, 0, MC_EMEM_ADR_CFG_CHANNEL_ENABLE);
+ value = mc_ch_readl(mc, 0, mc->soc->regs->cfg_channel_enable);
if (value <= 0) {
mc->num_channels = mc->soc->num_channels;
return;
@@ -935,25 +950,32 @@ static int tegra_mc_probe(struct platform_device *pdev)
tegra_mc_num_channel_enabled(mc);
- if (mc->soc->ops && mc->soc->ops->handle_irq) {
- mc->irq = platform_get_irq(pdev, 0);
- if (mc->irq < 0)
- return mc->irq;
+ if (mc->soc->handle_irq) {
+ unsigned int i;
WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n");
- if (mc->soc->num_channels)
- mc_ch_writel(mc, MC_BROADCAST_CHANNEL, mc->soc->intmask,
- MC_INTMASK);
- else
- mc_writel(mc, mc->soc->intmask, MC_INTMASK);
+ for (i = 0; i < mc->soc->num_interrupts; i++) {
+ int irq;
- err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0,
- dev_name(&pdev->dev), mc);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
- err);
- return err;
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(&pdev->dev, irq, mc->soc->handle_irq[i], 0,
+ dev_name(&pdev->dev), mc);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", irq, err);
+ return err;
+ }
+ }
+
+ for (i = 0; i < mc->soc->num_intmasks; i++) {
+ if (mc->soc->num_channels)
+ mc_ch_writel(mc, MC_BROADCAST_CHANNEL, mc->soc->intmasks[i].mask,
+ mc->soc->intmasks[i].reg);
+ else
+ mc_writel(mc, mc->soc->intmasks[i].mask, mc->soc->intmasks[i].reg);
}
}
@@ -971,8 +993,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) {
mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
if (IS_ERR(mc->smmu)) {
- dev_err(&pdev->dev, "failed to probe SMMU: %ld\n",
- PTR_ERR(mc->smmu));
+ dev_err(&pdev->dev, "failed to probe SMMU: %pe\n", mc->smmu);
mc->smmu = NULL;
}
}
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index 1d97cf4d3a94..649b54369263 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (C) 2014-2025 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#ifndef MEMORY_TEGRA_MC_H
@@ -13,15 +13,36 @@
#include <soc/tegra/mc.h>
#define MC_INTSTATUS 0x00
+/* Bit field of MC_INTSTATUS register */
+#define MC_INT_DECERR_EMEM BIT(6)
+#define MC_INT_INVALID_GART_PAGE BIT(7)
+#define MC_INT_SECURITY_VIOLATION BIT(8)
+#define MC_INT_ARBITRATION_EMEM BIT(9)
+#define MC_INT_INVALID_SMMU_PAGE BIT(10)
+#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
+#define MC_INT_DECERR_VPR BIT(12)
+#define MC_INT_SECERR_SEC BIT(13)
+#define MC_INT_DECERR_MTS BIT(16)
+#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17)
+#define MC_INT_DECERR_ROUTE_SANITY BIT(20)
+#define MC_INT_DECERR_ROUTE_SANITY_GIC_MSI BIT(21)
+
#define MC_INTMASK 0x04
-#define MC_ERR_STATUS 0x08
-#define MC_ERR_ADR 0x0c
#define MC_GART_ERROR_REQ 0x30
#define MC_EMEM_ADR_CFG 0x54
+#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
+
#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
#define MC_SECURITY_VIOLATION_STATUS 0x74
#define MC_EMEM_ARB_CFG 0x90
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) ((x) & 0x1ff)
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
+
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
+#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE BIT(30)
+#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE BIT(31)
+#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK 0x1ff
+
#define MC_EMEM_ARB_TIMING_RCD 0x98
#define MC_EMEM_ARB_TIMING_RP 0x9c
#define MC_EMEM_ARB_TIMING_RC 0xa0
@@ -41,60 +62,97 @@
#define MC_EMEM_ARB_MISC1 0xdc
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
#define MC_EMEM_ARB_OVERRIDE 0xe8
+#define MC_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
+
#define MC_TIMING_CONTROL_DBG 0xf8
#define MC_TIMING_CONTROL 0xfc
-#define MC_ERR_VPR_STATUS 0x654
-#define MC_ERR_VPR_ADR 0x658
-#define MC_ERR_SEC_STATUS 0x67c
-#define MC_ERR_SEC_ADR 0x680
-#define MC_ERR_MTS_STATUS 0x9b0
-#define MC_ERR_MTS_ADR 0x9b4
-#define MC_ERR_ROUTE_SANITY_STATUS 0x9c0
-#define MC_ERR_ROUTE_SANITY_ADR 0x9c4
-#define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00
-#define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04
-#define MC_EMEM_ADR_CFG_CHANNEL_ENABLE 0xdf8
-#define MC_GLOBAL_INTSTATUS 0xf24
-#define MC_ERR_ADR_HI 0x11fc
+#define MC_TIMING_UPDATE BIT(0)
-#define MC_INT_DECERR_ROUTE_SANITY BIT(20)
-#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17)
-#define MC_INT_DECERR_MTS BIT(16)
-#define MC_INT_SECERR_SEC BIT(13)
-#define MC_INT_DECERR_VPR BIT(12)
-#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
-#define MC_INT_INVALID_SMMU_PAGE BIT(10)
-#define MC_INT_ARBITRATION_EMEM BIT(9)
-#define MC_INT_SECURITY_VIOLATION BIT(8)
-#define MC_INT_INVALID_GART_PAGE BIT(7)
-#define MC_INT_DECERR_EMEM BIT(6)
+#define MC_GLOBAL_INTSTATUS 0xf24
-#define MC_ERR_STATUS_TYPE_SHIFT 28
-#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (0x6 << 28)
-#define MC_ERR_STATUS_TYPE_MASK (0x7 << 28)
-#define MC_ERR_STATUS_READABLE BIT(27)
-#define MC_ERR_STATUS_WRITABLE BIT(26)
-#define MC_ERR_STATUS_NONSECURE BIT(25)
-#define MC_ERR_STATUS_ADR_HI_SHIFT 20
-#define MC_ERR_STATUS_ADR_HI_MASK 0x3
-#define MC_ERR_STATUS_SECURITY BIT(17)
+/* Bit field of MC_ERR_STATUS_0 register */
#define MC_ERR_STATUS_RW BIT(16)
+#define MC_ERR_STATUS_SECURITY BIT(17)
+#define MC_ERR_STATUS_NONSECURE BIT(25)
+#define MC_ERR_STATUS_WRITABLE BIT(26)
+#define MC_ERR_STATUS_READABLE BIT(27)
-#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
-
-#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) ((x) & 0x1ff)
-#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
-
-#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK 0x1ff
-#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE BIT(30)
-#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE BIT(31)
+#define MC_ERR_STATUS_GSC_ADR_HI_MASK 0xffff
+#define MC_ERR_STATUS_GSC_ADR_HI_SHIFT 16
+#define MC_ERR_STATUS_RT_ADR_HI_SHIFT 15
-#define MC_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
+#define MC_ERR_STATUS_TYPE_SHIFT 28
+#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (0x6 << 28)
+#define MC_ERR_STATUS_RT_TYPE_MASK (0xf << 28)
+#define MC_ERR_STATUS_RT_TYPE_SHIFT 28
-#define MC_TIMING_UPDATE BIT(0)
+#define MC_ERR_STATUS_ADR_HI_SHIFT 20
#define MC_BROADCAST_CHANNEL ~0
+/* Tegra264 specific registers */
+
+/* Registers for MSS HUB */
+#define MSS_HUB_GLOBAL_INTSTATUS_0 0x6000
+#define MSS_HUBC_INTR BIT(0)
+#define MSS_HUB_GLOBAL_MASK 0x7F00
+#define MSS_HUB_GLOBAL_SHIFT 8
+
+#define MSS_HUB_HUBC_INTSTATUS_0 0x6008
+#define MSS_HUB_INTRSTATUS_0 0x600c
+#define MSS_HUB_HUBC_INTMASK_0 0x6010
+#define MSS_HUB_HUBC_SCRUB_DONE_INTMASK BIT(0)
+
+#define MSS_HUB_HUBC_INTPRIORITY_0 0x6014
+#define MSS_HUB_INTRMASK_0 0x6018
+#define MSS_HUB_COALESCER_ERR_INTMASK BIT(0)
+#define MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK BIT(1)
+#define MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK BIT(2)
+#define MSS_HUB_MSI_ERR_INTMASK BIT(3)
+#define MSS_HUB_POISON_RSP_INTMASK BIT(4)
+#define MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK BIT(5)
+#define MSS_HUB_RESERVED_PA_ERR_INTMASK BIT(6)
+
+#define MSS_HUB_INTRPRIORITY_0 0x601c
+#define MSS_HUB_SMMU_BYPASS_ALLOW_ERR_STATUS_0 0x6020
+#define MSS_HUB_MSI_ERR_STATUS_0 0x6024
+#define MSS_HUB_POISON_RSP_STATUS_0 0x6028
+#define MSS_HUB_COALESCE_ERR_STATUS_0 0x60e0
+#define MSS_HUB_COALESCE_ERR_ADR_HI_0 0x60e4
+#define MSS_HUB_COALESCE_ERR_ADR_0 0x60e8
+#define MSS_HUB_RESTRICTED_ACCESS_ERR_STATUS_0 0x638c
+#define MSS_HUB_RESERVED_PA_ERR_STATUS_0 0x6390
+#define MSS_HUB_ILLEGAL_TBUGRP_ID_ERR_STATUS_0 0x63b0
+
+/* Registers for channels */
+#define MC_CH_INTSTATUS_0 0x82d4
+#define MC_CH_INTMASK_0 0x82d8
+#define WCAM_ERR_INTMASK BIT(19)
+
+#define MC_ERR_GENERALIZED_CARVEOUT_STATUS_1_0 0xbc74
+
+/* Registers for MCF */
+#define MCF_COMMON_INTSTATUS0_0_0 0xce04
+#define MCF_INTSTATUS_0 0xce2c
+#define MCF_INTMASK_0 0xce30
+#define MCF_INTPRIORITY_0 0xce34
+
+/* Registers for SBS */
+#define MSS_SBS_INTSTATUS_0 0xec08
+#define MSS_SBS_INTMASK_0 0xec0c
+#define MSS_SBS_FILL_FIFO_ISO_OVERFLOW_INTMASK BIT(0)
+#define MSS_SBS_FILL_FIFO_SISO_OVERFLOW_INTMASK BIT(1)
+#define MSS_SBS_FILL_FIFO_NISO_OVERFLOW_INTMASK BIT(2)
+
+/* Bit field of MC_ERR_ROUTE_SANITY_STATUS_0 register */
+#define MC_ERR_ROUTE_SANITY_RW BIT(12)
+#define MC_ERR_ROUTE_SANITY_SEC BIT(13)
+
+#define ERR_GENERALIZED_APERTURE_ID_SHIFT 0
+#define ERR_GENERALIZED_APERTURE_ID_MASK 0x1F
+#define ERR_GENERALIZED_CARVEOUT_APERTURE_ID_SHIFT 5
+#define ERR_GENERALIZED_CARVEOUT_APERTURE_ID_MASK 0x1F
+
static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents)
{
val = val * percents;
@@ -203,8 +261,9 @@ extern const struct tegra_mc_ops tegra186_mc_ops;
#endif
irqreturn_t tegra30_mc_handle_irq(int irq, void *data);
+extern const irq_handler_t tegra30_mc_irq_handlers[1];
extern const char * const tegra_mc_status_names[32];
-extern const char * const tegra_mc_error_names[8];
+extern const char * const tegra20_mc_error_names[8];
/*
* These IDs are for internal use of Tegra ICC drivers. The ID numbers are
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 41350570c815..02dd4e26288a 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/of.h>
@@ -1101,6 +1101,14 @@ static const struct tegra_mc_reset tegra114_mc_resets[] = {
TEGRA114_MC_RESET(VI, 0x200, 0x204, 17),
};
+static const struct tegra_mc_intmask tegra114_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra114_mc_soc = {
.clients = tegra114_mc_clients,
.num_clients = ARRAY_SIZE(tegra114_mc_clients),
@@ -1108,10 +1116,14 @@ const struct tegra_mc_soc tegra114_mc_soc = {
.atom_size = 32,
.client_id_mask = 0x7f,
.smmu = &tegra114_smmu_soc,
- .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
- MC_INT_DECERR_EMEM,
+ .intmasks = tegra114_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra114_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra114_mc_resets,
.num_resets = ARRAY_SIZE(tegra114_mc_resets),
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c
index ff26815e51f1..5cfbc169c5f9 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -608,7 +608,7 @@ static int tegra124_emc_prepare_timing_change(struct tegra_emc *emc,
if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_NONE;
- else if (timing->emc_mode_1 & 0x1)
+ else if (!(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_ON;
else
dll_change = DLL_CHANGE_OFF;
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 991d4f7bc070..df87c5038625 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/of.h>
@@ -1258,6 +1258,15 @@ static const struct tegra_smmu_soc tegra124_smmu_soc = {
.num_asids = 128,
};
+static const struct tegra_mc_intmask tegra124_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra124_mc_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
@@ -1267,14 +1276,18 @@ const struct tegra_mc_soc tegra124_mc_soc = {
.smmu = &tegra124_smmu_soc,
.emem_regs = tegra124_mc_emem_regs,
.num_emem_regs = ARRAY_SIZE(tegra124_mc_emem_regs),
- .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra124_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra124_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra124_mc_resets,
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
.icc_ops = &tegra124_mc_icc_ops,
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
#endif /* CONFIG_ARCH_TEGRA_124_SOC */
@@ -1292,6 +1305,15 @@ static const struct tegra_smmu_soc tegra132_smmu_soc = {
.num_asids = 128,
};
+static const struct tegra_mc_intmask tegra132_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra132_mc_soc = {
.clients = tegra124_mc_clients,
.num_clients = ARRAY_SIZE(tegra124_mc_clients),
@@ -1299,13 +1321,17 @@ const struct tegra_mc_soc tegra132_mc_soc = {
.atom_size = 32,
.client_id_mask = 0x7f,
.smmu = &tegra132_smmu_soc,
- .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra132_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra132_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra124_mc_resets,
.num_resets = ARRAY_SIZE(tegra124_mc_resets),
.icc_ops = &tegra124_mc_icc_ops,
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
#endif /* CONFIG_ARCH_TEGRA_132_SOC */
diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c
index dfddceecdd1a..03ebab6fbe68 100644
--- a/drivers/memory/tegra/tegra186-emc.c
+++ b/drivers/memory/tegra/tegra186-emc.c
@@ -22,6 +22,7 @@ struct tegra186_emc {
struct tegra_bpmp *bpmp;
struct device *dev;
struct clk *clk;
+ struct clk *clk_dbb;
struct tegra186_emc_dvfs *dvfs;
unsigned int num_dvfs;
@@ -328,6 +329,13 @@ static int tegra186_emc_probe(struct platform_device *pdev)
goto put_bpmp;
}
+ emc->clk_dbb = devm_clk_get_optional_enabled(&pdev->dev, "dbb");
+ if (IS_ERR(emc->clk_dbb)) {
+ err = dev_err_probe(&pdev->dev, PTR_ERR(emc->clk_dbb),
+ "failed to get DBB clock\n");
+ goto put_bpmp;
+ }
+
platform_set_drvdata(pdev, emc);
emc->dev = &pdev->dev;
diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c
index aee11457bf8e..91d56165605f 100644
--- a/drivers/memory/tegra/tegra186.c
+++ b/drivers/memory/tegra/tegra186.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2017-2025 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2017-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/io.h>
@@ -174,7 +174,6 @@ const struct tegra_mc_ops tegra186_mc_ops = {
.remove = tegra186_mc_remove,
.resume = tegra186_mc_resume,
.probe_device = tegra186_mc_probe_device,
- .handle_irq = tegra30_mc_handle_irq,
};
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
@@ -902,17 +901,30 @@ static const struct tegra_mc_client tegra186_mc_clients[] = {
},
};
+static const struct tegra_mc_intmask tegra186_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
+ MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra186_mc_soc = {
.num_clients = ARRAY_SIZE(tegra186_mc_clients),
.clients = tegra186_mc_clients,
.num_address_bits = 40,
.num_channels = 4,
.client_id_mask = 0xff,
- .intmask = MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra186_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra186_mc_intmasks),
.ops = &tegra186_mc_ops,
.ch_intmask = 0x0000000f,
.global_intstatus_channel_shift = 0,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
#endif
diff --git a/drivers/memory/tegra/tegra194.c b/drivers/memory/tegra/tegra194.c
index 26035ac3a1eb..a8cc57690696 100644
--- a/drivers/memory/tegra/tegra194.c
+++ b/drivers/memory/tegra/tegra194.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2017-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <soc/tegra/mc.h>
@@ -1343,19 +1343,31 @@ static const struct tegra_mc_client tegra194_mc_clients[] = {
},
};
+static const struct tegra_mc_intmask tegra194_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_ROUTE_SANITY | MC_INT_DECERR_GENERALIZED_CARVEOUT |
+ MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra194_mc_soc = {
.num_clients = ARRAY_SIZE(tegra194_mc_clients),
.clients = tegra194_mc_clients,
.num_address_bits = 40,
.num_channels = 16,
.client_id_mask = 0xff,
- .intmask = MC_INT_DECERR_ROUTE_SANITY |
- MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra194_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra194_mc_intmasks),
.has_addr_hi_reg = true,
.ops = &tegra186_mc_ops,
.icc_ops = &tegra_mc_icc_ops,
.ch_intmask = 0x00000f00,
.global_intstatus_channel_shift = 8,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c
index 4748113bfe9d..27dd6886f86e 100644
--- a/drivers/memory/tegra/tegra20.c
+++ b/drivers/memory/tegra/tegra20.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2012-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/bitfield.h>
@@ -695,7 +695,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
unsigned int bit;
/* mask all interrupts to avoid flooding */
- status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask;
+ status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmasks[0].mask;
if (!status)
return IRQ_NONE;
@@ -713,7 +713,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
value = mc_readl(mc, reg);
id = value & mc->soc->client_id_mask;
- desc = tegra_mc_error_names[2];
+ desc = tegra20_mc_error_names[2];
if (value & BIT(31))
direction = "write";
@@ -724,7 +724,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
value = mc_readl(mc, reg);
id = (value >> 1) & mc->soc->client_id_mask;
- desc = tegra_mc_error_names[2];
+ desc = tegra20_mc_error_names[2];
if (value & BIT(0))
direction = "write";
@@ -736,7 +736,7 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
id = value & mc->soc->client_id_mask;
type = (value & BIT(30)) ? 4 : 3;
- desc = tegra_mc_error_names[type];
+ desc = tegra20_mc_error_names[type];
secure = "secure ";
if (value & BIT(31))
@@ -761,9 +761,20 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static const irq_handler_t tegra20_mc_irq_handlers[] = {
+ tegra20_mc_handle_irq
+};
+
static const struct tegra_mc_ops tegra20_mc_ops = {
.probe = tegra20_mc_probe,
- .handle_irq = tegra20_mc_handle_irq,
+};
+
+static const struct tegra_mc_intmask tegra20_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
+ MC_INT_DECERR_EMEM,
+ },
};
const struct tegra_mc_soc tegra20_mc_soc = {
@@ -771,11 +782,15 @@ const struct tegra_mc_soc tegra20_mc_soc = {
.num_clients = ARRAY_SIZE(tegra20_mc_clients),
.num_address_bits = 32,
.client_id_mask = 0x3f,
- .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
- MC_INT_DECERR_EMEM,
+ .intmasks = tegra20_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra20_mc_intmasks),
.reset_ops = &tegra20_mc_reset_ops,
.resets = tegra20_mc_resets,
.num_resets = ARRAY_SIZE(tegra20_mc_resets),
.icc_ops = &tegra20_mc_icc_ops,
.ops = &tegra20_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra20_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra20_mc_irq_handlers),
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index 3c2949c16fde..f58f3ef6f681 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2015 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2015-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <dt-bindings/memory/tegra210-mc.h>
@@ -1273,6 +1273,15 @@ static const struct tegra_mc_reset tegra210_mc_resets[] = {
TEGRA210_MC_RESET(TSECB, 0x970, 0x974, 13),
};
+static const struct tegra_mc_intmask tegra210_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra210_mc_soc = {
.clients = tegra210_mc_clients,
.num_clients = ARRAY_SIZE(tegra210_mc_clients),
@@ -1280,11 +1289,15 @@ const struct tegra_mc_soc tegra210_mc_soc = {
.atom_size = 64,
.client_id_mask = 0xff,
.smmu = &tegra210_smmu_soc,
- .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra210_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra210_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra210_mc_resets,
.num_resets = ARRAY_SIZE(tegra210_mc_resets),
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c
index 5f57cea48b62..87b22038a5fb 100644
--- a/drivers/memory/tegra/tegra234.c
+++ b/drivers/memory/tegra/tegra234.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2022-2023, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2022-2026, NVIDIA CORPORATION. All rights reserved.
*/
#include <soc/tegra/mc.h>
@@ -1132,16 +1132,23 @@ static const struct tegra_mc_icc_ops tegra234_mc_icc_ops = {
.set = tegra234_mc_icc_set,
};
+static const struct tegra_mc_intmask tegra234_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_DECERR_ROUTE_SANITY | MC_INT_DECERR_GENERALIZED_CARVEOUT |
+ MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra234_mc_soc = {
.num_clients = ARRAY_SIZE(tegra234_mc_clients),
.clients = tegra234_mc_clients,
.num_address_bits = 40,
.num_channels = 16,
.client_id_mask = 0x1ff,
- .intmask = MC_INT_DECERR_ROUTE_SANITY |
- MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra234_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra234_mc_intmasks),
.has_addr_hi_reg = true,
.ops = &tegra186_mc_ops,
.icc_ops = &tegra234_mc_icc_ops,
@@ -1152,4 +1159,9 @@ const struct tegra_mc_soc tegra234_mc_soc = {
* supported.
*/
.num_carveouts = 32,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_addr_hi_mask = 0x3,
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/memory/tegra/tegra264.c b/drivers/memory/tegra/tegra264.c
index 5203e6c11372..e43ef14da1ee 100644
--- a/drivers/memory/tegra/tegra264.c
+++ b/drivers/memory/tegra/tegra264.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2025, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2025-2026, NVIDIA CORPORATION. All rights reserved.
*/
#include <dt-bindings/memory/nvidia,tegra264.h>
@@ -188,6 +188,41 @@ static const struct tegra_mc_client tegra264_mc_clients[] = {
},
};
+static const char *const tegra264_hub_error_names[32] = {
+ [0] = "coalescer error",
+ [1] = "SMMU BYPASS ALLOW error",
+ [2] = "Illegal tbugrp_id error",
+ [3] = "Malformed MSI request error",
+ [4] = "Read response with poison bit error",
+ [5] = "Restricted access violation error",
+ [6] = "Reserved PA error",
+};
+
+static const char *const tegra264_mc_error_names[4] = {
+ [1] = "EMEM decode error",
+ [2] = "TrustZone violation",
+ [3] = "Carveout violation",
+};
+
+static const char *const tegra264_rt_error_names[16] = {
+ [1] = "DECERR_PARTIAL_POPULATED",
+ [2] = "DECERR_SMMU_BYPASS",
+ [3] = "DECERR_INVALID_MMIO",
+ [4] = "DECERR_INVALID_GIC_MSI",
+ [5] = "DECERR_ATOMIC_SYSRAM",
+ [9] = "DECERR_REMOTE_REQ_PRE_BOOT",
+ [10] = "DECERR_ISO_OVER_C2C",
+ [11] = "DECERR_UNSUPPORTED_SBS_OPCODE",
+ [12] = "DECERR_SBS_REQ_OVER_SISO_LL",
+};
+
+/*
+ * MC instance aperture mapping for hubc registers
+ */
+static const int mc_hubc_aperture_number[5] = {
+ 7, 8, 9, 10, 11
+};
+
/*
* tegra264_mc_icc_set() - Pass MC client info to the BPMP-FW
* @src: ICC node for Memory Controller's (MC) Client
@@ -283,6 +318,312 @@ static int tegra264_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pea
return 0;
}
+static void mcf_log_fault(struct tegra_mc *mc, u32 channel, unsigned long mcf_ch_intstatus)
+{
+ unsigned int bit;
+
+ for_each_set_bit(bit, &mcf_ch_intstatus, 32) {
+ const char *client = "unknown", *desc = "NA";
+ u32 status_reg, status1_reg = 0, addr_reg, addr_hi_reg = 0, err_type_mask = 0;
+ u32 value, client_id, i, addr_hi_shift = 0, addr_hi_mask = 0, status1;
+ u32 mc_rw_bit = MC_ERR_STATUS_RW, mc_sec_bit = MC_ERR_STATUS_SECURITY;
+ phys_addr_t addr = 0;
+ u8 type;
+
+ switch (BIT(bit)) {
+ case MC_INT_DECERR_EMEM:
+ case MC_INT_SECURITY_VIOLATION:
+ status_reg = mc->soc->regs->err_status;
+ addr_reg = mc->soc->regs->err_add;
+ addr_hi_reg = mc->soc->regs->err_add_hi;
+ err_type_mask = mc->soc->mc_err_status_type_mask;
+ break;
+
+ case MC_INT_DECERR_VPR:
+ status_reg = mc->soc->regs->err_vpr_status;
+ addr_reg = mc->soc->regs->err_vpr_add;
+ addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ break;
+
+ case MC_INT_SECERR_SEC:
+ status_reg = mc->soc->regs->err_sec_status;
+ addr_reg = mc->soc->regs->err_sec_add;
+ addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ break;
+
+ case MC_INT_DECERR_MTS:
+ status_reg = mc->soc->regs->err_mts_status;
+ addr_reg = mc->soc->regs->err_mts_add;
+ addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ break;
+
+ case MC_INT_DECERR_GENERALIZED_CARVEOUT:
+ status_reg = mc->soc->regs->err_gen_co_status;
+ status1_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS_1_0;
+ addr_reg = mc->soc->regs->err_gen_co_add;
+ addr_hi_shift = MC_ERR_STATUS_GSC_ADR_HI_SHIFT;
+ addr_hi_mask = MC_ERR_STATUS_GSC_ADR_HI_MASK;
+ break;
+
+ case MC_INT_DECERR_ROUTE_SANITY:
+ case MC_INT_DECERR_ROUTE_SANITY_GIC_MSI:
+ status_reg = mc->soc->regs->err_route_status;
+ addr_reg = mc->soc->regs->err_route_add;
+ addr_hi_shift = MC_ERR_STATUS_RT_ADR_HI_SHIFT;
+ addr_hi_mask = mc->soc->mc_addr_hi_mask;
+ mc_sec_bit = MC_ERR_ROUTE_SANITY_SEC;
+ mc_rw_bit = MC_ERR_ROUTE_SANITY_RW;
+ err_type_mask = MC_ERR_STATUS_RT_TYPE_MASK;
+ break;
+
+ default:
+ dev_err_ratelimited(mc->dev, "Incorrect MC interrupt mask\n");
+ return;
+ }
+
+ value = mc_ch_readl(mc, channel, status_reg);
+ if (addr_hi_reg) {
+ addr = mc_ch_readl(mc, channel, addr_hi_reg);
+ } else {
+ if (!status1_reg) {
+ addr = ((value >> addr_hi_shift) & addr_hi_mask);
+ } else {
+ status1 = mc_ch_readl(mc, channel, status1_reg);
+ addr = ((status1 >> addr_hi_shift) & addr_hi_mask);
+ }
+ }
+
+ addr <<= 32;
+ addr |= mc_ch_readl(mc, channel, addr_reg);
+
+ client_id = value & mc->soc->client_id_mask;
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ if (mc->soc->clients[i].id == client_id) {
+ client = mc->soc->clients[i].name;
+ break;
+ }
+ }
+
+ if (err_type_mask == MC_ERR_STATUS_RT_TYPE_MASK) {
+ type = (value & err_type_mask) >>
+ MC_ERR_STATUS_RT_TYPE_SHIFT;
+ desc = tegra264_rt_error_names[type];
+ } else if (err_type_mask) {
+ type = (value & err_type_mask) >>
+ MC_ERR_STATUS_TYPE_SHIFT;
+ desc = tegra264_mc_error_names[type];
+ }
+
+ dev_err_ratelimited(mc->dev, "%s: %s %s @%pa: %s (%s)\n",
+ client, value & mc_sec_bit ? "secure" : "non-secure",
+ value & mc_rw_bit ? "write" : "read", &addr,
+ tegra_mc_status_names[bit] ?: "unknown", desc);
+ if (status1_reg)
+ dev_err_ratelimited(mc->dev, "gsc_apr_id=%u gsc_co_apr_id=%u\n",
+ ((status1 >> ERR_GENERALIZED_APERTURE_ID_SHIFT)
+ & ERR_GENERALIZED_APERTURE_ID_MASK),
+ ((status1 >> ERR_GENERALIZED_CARVEOUT_APERTURE_ID_SHIFT)
+ & ERR_GENERALIZED_CARVEOUT_APERTURE_ID_MASK));
+ }
+
+ /* clear interrupts */
+ mc_ch_writel(mc, channel, mcf_ch_intstatus, MCF_INTSTATUS_0);
+}
+
+static irqreturn_t handle_mcf_irq(int irq, void *data)
+{
+ struct tegra_mc *mc = data;
+ unsigned long common_intstat, intstatus;
+ u32 slice;
+
+ /* Read MCF_COMMON_INTSTATUS0_0_0 from MCB block */
+ common_intstat = mc_ch_readl(mc, MC_BROADCAST_CHANNEL, MCF_COMMON_INTSTATUS0_0_0);
+ if (common_intstat == 0) {
+ dev_warn(mc->dev, "No interrupt in MCF\n");
+ return IRQ_NONE;
+ }
+
+ for_each_set_bit(slice, &common_intstat, 32) {
+ /* Find out the slice number on which interrupt occurred */
+ if (slice > 4) {
+ dev_err(mc->dev, "Slice index out of bounds: %u\n", slice);
+ return IRQ_NONE;
+ }
+
+ intstatus = mc_ch_readl(mc, slice, MCF_INTSTATUS_0);
+ if (intstatus != 0)
+ mcf_log_fault(mc, slice, intstatus);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hub_log_fault(struct tegra_mc *mc, u32 hub, unsigned long hub_intstat)
+{
+ unsigned int bit;
+
+ for_each_set_bit(bit, &hub_intstat, 32) {
+ const char *client = "unknown";
+ u32 client_id, status_reg, value, i;
+ phys_addr_t addr = 0;
+
+ switch (BIT(bit)) {
+ case MSS_HUB_COALESCER_ERR_INTMASK:
+ status_reg = MSS_HUB_COALESCE_ERR_STATUS_0;
+ addr = mc_ch_readl(mc, hub, MSS_HUB_COALESCE_ERR_ADR_HI_0);
+ addr <<= 32;
+ addr |= mc_ch_readl(mc, hub, MSS_HUB_COALESCE_ERR_ADR_0);
+ break;
+
+ case MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK:
+ status_reg = MSS_HUB_SMMU_BYPASS_ALLOW_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK:
+ status_reg = MSS_HUB_ILLEGAL_TBUGRP_ID_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_MSI_ERR_INTMASK:
+ status_reg = MSS_HUB_MSI_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_POISON_RSP_INTMASK:
+ status_reg = MSS_HUB_POISON_RSP_STATUS_0;
+ break;
+
+ case MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK:
+ status_reg = MSS_HUB_RESTRICTED_ACCESS_ERR_STATUS_0;
+ break;
+
+ case MSS_HUB_RESERVED_PA_ERR_INTMASK:
+ status_reg = MSS_HUB_RESERVED_PA_ERR_STATUS_0;
+ break;
+
+ default:
+ dev_err_ratelimited(mc->dev, "Incorrect HUB interrupt mask\n");
+ return;
+ }
+
+ value = mc_ch_readl(mc, hub, status_reg);
+
+ client_id = value & mc->soc->client_id_mask;
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ if (mc->soc->clients[i].id == client_id) {
+ client = mc->soc->clients[i].name;
+ break;
+ }
+ }
+
+ dev_err_ratelimited(mc->dev, "%s: @%pa: %s status: 0x%x\n",
+ client, &addr, tegra264_hub_error_names[bit] ?: "unknown",
+ value);
+ }
+
+ /* clear interrupts */
+ mc_ch_writel(mc, hub, hub_intstat, MSS_HUB_INTRSTATUS_0);
+}
+
+static irqreturn_t handle_hub_irq(int irq, void *data, int mc_hubc_aperture_number)
+{
+ struct tegra_mc *mc = data;
+ u32 global_intstat;
+ unsigned long hub_interrupt, intstat, hub;
+
+ /* Read MSS_HUB_GLOBAL_INTSTATUS_0 from mc_hubc_aperture_number block */
+ global_intstat = mc_ch_readl(mc, mc_hubc_aperture_number, MSS_HUB_GLOBAL_INTSTATUS_0);
+ if (global_intstat == 0) {
+ dev_warn(mc->dev, "No interrupt in HUB/HUBC\n");
+ return IRQ_NONE;
+ }
+
+ /* Handle interrupt from hubc */
+ if (global_intstat & MSS_HUBC_INTR) {
+ /* Read MSS_HUB_HUBC_INTSTATUS_0 from block mc_hubc_aperture_number */
+ intstat = mc_ch_readl(mc, mc_hubc_aperture_number, MSS_HUB_HUBC_INTSTATUS_0);
+ if (intstat != 0) {
+ dev_err_ratelimited(mc->dev, "Scrubber operation status: 0x%lx\n",
+ intstat);
+ /* Clear hubc interrupt */
+ mc_ch_writel(mc, mc_hubc_aperture_number, intstat,
+ MSS_HUB_HUBC_INTSTATUS_0);
+ }
+ }
+
+ hub_interrupt = (global_intstat & MSS_HUB_GLOBAL_MASK) >> MSS_HUB_GLOBAL_SHIFT;
+ /* Handle interrupt from hub */
+ for_each_set_bit(hub, &hub_interrupt, 32) {
+ /* Read MSS_HUB_INTRSTATUS_0 from block MCi */
+ intstat = mc_ch_readl(mc, hub, MSS_HUB_INTRSTATUS_0);
+ if (intstat != 0)
+ hub_log_fault(mc, hub, intstat);
+ }
+
+ /* Clear global interrupt status register */
+ mc_ch_writel(mc, mc_hubc_aperture_number, global_intstat, MSS_HUB_GLOBAL_INTSTATUS_0);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_disp_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[0]);
+}
+
+static irqreturn_t handle_system_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[1]);
+}
+
+static irqreturn_t handle_vision_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[2]);
+}
+
+static irqreturn_t handle_uphy_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[3]);
+}
+
+static irqreturn_t handle_top_hub_irq(int irq, void *data)
+{
+ return handle_hub_irq(irq, data, mc_hubc_aperture_number[4]);
+}
+
+static irqreturn_t handle_generic_irq(struct tegra_mc *mc, unsigned long intstat_reg)
+{
+ u32 intstat, i;
+
+ /* Iterate over all MC blocks to read INTSTATUS */
+ for (i = 0; i < mc->num_channels; i++) {
+ intstat = mc_ch_readl(mc, i, intstat_reg);
+ if (intstat) {
+ dev_err_ratelimited(mc->dev, "channel: %i status: 0x%x\n", i, intstat);
+ /* Clear interrupt */
+ mc_ch_writel(mc, i, intstat, intstat_reg);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_sbs_irq(int irq, void *data)
+{
+ return handle_generic_irq((struct tegra_mc *)data, MSS_SBS_INTSTATUS_0);
+}
+
+static irqreturn_t handle_channel_irq(int irq, void *data)
+{
+ return handle_generic_irq((struct tegra_mc *)data, MC_CH_INTSTATUS_0);
+}
+
+static const irq_handler_t tegra264_mc_irq_handlers[8] = {
+ handle_mcf_irq, handle_disp_hub_irq, handle_vision_hub_irq,
+ handle_system_hub_irq, handle_uphy_hub_irq, handle_top_hub_irq,
+ handle_sbs_irq, handle_channel_irq
+};
+
static const struct tegra_mc_icc_ops tegra264_mc_icc_ops = {
.xlate = tegra_mc_icc_xlate,
.aggregate = tegra264_mc_icc_aggregate,
@@ -290,16 +631,80 @@ static const struct tegra_mc_icc_ops tegra264_mc_icc_ops = {
.set = tegra264_mc_icc_set,
};
+static const struct tegra_mc_regs tegra264_mc_regs = {
+ .cfg_channel_enable = 0x8870,
+ .err_status = 0xbc00,
+ .err_add = 0xbc04,
+ .err_add_hi = 0xbc08,
+ .err_vpr_status = 0xbc20,
+ .err_vpr_add = 0xbc24,
+ .err_sec_status = 0xbc3c,
+ .err_sec_add = 0xbc40,
+ .err_mts_status = 0xbc5c,
+ .err_mts_add = 0xbc60,
+ .err_gen_co_status = 0xbc78,
+ .err_gen_co_add = 0xbc7c,
+ .err_route_status = 0xbc64,
+ .err_route_add = 0xbc68,
+};
+
+static const struct tegra_mc_intmask tegra264_mc_intmasks[] = {
+ {
+ .reg = MCF_INTMASK_0,
+ .mask = MC_INT_DECERR_ROUTE_SANITY_GIC_MSI | MC_INT_DECERR_ROUTE_SANITY |
+ MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
+ MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+ {
+ .reg = MCF_INTPRIORITY_0,
+ .mask = MC_INT_DECERR_ROUTE_SANITY_GIC_MSI | MC_INT_DECERR_ROUTE_SANITY |
+ MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
+ MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+ {
+ .reg = MSS_HUB_INTRMASK_0,
+ .mask = MSS_HUB_COALESCER_ERR_INTMASK | MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK |
+ MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK | MSS_HUB_MSI_ERR_INTMASK |
+ MSS_HUB_POISON_RSP_INTMASK | MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK |
+ MSS_HUB_RESERVED_PA_ERR_INTMASK,
+ },
+ {
+ .reg = MSS_HUB_INTRPRIORITY_0,
+ .mask = MSS_HUB_COALESCER_ERR_INTMASK | MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK |
+ MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK | MSS_HUB_MSI_ERR_INTMASK |
+ MSS_HUB_POISON_RSP_INTMASK | MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK |
+ MSS_HUB_RESERVED_PA_ERR_INTMASK,
+ },
+ {
+ .reg = MSS_HUB_HUBC_INTMASK_0,
+ .mask = MSS_HUB_HUBC_SCRUB_DONE_INTMASK,
+ },
+ {
+ .reg = MSS_HUB_HUBC_INTPRIORITY_0,
+ .mask = MSS_HUB_HUBC_SCRUB_DONE_INTMASK,
+ },
+ {
+ .reg = MSS_SBS_INTMASK_0,
+ .mask = MSS_SBS_FILL_FIFO_ISO_OVERFLOW_INTMASK |
+ MSS_SBS_FILL_FIFO_SISO_OVERFLOW_INTMASK |
+ MSS_SBS_FILL_FIFO_NISO_OVERFLOW_INTMASK,
+ },
+ {
+ .reg = MC_CH_INTMASK_0,
+ .mask = WCAM_ERR_INTMASK,
+ }
+};
+
const struct tegra_mc_soc tegra264_mc_soc = {
.num_clients = ARRAY_SIZE(tegra264_mc_clients),
.clients = tegra264_mc_clients,
.num_address_bits = 40,
.num_channels = 16,
.client_id_mask = 0x1ff,
- .intmask = MC_INT_DECERR_ROUTE_SANITY |
- MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS |
- MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
- MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
+ .intmasks = tegra264_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra264_mc_intmasks),
.has_addr_hi_reg = true,
.ops = &tegra186_mc_ops,
.icc_ops = &tegra264_mc_icc_ops,
@@ -310,4 +715,9 @@ const struct tegra_mc_soc tegra264_mc_soc = {
* supported.
*/
.num_carveouts = 32,
+ .mc_addr_hi_mask = 0xff,
+ .mc_err_status_type_mask = (0x3 << 28),
+ .regs = &tegra264_mc_regs,
+ .handle_irq = tegra264_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra264_mc_irq_handlers),
};
diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c
index 606106dd2b32..5812c8cd6ce4 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG);
emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1))
+ if (emc->dll_on == !(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_NONE;
- else if (timing->emc_mode_1 & 0x1)
+ else if (!(timing->emc_mode_1 & 0x1))
dll_change = DLL_CHANGE_ON;
else
dll_change = DLL_CHANGE_OFF;
- emc->dll_on = !!(timing->emc_mode_1 & 0x1);
+ emc->dll_on = !(timing->emc_mode_1 & 0x1);
if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL))
emc->zcal_long = true;
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index a6bcde4b92c0..8389e3af0121 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/device.h>
@@ -1384,6 +1384,14 @@ static const struct tegra_mc_icc_ops tegra30_mc_icc_ops = {
.set = tegra30_mc_icc_set,
};
+static const struct tegra_mc_intmask tegra30_mc_intmasks[] = {
+ {
+ .reg = MC_INTMASK,
+ .mask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM,
+ },
+};
+
const struct tegra_mc_soc tegra30_mc_soc = {
.clients = tegra30_mc_clients,
.num_clients = ARRAY_SIZE(tegra30_mc_clients),
@@ -1393,11 +1401,15 @@ const struct tegra_mc_soc tegra30_mc_soc = {
.smmu = &tegra30_smmu_soc,
.emem_regs = tegra30_mc_emem_regs,
.num_emem_regs = ARRAY_SIZE(tegra30_mc_emem_regs),
- .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
- MC_INT_DECERR_EMEM,
+ .intmasks = tegra30_mc_intmasks,
+ .num_intmasks = ARRAY_SIZE(tegra30_mc_intmasks),
.reset_ops = &tegra_mc_reset_ops_common,
.resets = tegra30_mc_resets,
.num_resets = ARRAY_SIZE(tegra30_mc_resets),
.icc_ops = &tegra30_mc_icc_ops,
.ops = &tegra30_mc_ops,
+ .regs = &tegra20_mc_regs,
+ .handle_irq = tegra30_mc_irq_handlers,
+ .num_interrupts = ARRAY_SIZE(tegra30_mc_irq_handlers),
+ .mc_err_status_type_mask = (0x7 << 28),
};
diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c
index 537ea65685bf..0e23b9d9f7ee 100644
--- a/drivers/mfd/sec-acpm.c
+++ b/drivers/mfd/sec-acpm.c
@@ -367,7 +367,7 @@ static const struct regmap_config s2mpg11_regmap_config_meter = {
};
struct sec_pmic_acpm_shared_bus_context {
- const struct acpm_handle *acpm;
+ struct acpm_handle *acpm;
unsigned int acpm_chan_id;
u8 speedy_channel;
};
@@ -390,7 +390,7 @@ static int sec_pmic_acpm_bus_write(void *context, const void *data,
size_t count)
{
struct sec_pmic_acpm_bus_context *ctx = context;
- const struct acpm_handle *acpm = ctx->shared->acpm;
+ struct acpm_handle *acpm = ctx->shared->acpm;
const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops;
size_t val_count = count - BITS_TO_BYTES(ACPM_ADDR_BITS);
const u8 *d = data;
@@ -410,7 +410,7 @@ static int sec_pmic_acpm_bus_read(void *context, const void *reg_buf, size_t reg
void *val_buf, size_t val_size)
{
struct sec_pmic_acpm_bus_context *ctx = context;
- const struct acpm_handle *acpm = ctx->shared->acpm;
+ struct acpm_handle *acpm = ctx->shared->acpm;
const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops;
const u8 *r = reg_buf;
u8 reg;
@@ -429,7 +429,7 @@ static int sec_pmic_acpm_bus_reg_update_bits(void *context, unsigned int reg, un
unsigned int val)
{
struct sec_pmic_acpm_bus_context *ctx = context;
- const struct acpm_handle *acpm = ctx->shared->acpm;
+ struct acpm_handle *acpm = ctx->shared->acpm;
const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops;
return pmic_ops->update_reg(acpm, ctx->shared->acpm_chan_id, ctx->type, reg & 0xff,
@@ -480,7 +480,7 @@ static int sec_pmic_acpm_probe(struct platform_device *pdev)
struct regmap *regmap_common, *regmap_pmic, *regmap;
const struct sec_pmic_acpm_platform_data *pdata;
struct sec_pmic_acpm_shared_bus_context *shared_ctx;
- const struct acpm_handle *acpm;
+ struct acpm_handle *acpm;
struct device *dev = &pdev->dev;
int ret, irq;
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
index 0b1dff01e04c..cce477e86ef9 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
@@ -4,6 +4,7 @@
* Author: Clément Le Goffic <clement.legoffic@foss.st.com> for STMicroelectronics.
*/
#include <linux/bits.h>
+#include <linux/bus/stm32_firewall_device.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/generic.h>
@@ -46,9 +47,11 @@ struct stm32_hdp {
void __iomem *base;
struct clk *clk;
struct pinctrl_dev *pctl_dev;
+ struct stm32_firewall *firewall;
struct gpio_generic_chip gpio_chip;
u32 mux_conf;
u32 gposet_conf;
+ int nb_firewall_entries;
const char * const *func_name;
};
@@ -615,6 +618,13 @@ static int stm32_hdp_probe(struct platform_device *pdev)
return -ENOMEM;
hdp->dev = dev;
+ if (IS_ENABLED(CONFIG_STM32_FIREWALL)) {
+ err = stm32_firewall_get_grant_all_access(dev, &hdp->firewall,
+ &hdp->nb_firewall_entries);
+ if (err)
+ return err;
+ }
+
platform_set_drvdata(pdev, hdp);
hdp->base = devm_platform_ioremap_resource(pdev, 0);
@@ -670,8 +680,12 @@ static int stm32_hdp_probe(struct platform_device *pdev)
static void stm32_hdp_remove(struct platform_device *pdev)
{
struct stm32_hdp *hdp = platform_get_drvdata(pdev);
+ int i;
writel_relaxed(HDP_CTRL_DISABLE, hdp->base + HDP_CTRL);
+
+ for (i = 0; i < hdp->nb_firewall_entries; i++)
+ stm32_firewall_release_access(&hdp->firewall[i]);
}
static int stm32_hdp_suspend(struct device *dev)
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 7ce151f6a7e4..2fda1d9622f4 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -257,6 +257,8 @@ config RESET_RZG2L_USBPHY_CTRL
config RESET_RZV2H_USB2PHY
tristate "Renesas RZ/V2H(P) (and similar SoCs) USB2PHY Reset driver"
depends on ARCH_RENESAS || COMPILE_TEST
+ select AUXILIARY_BUS
+ select REGMAP_MMIO
help
Support for USB2PHY Port reset Control found on the RZ/V2H(P) SoC
(and similar SoCs).
@@ -291,6 +293,13 @@ config RESET_SIMPLE
- SiFive FU740 SoCs
- Sophgo SoCs
+config RESET_SKY1
+ bool "Cix Sky1 reset controller"
+ depends on ARCH_CIX || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This enables the reset controller for Cix Sky1.
+
config RESET_SOCFPGA
bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
default ARM && ARCH_INTEL_SOCFPGA
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index fc0cc99f8514..d1b8c66e5086 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
obj-$(CONFIG_RESET_RZV2H_USB2PHY) += reset-rzv2h-usb2phy.o
obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
+obj-$(CONFIG_RESET_SKY1) += reset-sky1.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 352c2360603b..38e189d04d09 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/fwnode.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
@@ -20,9 +21,11 @@
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/reset.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
+#include <linux/srcu.h>
static DEFINE_MUTEX(reset_list_mutex);
static LIST_HEAD(reset_controller_list);
@@ -36,6 +39,7 @@ static DEFINE_IDA(reset_gpio_ida);
* struct reset_control - a reset control
* @rcdev: a pointer to the reset controller device
* this reset control belongs to
+ * @srcu: protects the rcdev pointer from removal during consumer access
* @list: list entry for the rcdev's reset controller list
* @id: ID of the reset controller in the reset
* controller device
@@ -47,9 +51,11 @@ static DEFINE_IDA(reset_gpio_ida);
* @triggered_count: Number of times this reset line has been reset. Currently
* only used for shared resets, which means that the value
* will be either 0 or 1.
+ * @lock: serializes the internals of reset_control_acquire()
*/
struct reset_control {
- struct reset_controller_dev *rcdev;
+ struct reset_controller_dev __rcu *rcdev;
+ struct srcu_struct srcu;
struct list_head list;
unsigned int id;
struct kref refcnt;
@@ -58,6 +64,7 @@ struct reset_control {
bool array;
atomic_t deassert_count;
atomic_t triggered_count;
+ struct mutex lock;
};
/**
@@ -74,14 +81,16 @@ struct reset_control_array {
/**
* struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices
- * @of_args: phandle to the reset controller with all the args like GPIO number
+ * @ref_args: Reference to the reset controller with all the args like GPIO number
* @swnode: Software node containing the reference to the GPIO provider
* @list: list entry for the reset_gpio_lookup_list
+ * @adev: Auxiliary device representing the reset controller
*/
struct reset_gpio_lookup {
- struct of_phandle_args of_args;
+ struct fwnode_reference_args ref_args;
struct fwnode_handle *swnode;
struct list_head list;
+ struct auxiliary_device adev;
};
static const char *rcdev_name(struct reset_controller_dev *rcdev)
@@ -89,27 +98,24 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
if (rcdev->dev)
return dev_name(rcdev->dev);
- if (rcdev->of_node)
- return rcdev->of_node->full_name;
-
- if (rcdev->of_args)
- return rcdev->of_args->np->full_name;
+ if (rcdev->fwnode)
+ return fwnode_get_name(rcdev->fwnode);
return NULL;
}
/**
- * of_reset_simple_xlate - translate reset_spec to the reset line number
+ * fwnode_reset_simple_xlate - translate reset_spec to the reset line number
* @rcdev: a pointer to the reset controller device
- * @reset_spec: reset line specifier as found in the device tree
+ * @reset_spec: reset line specifier as found in firmware
*
- * This static translation function is used by default if of_xlate in
- * :c:type:`reset_controller_dev` is not set. It is useful for all reset
- * controllers with 1:1 mapping, where reset lines can be indexed by number
- * without gaps.
+ * This static translation function is used by default if neither fwnode_xlate
+ * not of_xlate in :c:type:`reset_controller_dev` is not set. It is useful for
+ * all reset controllers with 1:1 mapping, where reset lines can be indexed by
+ * number without gaps.
*/
-static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
- const struct of_phandle_args *reset_spec)
+static int fwnode_reset_simple_xlate(struct reset_controller_dev *rcdev,
+ const struct fwnode_reference_args *reset_spec)
{
if (reset_spec->args[0] >= rcdev->nr_resets)
return -EINVAL;
@@ -123,33 +129,71 @@ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
*/
int reset_controller_register(struct reset_controller_dev *rcdev)
{
- if (rcdev->of_node && rcdev->of_args)
+ if ((rcdev->of_node && rcdev->fwnode) || (rcdev->of_xlate && rcdev->fwnode_xlate))
return -EINVAL;
- if (!rcdev->of_xlate) {
- rcdev->of_reset_n_cells = 1;
- rcdev->of_xlate = of_reset_simple_xlate;
+ if (rcdev->of_node && !rcdev->fwnode)
+ rcdev->fwnode = of_fwnode_handle(rcdev->of_node);
+
+ if (!rcdev->fwnode) {
+ rcdev->fwnode = dev_fwnode(rcdev->dev);
+ if (!rcdev->fwnode)
+ return -EINVAL;
+ }
+
+ if (rcdev->of_xlate)
+ rcdev->fwnode_reset_n_cells = rcdev->of_reset_n_cells;
+
+ if (!rcdev->fwnode_xlate && !rcdev->of_xlate) {
+ rcdev->fwnode_xlate = fwnode_reset_simple_xlate;
+ rcdev->fwnode_reset_n_cells = 1;
}
INIT_LIST_HEAD(&rcdev->reset_control_head);
+ mutex_init(&rcdev->lock);
+
+ guard(mutex)(&reset_list_mutex);
- mutex_lock(&reset_list_mutex);
list_add(&rcdev->list, &reset_controller_list);
- mutex_unlock(&reset_list_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(reset_controller_register);
+static void reset_controller_remove(struct reset_controller_dev *rcdev,
+ struct reset_control *rstc)
+{
+ lockdep_assert_held(&rcdev->lock);
+
+ list_del(&rstc->list);
+ module_put(rcdev->owner);
+ put_device(rcdev->dev);
+}
+
/**
* reset_controller_unregister - unregister a reset controller device
* @rcdev: a pointer to the reset controller device
*/
void reset_controller_unregister(struct reset_controller_dev *rcdev)
{
- mutex_lock(&reset_list_mutex);
- list_del(&rcdev->list);
- mutex_unlock(&reset_list_mutex);
+ struct reset_control *rstc, *pos;
+
+ scoped_guard(mutex, &reset_list_mutex)
+ list_del(&rcdev->list);
+
+ scoped_guard(mutex, &rcdev->lock) {
+ /*
+ * Numb but don't free the remaining reset control handles that are
+ * still held by consumers.
+ */
+ list_for_each_entry_safe(rstc, pos, &rcdev->reset_control_head, list) {
+ rcu_assign_pointer(rstc->rcdev, NULL);
+ synchronize_srcu(&rstc->srcu);
+ reset_controller_remove(rcdev, rstc);
+ }
+ }
+
+ mutex_destroy(&rcdev->lock);
}
EXPORT_SYMBOL_GPL(reset_controller_unregister);
@@ -326,6 +370,7 @@ static inline bool reset_control_is_array(struct reset_control *rstc)
*/
int reset_control_reset(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
int ret;
if (!rstc)
@@ -337,7 +382,13 @@ int reset_control_reset(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_reset(rstc_to_array(rstc));
- if (!rstc->rcdev->ops->reset)
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
+ if (!rcdev->ops->reset)
return -ENOTSUPP;
if (rstc->shared) {
@@ -351,7 +402,7 @@ int reset_control_reset(struct reset_control *rstc)
return -EPERM;
}
- ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+ ret = rcdev->ops->reset(rcdev, rstc->id);
if (rstc->shared && ret)
atomic_dec(&rstc->triggered_count);
@@ -384,7 +435,7 @@ int reset_control_bulk_reset(int num_rstcs,
EXPORT_SYMBOL_GPL(reset_control_bulk_reset);
/**
- * reset_control_rearm - allow shared reset line to be re-triggered"
+ * reset_control_rearm - allow shared reset line to be re-triggered
* @rstc: reset controller
*
* On a shared reset line the actual reset pulse is only triggered once for the
@@ -441,6 +492,8 @@ EXPORT_SYMBOL_GPL(reset_control_rearm);
*/
int reset_control_assert(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
+
if (!rstc)
return 0;
@@ -450,6 +503,12 @@ int reset_control_assert(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_assert(rstc_to_array(rstc));
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
if (rstc->shared) {
if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
return -EINVAL;
@@ -464,7 +523,7 @@ int reset_control_assert(struct reset_control *rstc)
* Shared reset controls allow the reset line to be in any state
* after this call, so doing nothing is a valid option.
*/
- if (!rstc->rcdev->ops->assert)
+ if (!rcdev->ops->assert)
return 0;
} else {
/*
@@ -472,17 +531,17 @@ int reset_control_assert(struct reset_control *rstc)
* is no way to guarantee that the reset line is asserted after
* this call.
*/
- if (!rstc->rcdev->ops->assert)
+ if (!rcdev->ops->assert)
return -ENOTSUPP;
if (!rstc->acquired) {
WARN(1, "reset %s (ID: %u) is not acquired\n",
- rcdev_name(rstc->rcdev), rstc->id);
+ rcdev_name(rcdev), rstc->id);
return -EPERM;
}
}
- return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+ return rcdev->ops->assert(rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_assert);
@@ -529,6 +588,8 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_assert);
*/
int reset_control_deassert(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
+
if (!rstc)
return 0;
@@ -538,6 +599,12 @@ int reset_control_deassert(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_deassert(rstc_to_array(rstc));
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
if (rstc->shared) {
if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
return -EINVAL;
@@ -547,7 +614,7 @@ int reset_control_deassert(struct reset_control *rstc)
} else {
if (!rstc->acquired) {
WARN(1, "reset %s (ID: %u) is not acquired\n",
- rcdev_name(rstc->rcdev), rstc->id);
+ rcdev_name(rcdev), rstc->id);
return -EPERM;
}
}
@@ -559,10 +626,10 @@ int reset_control_deassert(struct reset_control *rstc)
* case, the reset controller driver should implement .deassert() and
* return -ENOTSUPP.
*/
- if (!rstc->rcdev->ops->deassert)
+ if (!rcdev->ops->deassert)
return 0;
- return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+ return rcdev->ops->deassert(rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_deassert);
@@ -604,14 +671,22 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_deassert);
*/
int reset_control_status(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
+
if (!rstc)
return 0;
if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
return -EINVAL;
- if (rstc->rcdev->ops->status)
- return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
+ if (rcdev->ops->status)
+ return rcdev->ops->status(rcdev, rstc->id);
return -ENOTSUPP;
}
@@ -639,6 +714,7 @@ EXPORT_SYMBOL_GPL(reset_control_status);
*/
int reset_control_acquire(struct reset_control *rstc)
{
+ struct reset_controller_dev *rcdev;
struct reset_control *rc;
if (!rstc)
@@ -650,25 +726,28 @@ int reset_control_acquire(struct reset_control *rstc)
if (reset_control_is_array(rstc))
return reset_control_array_acquire(rstc_to_array(rstc));
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&rstc->lock);
- if (rstc->acquired) {
- mutex_unlock(&reset_list_mutex);
+ if (rstc->acquired)
return 0;
- }
- list_for_each_entry(rc, &rstc->rcdev->reset_control_head, list) {
- if (rstc != rc && rstc->id == rc->id) {
- if (rc->acquired) {
- mutex_unlock(&reset_list_mutex);
- return -EBUSY;
+ guard(srcu)(&rstc->srcu);
+
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ return -ENODEV;
+
+ scoped_guard(mutex, &rcdev->lock) {
+ list_for_each_entry(rc, &rcdev->reset_control_head, list) {
+ if (rstc != rc && rstc->id == rc->id) {
+ if (rc->acquired)
+ return -EBUSY;
}
}
}
rstc->acquired = true;
- mutex_unlock(&reset_list_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(reset_control_acquire);
@@ -752,8 +831,9 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
struct reset_control *rstc;
+ int ret;
- lockdep_assert_held(&reset_list_mutex);
+ lockdep_assert_held(&rcdev->lock);
/* Expect callers to filter out OPTIONAL and DEASSERTED bits */
if (WARN_ON(flags & ~(RESET_CONTROL_FLAGS_BIT_SHARED |
@@ -782,15 +862,23 @@ __reset_control_get_internal(struct reset_controller_dev *rcdev,
if (!rstc)
return ERR_PTR(-ENOMEM);
+ ret = init_srcu_struct(&rstc->srcu);
+ if (ret) {
+ kfree(rstc);
+ return ERR_PTR(ret);
+ }
+
if (!try_module_get(rcdev->owner)) {
+ cleanup_srcu_struct(&rstc->srcu);
kfree(rstc);
return ERR_PTR(-ENODEV);
}
- rstc->rcdev = rcdev;
+ rcu_assign_pointer(rstc->rcdev, rcdev);
list_add(&rstc->list, &rcdev->reset_control_head);
rstc->id = index;
kref_init(&rstc->refcnt);
+ mutex_init(&rstc->lock);
rstc->acquired = acquired;
rstc->shared = shared;
get_device(rcdev->dev);
@@ -802,76 +890,133 @@ static void __reset_control_release(struct kref *kref)
{
struct reset_control *rstc = container_of(kref, struct reset_control,
refcnt);
+ struct reset_controller_dev *rcdev;
- lockdep_assert_held(&reset_list_mutex);
+ lockdep_assert_held(&rstc->srcu);
- module_put(rstc->rcdev->owner);
+ rcdev = rcu_replace_pointer(rstc->rcdev, NULL, true);
+ if (rcdev) {
+ lockdep_assert_held(&rcdev->lock);
+ reset_controller_remove(rcdev, rstc);
+ }
- list_del(&rstc->list);
- put_device(rstc->rcdev->dev);
- kfree(rstc);
+ mutex_destroy(&rstc->lock);
}
-static void __reset_control_put_internal(struct reset_control *rstc)
+static void reset_control_put_internal(struct reset_control *rstc)
{
- lockdep_assert_held(&reset_list_mutex);
+ struct reset_controller_dev *rcdev;
+ int ret = 0;
if (IS_ERR_OR_NULL(rstc))
return;
- kref_put(&rstc->refcnt, __reset_control_release);
+ scoped_guard(srcu, &rstc->srcu) {
+ rcdev = srcu_dereference(rstc->rcdev, &rstc->srcu);
+ if (!rcdev)
+ /* Already released. */
+ return;
+
+ guard(mutex)(&rcdev->lock);
+ ret = kref_put(&rstc->refcnt, __reset_control_release);
+ }
+
+ if (ret) {
+ synchronize_srcu(&rstc->srcu);
+ cleanup_srcu_struct(&rstc->srcu);
+ kfree(rstc);
+ }
}
static void reset_gpio_aux_device_release(struct device *dev)
{
- struct auxiliary_device *adev = to_auxiliary_dev(dev);
-
- kfree(adev);
+ WARN(1, "reset-gpio device %s should never have been removed", dev_name(dev));
}
-static int reset_add_gpio_aux_device(struct device *parent,
- struct fwnode_handle *swnode,
- int id, void *pdata)
+static int reset_create_gpio_aux_device(struct reset_gpio_lookup *rgpio_dev,
+ struct device *parent)
{
- struct auxiliary_device *adev;
- int ret;
+ struct auxiliary_device *adev = &rgpio_dev->adev;
+ int ret, id;
- adev = kzalloc_obj(*adev);
- if (!adev)
+ id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
+ if (id < 0)
return -ENOMEM;
adev->id = id;
adev->name = "gpio";
adev->dev.parent = parent;
- adev->dev.platform_data = pdata;
+ adev->dev.platform_data = &rgpio_dev->ref_args;
adev->dev.release = reset_gpio_aux_device_release;
- device_set_node(&adev->dev, swnode);
+ device_set_node(&adev->dev, rgpio_dev->swnode);
ret = auxiliary_device_init(adev);
if (ret) {
- kfree(adev);
+ ida_free(&reset_gpio_ida, id);
return ret;
}
ret = __auxiliary_device_add(adev, "reset");
if (ret) {
auxiliary_device_uninit(adev);
+ ida_free(&reset_gpio_ida, id);
return ret;
}
- return ret;
+ return 0;
+}
+
+static void reset_gpio_add_devlink(struct fwnode_handle *fwnode,
+ struct reset_gpio_lookup *rgpio_dev)
+{
+ struct device *consumer;
+
+ /*
+ * We must use get_dev_from_fwnode() and not ref_find_device_by_node()
+ * because the latter only considers the platform bus while we want to
+ * get consumers of any kind that can be associated with firmware
+ * nodes: auxiliary, soundwire, etc.
+ */
+ consumer = get_dev_from_fwnode(fwnode);
+ if (consumer) {
+ if (!device_link_add(consumer, &rgpio_dev->adev.dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER))
+ pr_warn("Failed to create a device link between reset-gpio and its consumer");
+
+ put_device(consumer);
+ }
+ /*
+ * else { }
+ *
+ * TODO: If ever there's a case where we need to support shared
+ * reset-gpios retrieved from a device node for which there's no
+ * device present yet, this is where we'd set up a notifier waiting
+ * for the device to appear in the system. This would be a lot of code
+ * that would go unused for now so let's cross that bridge when and if
+ * we get there.
+ */
+}
+
+/* TODO: move it out into drivers/base/ */
+static bool fwnode_reference_args_equal(const struct fwnode_reference_args *left,
+ const struct fwnode_reference_args *right)
+{
+ return left->fwnode == right->fwnode && left->nargs == right->nargs &&
+ !memcmp(left->args, right->args, sizeof(left->args[0]) * left->nargs);
}
/*
- * @args: phandle to the GPIO provider with all the args like GPIO number
+ * @np: OF-node associated with the consumer
+ * @args: Reference to the GPIO provider with all the args like GPIO number
*/
-static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
+static int __reset_add_reset_gpio_device(struct fwnode_handle *fwnode,
+ const struct fwnode_reference_args *args)
{
struct property_entry properties[3] = { };
- unsigned int offset, of_flags, lflags;
+ unsigned int offset, flags, lflags;
struct reset_gpio_lookup *rgpio_dev;
struct device *parent;
- int id, ret, prop = 0;
+ int ret, prop = 0;
/*
* Currently only #gpio-cells=2 is supported with the meaning of:
@@ -879,7 +1024,7 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
* args[1]: GPIO flags
* TODO: Handle other cases.
*/
- if (args->args_count != 2)
+ if (args->nargs != 2)
return -ENOENT;
/*
@@ -890,7 +1035,7 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
lockdep_assert_not_held(&reset_list_mutex);
offset = args->args[0];
- of_flags = args->args[1];
+ flags = args->args[1];
/*
* Later we map GPIO flags between OF and Linux, however not all
@@ -900,90 +1045,89 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
* FIXME: Find a better way of translating OF flags to GPIO lookup
* flags.
*/
- if (of_flags > GPIO_ACTIVE_LOW) {
+ if (flags > GPIO_ACTIVE_LOW) {
pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
- of_flags, offset);
+ flags, offset);
return -EINVAL;
}
struct gpio_device *gdev __free(gpio_device_put) =
- gpio_device_find_by_fwnode(of_fwnode_handle(args->np));
+ gpio_device_find_by_fwnode(args->fwnode);
if (!gdev)
return -EPROBE_DEFER;
guard(mutex)(&reset_gpio_lookup_mutex);
list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) {
- if (args->np == rgpio_dev->of_args.np) {
- if (of_phandle_args_equal(args, &rgpio_dev->of_args))
- return 0; /* Already on the list, done */
+ if (fwnode_reference_args_equal(args, &rgpio_dev->ref_args)) {
+ /*
+ * Already on the list, create the device link
+ * and stop here.
+ */
+ reset_gpio_add_devlink(fwnode, rgpio_dev);
+ return 0;
}
}
- lflags = GPIO_PERSISTENT | (of_flags & GPIO_ACTIVE_LOW);
+ lflags = GPIO_PERSISTENT | (flags & GPIO_ACTIVE_LOW);
parent = gpio_device_to_device(gdev);
properties[prop++] = PROPERTY_ENTRY_STRING("compatible", "reset-gpio");
properties[prop++] = PROPERTY_ENTRY_GPIO("reset-gpios", parent->fwnode, offset, lflags);
- id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
- if (id < 0)
- return id;
-
/* Not freed on success, because it is persisent subsystem data. */
rgpio_dev = kzalloc_obj(*rgpio_dev);
- if (!rgpio_dev) {
- ret = -ENOMEM;
- goto err_ida_free;
- }
+ if (!rgpio_dev)
+ return -ENOMEM;
- rgpio_dev->of_args = *args;
+ rgpio_dev->ref_args = *args;
/*
- * We keep the device_node reference, but of_args.np is put at the end
- * of __of_reset_control_get(), so get it one more time.
+ * We keep the fwnode_handle reference, but ref_args.fwnode is put at
+ * the end of __fwnode_reset_control_get(), so get it one more time.
* Hold reference as long as rgpio_dev memory is valid.
*/
- of_node_get(rgpio_dev->of_args.np);
+ fwnode_handle_get(rgpio_dev->ref_args.fwnode);
rgpio_dev->swnode = fwnode_create_software_node(properties, NULL);
if (IS_ERR(rgpio_dev->swnode)) {
ret = PTR_ERR(rgpio_dev->swnode);
- goto err_put_of_node;
+ goto err_put_fwnode;
}
- ret = reset_add_gpio_aux_device(parent, rgpio_dev->swnode, id,
- &rgpio_dev->of_args);
+ ret = reset_create_gpio_aux_device(rgpio_dev, parent);
if (ret)
goto err_del_swnode;
+ reset_gpio_add_devlink(fwnode, rgpio_dev);
list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
return 0;
err_del_swnode:
fwnode_remove_software_node(rgpio_dev->swnode);
-err_put_of_node:
- of_node_put(rgpio_dev->of_args.np);
+err_put_fwnode:
+ fwnode_handle_put(rgpio_dev->ref_args.fwnode);
kfree(rgpio_dev);
-err_ida_free:
- ida_free(&reset_gpio_ida, id);
return ret;
}
-static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args,
- bool gpio_fallback)
+static struct reset_controller_dev *
+__reset_find_rcdev(const struct fwnode_reference_args *args, bool gpio_fallback)
{
+ struct fwnode_reference_args *rc_args;
struct reset_controller_dev *rcdev;
lockdep_assert_held(&reset_list_mutex);
list_for_each_entry(rcdev, &reset_controller_list, list) {
- if (gpio_fallback) {
- if (rcdev->of_args && of_phandle_args_equal(args,
- rcdev->of_args))
+ if (gpio_fallback && rcdev->dev &&
+ device_is_compatible(rcdev->dev, "reset-gpio")) {
+ rc_args = dev_get_platdata(rcdev->dev);
+
+ if (fwnode_reference_args_equal(args, rc_args))
return rcdev;
} else {
- if (args->np == rcdev->of_node)
+ if (args->fwnode == rcdev->fwnode)
return rcdev;
}
}
@@ -992,31 +1136,31 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a
}
struct reset_control *
-__of_reset_control_get(struct device_node *node, const char *id, int index,
- enum reset_control_flags flags)
+__fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int index,
+ enum reset_control_flags flags)
{
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
bool gpio_fallback = false;
- struct reset_control *rstc;
+ struct reset_control *rstc = ERR_PTR(-EINVAL);
struct reset_controller_dev *rcdev;
- struct of_phandle_args args;
- int rstc_id;
+ struct fwnode_reference_args args;
+ struct of_phandle_args of_args;
+ int rstc_id = -EINVAL;
int ret;
- if (!node)
+ if (!fwnode)
return ERR_PTR(-EINVAL);
if (id) {
- index = of_property_match_string(node,
- "reset-names", id);
+ index = fwnode_property_match_string(fwnode, "reset-names", id);
if (index == -EILSEQ)
return ERR_PTR(index);
if (index < 0)
return optional ? NULL : ERR_PTR(-ENOENT);
}
- ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
- index, &args);
+ ret = fwnode_property_get_reference_args(fwnode, "resets", "#reset-cells",
+ 0, index, &args);
if (ret == -EINVAL)
return ERR_PTR(ret);
if (ret) {
@@ -1027,51 +1171,65 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
* There can be only one reset-gpio for regular devices, so
* don't bother with the "reset-gpios" phandle index.
*/
- ret = of_parse_phandle_with_args(node, "reset-gpios", "#gpio-cells",
- 0, &args);
+ ret = fwnode_property_get_reference_args(fwnode, "reset-gpios",
+ "#gpio-cells", 0, 0, &args);
if (ret)
return optional ? NULL : ERR_PTR(ret);
gpio_fallback = true;
- ret = __reset_add_reset_gpio_device(&args);
+ ret = __reset_add_reset_gpio_device(fwnode, &args);
if (ret) {
- rstc = ERR_PTR(ret);
- goto out_put;
+ fwnode_handle_put(args.fwnode);
+ return ERR_PTR(ret);
}
}
- mutex_lock(&reset_list_mutex);
+ guard(mutex)(&reset_list_mutex);
+
rcdev = __reset_find_rcdev(&args, gpio_fallback);
if (!rcdev) {
rstc = ERR_PTR(-EPROBE_DEFER);
- goto out_unlock;
+ goto out_put;
}
- if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
+ if (WARN_ON(args.nargs != rcdev->fwnode_reset_n_cells)) {
rstc = ERR_PTR(-EINVAL);
- goto out_unlock;
+ goto out_put;
}
- rstc_id = rcdev->of_xlate(rcdev, &args);
+ if (rcdev->of_xlate && is_of_node(fwnode)) {
+ ret = of_parse_phandle_with_args(to_of_node(fwnode),
+ gpio_fallback ? "reset-gpios" : "resets",
+ gpio_fallback ? "#gpio-cells" : "#reset-cells",
+ gpio_fallback ? 0 : index,
+ &of_args);
+ if (ret) {
+ rstc = ERR_PTR(ret);
+ goto out_put;
+ }
+
+ rstc_id = rcdev->of_xlate(rcdev, &of_args);
+ of_node_put(of_args.np);
+ } else if (rcdev->fwnode_xlate) {
+ rstc_id = rcdev->fwnode_xlate(rcdev, &args);
+ }
if (rstc_id < 0) {
rstc = ERR_PTR(rstc_id);
- goto out_unlock;
+ goto out_put;
}
flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
- /* reset_list_mutex also protects the rcdev's reset_control list */
- rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
+ scoped_guard(mutex, &rcdev->lock)
+ rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
-out_unlock:
- mutex_unlock(&reset_list_mutex);
out_put:
- of_node_put(args.np);
+ fwnode_handle_put(args.fwnode);
return rstc;
}
-EXPORT_SYMBOL_GPL(__of_reset_control_get);
+EXPORT_SYMBOL_GPL(__fwnode_reset_control_get);
struct reset_control *__reset_control_get(struct device *dev, const char *id,
int index, enum reset_control_flags flags)
@@ -1079,12 +1237,13 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED;
bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED;
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
if (WARN_ON(shared && acquired))
return ERR_PTR(-EINVAL);
- if (dev->of_node)
- return __of_reset_control_get(dev->of_node, id, index, flags);
+ if (fwnode)
+ return __fwnode_reset_control_get(fwnode, id, index, flags);
return optional ? NULL : ERR_PTR(-ENOENT);
}
@@ -1107,10 +1266,9 @@ int __reset_control_bulk_get(struct device *dev, int num_rstcs,
return 0;
err:
- mutex_lock(&reset_list_mutex);
while (i--)
- __reset_control_put_internal(rstcs[i].rstc);
- mutex_unlock(&reset_list_mutex);
+ reset_control_put_internal(rstcs[i].rstc);
+
return ret;
}
EXPORT_SYMBOL_GPL(__reset_control_bulk_get);
@@ -1119,10 +1277,8 @@ static void reset_control_array_put(struct reset_control_array *resets)
{
int i;
- mutex_lock(&reset_list_mutex);
for (i = 0; i < resets->num_rstcs; i++)
- __reset_control_put_internal(resets->rstc[i]);
- mutex_unlock(&reset_list_mutex);
+ reset_control_put_internal(resets->rstc[i]);
kfree(resets);
}
@@ -1140,9 +1296,7 @@ void reset_control_put(struct reset_control *rstc)
return;
}
- mutex_lock(&reset_list_mutex);
- __reset_control_put_internal(rstc);
- mutex_unlock(&reset_list_mutex);
+ reset_control_put_internal(rstc);
}
EXPORT_SYMBOL_GPL(reset_control_put);
@@ -1153,10 +1307,8 @@ EXPORT_SYMBOL_GPL(reset_control_put);
*/
void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
- mutex_lock(&reset_list_mutex);
while (num_rstcs--)
- __reset_control_put_internal(rstcs[num_rstcs].rstc);
- mutex_unlock(&reset_list_mutex);
+ reset_control_put_internal(rstcs[num_rstcs].rstc);
}
EXPORT_SYMBOL_GPL(reset_control_bulk_put);
@@ -1317,21 +1469,35 @@ EXPORT_SYMBOL_GPL(__device_reset);
*/
/**
- * of_reset_control_get_count - Count number of resets available with a device
+ * fwnode_reset_control_get_count - Count number of resets available with a device
*
- * @node: device node that contains 'resets'.
+ * @fwnode: firmware node that contains 'resets'.
*
* Returns positive reset count on success, or error number on failure and
* on count being zero.
*/
-static int of_reset_control_get_count(struct device_node *node)
+static int fwnode_reset_control_get_count(struct fwnode_handle *fwnode)
{
- int count;
+ struct fwnode_reference_args args;
+ int count = 0, ret;
- if (!node)
+ if (!fwnode)
return -EINVAL;
- count = of_count_phandle_with_args(node, "resets", "#reset-cells");
+ for (;;) {
+ ret = fwnode_property_get_reference_args(fwnode, "resets", "#reset-cells",
+ 0, count, &args);
+ if (ret) {
+ if (ret == -ENOENT)
+ break;
+
+ return ret;
+ }
+
+ fwnode_handle_put(args.fwnode);
+ count++;
+ }
+
if (count == 0)
count = -ENOENT;
@@ -1339,23 +1505,24 @@ static int of_reset_control_get_count(struct device_node *node)
}
/**
- * of_reset_control_array_get - Get a list of reset controls using
- * device node.
+ * fwnode_reset_control_array_get - Get a list of reset controls using
+ * a firmware node.
*
- * @np: device node for the device that requests the reset controls array
+ * @fwnode: firmware node for the device that requests the reset controls array
* @flags: whether reset controls are shared, optional, acquired
*
* Returns pointer to allocated reset_control on success or error on failure
*/
struct reset_control *
-of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags)
+fwnode_reset_control_array_get(struct fwnode_handle *fwnode,
+ enum reset_control_flags flags)
{
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
struct reset_control_array *resets;
struct reset_control *rstc;
int num, i;
- num = of_reset_control_get_count(np);
+ num = fwnode_reset_control_get_count(fwnode);
if (num < 0)
return optional ? NULL : ERR_PTR(num);
@@ -1365,7 +1532,7 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
resets->num_rstcs = num;
for (i = 0; i < num; i++) {
- rstc = __of_reset_control_get(np, NULL, i, flags);
+ rstc = __fwnode_reset_control_get(fwnode, NULL, i, flags);
if (IS_ERR(rstc))
goto err_rst;
resets->rstc[i] = rstc;
@@ -1375,16 +1542,14 @@ of_reset_control_array_get(struct device_node *np, enum reset_control_flags flag
return &resets->base;
err_rst:
- mutex_lock(&reset_list_mutex);
while (--i >= 0)
- __reset_control_put_internal(resets->rstc[i]);
- mutex_unlock(&reset_list_mutex);
+ reset_control_put_internal(resets->rstc[i]);
kfree(resets);
return rstc;
}
-EXPORT_SYMBOL_GPL(of_reset_control_array_get);
+EXPORT_SYMBOL_GPL(fwnode_reset_control_array_get);
/**
* devm_reset_control_array_get - Resource managed reset control array get
@@ -1408,7 +1573,7 @@ devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags)
if (!ptr)
return ERR_PTR(-ENOMEM);
- rstc = of_reset_control_array_get(dev->of_node, flags);
+ rstc = fwnode_reset_control_array_get(dev_fwnode(dev), flags);
if (IS_ERR_OR_NULL(rstc)) {
devres_free(ptr);
return rstc;
@@ -1431,8 +1596,10 @@ EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
*/
int reset_control_get_count(struct device *dev)
{
- if (dev->of_node)
- return of_reset_control_get_count(dev->of_node);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+ if (fwnode)
+ return fwnode_reset_control_get_count(fwnode);
return -ENOENT;
}
diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c
index b5d620132052..4c4e69eb32bb 100644
--- a/drivers/reset/reset-ath79.c
+++ b/drivers/reset/reset-ath79.c
@@ -15,7 +15,6 @@
struct ath79_reset {
struct reset_controller_dev rcdev;
- struct notifier_block restart_nb;
void __iomem *base;
spinlock_t lock;
};
@@ -72,11 +71,9 @@ static const struct reset_control_ops ath79_reset_ops = {
.status = ath79_reset_status,
};
-static int ath79_reset_restart_handler(struct notifier_block *nb,
- unsigned long action, void *data)
+static int ath79_reset_restart_handler(struct sys_off_data *data)
{
- struct ath79_reset *ath79_reset =
- container_of(nb, struct ath79_reset, restart_nb);
+ struct ath79_reset *ath79_reset = data->cb_data;
ath79_reset_assert(&ath79_reset->rcdev, FULL_CHIP_RESET);
@@ -108,10 +105,7 @@ static int ath79_reset_probe(struct platform_device *pdev)
if (err)
return err;
- ath79_reset->restart_nb.notifier_call = ath79_reset_restart_handler;
- ath79_reset->restart_nb.priority = 128;
-
- err = register_restart_handler(&ath79_reset->restart_nb);
+ err = devm_register_restart_handler(&pdev->dev, ath79_reset_restart_handler, ath79_reset);
if (err)
dev_warn(&pdev->dev, "Failed to register restart handler\n");
diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c
index 0a1610d9e78a..26aa2c3a2e68 100644
--- a/drivers/reset/reset-gpio.c
+++ b/drivers/reset/reset-gpio.c
@@ -4,7 +4,7 @@
#include <linux/gpio/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/property.h>
#include <linux/reset-controller.h>
struct reset_gpio_priv {
@@ -46,34 +46,22 @@ static const struct reset_control_ops reset_gpio_ops = {
.status = reset_gpio_status,
};
-static int reset_gpio_of_xlate(struct reset_controller_dev *rcdev,
- const struct of_phandle_args *reset_spec)
+static int reset_gpio_fwnode_xlate(struct reset_controller_dev *rcdev,
+ const struct fwnode_reference_args *reset_spec)
{
return reset_spec->args[0];
}
-static void reset_gpio_of_node_put(void *data)
-{
- of_node_put(data);
-}
-
static int reset_gpio_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct device *dev = &adev->dev;
- struct of_phandle_args *platdata = dev_get_platdata(dev);
struct reset_gpio_priv *priv;
- int ret;
-
- if (!platdata)
- return -EINVAL;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- auxiliary_set_drvdata(adev, &priv->rc);
-
priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(priv->reset))
return dev_err_probe(dev, PTR_ERR(priv->reset),
@@ -82,15 +70,10 @@ static int reset_gpio_probe(struct auxiliary_device *adev,
priv->rc.ops = &reset_gpio_ops;
priv->rc.owner = THIS_MODULE;
priv->rc.dev = dev;
- priv->rc.of_args = platdata;
- ret = devm_add_action_or_reset(dev, reset_gpio_of_node_put,
- priv->rc.of_node);
- if (ret)
- return ret;
/* Cells to match GPIO specifier, but it's not really used */
- priv->rc.of_reset_n_cells = 2;
- priv->rc.of_xlate = reset_gpio_of_xlate;
+ priv->rc.fwnode_reset_n_cells = 2;
+ priv->rc.fwnode_xlate = reset_gpio_fwnode_xlate;
priv->rc.nr_resets = 1;
return devm_reset_controller_register(dev, &priv->rc);
diff --git a/drivers/reset/reset-intel-gw.c b/drivers/reset/reset-intel-gw.c
index a5ce3350cb5e..0db64cc8a282 100644
--- a/drivers/reset/reset-intel-gw.c
+++ b/drivers/reset/reset-intel-gw.c
@@ -28,7 +28,6 @@ struct intel_reset_soc {
struct intel_reset_data {
struct reset_controller_dev rcdev;
- struct notifier_block restart_nb;
const struct intel_reset_soc *soc_data;
struct regmap *regmap;
struct device *dev;
@@ -153,12 +152,10 @@ static int intel_reset_xlate(struct reset_controller_dev *rcdev,
return id;
}
-static int intel_reset_restart_handler(struct notifier_block *nb,
- unsigned long action, void *data)
+static int intel_reset_restart_handler(struct sys_off_data *data)
{
- struct intel_reset_data *reset_data;
+ struct intel_reset_data *reset_data = data->cb_data;
- reset_data = container_of(nb, struct intel_reset_data, restart_nb);
intel_assert_device(&reset_data->rcdev, reset_data->reboot_id);
return NOTIFY_DONE;
@@ -215,9 +212,7 @@ static int intel_reset_probe(struct platform_device *pdev)
if (data->soc_data->legacy)
data->reboot_id |= FIELD_PREP(STAT_BIT_OFFSET_MASK, rb_id[2]);
- data->restart_nb.notifier_call = intel_reset_restart_handler;
- data->restart_nb.priority = 128;
- register_restart_handler(&data->restart_nb);
+ devm_register_restart_handler(&pdev->dev, intel_reset_restart_handler, data);
return 0;
}
diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c
index e42b2f24a93d..8ac9f237e1ce 100644
--- a/drivers/reset/reset-lpc18xx.c
+++ b/drivers/reset/reset-lpc18xx.c
@@ -31,7 +31,6 @@
struct lpc18xx_rgu_data {
struct reset_controller_dev rcdev;
- struct notifier_block restart_nb;
struct clk *clk_delay;
struct clk *clk_reg;
void __iomem *base;
@@ -41,11 +40,9 @@ struct lpc18xx_rgu_data {
#define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev)
-static int lpc18xx_rgu_restart(struct notifier_block *nb, unsigned long mode,
- void *cmd)
+static int lpc18xx_rgu_restart(struct sys_off_data *data)
{
- struct lpc18xx_rgu_data *rc = container_of(nb, struct lpc18xx_rgu_data,
- restart_nb);
+ struct lpc18xx_rgu_data *rc = data->cb_data;
writel(BIT(LPC18XX_RGU_CORE_RST), rc->base + LPC18XX_RGU_CTRL0);
mdelay(2000);
@@ -178,9 +175,8 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(&pdev->dev, ret, "unable to register device\n");
- rc->restart_nb.priority = 192,
- rc->restart_nb.notifier_call = lpc18xx_rgu_restart,
- ret = register_restart_handler(&rc->restart_nb);
+ ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, 192,
+ lpc18xx_rgu_restart, rc);
if (ret)
dev_warn(&pdev->dev, "failed to register restart handler\n");
diff --git a/drivers/reset/reset-ma35d1.c b/drivers/reset/reset-ma35d1.c
index 54e53863c98a..4ee901f00132 100644
--- a/drivers/reset/reset-ma35d1.c
+++ b/drivers/reset/reset-ma35d1.c
@@ -19,7 +19,6 @@
struct ma35d1_reset_data {
struct reset_controller_dev rcdev;
- struct notifier_block restart_handler;
void __iomem *base;
/* protect registers against concurrent read-modify-write */
spinlock_t lock;
@@ -125,10 +124,9 @@ static const struct {
[MA35D1_RESET_SSPCC] = {0x2C, 31}
};
-static int ma35d1_restart_handler(struct notifier_block *this, unsigned long mode, void *cmd)
+static int ma35d1_restart_handler(struct sys_off_data *sys_off_data)
{
- struct ma35d1_reset_data *data =
- container_of(this, struct ma35d1_reset_data, restart_handler);
+ struct ma35d1_reset_data *data = sys_off_data->cb_data;
u32 id = MA35D1_RESET_CHIP;
writel_relaxed(BIT(ma35d1_reset_map[id].bit),
@@ -213,11 +211,10 @@ static int ma35d1_reset_probe(struct platform_device *pdev)
reset_data->rcdev.nr_resets = MA35D1_RESET_COUNT;
reset_data->rcdev.ops = &ma35d1_reset_ops;
reset_data->rcdev.of_node = dev->of_node;
- reset_data->restart_handler.notifier_call = ma35d1_restart_handler;
- reset_data->restart_handler.priority = 192;
spin_lock_init(&reset_data->lock);
- err = register_restart_handler(&reset_data->restart_handler);
+ err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART, 192,
+ ma35d1_restart_handler, reset_data);
if (err)
dev_warn(&pdev->dev, "failed to register restart handler\n");
diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c
index 4070a4b6663f..a762d0215e76 100644
--- a/drivers/reset/reset-npcm.c
+++ b/drivers/reset/reset-npcm.c
@@ -89,7 +89,6 @@ static const struct npcm_reset_info npxm8xx_reset_info[] = {
struct npcm_rc_data {
struct reset_controller_dev rcdev;
- struct notifier_block restart_nb;
const struct npcm_reset_info *info;
struct regmap *gcr_regmap;
u32 sw_reset_number;
@@ -100,11 +99,9 @@ struct npcm_rc_data {
#define to_rc_data(p) container_of(p, struct npcm_rc_data, rcdev)
-static int npcm_rc_restart(struct notifier_block *nb, unsigned long mode,
- void *cmd)
+static int npcm_rc_restart(struct sys_off_data *data)
{
- struct npcm_rc_data *rc = container_of(nb, struct npcm_rc_data,
- restart_nb);
+ struct npcm_rc_data *rc = data->cb_data;
writel(NPCM_SWRST << rc->sw_reset_number, rc->base + NPCM_SWRSTR);
mdelay(1000);
@@ -472,9 +469,8 @@ static int npcm_rc_probe(struct platform_device *pdev)
if (!of_property_read_u32(pdev->dev.of_node, "nuvoton,sw-reset-number",
&rc->sw_reset_number)) {
if (rc->sw_reset_number && rc->sw_reset_number < 5) {
- rc->restart_nb.priority = 192;
- rc->restart_nb.notifier_call = npcm_rc_restart;
- ret = register_restart_handler(&rc->restart_nb);
+ ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART, 192,
+ npcm_rc_restart, rc);
if (ret) {
dev_warn(&pdev->dev, "failed to register restart handler\n");
return ret;
diff --git a/drivers/reset/reset-rzv2h-usb2phy.c b/drivers/reset/reset-rzv2h-usb2phy.c
index ae643575b067..d96042e28cd5 100644
--- a/drivers/reset/reset-rzv2h-usb2phy.c
+++ b/drivers/reset/reset-rzv2h-usb2phy.c
@@ -5,42 +5,39 @@
* Copyright (C) 2025 Renesas Electronics Corporation
*/
-#include <linux/cleanup.h>
+#include <linux/auxiliary_bus.h>
#include <linux/delay.h>
+#include <linux/idr.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/reset-controller.h>
-struct rzv2h_usb2phy_regval {
- u16 reg;
- u16 val;
-};
+static DEFINE_IDA(auxiliary_ids);
struct rzv2h_usb2phy_reset_of_data {
- const struct rzv2h_usb2phy_regval *init_vals;
- unsigned int init_val_count;
+ const struct reg_sequence *init_seq;
+ unsigned int init_nseq;
+
+ const struct reg_sequence *assert_seq;
+ unsigned int assert_nseq;
+
+ const struct reg_sequence *deassert_seq;
+ unsigned int deassert_nseq;
u16 reset_reg;
- u16 reset_assert_val;
- u16 reset_deassert_val;
u16 reset_status_bits;
- u16 reset_release_val;
-
- u16 reset2_reg;
- u16 reset2_acquire_val;
- u16 reset2_release_val;
};
struct rzv2h_usb2phy_reset_priv {
const struct rzv2h_usb2phy_reset_of_data *data;
- void __iomem *base;
+ struct regmap *regmap;
struct device *dev;
struct reset_controller_dev rcdev;
- spinlock_t lock; /* protects register accesses */
};
static inline struct rzv2h_usb2phy_reset_priv
@@ -49,81 +46,31 @@ static inline struct rzv2h_usb2phy_reset_priv
return container_of(rcdev, struct rzv2h_usb2phy_reset_priv, rcdev);
}
-/* This function must be called only after pm_runtime_resume_and_get() has been called */
-static void rzv2h_usbphy_assert_helper(struct rzv2h_usb2phy_reset_priv *priv)
-{
- const struct rzv2h_usb2phy_reset_of_data *data = priv->data;
-
- scoped_guard(spinlock, &priv->lock) {
- writel(data->reset2_acquire_val, priv->base + data->reset2_reg);
- writel(data->reset_assert_val, priv->base + data->reset_reg);
- }
-
- usleep_range(11, 20);
-}
-
static int rzv2h_usbphy_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev);
- struct device *dev = priv->dev;
- int ret;
-
- ret = pm_runtime_resume_and_get(dev);
- if (ret) {
- dev_err(dev, "pm_runtime_resume_and_get failed\n");
- return ret;
- }
-
- rzv2h_usbphy_assert_helper(priv);
- pm_runtime_put(dev);
-
- return 0;
+ return regmap_multi_reg_write(priv->regmap, priv->data->assert_seq,
+ priv->data->assert_nseq);
}
static int rzv2h_usbphy_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev);
- const struct rzv2h_usb2phy_reset_of_data *data = priv->data;
- struct device *dev = priv->dev;
- int ret;
-
- ret = pm_runtime_resume_and_get(dev);
- if (ret) {
- dev_err(dev, "pm_runtime_resume_and_get failed\n");
- return ret;
- }
- scoped_guard(spinlock, &priv->lock) {
- writel(data->reset_deassert_val, priv->base + data->reset_reg);
- writel(data->reset2_release_val, priv->base + data->reset2_reg);
- writel(data->reset_release_val, priv->base + data->reset_reg);
- }
-
- pm_runtime_put(dev);
-
- return 0;
+ return regmap_multi_reg_write(priv->regmap, priv->data->deassert_seq,
+ priv->data->deassert_nseq);
}
static int rzv2h_usbphy_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct rzv2h_usb2phy_reset_priv *priv = rzv2h_usbphy_rcdev_to_priv(rcdev);
- struct device *dev = priv->dev;
- int ret;
u32 reg;
- ret = pm_runtime_resume_and_get(dev);
- if (ret) {
- dev_err(dev, "pm_runtime_resume_and_get failed\n");
- return ret;
- }
-
- reg = readl(priv->base + priv->data->reset_reg);
-
- pm_runtime_put(dev);
+ regmap_read(priv->regmap, priv->data->reset_reg, &reg);
return (reg & priv->data->reset_status_bits) == priv->data->reset_status_bits;
}
@@ -141,12 +88,52 @@ static int rzv2h_usb2phy_reset_of_xlate(struct reset_controller_dev *rcdev,
return 0;
}
+static void rzv2h_usb2phy_reset_ida_free(void *data)
+{
+ struct auxiliary_device *adev = data;
+
+ ida_free(&auxiliary_ids, adev->id);
+}
+
+static int rzv2h_usb2phy_reset_mux_register(struct device *dev,
+ const char *mux_name)
+{
+ struct auxiliary_device *adev;
+ int id;
+
+ id = ida_alloc(&auxiliary_ids, GFP_KERNEL);
+ if (id < 0)
+ return id;
+
+ adev = __devm_auxiliary_device_create(dev, dev->driver->name,
+ mux_name, NULL, id);
+ if (!adev) {
+ ida_free(&auxiliary_ids, id);
+ return -ENOMEM;
+ }
+
+ return devm_add_action_or_reset(dev, rzv2h_usb2phy_reset_ida_free, adev);
+}
+
+static const struct regmap_config rzv2h_usb2phy_reset_regconf = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .can_sleep = true,
+};
+
+static void rzv2h_usb2phy_reset_pm_runtime_put(void *data)
+{
+ pm_runtime_put(data);
+}
+
static int rzv2h_usb2phy_reset_probe(struct platform_device *pdev)
{
const struct rzv2h_usb2phy_reset_of_data *data;
struct rzv2h_usb2phy_reset_priv *priv;
struct device *dev = &pdev->dev;
struct reset_control *rstc;
+ void __iomem *base;
int error;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -156,17 +143,19 @@ static int rzv2h_usb2phy_reset_probe(struct platform_device *pdev)
data = of_device_get_match_data(dev);
priv->data = data;
priv->dev = dev;
- priv->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(priv->base))
- return PTR_ERR(priv->base);
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base, &rzv2h_usb2phy_reset_regconf);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
rstc = devm_reset_control_get_shared_deasserted(dev, NULL);
if (IS_ERR(rstc))
return dev_err_probe(dev, PTR_ERR(rstc),
"failed to get deasserted reset\n");
- spin_lock_init(&priv->lock);
-
error = devm_pm_runtime_enable(dev);
if (error)
return dev_err_probe(dev, error, "Failed to enable pm_runtime\n");
@@ -175,13 +164,14 @@ static int rzv2h_usb2phy_reset_probe(struct platform_device *pdev)
if (error)
return dev_err_probe(dev, error, "pm_runtime_resume_and_get failed\n");
- for (unsigned int i = 0; i < data->init_val_count; i++)
- writel(data->init_vals[i].val, priv->base + data->init_vals[i].reg);
-
- /* keep usb2phy in asserted state */
- rzv2h_usbphy_assert_helper(priv);
+ error = devm_add_action_or_reset(dev, rzv2h_usb2phy_reset_pm_runtime_put,
+ dev);
+ if (error)
+ return dev_err_probe(dev, error, "unable to register cleanup action\n");
- pm_runtime_put(dev);
+ error = regmap_multi_reg_write(priv->regmap, data->init_seq, data->init_nseq);
+ if (error)
+ return dev_err_probe(dev, error, "failed to initialize PHY registers\n");
priv->rcdev.ops = &rzv2h_usbphy_reset_ops;
priv->rcdev.of_reset_n_cells = 0;
@@ -190,30 +180,47 @@ static int rzv2h_usb2phy_reset_probe(struct platform_device *pdev)
priv->rcdev.of_node = dev->of_node;
priv->rcdev.dev = dev;
- return devm_reset_controller_register(dev, &priv->rcdev);
+ error = devm_reset_controller_register(dev, &priv->rcdev);
+ if (error)
+ return dev_err_probe(dev, error, "could not register reset controller\n");
+
+ error = rzv2h_usb2phy_reset_mux_register(dev, "vbenctl");
+ if (error)
+ return dev_err_probe(dev, error, "could not register aux mux\n");
+
+ return 0;
}
/*
* initialization values required to prepare the PHY to receive
* assert and deassert requests.
*/
-static const struct rzv2h_usb2phy_regval rzv2h_init_vals[] = {
- { .reg = 0xc10, .val = 0x67c },
- { .reg = 0xc14, .val = 0x1f },
- { .reg = 0x600, .val = 0x909 },
+static const struct reg_sequence rzv2h_init_seq[] = {
+ { .reg = 0xc10, .def = 0x67c },
+ { .reg = 0xc14, .def = 0x01f },
+ { .reg = 0x600, .def = 0x909 },
+};
+
+static const struct reg_sequence rzv2h_assert_seq[] = {
+ { .reg = 0xb04, .def = 0x303 },
+ { .reg = 0x000, .def = 0x206, .delay_us = 11 },
+};
+
+static const struct reg_sequence rzv2h_deassert_seq[] = {
+ { .reg = 0x000, .def = 0x200 },
+ { .reg = 0xb04, .def = 0x003 },
+ { .reg = 0x000, .def = 0x000 },
};
static const struct rzv2h_usb2phy_reset_of_data rzv2h_reset_of_data = {
- .init_vals = rzv2h_init_vals,
- .init_val_count = ARRAY_SIZE(rzv2h_init_vals),
+ .init_seq = rzv2h_init_seq,
+ .init_nseq = ARRAY_SIZE(rzv2h_init_seq),
+ .assert_seq = rzv2h_assert_seq,
+ .assert_nseq = ARRAY_SIZE(rzv2h_assert_seq),
+ .deassert_seq = rzv2h_deassert_seq,
+ .deassert_nseq = ARRAY_SIZE(rzv2h_deassert_seq),
.reset_reg = 0,
- .reset_assert_val = 0x206,
.reset_status_bits = BIT(2),
- .reset_deassert_val = 0x200,
- .reset_release_val = 0x0,
- .reset2_reg = 0xb04,
- .reset2_acquire_val = 0x303,
- .reset2_release_val = 0x3,
};
static const struct of_device_id rzv2h_usb2phy_reset_of_match[] = {
diff --git a/drivers/reset/reset-sky1.c b/drivers/reset/reset-sky1.c
new file mode 100644
index 000000000000..78e80a533c39
--- /dev/null
+++ b/drivers/reset/reset-sky1.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *
+ * CIX System Reset Controller (SRC) driver
+ *
+ * Author: Jerry Zhu <jerry.zhu@cixtech.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/reset/cix,sky1-system-control.h>
+#include <dt-bindings/reset/cix,sky1-s5-system-control.h>
+
+#define SKY1_RESET_SLEEP_MIN_US 50
+#define SKY1_RESET_SLEEP_MAX_US 100
+
+struct sky1_src_signal {
+ unsigned int offset;
+ unsigned int bit;
+};
+
+struct sky1_src_variant {
+ const struct sky1_src_signal *signals;
+ unsigned int signals_num;
+};
+
+struct sky1_src {
+ struct reset_controller_dev rcdev;
+ const struct sky1_src_signal *signals;
+ struct regmap *regmap;
+};
+
+enum {
+ CSU_PM_RESET = 0x304,
+ SENSORFUSION_RESET = 0x308,
+ SENSORFUSION_NOC_RESET = 0x30c,
+ RESET_GROUP0_S0_DOMAIN_0 = 0x400,
+ RESET_GROUP0_S0_DOMAIN_1 = 0x404,
+ RESET_GROUP1_USB_PHYS = 0x408,
+ RESET_GROUP1_USB_CONTROLLERS = 0x40c,
+ RESET_GROUP0_RCSU = 0x800,
+ RESET_GROUP1_RCSU = 0x804,
+};
+
+static const struct sky1_src_signal sky1_src_signals[] = {
+ /* reset group1 for s0 domain modules */
+ [SKY1_CSU_PM_RESET_N] = { CSU_PM_RESET, BIT(0) },
+ [SKY1_SENSORFUSION_RESET_N] = { SENSORFUSION_RESET, BIT(0) },
+ [SKY1_SENSORFUSION_NOC_RESET_N] = { SENSORFUSION_NOC_RESET, BIT(0) },
+ [SKY1_DDRC_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(0) },
+ [SKY1_GIC_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(1) },
+ [SKY1_CI700_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(2) },
+ [SKY1_SYS_NI700_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(3) },
+ [SKY1_MM_NI700_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(4) },
+ [SKY1_PCIE_NI700_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(5) },
+ [SKY1_GPU_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(6) },
+ [SKY1_NPUTOP_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(7) },
+ [SKY1_NPUCORE0_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(8) },
+ [SKY1_NPUCORE1_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(9) },
+ [SKY1_NPUCORE2_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(10) },
+ [SKY1_VPU_RESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(11) },
+ [SKY1_ISP_SRESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(12) },
+ [SKY1_ISP_ARESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(13) },
+ [SKY1_ISP_HRESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(14) },
+ [SKY1_ISP_GDCRESET_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(15) },
+ [SKY1_DPU_RESET0_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(16) },
+ [SKY1_DPU_RESET1_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(17) },
+ [SKY1_DPU_RESET2_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(18) },
+ [SKY1_DPU_RESET3_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(19) },
+ [SKY1_DPU_RESET4_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(20) },
+ [SKY1_DP_RESET0_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(21) },
+ [SKY1_DP_RESET1_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(22) },
+ [SKY1_DP_RESET2_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(23) },
+ [SKY1_DP_RESET3_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(24) },
+ [SKY1_DP_RESET4_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(25) },
+ [SKY1_DP_PHY_RST_N] = { RESET_GROUP0_S0_DOMAIN_0, BIT(26) },
+
+ /* reset group1 for s0 domain modules */
+ [SKY1_AUDIO_HIFI5_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(0) },
+ [SKY1_AUDIO_HIFI5_NOC_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(1) },
+ [SKY1_CSIDPHY_PRST0_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(2) },
+ [SKY1_CSIDPHY_CMNRST0_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(3) },
+ [SKY1_CSI0_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(4) },
+ [SKY1_CSIDPHY_PRST1_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(5) },
+ [SKY1_CSIDPHY_CMNRST1_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(6) },
+ [SKY1_CSI1_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(7) },
+ [SKY1_CSI2_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(8) },
+ [SKY1_CSI3_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(9) },
+ [SKY1_CSIBRDGE0_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(10) },
+ [SKY1_CSIBRDGE1_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(11) },
+ [SKY1_CSIBRDGE2_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(12) },
+ [SKY1_CSIBRDGE3_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(13) },
+ [SKY1_GMAC0_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(14) },
+ [SKY1_GMAC1_RST_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(15) },
+ [SKY1_PCIE0_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(16) },
+ [SKY1_PCIE1_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(17) },
+ [SKY1_PCIE2_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(18) },
+ [SKY1_PCIE3_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(19) },
+ [SKY1_PCIE4_RESET_N] = { RESET_GROUP0_S0_DOMAIN_1, BIT(20) },
+
+ /* reset group1 for usb phys */
+ [SKY1_USB_DP_PHY0_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(0) },
+ [SKY1_USB_DP_PHY1_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(1) },
+ [SKY1_USB_DP_PHY2_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(2) },
+ [SKY1_USB_DP_PHY3_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(3) },
+ [SKY1_USB_DP_PHY0_RST_N] = { RESET_GROUP1_USB_PHYS, BIT(4) },
+ [SKY1_USB_DP_PHY1_RST_N] = { RESET_GROUP1_USB_PHYS, BIT(5) },
+ [SKY1_USB_DP_PHY2_RST_N] = { RESET_GROUP1_USB_PHYS, BIT(6) },
+ [SKY1_USB_DP_PHY3_RST_N] = { RESET_GROUP1_USB_PHYS, BIT(7) },
+ [SKY1_USBPHY_SS_PST_N] = { RESET_GROUP1_USB_PHYS, BIT(8) },
+ [SKY1_USBPHY_SS_RST_N] = { RESET_GROUP1_USB_PHYS, BIT(9) },
+ [SKY1_USBPHY_HS0_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(10) },
+ [SKY1_USBPHY_HS1_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(11) },
+ [SKY1_USBPHY_HS2_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(12) },
+ [SKY1_USBPHY_HS3_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(13) },
+ [SKY1_USBPHY_HS4_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(14) },
+ [SKY1_USBPHY_HS5_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(15) },
+ [SKY1_USBPHY_HS6_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(16) },
+ [SKY1_USBPHY_HS7_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(17) },
+ [SKY1_USBPHY_HS8_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(18) },
+ [SKY1_USBPHY_HS9_PRST_N] = { RESET_GROUP1_USB_PHYS, BIT(19) },
+
+ /* reset group1 for usb controllers */
+ [SKY1_USBC_SS0_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(0) },
+ [SKY1_USBC_SS1_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(1) },
+ [SKY1_USBC_SS2_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(2) },
+ [SKY1_USBC_SS3_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(3) },
+ [SKY1_USBC_SS4_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(4) },
+ [SKY1_USBC_SS5_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(5) },
+ [SKY1_USBC_SS0_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(6) },
+ [SKY1_USBC_SS1_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(7) },
+ [SKY1_USBC_SS2_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(8) },
+ [SKY1_USBC_SS3_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(9) },
+ [SKY1_USBC_SS4_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(10) },
+ [SKY1_USBC_SS5_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(11) },
+ [SKY1_USBC_HS0_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(12) },
+ [SKY1_USBC_HS1_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(13) },
+ [SKY1_USBC_HS2_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(14) },
+ [SKY1_USBC_HS3_PRST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(15) },
+ [SKY1_USBC_HS0_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(16) },
+ [SKY1_USBC_HS1_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(17) },
+ [SKY1_USBC_HS2_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(18) },
+ [SKY1_USBC_HS3_RST_N] = { RESET_GROUP1_USB_CONTROLLERS, BIT(19) },
+
+ /* reset group0 for rcsu */
+ [SKY1_AUDIO_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(0) },
+ [SKY1_CI700_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(1) },
+ [SKY1_CSI_RCSU0_RESET_N] = { RESET_GROUP0_RCSU, BIT(2) },
+ [SKY1_CSI_RCSU1_RESET_N] = { RESET_GROUP0_RCSU, BIT(3) },
+ [SKY1_CSU_PM_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(4) },
+ [SKY1_DDR_BROADCAST_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(5) },
+ [SKY1_DDR_CTRL_RCSU_0_RESET_N] = { RESET_GROUP0_RCSU, BIT(6) },
+ [SKY1_DDR_CTRL_RCSU_1_RESET_N] = { RESET_GROUP0_RCSU, BIT(7) },
+ [SKY1_DDR_CTRL_RCSU_2_RESET_N] = { RESET_GROUP0_RCSU, BIT(8) },
+ [SKY1_DDR_CTRL_RCSU_3_RESET_N] = { RESET_GROUP0_RCSU, BIT(9) },
+ [SKY1_DDR_TZC400_RCSU_0_RESET_N] = { RESET_GROUP0_RCSU, BIT(10) },
+ [SKY1_DDR_TZC400_RCSU_1_RESET_N] = { RESET_GROUP0_RCSU, BIT(11) },
+ [SKY1_DDR_TZC400_RCSU_2_RESET_N] = { RESET_GROUP0_RCSU, BIT(12) },
+ [SKY1_DDR_TZC400_RCSU_3_RESET_N] = { RESET_GROUP0_RCSU, BIT(13) },
+ [SKY1_DP0_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(14) },
+ [SKY1_DP1_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(15) },
+ [SKY1_DP2_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(16) },
+ [SKY1_DP3_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(17) },
+ [SKY1_DP4_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(18) },
+ [SKY1_DPU0_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(19) },
+ [SKY1_DPU1_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(20) },
+ [SKY1_DPU2_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(21) },
+ [SKY1_DPU3_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(22) },
+ [SKY1_DPU4_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(23) },
+ [SKY1_DSU_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(24) },
+ [SKY1_FCH_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(25) },
+ [SKY1_GICD_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(26) },
+ [SKY1_GMAC_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(27) },
+ [SKY1_GPU_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(28) },
+ [SKY1_ISP_RCSU0_RESET_N] = { RESET_GROUP0_RCSU, BIT(29) },
+ [SKY1_ISP_RCSU1_RESET_N] = { RESET_GROUP0_RCSU, BIT(30) },
+ [SKY1_NI700_MMHUB_RCSU_RESET_N] = { RESET_GROUP0_RCSU, BIT(31) },
+
+ /* reset group1 for rcsu */
+ [SKY1_NPU_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(0) },
+ [SKY1_NI700_PCIE_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(1) },
+ [SKY1_PCIE_X421_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(2) },
+ [SKY1_PCIE_X8_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(3) },
+ [SKY1_SF_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(4) },
+ [SKY1_RCSU_SMMU_MMHUB_RESET_N] = { RESET_GROUP1_RCSU, BIT(5) },
+ [SKY1_RCSU_SMMU_PCIEHUB_RESET_N] = { RESET_GROUP1_RCSU, BIT(6) },
+ [SKY1_RCSU_SYSHUB_RESET_N] = { RESET_GROUP1_RCSU, BIT(7) },
+ [SKY1_NI700_SMN_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(8) },
+ [SKY1_NI700_SYSHUB_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(9) },
+ [SKY1_RCSU_USB2_HOST0_RESET_N] = { RESET_GROUP1_RCSU, BIT(10) },
+ [SKY1_RCSU_USB2_HOST1_RESET_N] = { RESET_GROUP1_RCSU, BIT(11) },
+ [SKY1_RCSU_USB2_HOST2_RESET_N] = { RESET_GROUP1_RCSU, BIT(12) },
+ [SKY1_RCSU_USB2_HOST3_RESET_N] = { RESET_GROUP1_RCSU, BIT(13) },
+ [SKY1_RCSU_USB3_TYPEA_DRD_RESET_N] = { RESET_GROUP1_RCSU, BIT(14) },
+ [SKY1_RCSU_USB3_TYPEC_DRD_RESET_N] = { RESET_GROUP1_RCSU, BIT(15) },
+ [SKY1_RCSU_USB3_TYPEC_HOST0_RESET_N] = { RESET_GROUP1_RCSU, BIT(16) },
+ [SKY1_RCSU_USB3_TYPEC_HOST1_RESET_N] = { RESET_GROUP1_RCSU, BIT(17) },
+ [SKY1_RCSU_USB3_TYPEC_HOST2_RESET_N] = { RESET_GROUP1_RCSU, BIT(18) },
+ [SKY1_VPU_RCSU_RESET_N] = { RESET_GROUP1_RCSU, BIT(19) },
+};
+
+static const struct sky1_src_variant variant_sky1 = {
+ .signals = sky1_src_signals,
+ .signals_num = ARRAY_SIZE(sky1_src_signals),
+};
+
+enum {
+ FCH_SW_RST_FUNC = 0x8,
+ FCH_SW_RST_BUS = 0xc,
+ FCH_SW_XSPI = 0x10,
+};
+
+static const struct sky1_src_signal sky1_src_fch_signals[] = {
+ /* resets for fch_sw_rst_func */
+ [SW_I3C0_RST_FUNC_G_N] = { FCH_SW_RST_FUNC, BIT(0) },
+ [SW_I3C0_RST_FUNC_I_N] = { FCH_SW_RST_FUNC, BIT(1) },
+ [SW_I3C1_RST_FUNC_G_N] = { FCH_SW_RST_FUNC, BIT(2) },
+ [SW_I3C1_RST_FUNC_I_N] = { FCH_SW_RST_FUNC, BIT(3) },
+ [SW_UART0_RST_FUNC_N] = { FCH_SW_RST_FUNC, BIT(4) },
+ [SW_UART1_RST_FUNC_N] = { FCH_SW_RST_FUNC, BIT(5) },
+ [SW_UART2_RST_FUNC_N] = { FCH_SW_RST_FUNC, BIT(6) },
+ [SW_UART3_RST_FUNC_N] = { FCH_SW_RST_FUNC, BIT(7) },
+ [SW_TIMER_RST_FUNC_N] = { FCH_SW_RST_FUNC, BIT(20) },
+
+ /* resets for fch_sw_rst_bus */
+ [SW_I3C0_RST_APB_N] = { FCH_SW_RST_BUS, BIT(0) },
+ [SW_I3C1_RST_APB_N] = { FCH_SW_RST_BUS, BIT(1) },
+ [SW_DMA_RST_AXI_N] = { FCH_SW_RST_BUS, BIT(2) },
+ [SW_UART0_RST_APB_N] = { FCH_SW_RST_BUS, BIT(4) },
+ [SW_UART1_RST_APB_N] = { FCH_SW_RST_BUS, BIT(5) },
+ [SW_UART2_RST_APB_N] = { FCH_SW_RST_BUS, BIT(6) },
+ [SW_UART3_RST_APB_N] = { FCH_SW_RST_BUS, BIT(7) },
+ [SW_SPI0_RST_APB_N] = { FCH_SW_RST_BUS, BIT(8) },
+ [SW_SPI1_RST_APB_N] = { FCH_SW_RST_BUS, BIT(9) },
+ [SW_I2C0_RST_APB_N] = { FCH_SW_RST_BUS, BIT(12) },
+ [SW_I2C1_RST_APB_N] = { FCH_SW_RST_BUS, BIT(13) },
+ [SW_I2C2_RST_APB_N] = { FCH_SW_RST_BUS, BIT(14) },
+ [SW_I2C3_RST_APB_N] = { FCH_SW_RST_BUS, BIT(15) },
+ [SW_I2C4_RST_APB_N] = { FCH_SW_RST_BUS, BIT(16) },
+ [SW_I2C5_RST_APB_N] = { FCH_SW_RST_BUS, BIT(17) },
+ [SW_I2C6_RST_APB_N] = { FCH_SW_RST_BUS, BIT(18) },
+ [SW_I2C7_RST_APB_N] = { FCH_SW_RST_BUS, BIT(19) },
+ [SW_GPIO_RST_APB_N] = { FCH_SW_RST_BUS, BIT(21) },
+
+ /* resets for fch_sw_xspi */
+ [SW_XSPI_REG_RST_N] = { FCH_SW_XSPI, BIT(0) },
+ [SW_XSPI_SYS_RST_N] = { FCH_SW_XSPI, BIT(1) },
+};
+
+static const struct sky1_src_variant variant_sky1_fch = {
+ .signals = sky1_src_fch_signals,
+ .signals_num = ARRAY_SIZE(sky1_src_fch_signals),
+};
+
+static struct sky1_src *to_sky1_src(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct sky1_src, rcdev);
+}
+
+static int sky1_reset_set(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
+{
+ struct sky1_src *sky1src = to_sky1_src(rcdev);
+ const struct sky1_src_signal *signal = &sky1src->signals[id];
+ unsigned int value = assert ? 0 : signal->bit;
+
+ return regmap_update_bits(sky1src->regmap,
+ signal->offset, signal->bit, value);
+}
+
+static int sky1_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ sky1_reset_set(rcdev, id, true);
+ usleep_range(SKY1_RESET_SLEEP_MIN_US,
+ SKY1_RESET_SLEEP_MAX_US);
+ return 0;
+}
+
+static int sky1_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ sky1_reset_set(rcdev, id, false);
+ usleep_range(SKY1_RESET_SLEEP_MIN_US,
+ SKY1_RESET_SLEEP_MAX_US);
+ return 0;
+}
+
+static int sky1_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ sky1_reset_assert(rcdev, id);
+ sky1_reset_deassert(rcdev, id);
+ return 0;
+}
+
+static int sky1_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ unsigned int value = 0;
+ struct sky1_src *sky1src = to_sky1_src(rcdev);
+ const struct sky1_src_signal *signal = &sky1src->signals[id];
+
+ regmap_read(sky1src->regmap, signal->offset, &value);
+ return !(value & signal->bit);
+}
+
+static const struct reset_control_ops sky1_src_ops = {
+ .reset = sky1_reset,
+ .assert = sky1_reset_assert,
+ .deassert = sky1_reset_deassert,
+ .status = sky1_reset_status
+};
+
+static int sky1_reset_probe(struct platform_device *pdev)
+{
+ struct sky1_src *sky1src;
+ struct device *dev = &pdev->dev;
+ const struct sky1_src_variant *variant;
+
+ sky1src = devm_kzalloc(dev, sizeof(*sky1src), GFP_KERNEL);
+ if (!sky1src)
+ return -ENOMEM;
+
+ variant = of_device_get_match_data(dev);
+
+ sky1src->regmap = device_node_to_regmap(dev->of_node);
+ if (IS_ERR(sky1src->regmap)) {
+ return dev_err_probe(dev, PTR_ERR(sky1src->regmap),
+ "Unable to get sky1-src regmap");
+ }
+
+ sky1src->signals = variant->signals;
+ sky1src->rcdev.owner = THIS_MODULE;
+ sky1src->rcdev.nr_resets = variant->signals_num;
+ sky1src->rcdev.ops = &sky1_src_ops;
+ sky1src->rcdev.of_node = dev->of_node;
+ sky1src->rcdev.dev = dev;
+
+ return devm_reset_controller_register(dev, &sky1src->rcdev);
+}
+
+static const struct of_device_id sky1_sysreg_of_match[] = {
+ { .compatible = "cix,sky1-system-control", .data = &variant_sky1_fch},
+ { .compatible = "cix,sky1-s5-system-control", .data = &variant_sky1},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sky1_sysreg_of_match);
+
+static struct platform_driver sky1_reset_driver = {
+ .probe = sky1_reset_probe,
+ .driver = {
+ .name = "cix,sky1-rst",
+ .of_match_table = sky1_sysreg_of_match,
+ },
+};
+module_platform_driver(sky1_reset_driver)
+
+MODULE_AUTHOR("Jerry Zhu <jerry.zhu@cixtech.com>");
+MODULE_DESCRIPTION("Cix Sky1 reset driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/reset/reset-sunplus.c b/drivers/reset/reset-sunplus.c
index df58decab64d..58b087433759 100644
--- a/drivers/reset/reset-sunplus.c
+++ b/drivers/reset/reset-sunplus.c
@@ -100,7 +100,6 @@ static const u32 sp_resets[] = {
struct sp_reset {
struct reset_controller_dev rcdev;
- struct notifier_block notifier;
void __iomem *base;
};
@@ -154,10 +153,9 @@ static const struct reset_control_ops sp_reset_ops = {
.status = sp_reset_status,
};
-static int sp_restart(struct notifier_block *nb, unsigned long mode,
- void *cmd)
+static int sp_restart(struct sys_off_data *data)
{
- struct sp_reset *reset = container_of(nb, struct sp_reset, notifier);
+ struct sp_reset *reset = data->cb_data;
sp_reset_assert(&reset->rcdev, 0);
sp_reset_deassert(&reset->rcdev, 0);
@@ -189,10 +187,8 @@ static int sp_reset_probe(struct platform_device *pdev)
if (ret)
return ret;
- reset->notifier.notifier_call = sp_restart;
- reset->notifier.priority = 192;
-
- return register_restart_handler(&reset->notifier);
+ return devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_RESTART,
+ 192, sp_restart, reset);
}
static const struct of_device_id sp_reset_dt_ids[] = {
diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c
index 2324060b747c..38f78d78fa4f 100644
--- a/drivers/reset/sti/reset-syscfg.c
+++ b/drivers/reset/sti/reset-syscfg.c
@@ -41,7 +41,7 @@ struct syscfg_reset_channel {
struct syscfg_reset_controller {
struct reset_controller_dev rst;
bool active_low;
- struct syscfg_reset_channel *channels;
+ struct syscfg_reset_channel channels[];
};
#define to_syscfg_reset_controller(_rst) \
@@ -135,15 +135,10 @@ static int syscfg_reset_controller_register(struct device *dev,
struct syscfg_reset_controller *rc;
int i, err;
- rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL);
+ rc = devm_kzalloc(dev, struct_size(rc, channels, data->nr_channels), GFP_KERNEL);
if (!rc)
return -ENOMEM;
- rc->channels = devm_kcalloc(dev, data->nr_channels,
- sizeof(*rc->channels), GFP_KERNEL);
- if (!rc->channels)
- return -ENOMEM;
-
rc->rst.ops = &syscfg_reset_ops;
rc->rst.of_node = dev->of_node;
rc->rst.nr_resets = data->nr_channels;
diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c
index 2af3bfda313e..0cc2953d59a5 100644
--- a/drivers/soc/hisilicon/kunpeng_hccs.c
+++ b/drivers/soc/hisilicon/kunpeng_hccs.c
@@ -961,7 +961,7 @@ static ssize_t link_fsm_show(struct kobject *kobj,
struct hccs_link_status link_status = {0};
const struct {
u8 link_fsm;
- char *str;
+ const char *str;
} link_fsm_map[] = {
{HCCS_PORT_RESET, "reset"},
{HCCS_PORT_SETUP, "setup"},
@@ -1621,8 +1621,7 @@ static void hccs_remove_topo_dirs(struct hccs_dev *hdev)
hccs_remove_misc_sysfs(hdev);
}
-static int hccs_create_hccs_dir(struct hccs_dev *hdev,
- struct hccs_die_info *die,
+static int hccs_create_hccs_dir(struct hccs_die_info *die,
struct hccs_port_info *port)
{
int ret;
@@ -1654,7 +1653,7 @@ static int hccs_create_die_dir(struct hccs_dev *hdev,
for (i = 0; i < die->port_num; i++) {
port = &die->ports[i];
- ret = hccs_create_hccs_dir(hdev, die, port);
+ ret = hccs_create_hccs_dir(die, port);
if (ret) {
dev_err(hdev->dev, "create hccs%u dir failed.\n",
port->port_id);
diff --git a/drivers/soc/microchip/Kconfig b/drivers/soc/microchip/Kconfig
index bcf554602561..af7946741bce 100644
--- a/drivers/soc/microchip/Kconfig
+++ b/drivers/soc/microchip/Kconfig
@@ -1,3 +1,14 @@
+config POLARFIRE_SOC_IRQ_MUX
+ bool "Microchip PolarFire SoC's GPIO IRQ Mux"
+ depends on ARCH_MICROCHIP
+ select REGMAP
+ select REGMAP_MMIO
+ default y
+ help
+ Support for the interrupt mux on Polarfire SoC. It sits between
+ the GPIO controllers and the PLIC, as only 41 interrupts are shared
+ between 3 GPIO controllers with a total of 70 interrupts.
+
config POLARFIRE_SOC_SYS_CTRL
tristate "Microchip PolarFire SoC (MPFS) system controller support"
depends on POLARFIRE_SOC_MAILBOX
diff --git a/drivers/soc/microchip/Makefile b/drivers/soc/microchip/Makefile
index 1a3a1594b089..55775db45ee7 100644
--- a/drivers/soc/microchip/Makefile
+++ b/drivers/soc/microchip/Makefile
@@ -1,2 +1,3 @@
+obj-$(CONFIG_POLARFIRE_SOC_IRQ_MUX) += mpfs-irqmux.o
obj-$(CONFIG_POLARFIRE_SOC_SYS_CTRL) += mpfs-sys-controller.o
obj-$(CONFIG_POLARFIRE_SOC_SYSCONS) += mpfs-control-scb.o mpfs-mss-top-sysreg.o
diff --git a/drivers/soc/microchip/mpfs-irqmux.c b/drivers/soc/microchip/mpfs-irqmux.c
new file mode 100644
index 000000000000..ae15e913e780
--- /dev/null
+++ b/drivers/soc/microchip/mpfs-irqmux.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Largely copied from rzn1_irqmux.c
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MPFS_IRQMUX_CR 0x54
+#define MPFS_IRQMUX_NUM_CHILDREN 96
+#define MPFS_IRQMUX_NUM_DIRECT 38
+#define MPFS_IRQMUX_DIRECT_START 13
+#define MPFS_IRQMUX_DIRECT_END 50
+#define MPFS_IRQMUX_NONDIRECT_END 53
+
+static int mpfs_irqmux_is_direct_mode(struct device *dev,
+ const struct of_phandle_args *parent_args)
+{
+ if (parent_args->args_count != 1) {
+ dev_err(dev, "Invalid interrupt-map item\n");
+ return -EINVAL;
+ }
+
+ if (parent_args->args[0] < MPFS_IRQMUX_DIRECT_START ||
+ parent_args->args[0] > MPFS_IRQMUX_NONDIRECT_END) {
+ dev_err(dev, "Invalid interrupt %u\n", parent_args->args[0]);
+ return -EINVAL;
+ }
+
+ if (parent_args->args[0] > MPFS_IRQMUX_DIRECT_END)
+ return 0;
+
+ return 1;
+}
+
+static int mpfs_irqmux_probe(struct platform_device *pdev)
+{
+ DECLARE_BITMAP(child_done, MPFS_IRQMUX_NUM_CHILDREN) = {};
+ DECLARE_BITMAP(parent_done, MPFS_IRQMUX_NUM_DIRECT) = {};
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct of_imap_parser imap_parser;
+ struct of_imap_item imap_item;
+ struct regmap *regmap;
+ int ret, direct_mode, line, controller, gpio, parent_line;
+ u32 tmp, val = 0, old;
+
+ regmap = device_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to find syscon regmap\n");
+
+ /* We support only #interrupt-cells = <1> and #address-cells = <0> */
+ ret = of_property_read_u32(np, "#interrupt-cells", &tmp);
+ if (ret)
+ return ret;
+ if (tmp != 1)
+ return -EINVAL;
+
+ ret = of_property_read_u32(np, "#address-cells", &tmp);
+ if (ret)
+ return ret;
+ if (tmp != 0)
+ return -EINVAL;
+
+ ret = of_imap_parser_init(&imap_parser, np, &imap_item);
+ if (ret)
+ return ret;
+
+ for_each_of_imap_item(&imap_parser, &imap_item) {
+
+ direct_mode = mpfs_irqmux_is_direct_mode(dev, &imap_item.parent_args);
+ if (direct_mode < 0) {
+ of_node_put(imap_item.parent_args.np);
+ return direct_mode;
+ }
+
+ line = imap_item.child_imap[0];
+ gpio = line % 32;
+ controller = line / 32;
+
+ if (controller > 2) {
+ of_node_put(imap_item.parent_args.np);
+ dev_err(dev, "child interrupt number too large: %d\n", line);
+ return -EINVAL;
+ }
+
+ if (test_and_set_bit(line, child_done)) {
+ of_node_put(imap_item.parent_args.np);
+ dev_err(dev, "mux child line %d already defined in interrupt-map\n",
+ line);
+ return -EINVAL;
+ }
+
+ parent_line = imap_item.parent_args.args[0] - MPFS_IRQMUX_DIRECT_START;
+ if (direct_mode && test_and_set_bit(parent_line, parent_done)) {
+ of_node_put(imap_item.parent_args.np);
+ dev_err(dev, "mux parent line %d already defined in interrupt-map\n",
+ line);
+ return -EINVAL;
+ }
+
+ /*
+ * There are 41 interrupts assigned to GPIOs, of which 38 are "direct". Since the
+ * mux has 32 bits only, 6 of these exclusive/"direct" interrupts remain. These
+ * are used by GPIO controller 1's lines 18 to 23. Nothing needs to be done
+ * for these interrupts.
+ */
+ if (controller == 1 && gpio >= 18)
+ continue;
+
+ /*
+ * The mux has a single register, where bits 0 to 13 mux between GPIO controller
+ * 1's 14 GPIOs and GPIO controller 2's first 14 GPIOs. The remaining bits mux
+ * between the first 18 GPIOs of controller 1 and the last 18 GPIOS of
+ * controller 2. If a bit in the mux's control register is set, the
+ * corresponding interrupt line for GPIO controller 0 or 1 will be put in
+ * "non-direct" mode. If cleared, the "fabric" controller's will.
+ *
+ * Register layout:
+ * GPIO 1 interrupt line 17 | mux bit 31 | GPIO 2 interrupt line 31
+ * ... | ... | ...
+ * ... | ... | ...
+ * GPIO 1 interrupt line 0 | mux bit 14 | GPIO 2 interrupt line 14
+ * GPIO 0 interrupt line 13 | mux bit 13 | GPIO 2 interrupt line 13
+ * ... | ... | ...
+ * ... | ... | ...
+ * GPIO 0 interrupt line 0 | mux bit 0 | GPIO 2 interrupt line 0
+ *
+ * As the binding mandates 70 items, one for each GPIO line, there's no need to
+ * handle anything for GPIO controller 2, since the bit will be set for the
+ * corresponding line in GPIO controller 0 or 1.
+ */
+ if (controller == 2)
+ continue;
+
+ /*
+ * If in direct mode, the bit is cleared, nothing needs to be done as val is zero
+ * initialised and that's the direct mode setting for GPIO controller 0 and 1.
+ */
+ if (direct_mode)
+ continue;
+
+ if (controller == 0)
+ val |= 1U << gpio;
+ else
+ val |= 1U << (gpio + 14);
+ }
+
+ regmap_read(regmap, MPFS_IRQMUX_CR, &old);
+ regmap_write(regmap, MPFS_IRQMUX_CR, val);
+
+ if (val != old)
+ dev_info(dev, "firmware mux setting of 0x%x overwritten to 0x%x\n", old, val);
+
+ return 0;
+}
+
+static const struct of_device_id mpfs_irqmux_of_match[] = {
+ { .compatible = "microchip,mpfs-irqmux", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mpfs_irqmux_of_match);
+
+static struct platform_driver mpfs_irqmux_driver = {
+ .probe = mpfs_irqmux_probe,
+ .driver = {
+ .name = "mpfs_irqmux",
+ .of_match_table = mpfs_irqmux_of_match,
+ },
+};
+module_platform_driver(mpfs_irqmux_driver);
+
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_DESCRIPTION("Polarfire SoC interrupt mux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c
index 10b2fc39da66..92d1142a59e6 100644
--- a/drivers/soc/microchip/mpfs-sys-controller.c
+++ b/drivers/soc/microchip/mpfs-sys-controller.c
@@ -36,6 +36,11 @@ struct mpfs_sys_controller {
struct kref consumers;
};
+struct mpfs_syscon_config {
+ unsigned int nb_subdevs;
+ struct platform_device *subdevs;
+};
+
int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg)
{
unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS);
@@ -110,25 +115,11 @@ struct mtd_info *mpfs_sys_controller_get_flash(struct mpfs_sys_controller *mpfs_
}
EXPORT_SYMBOL(mpfs_sys_controller_get_flash);
-static struct platform_device subdevs[] = {
- {
- .name = "mpfs-rng",
- .id = -1,
- },
- {
- .name = "mpfs-generic-service",
- .id = -1,
- },
- {
- .name = "mpfs-auto-update",
- .id = -1,
- },
-};
-
static int mpfs_sys_controller_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mpfs_sys_controller *sys_controller;
+ struct mpfs_syscon_config *of_data;
struct device_node *np;
int i, ret;
@@ -165,11 +156,17 @@ no_flash:
platform_set_drvdata(pdev, sys_controller);
+ of_data = (struct mpfs_syscon_config *) device_get_match_data(dev);
+ if (!of_data) {
+ dev_err(dev, "Error getting match data\n");
+ return -EINVAL;
+ }
- for (i = 0; i < ARRAY_SIZE(subdevs); i++) {
- subdevs[i].dev.parent = dev;
- if (platform_device_register(&subdevs[i]))
- dev_warn(dev, "Error registering sub device %s\n", subdevs[i].name);
+ for (i = 0; i < of_data->nb_subdevs; i++) {
+ of_data->subdevs[i].dev.parent = dev;
+ if (platform_device_register(&of_data->subdevs[i]))
+ dev_warn(dev, "Error registering sub device %s\n",
+ of_data->subdevs[i].name);
}
dev_info(&pdev->dev, "Registered MPFS system controller\n");
@@ -188,8 +185,45 @@ static void mpfs_sys_controller_remove(struct platform_device *pdev)
mpfs_sys_controller_put(sys_controller);
}
+static struct platform_device mpfs_subdevs[] = {
+ {
+ .name = "mpfs-rng",
+ .id = -1,
+ },
+ {
+ .name = "mpfs-generic-service",
+ .id = -1,
+ },
+ {
+ .name = "mpfs-auto-update",
+ .id = -1,
+ },
+};
+
+static struct platform_device pic64gx_subdevs[] = {
+ {
+ .name = "mpfs-rng",
+ .id = -1,
+ },
+ {
+ .name = "mpfs-generic-service",
+ .id = -1,
+ },
+};
+
+static const struct mpfs_syscon_config mpfs_config = {
+ .nb_subdevs = ARRAY_SIZE(mpfs_subdevs),
+ .subdevs = mpfs_subdevs,
+};
+
+static const struct mpfs_syscon_config pic64gx_config = {
+ .nb_subdevs = ARRAY_SIZE(pic64gx_subdevs),
+ .subdevs = pic64gx_subdevs,
+};
+
static const struct of_device_id mpfs_sys_controller_of_match[] = {
- {.compatible = "microchip,mpfs-sys-controller", },
+ {.compatible = "microchip,mpfs-sys-controller", .data = &mpfs_config},
+ {.compatible = "microchip,pic64gx-sys-controller", .data = &pic64gx_config},
{},
};
MODULE_DEVICE_TABLE(of, mpfs_sys_controller_of_match);
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index ad5899d083f3..0161ceec8842 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -5,7 +5,6 @@
*/
#include <linux/bitfield.h>
-#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h>
@@ -1782,6 +1781,94 @@ static const struct llcc_slice_config sc8280xp_data[] = {
},
};
+static const struct llcc_slice_config sdm670_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_ROTATOR,
+ .slice_id = 4,
+ .max_cap = 384,
+ .priority = 2,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0xe,
+ .cache_mode = 2,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_VOICE,
+ .slice_id = 5,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 6,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MDM,
+ .slice_id = 8,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 12,
+ .max_cap = 384,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0x0,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 13,
+ .max_cap = 512,
+ .priority = 1,
+ .bonus_ways = 0xf,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf,
+ .res_ways = 0x0,
+ .cache_mode = 0,
+ .dis_cap_alloc = true,
+ .retain_on_pc = true,
+ },
+};
+
static const struct llcc_slice_config sdm845_data[] = {{
.usecase_id = LLCC_CPUSS,
.slice_id = 1,
@@ -3943,7 +4030,7 @@ static const struct llcc_slice_config x1e80100_data[] = {
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
- .trp_ecc_sb_err_syn0 = 0x2304c,
+ .trp_ecc_sb_err_syn0 = 0x2034c,
.trp_ecc_db_err_syn0 = 0x20370,
.trp_ecc_error_cntr_clear = 0x20440,
.trp_interrupt_0_status = 0x20480,
@@ -4196,6 +4283,17 @@ static const struct qcom_llcc_config sc8280xp_cfg[] = {
},
};
+static const struct qcom_llcc_config sdm670_cfg[] = {
+ {
+ .sct_data = sdm670_data,
+ .size = ARRAY_SIZE(sdm670_data),
+ .skip_llcc_cfg = true,
+ .reg_offset = llcc_v1_reg_offset,
+ .edac_reg_offset = &llcc_v1_edac_reg_offset,
+ .no_edac = true,
+ },
+};
+
static const struct qcom_llcc_config sdm845_cfg[] = {
{
.sct_data = sdm845_data,
@@ -4364,6 +4462,11 @@ static const struct qcom_sct_config sc8280xp_cfgs = {
.num_config = ARRAY_SIZE(sc8280xp_cfg),
};
+static const struct qcom_sct_config sdm670_cfgs = {
+ .llcc_config = sdm670_cfg,
+ .num_config = ARRAY_SIZE(sdm670_cfg),
+};
+
static const struct qcom_sct_config sdm845_cfgs = {
.llcc_config = sdm845_cfg,
.num_config = ARRAY_SIZE(sdm845_cfg),
@@ -4431,8 +4534,7 @@ static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
struct llcc_slice_desc *llcc_slice_getd(u32 uid)
{
const struct llcc_slice_config *cfg;
- struct llcc_slice_desc *desc;
- u32 sz, count;
+ u32 sz, i;
if (IS_ERR(drv_data))
return ERR_CAST(drv_data);
@@ -4440,21 +4542,14 @@ struct llcc_slice_desc *llcc_slice_getd(u32 uid)
cfg = drv_data->cfg;
sz = drv_data->cfg_size;
- for (count = 0; cfg && count < sz; count++, cfg++)
+ for (i = 0; cfg && i < sz; i++, cfg++)
if (cfg->usecase_id == uid)
break;
- if (count == sz || !cfg)
+ if (i == sz)
return ERR_PTR(-ENODEV);
- desc = kzalloc_obj(*desc);
- if (!desc)
- return ERR_PTR(-ENOMEM);
-
- desc->slice_id = cfg->slice_id;
- desc->slice_size = cfg->max_cap;
-
- return desc;
+ return &drv_data->desc[i];
}
EXPORT_SYMBOL_GPL(llcc_slice_getd);
@@ -4465,7 +4560,7 @@ EXPORT_SYMBOL_GPL(llcc_slice_getd);
void llcc_slice_putd(struct llcc_slice_desc *desc)
{
if (!IS_ERR_OR_NULL(desc))
- kfree(desc);
+ return;
}
EXPORT_SYMBOL_GPL(llcc_slice_putd);
@@ -4540,25 +4635,21 @@ int llcc_slice_activate(struct llcc_slice_desc *desc)
if (IS_ERR_OR_NULL(desc))
return -EINVAL;
- mutex_lock(&drv_data->lock);
- if (test_bit(desc->slice_id, drv_data->bitmap)) {
- mutex_unlock(&drv_data->lock);
+ guard(mutex)(&drv_data->lock);
+ /* Already active; try to take another reference. */
+ if (refcount_inc_not_zero(&desc->refcount))
return 0;
- }
act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT;
-
ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
DEACTIVATE);
- if (ret) {
- mutex_unlock(&drv_data->lock);
+ if (ret)
return ret;
- }
- __set_bit(desc->slice_id, drv_data->bitmap);
- mutex_unlock(&drv_data->lock);
+ /* Set first reference */
+ refcount_set(&desc->refcount, 1);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(llcc_slice_activate);
@@ -4580,24 +4671,21 @@ int llcc_slice_deactivate(struct llcc_slice_desc *desc)
if (IS_ERR_OR_NULL(desc))
return -EINVAL;
- mutex_lock(&drv_data->lock);
- if (!test_bit(desc->slice_id, drv_data->bitmap)) {
- mutex_unlock(&drv_data->lock);
+ guard(mutex)(&drv_data->lock);
+ /* refcount > 1, drop one ref and we’re done. */
+ if (refcount_dec_not_one(&desc->refcount))
return 0;
- }
- act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
+ act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
ACTIVATE);
- if (ret) {
- mutex_unlock(&drv_data->lock);
+ if (ret)
return ret;
- }
- __clear_bit(desc->slice_id, drv_data->bitmap);
- mutex_unlock(&drv_data->lock);
+ /* Finalize: atomically transition 1 -> 0 */
+ WARN_ON_ONCE(!refcount_dec_if_one(&desc->refcount));
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
@@ -4638,7 +4726,7 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
u32 attr1_val;
u32 attr0_val;
u32 max_cap_cacheline;
- struct llcc_slice_desc desc;
+ struct llcc_slice_desc *desc;
attr1_val = config->cache_mode;
attr1_val |= config->probe_target_ways << ATTR1_PROBE_TARGET_WAYS_SHIFT;
@@ -4787,8 +4875,11 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
}
if (config->activate_on_init) {
- desc.slice_id = config->slice_id;
- ret = llcc_slice_activate(&desc);
+ desc = llcc_slice_getd(config->usecase_id);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ ret = llcc_slice_activate(desc);
}
return ret;
@@ -5101,18 +5192,18 @@ static int qcom_llcc_probe(struct platform_device *pdev)
llcc_cfg = cfg->sct_data;
sz = cfg->size;
-
- for (i = 0; i < sz; i++)
- if (llcc_cfg[i].slice_id > drv_data->max_slices)
- drv_data->max_slices = llcc_cfg[i].slice_id;
-
- drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices,
- GFP_KERNEL);
- if (!drv_data->bitmap) {
+ drv_data->desc = devm_kcalloc(dev, sz, sizeof(struct llcc_slice_desc), GFP_KERNEL);
+ if (!drv_data->desc) {
ret = -ENOMEM;
goto err;
}
+ for (i = 0; i < sz; i++) {
+ drv_data->desc[i].slice_id = llcc_cfg[i].slice_id;
+ drv_data->desc[i].slice_size = llcc_cfg[i].max_cap;
+ refcount_set(&drv_data->desc[i].refcount, 0);
+ }
+
drv_data->cfg = llcc_cfg;
drv_data->cfg_size = sz;
drv_data->edac_reg_offset = cfg->edac_reg_offset;
@@ -5160,6 +5251,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfgs },
{ .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfgs },
{ .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfgs },
+ { .compatible = "qcom,sdm670-llcc", .data = &sdm670_cfgs },
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfgs },
{ .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfgs },
{ .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfgs },
diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c
index 6a23f18b0281..96ca0b87bfc4 100644
--- a/drivers/soc/qcom/ocmem.c
+++ b/drivers/soc/qcom/ocmem.c
@@ -196,17 +196,16 @@ struct ocmem *of_get_ocmem(struct device *dev)
}
pdev = of_find_device_by_node(devnode->parent);
- if (!pdev) {
- dev_err(dev, "Cannot find device node %s\n", devnode->name);
- return ERR_PTR(-EPROBE_DEFER);
- }
+ if (!pdev)
+ return dev_err_ptr_probe(dev, -EPROBE_DEFER,
+ "Cannot find device node %s\n",
+ devnode->name);
ocmem = platform_get_drvdata(pdev);
put_device(&pdev->dev);
- if (!ocmem) {
- dev_err(dev, "Cannot get ocmem\n");
- return ERR_PTR(-ENODEV);
- }
+ if (!ocmem)
+ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n");
+
return ocmem;
}
EXPORT_SYMBOL_GPL(of_get_ocmem);
@@ -308,7 +307,7 @@ static int ocmem_dev_probe(struct platform_device *pdev)
ocmem->dev = dev;
ocmem->config = device_get_match_data(dev);
- ocmem->core_clk = devm_clk_get(dev, "core");
+ ocmem->core_clk = devm_clk_get_optional(dev, "core");
if (IS_ERR(ocmem->core_clk))
return dev_err_probe(dev, PTR_ERR(ocmem->core_clk),
"Unable to get core clock\n");
diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c
index 72259f489075..6d879e1540b0 100644
--- a/drivers/soc/qcom/pdr_interface.c
+++ b/drivers/soc/qcom/pdr_interface.c
@@ -523,7 +523,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
if (!pds)
return ERR_PTR(-ENOMEM);
- pds->service = SERVREG_NOTIFIER_SERVICE;
+ pds->service = QMI_SERVICE_ID_SERVREG_NOTIF;
strscpy(pds->service_name, service_name, sizeof(pds->service_name));
strscpy(pds->service_path, service_path, sizeof(pds->service_path));
pds->need_locator_lookup = true;
@@ -678,7 +678,7 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state,
if (ret < 0)
goto destroy_indack;
- ret = qmi_add_lookup(&pdr->locator_hdl, SERVREG_LOCATOR_SERVICE, 1, 1);
+ ret = qmi_add_lookup(&pdr->locator_hdl, QMI_SERVICE_ID_SERVREG_LOC, 1, 1);
if (ret < 0)
goto release_qmi_handle;
diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h
index 047c0160b617..d867e9b5e973 100644
--- a/drivers/soc/qcom/pdr_internal.h
+++ b/drivers/soc/qcom/pdr_internal.h
@@ -4,9 +4,6 @@
#include <linux/soc/qcom/pdr.h>
-#define SERVREG_LOCATOR_SERVICE 0x40
-#define SERVREG_NOTIFIER_SERVICE 0x42
-
#define SERVREG_REGISTER_LISTENER_REQ 0x20
#define SERVREG_GET_DOMAIN_LIST_REQ 0x21
#define SERVREG_STATE_UPDATED_IND_ID 0x22
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
index 627f96ca322e..3042261578aa 100644
--- a/drivers/soc/qcom/pmic_glink.c
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -23,13 +23,19 @@ enum {
PMIC_GLINK_CLIENT_UCSI,
};
+struct pmic_glink_data {
+ unsigned long client_mask;
+ const char *charger_pdr_service_name;
+ const char *charger_pdr_service_path;
+};
+
struct pmic_glink {
struct device *dev;
struct pdr_handle *pdr;
struct rpmsg_endpoint *ept;
- unsigned long client_mask;
+ const struct pmic_glink_data *data;
struct auxiliary_device altmode_aux;
struct auxiliary_device ps_aux;
@@ -292,7 +298,6 @@ static struct rpmsg_driver pmic_glink_rpmsg_driver = {
static int pmic_glink_probe(struct platform_device *pdev)
{
- const unsigned long *match_data;
struct pdr_service *service;
struct pmic_glink *pg;
int ret;
@@ -309,12 +314,10 @@ static int pmic_glink_probe(struct platform_device *pdev)
spin_lock_init(&pg->client_lock);
mutex_init(&pg->state_lock);
- match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);
- if (!match_data)
+ pg->data = of_device_get_match_data(&pdev->dev);
+ if (!pg->data)
return -EINVAL;
- pg->client_mask = *match_data;
-
pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
if (IS_ERR(pg->pdr)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr),
@@ -322,27 +325,30 @@ static int pmic_glink_probe(struct platform_device *pdev)
return ret;
}
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi");
if (ret)
goto out_release_pdr_handle;
}
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
if (ret)
goto out_release_ucsi_aux;
}
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) {
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) {
ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
if (ret)
goto out_release_altmode_aux;
}
- service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
- if (IS_ERR(service)) {
- ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
- "failed adding pdr lookup for charger_pd\n");
- goto out_release_aux_devices;
+ if (pg->data->charger_pdr_service_name && pg->data->charger_pdr_service_path) {
+ service = pdr_add_lookup(pg->pdr, pg->data->charger_pdr_service_name,
+ pg->data->charger_pdr_service_path);
+ if (IS_ERR(service)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
+ "failed adding pdr lookup for charger_pd\n");
+ goto out_release_aux_devices;
+ }
}
mutex_lock(&__pmic_glink_lock);
@@ -352,13 +358,13 @@ static int pmic_glink_probe(struct platform_device *pdev)
return 0;
out_release_aux_devices:
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux);
out_release_altmode_aux:
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
out_release_ucsi_aux:
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
out_release_pdr_handle:
pdr_handle_release(pg->pdr);
@@ -372,23 +378,35 @@ static void pmic_glink_remove(struct platform_device *pdev)
pdr_handle_release(pg->pdr);
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
pmic_glink_del_aux_device(pg, &pg->ps_aux);
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
pmic_glink_del_aux_device(pg, &pg->altmode_aux);
- if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
+ if (pg->data->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
guard(mutex)(&__pmic_glink_lock);
__pmic_glink = NULL;
}
-static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
- BIT(PMIC_GLINK_CLIENT_ALTMODE) |
- BIT(PMIC_GLINK_CLIENT_UCSI);
+static const struct pmic_glink_data pmic_glink_adsp_data = {
+ .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
+ BIT(PMIC_GLINK_CLIENT_ALTMODE) |
+ BIT(PMIC_GLINK_CLIENT_UCSI),
+ .charger_pdr_service_name = "tms/servreg",
+ .charger_pdr_service_path = "msm/adsp/charger_pd",
+};
+
+static const struct pmic_glink_data pmic_glink_soccp_data = {
+ .client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
+ BIT(PMIC_GLINK_CLIENT_ALTMODE) |
+ BIT(PMIC_GLINK_CLIENT_UCSI),
+};
static const struct of_device_id pmic_glink_of_match[] = {
- { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask },
+ { .compatible = "qcom,glymur-pmic-glink", .data = &pmic_glink_soccp_data },
+ { .compatible = "qcom,kaanapali-pmic-glink", .data = &pmic_glink_soccp_data },
+ { .compatible = "qcom,pmic-glink", .data = &pmic_glink_adsp_data },
{}
};
MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index a543ab9bee6c..c255662b8fc3 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -355,7 +355,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
/* Normalize state */
cdev_state = !!state;
- if (qmp_cdev->state == state)
+ if (qmp_cdev->state == cdev_state)
return 0;
ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c
index dc10bc859ff4..bb99f003844b 100644
--- a/drivers/soc/qcom/qcom_pd_mapper.c
+++ b/drivers/soc/qcom/qcom_pd_mapper.c
@@ -360,6 +360,14 @@ static const struct qcom_pdm_domain_data mpss_wlan_pd = {
},
};
+static const struct qcom_pdm_domain_data *glymur_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ NULL,
+};
+
static const struct qcom_pdm_domain_data *kaanapali_domains[] = {
&adsp_audio_pd,
&adsp_root_pd,
@@ -401,6 +409,16 @@ static const struct qcom_pdm_domain_data *qcs404_domains[] = {
NULL,
};
+static const struct qcom_pdm_domain_data *qcs615_domains[] = {
+ &adsp_audio_pd,
+ &adsp_root_pd,
+ &adsp_sensor_pd,
+ &cdsp_root_pd,
+ &mpss_root_pd,
+ &mpss_wlan_pd,
+ NULL,
+};
+
static const struct qcom_pdm_domain_data *sc7180_domains[] = {
&adsp_audio_pd,
&adsp_root_pd_pdr,
@@ -560,8 +578,12 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = {
{ .compatible = "qcom,apq8064", .data = NULL, },
{ .compatible = "qcom,apq8074", .data = NULL, },
{ .compatible = "qcom,apq8084", .data = NULL, },
+ { .compatible = "qcom,eliza", .data = sm8550_domains, },
{ .compatible = "qcom,apq8096", .data = msm8996_domains, },
+ { .compatible = "qcom,glymur", .data = glymur_domains, },
{ .compatible = "qcom,kaanapali", .data = kaanapali_domains, },
+ { .compatible = "qcom,mahua", .data = glymur_domains, },
+ { .compatible = "qcom,milos", .data = sm8550_domains, },
{ .compatible = "qcom,msm8226", .data = NULL, },
{ .compatible = "qcom,msm8909", .data = NULL, },
{ .compatible = "qcom,msm8916", .data = NULL, },
@@ -572,6 +594,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = {
{ .compatible = "qcom,qcm2290", .data = qcm2290_domains, },
{ .compatible = "qcom,qcm6490", .data = sc7280_domains, },
{ .compatible = "qcom,qcs404", .data = qcs404_domains, },
+ { .compatible = "qcom,qcs615", .data = qcs615_domains, },
{ .compatible = "qcom,sc7180", .data = sc7180_domains, },
{ .compatible = "qcom,sc7280", .data = sc7280_domains, },
{ .compatible = "qcom,sc8180x", .data = sc8180x_domains, },
@@ -615,15 +638,9 @@ static struct qcom_pdm_data *qcom_pdm_start(void)
const struct qcom_pdm_domain_data * const *domains;
const struct of_device_id *match;
struct qcom_pdm_data *data;
- struct device_node *root;
int ret, i;
- root = of_find_node_by_path("/");
- if (!root)
- return ERR_PTR(-ENODEV);
-
- match = of_match_node(qcom_pdm_domains, root);
- of_node_put(root);
+ match = of_match_node(qcom_pdm_domains, of_root);
if (!match) {
pr_notice("PDM: no support for the platform, userspace daemon might be required.\n");
return ERR_PTR(-ENODEV);
@@ -656,7 +673,7 @@ static struct qcom_pdm_data *qcom_pdm_start(void)
goto err_stop;
}
- ret = qmi_add_server(&data->handle, SERVREG_LOCATOR_SERVICE,
+ ret = qmi_add_server(&data->handle, QMI_SERVICE_ID_SERVREG_LOC,
SERVREG_QMI_VERSION, SERVREG_QMI_INSTANCE);
if (ret) {
pr_err("PDM: error adding server %d\n", ret);
diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
index cb515c2340c1..af0ceeaf6e07 100644
--- a/drivers/soc/qcom/smp2p.c
+++ b/drivers/soc/qcom/smp2p.c
@@ -36,6 +36,10 @@
* The driver uses the Linux GPIO and interrupt framework to expose a virtual
* GPIO for each outbound entry and a virtual interrupt controller for each
* inbound entry.
+ *
+ * V2 of SMP2P allows remote processors to write to outbound smp2p items before
+ * the full smp2p connection is negotiated. This is important for processors
+ * started before linux runs.
*/
#define SMP2P_MAX_ENTRY 16
@@ -47,11 +51,12 @@
#define SMP2P_MAGIC 0x504d5324
#define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK
+#define MAX_VERSION 2
/**
* struct smp2p_smem_item - in memory communication structure
* @magic: magic number
- * @version: version - must be 1
+ * @version: version
* @features: features flag - currently unused
* @local_pid: processor id of sending end
* @remote_pid: processor id of receiving end
@@ -180,14 +185,22 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p)
{
struct smp2p_smem_item *in = smp2p->in;
+ struct smp2p_entry *entry;
+ bool restart_done;
bool restart;
if (!smp2p->ssr_ack_enabled)
return false;
- restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT);
+ restart_done = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT);
+ restart = restart_done != smp2p->ssr_ack;
+ list_for_each_entry(entry, &smp2p->inbound, node) {
+ if (!entry->value)
+ continue;
+ entry->last_value = 0;
+ }
- return restart != smp2p->ssr_ack;
+ return restart;
}
static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p)
@@ -219,7 +232,57 @@ static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p)
smp2p->negotiation_done = true;
trace_smp2p_negotiate(smp2p->dev, out->features);
+ } else if (in->version && in->version < out->version) {
+ out->version = in->version;
+ qcom_smp2p_kick(smp2p);
+ }
+}
+
+static int qcom_smp2p_in_version(struct qcom_smp2p *smp2p)
+{
+ unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND];
+ unsigned int pid = smp2p->remote_pid;
+ struct smp2p_smem_item *in;
+ size_t size;
+
+ in = qcom_smem_get(pid, smem_id, &size);
+ if (IS_ERR(in))
+ return 0;
+
+ return in->version;
+}
+
+static void qcom_smp2p_start_in(struct qcom_smp2p *smp2p)
+{
+ unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND];
+ unsigned int pid = smp2p->remote_pid;
+ char buf[SMP2P_MAX_ENTRY_NAME];
+ struct smp2p_smem_item *in;
+ struct smp2p_entry *entry;
+ size_t size;
+ int i;
+
+ in = qcom_smem_get(pid, smem_id, &size);
+ if (IS_ERR(in))
+ return;
+
+ smp2p->in = in;
+
+ /* Check if version is initialized by the remote. */
+ if (in->version == 0)
+ return;
+
+ for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
+ list_for_each_entry(entry, &smp2p->inbound, node) {
+ memcpy(buf, in->entries[i].name, sizeof(buf));
+ if (!strcmp(buf, entry->name)) {
+ entry->value = &in->entries[i].value;
+ entry->last_value = readl(entry->value);
+ break;
+ }
+ }
}
+ smp2p->valid_entries = i;
}
static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
@@ -368,12 +431,31 @@ static void smp2p_irq_print_chip(struct irq_data *irqd, struct seq_file *p)
seq_printf(p, "%8s", dev_name(entry->smp2p->dev));
}
+static int smp2p_irq_get_irqchip_state(struct irq_data *irqd, enum irqchip_irq_state which,
+ bool *state)
+{
+ struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
+ u32 val;
+
+ if (which != IRQCHIP_STATE_LINE_LEVEL)
+ return -EINVAL;
+
+ if (!entry->value)
+ return -ENODEV;
+
+ val = readl(entry->value);
+ *state = !!(val & BIT(irqd_to_hwirq(irqd)));
+
+ return 0;
+}
+
static struct irq_chip smp2p_irq_chip = {
.name = "smp2p",
.irq_mask = smp2p_mask_irq,
.irq_unmask = smp2p_unmask_irq,
.irq_set_type = smp2p_set_irq_type,
.irq_print_chip = smp2p_irq_print_chip,
+ .irq_get_irqchip_state = smp2p_irq_get_irqchip_state,
};
static int smp2p_irq_map(struct irq_domain *d,
@@ -464,6 +546,7 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
struct smp2p_smem_item *out;
unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND];
unsigned pid = smp2p->remote_pid;
+ u8 in_version;
int ret;
ret = qcom_smem_alloc(pid, smem_id, sizeof(*out));
@@ -485,12 +568,21 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
out->valid_entries = 0;
out->features = SMP2P_ALL_FEATURES;
+ in_version = qcom_smp2p_in_version(smp2p);
+ if (in_version > MAX_VERSION) {
+ dev_err(smp2p->dev, "Unsupported smp2p version %d\n", in_version);
+ return -EINVAL;
+ }
+
/*
* Make sure the rest of the header is written before we validate the
* item by writing a valid version number.
*/
wmb();
- out->version = 1;
+ if (in_version && in_version <= 2)
+ out->version = in_version;
+ else
+ out->version = 2;
qcom_smp2p_kick(smp2p);
@@ -618,6 +710,9 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
}
}
+ /* Check inbound entries in the case of early boot processor */
+ qcom_smp2p_start_in(smp2p);
+
/* Kick the outgoing edge after allocating entries */
qcom_smp2p_kick(smp2p);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 003a2304d535..8ffd903ebddb 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -182,6 +182,7 @@ static const char *const pmic_models[] = {
[72] = "PMR735D",
[73] = "PM8550",
[74] = "PMK8550",
+ [76] = "PM7550BA",
[78] = "PMM8650AU",
[79] = "PMM8650AU_PSAIL",
[80] = "PM7550",
@@ -473,6 +474,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ5000) },
{ qcom_board_id(IPQ0509) },
{ qcom_board_id(IPQ0518) },
+ { qcom_board_id(SM7450) },
{ qcom_board_id(SM6375) },
{ qcom_board_id(IPQ9514) },
{ qcom_board_id(IPQ9550) },
@@ -488,10 +490,12 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SM8475) },
{ qcom_board_id(SM8475P) },
{ qcom_board_id(SA8255P) },
+ { qcom_board_id(SA8650P) },
{ qcom_board_id(SA8775P) },
{ qcom_board_id(QRU1000) },
{ qcom_board_id(SM8475_2) },
{ qcom_board_id(QDU1000) },
+ { qcom_board_id(SM7450P) },
{ qcom_board_id(X1E80100) },
{ qcom_board_id(SM8650) },
{ qcom_board_id(SM4450) },
@@ -522,6 +526,13 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(QCS8275) },
{ qcom_board_id(QCS9075) },
{ qcom_board_id(QCS615) },
+ { qcom_board_id(CQ7790M) },
+ { qcom_board_id(CQ7790S) },
+ { qcom_board_id(IPQ5200) },
+ { qcom_board_id(IPQ5210) },
+ { qcom_board_id(QCF2200) },
+ { qcom_board_id(QCF3200) },
+ { qcom_board_id(QCF3210) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c
index 1c25aaf55e52..3fe47d8f0f63 100644
--- a/drivers/soc/qcom/ubwc_config.c
+++ b/drivers/soc/qcom/ubwc_config.c
@@ -16,6 +16,17 @@ static const struct qcom_ubwc_cfg_data no_ubwc_data = {
/* no UBWC, no HBB */
};
+static const struct qcom_ubwc_cfg_data eliza_data = {
+ .ubwc_enc_version = UBWC_5_0,
+ .ubwc_dec_version = UBWC_5_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 14 for LP_DDR4 */
+ .highest_bank_bit = 15,
+ .macrotile_mode = true,
+};
+
static const struct qcom_ubwc_cfg_data kaanapali_data = {
.ubwc_enc_version = UBWC_6_0,
.ubwc_dec_version = UBWC_6_0,
@@ -217,22 +228,10 @@ static const struct qcom_ubwc_cfg_data sm8750_data = {
.macrotile_mode = true,
};
-static const struct qcom_ubwc_cfg_data x1e80100_data = {
- .ubwc_enc_version = UBWC_4_0,
- .ubwc_dec_version = UBWC_4_3,
- .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
- UBWC_SWIZZLE_ENABLE_LVL3,
- .ubwc_bank_spread = true,
- /* TODO: highest_bank_bit = 15 for LP_DDR4 */
- .highest_bank_bit = 16,
- .macrotile_mode = true,
-};
-
static const struct qcom_ubwc_cfg_data glymur_data = {
.ubwc_enc_version = UBWC_5_0,
.ubwc_dec_version = UBWC_5_0,
- .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
- UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_swizzle = 0,
.ubwc_bank_spread = true,
/* TODO: highest_bank_bit = 15 for LP_DDR4 */
.highest_bank_bit = 16,
@@ -244,8 +243,10 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = {
{ .compatible = "qcom,apq8026", .data = &no_ubwc_data },
{ .compatible = "qcom,apq8074", .data = &no_ubwc_data },
{ .compatible = "qcom,apq8096", .data = &msm8998_data },
+ { .compatible = "qcom,eliza", .data = &eliza_data, },
{ .compatible = "qcom,kaanapali", .data = &kaanapali_data, },
{ .compatible = "qcom,glymur", .data = &glymur_data},
+ { .compatible = "qcom,mahua", .data = &glymur_data },
{ .compatible = "qcom,msm8226", .data = &no_ubwc_data },
{ .compatible = "qcom,msm8916", .data = &no_ubwc_data },
{ .compatible = "qcom,msm8917", .data = &no_ubwc_data },
@@ -294,8 +295,8 @@ static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = {
{ .compatible = "qcom,sm8550", .data = &sm8550_data, },
{ .compatible = "qcom,sm8650", .data = &sm8550_data, },
{ .compatible = "qcom,sm8750", .data = &sm8750_data, },
- { .compatible = "qcom,x1e80100", .data = &x1e80100_data, },
- { .compatible = "qcom,x1p42100", .data = &x1e80100_data, },
+ { .compatible = "qcom,x1e80100", .data = &sm8550_data, },
+ { .compatible = "qcom,x1p42100", .data = &sm8550_data, },
{ }
};
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
index 62b424e90d90..ffb31a049d4a 100644
--- a/drivers/soc/qcom/wcnss_ctrl.c
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -94,7 +94,7 @@ struct wcnss_download_nv_req {
u16 seq;
u16 last;
u32 frag_size;
- u8 fragment[];
+ u8 fragment[] __counted_by(frag_size);
} __packed;
/**
@@ -201,16 +201,12 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
{
const struct firmware *fw;
struct device *dev = wcnss->dev;
+ struct wcnss_download_nv_req *req;
const char *nvbin = NVBIN_FILE;
const void *data;
ssize_t left;
int ret;
- struct wcnss_download_nv_req *req __free(kfree) = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE,
- GFP_KERNEL);
- if (!req)
- return -ENOMEM;
-
ret = of_property_read_string(dev->of_node, "firmware-name", &nvbin);
if (ret < 0 && ret != -EINVAL)
return ret;
@@ -224,11 +220,15 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
data = fw->data;
left = fw->size;
+ req = kzalloc_flex(*req, fragment, NV_FRAGMENT_SIZE);
+ if (!req)
+ return -ENOMEM;
+
+ req->frag_size = NV_FRAGMENT_SIZE;
req->hdr.type = WCNSS_DOWNLOAD_NV_REQ;
- req->hdr.len = sizeof(*req) + NV_FRAGMENT_SIZE;
+ req->hdr.len = struct_size(req, fragment, NV_FRAGMENT_SIZE);
req->last = 0;
- req->frag_size = NV_FRAGMENT_SIZE;
req->seq = 0;
do {
@@ -264,6 +264,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
release_fw:
release_firmware(fw);
+ kfree(req);
return ret;
}
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 1e50dc7c31cd..26bed0fdceb0 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -390,6 +390,14 @@ config ARCH_R9A08G045
help
This enables support for the Renesas RZ/G3S SoC variants.
+config ARCH_R9A08G046
+ bool "ARM64 Platform support for R9A08G046 (RZ/G3L)"
+ default y if ARCH_RENESAS
+ select ARCH_RZG2L
+ select SYSC_R9A08G046
+ help
+ This enables support for the Renesas RZ/G3L SoC variants.
+
config ARCH_R9A09G011
bool "ARM64 Platform support for R9A09G011 (RZ/V2M)"
default y if ARCH_RENESAS
@@ -474,6 +482,10 @@ config SYSC_R9A08G045
bool "Renesas System controller support for R9A08G045 (RZ/G3S)" if COMPILE_TEST
select SYSC_RZ
+config SYSC_R9A08G046
+ bool "Renesas System controller support for R9A08G046 (RZ/G3L)" if COMPILE_TEST
+ select SYSC_RZ
+
config SYS_R9A09G047
bool "Renesas System controller support for R9A09G047 (RZ/G3E)" if COMPILE_TEST
select SYSC_RZ
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 33d44d964d61..655dbcb08747 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -7,6 +7,7 @@ ifdef CONFIG_SMP
obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
endif
obj-$(CONFIG_SYSC_R9A08G045) += r9a08g045-sysc.o
+obj-$(CONFIG_SYSC_R9A08G046) += r9a08g046-sysc.o
obj-$(CONFIG_SYS_R9A09G047) += r9a09g047-sys.o
obj-$(CONFIG_SYS_R9A09G056) += r9a09g056-sys.o
obj-$(CONFIG_SYS_R9A09G057) += r9a09g057-sys.o
diff --git a/drivers/soc/renesas/r9a08g046-sysc.c b/drivers/soc/renesas/r9a08g046-sysc.c
new file mode 100644
index 000000000000..fd98df196d0a
--- /dev/null
+++ b/drivers/soc/renesas/r9a08g046-sysc.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3L System controller (SYSC) driver
+ *
+ * Copyright (C) 2026 Renesas Electronics Corp.
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include "rz-sysc.h"
+
+#define SYS_XSPI_MAP_STAADD_CS0 0x348
+#define SYS_XSPI_MAP_ENDADD_CS0 0x34c
+#define SYS_XSPI_MAP_STAADD_CS1 0x350
+#define SYS_XSPI_MAP_ENDADD_CS1 0x354
+#define SYS_GETH0_CFG 0x380
+#define SYS_GETH1_CFG 0x390
+#define SYS_PCIE_CFG 0x3a0
+#define SYS_PCIE_MON 0x3a4
+#define SYS_PCIE_PHY 0x3b4
+#define SYS_I2C0_CFG 0x400
+#define SYS_I2C1_CFG 0x410
+#define SYS_I2C2_CFG 0x420
+#define SYS_I2C3_CFG 0x430
+#define SYS_I3C_CFG 0x440
+#define SYS_PWRRDY_N 0xd70
+#define SYS_IPCONT_SEL_CLONECH 0xe2c
+
+static bool rzg3l_regmap_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_XSPI_MAP_STAADD_CS0:
+ case SYS_XSPI_MAP_ENDADD_CS0:
+ case SYS_XSPI_MAP_STAADD_CS1:
+ case SYS_XSPI_MAP_ENDADD_CS1:
+ case SYS_GETH0_CFG:
+ case SYS_GETH1_CFG:
+ case SYS_PCIE_CFG:
+ case SYS_PCIE_MON:
+ case SYS_PCIE_PHY:
+ case SYS_I2C0_CFG:
+ case SYS_I2C1_CFG:
+ case SYS_I2C2_CFG:
+ case SYS_I2C3_CFG:
+ case SYS_I3C_CFG:
+ case SYS_PWRRDY_N:
+ case SYS_IPCONT_SEL_CLONECH:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rzg3l_regmap_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SYS_XSPI_MAP_STAADD_CS0:
+ case SYS_XSPI_MAP_ENDADD_CS0:
+ case SYS_XSPI_MAP_STAADD_CS1:
+ case SYS_XSPI_MAP_ENDADD_CS1:
+ case SYS_PCIE_CFG:
+ case SYS_PCIE_PHY:
+ case SYS_I2C0_CFG:
+ case SYS_I2C1_CFG:
+ case SYS_I2C2_CFG:
+ case SYS_I2C3_CFG:
+ case SYS_I3C_CFG:
+ case SYS_PWRRDY_N:
+ case SYS_IPCONT_SEL_CLONECH:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct rz_sysc_soc_id_init_data rzg3l_sysc_soc_id_init_data __initconst = {
+ .family = "RZ/G3L",
+ .id = 0x87d9447,
+ .devid_offset = 0xa04,
+ .revision_mask = GENMASK(31, 28),
+ .specific_id_mask = GENMASK(27, 0),
+};
+
+const struct rz_sysc_init_data rzg3l_sysc_init_data __initconst = {
+ .soc_id_init_data = &rzg3l_sysc_soc_id_init_data,
+ .readable_reg = rzg3l_regmap_readable_reg,
+ .writeable_reg = rzg3l_regmap_writeable_reg,
+ .max_register = 0xe2c,
+};
diff --git a/drivers/soc/renesas/r9a09g047-sys.c b/drivers/soc/renesas/r9a09g047-sys.c
index e413b0eff9bf..ea3ca10fcc33 100644
--- a/drivers/soc/renesas/r9a09g047-sys.c
+++ b/drivers/soc/renesas/r9a09g047-sys.c
@@ -139,7 +139,7 @@ static bool rzg3e_regmap_writeable_reg(struct device *dev, unsigned int reg)
}
}
-const struct rz_sysc_init_data rzg3e_sys_init_data = {
+const struct rz_sysc_init_data rzg3e_sys_init_data __initconst = {
.soc_id_init_data = &rzg3e_sys_soc_id_init_data,
.readable_reg = rzg3e_regmap_readable_reg,
.writeable_reg = rzg3e_regmap_writeable_reg,
diff --git a/drivers/soc/renesas/r9a09g056-sys.c b/drivers/soc/renesas/r9a09g056-sys.c
index 42f5eff291fd..2a8ebc209961 100644
--- a/drivers/soc/renesas/r9a09g056-sys.c
+++ b/drivers/soc/renesas/r9a09g056-sys.c
@@ -136,7 +136,7 @@ static bool rzv2n_regmap_writeable_reg(struct device *dev, unsigned int reg)
}
}
-const struct rz_sysc_init_data rzv2n_sys_init_data = {
+const struct rz_sysc_init_data rzv2n_sys_init_data __initconst = {
.soc_id_init_data = &rzv2n_sys_soc_id_init_data,
.readable_reg = rzv2n_regmap_readable_reg,
.writeable_reg = rzv2n_regmap_writeable_reg,
diff --git a/drivers/soc/renesas/r9a09g057-sys.c b/drivers/soc/renesas/r9a09g057-sys.c
index 827c718ac7c5..f3e054206acb 100644
--- a/drivers/soc/renesas/r9a09g057-sys.c
+++ b/drivers/soc/renesas/r9a09g057-sys.c
@@ -161,7 +161,7 @@ static bool rzv2h_regmap_writeable_reg(struct device *dev, unsigned int reg)
}
}
-const struct rz_sysc_init_data rzv2h_sys_init_data = {
+const struct rz_sysc_init_data rzv2h_sys_init_data __initconst = {
.soc_id_init_data = &rzv2h_sys_soc_id_init_data,
.readable_reg = rzv2h_regmap_readable_reg,
.writeable_reg = rzv2h_regmap_writeable_reg,
diff --git a/drivers/soc/renesas/rz-sysc.c b/drivers/soc/renesas/rz-sysc.c
index 7471dc8736e6..161e8c38eea6 100644
--- a/drivers/soc/renesas/rz-sysc.c
+++ b/drivers/soc/renesas/rz-sysc.c
@@ -88,6 +88,9 @@ static const struct of_device_id rz_sysc_match[] = {
#ifdef CONFIG_SYSC_R9A08G045
{ .compatible = "renesas,r9a08g045-sysc", .data = &rzg3s_sysc_init_data },
#endif
+#ifdef CONFIG_SYSC_R9A08G046
+ { .compatible = "renesas,r9a08g046-sysc", .data = &rzg3l_sysc_init_data },
+#endif
#ifdef CONFIG_SYS_R9A09G047
{ .compatible = "renesas,r9a09g047-sys", .data = &rzg3e_sys_init_data },
#endif
diff --git a/drivers/soc/renesas/rz-sysc.h b/drivers/soc/renesas/rz-sysc.h
index 88929bf21cb1..921ee0d26c47 100644
--- a/drivers/soc/renesas/rz-sysc.h
+++ b/drivers/soc/renesas/rz-sysc.h
@@ -46,6 +46,7 @@ struct rz_sysc_init_data {
};
extern const struct rz_sysc_init_data rzg3e_sys_init_data;
+extern const struct rz_sysc_init_data rzg3l_sysc_init_data;
extern const struct rz_sysc_init_data rzg3s_sysc_init_data;
extern const struct rz_sysc_init_data rzv2h_sys_init_data;
extern const struct rz_sysc_init_data rzv2n_sys_init_data;
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index c0fc54c3cd35..073346c1542b 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -6,6 +6,7 @@ if ARM
config ARCH_TEGRA_2x_SOC
bool "Enable support for Tegra20 family"
+ default ARCH_TEGRA
select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
select ARM_ERRATA_720789
select ARM_ERRATA_754327 if SMP
@@ -23,6 +24,7 @@ config ARCH_TEGRA_2x_SOC
config ARCH_TEGRA_3x_SOC
bool "Enable support for Tegra30 family"
+ default ARCH_TEGRA
select ARM_ERRATA_754322
select ARM_ERRATA_764369 if SMP
select PINCTRL_TEGRA30
@@ -37,6 +39,7 @@ config ARCH_TEGRA_3x_SOC
config ARCH_TEGRA_114_SOC
bool "Enable support for Tegra114 family"
+ default ARCH_TEGRA
select ARM_ERRATA_798181 if SMP
select HAVE_ARM_ARCH_TIMER
select PINCTRL_TEGRA114
@@ -49,6 +52,7 @@ config ARCH_TEGRA_114_SOC
config ARCH_TEGRA_124_SOC
bool "Enable support for Tegra124 family"
+ default ARCH_TEGRA
select HAVE_ARM_ARCH_TIMER
select PINCTRL_TEGRA124
select SOC_TEGRA_FLOWCTRL
@@ -65,6 +69,7 @@ if ARM64
config ARCH_TEGRA_132_SOC
bool "NVIDIA Tegra132 SoC"
+ default ARCH_TEGRA
select PINCTRL_TEGRA124
select SOC_TEGRA_FLOWCTRL
select SOC_TEGRA_PMC
@@ -76,6 +81,7 @@ config ARCH_TEGRA_132_SOC
config ARCH_TEGRA_210_SOC
bool "NVIDIA Tegra210 SoC"
+ default ARCH_TEGRA
select PINCTRL_TEGRA210
select SOC_TEGRA_FLOWCTRL
select SOC_TEGRA_PMC
@@ -95,6 +101,7 @@ config ARCH_TEGRA_210_SOC
config ARCH_TEGRA_186_SOC
bool "NVIDIA Tegra186 SoC"
+ default ARCH_TEGRA
depends on !CPU_BIG_ENDIAN
select PINCTRL_TEGRA186
select MAILBOX
@@ -109,6 +116,7 @@ config ARCH_TEGRA_186_SOC
config ARCH_TEGRA_194_SOC
bool "NVIDIA Tegra194 SoC"
+ default ARCH_TEGRA
depends on !CPU_BIG_ENDIAN
select MAILBOX
select PINCTRL_TEGRA194
@@ -118,6 +126,7 @@ config ARCH_TEGRA_194_SOC
config ARCH_TEGRA_234_SOC
bool "NVIDIA Tegra234 SoC"
+ default ARCH_TEGRA
depends on !CPU_BIG_ENDIAN
select MAILBOX
select PINCTRL_TEGRA234
@@ -125,13 +134,24 @@ config ARCH_TEGRA_234_SOC
help
Enable support for the NVIDIA Tegra234 SoC.
+config ARCH_TEGRA_238_SOC
+ bool "NVIDIA Tegra238 SoC"
+ default ARCH_TEGRA
+ depends on !CPU_BIG_ENDIAN
+ select MAILBOX
+ select SOC_TEGRA_PMC
+ help
+ Enable support for the NVIDIA Tegra238 SoC.
+
config ARCH_TEGRA_241_SOC
bool "NVIDIA Tegra241 SoC"
+ default ARCH_TEGRA
help
Enable support for the NVIDIA Tegra241 SoC.
config ARCH_TEGRA_264_SOC
bool "NVIDIA Tegra264 SoC"
+ default ARCH_TEGRA
depends on !CPU_BIG_ENDIAN
select MAILBOX
select SOC_TEGRA_PMC
diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c
index a9adbcecd47c..fb26f085f691 100644
--- a/drivers/soc/tegra/cbb/tegra234-cbb.c
+++ b/drivers/soc/tegra/cbb/tegra234-cbb.c
@@ -89,6 +89,15 @@ enum tegra234_cbb_fabric_ids {
T234_MAX_FABRIC_ID,
};
+enum tegra238_cbb_fabric_ids {
+ T238_CBB_FABRIC_ID = 0,
+ T238_AON_FABRIC_ID = 4,
+ T238_PSC_FABRIC_ID = 5,
+ T238_BPMP_FABRIC_ID = 6,
+ T238_APE_FABRIC_ID = 7,
+ T238_MAX_FABRIC_ID,
+};
+
enum tegra264_cbb_fabric_ids {
T264_SYSTEM_CBB_FABRIC_ID,
T264_TOP_0_CBB_FABRIC_ID,
@@ -313,12 +322,37 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target
}
}
+static struct tegra234_cbb *tegra234_cbb_get_fabric(u8 fab_id)
+{
+ struct tegra_cbb *entry;
+
+ list_for_each_entry(entry, &cbb_list, node) {
+ struct tegra234_cbb *priv = to_tegra234_cbb(entry);
+
+ if (priv->fabric->fab_id == fab_id)
+ return priv;
+ }
+
+ return NULL;
+}
+
static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
u8 target_id, u8 fab_id)
{
const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map;
+ struct tegra234_cbb *target_cbb = NULL;
void __iomem *addr;
+ if (fab_id == cbb->fabric->fab_id)
+ target_cbb = cbb;
+ else
+ target_cbb = tegra234_cbb_get_fabric(fab_id);
+
+ if (!target_cbb) {
+ dev_err(cbb->base.dev, "could not find fabric for fab_id:%d\n", fab_id);
+ return;
+ }
+
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;
@@ -341,7 +375,7 @@ static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegr
* e) Goto step-a till all bits are set.
*/
- addr = cbb->regs + map[target_id].offset;
+ addr = target_cbb->regs + map[target_id].offset;
if (strstr(map[target_id].name, "AXI2APB")) {
addr += APB_BLOCK_TMO_STATUS_0;
@@ -881,7 +915,7 @@ static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = {
ARRAY_SIZE(tegra234_common_target_map) },
[T234_AON_FABRIC_ID] = { "aon-fabric", true,
tegra234_aon_target_map,
- ARRAY_SIZE(tegra234_bpmp_target_map) },
+ ARRAY_SIZE(tegra234_aon_target_map) },
[T234_PSC_FABRIC_ID] = { "psc-fabric" },
[T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
tegra234_bpmp_target_map,
@@ -974,6 +1008,127 @@ static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
.firewall_wr_ctl = 0x288,
};
+static const struct tegra234_target_lookup tegra238_ape_target_map[] = {
+ { "AXI2APB", 0x00000 },
+ { "AGIC", 0x15000 },
+ { "AMC", 0x16000 },
+ { "AST0", 0x17000 },
+ { "AST1", 0x18000 },
+ { "AST2", 0x19000 },
+ { "CBB", 0x1A000 },
+};
+
+static const struct tegra234_target_lookup tegra238_cbb_target_map[] = {
+ { "AON", 0x40000 },
+ { "APE", 0x50000 },
+ { "BPMP", 0x41000 },
+ { "HOST1X", 0x43000 },
+ { "STM", 0x44000 },
+ { "CBB_CENTRAL", 0x00000 },
+ { "PCIE_C0", 0x51000 },
+ { "PCIE_C1", 0x47000 },
+ { "PCIE_C2", 0x48000 },
+ { "PCIE_C3", 0x49000 },
+ { "GPU", 0x4C000 },
+ { "SMMU0", 0x4D000 },
+ { "SMMU1", 0x4E000 },
+ { "SMMU2", 0x4F000 },
+ { "PSC", 0x52000 },
+ { "AXI2APB_1", 0x70000 },
+ { "AXI2APB_12", 0x73000 },
+ { "AXI2APB_13", 0x74000 },
+ { "AXI2APB_15", 0x76000 },
+ { "AXI2APB_16", 0x77000 },
+ { "AXI2APB_18", 0x79000 },
+ { "AXI2APB_19", 0x7A000 },
+ { "AXI2APB_2", 0x7B000 },
+ { "AXI2APB_23", 0x7F000 },
+ { "AXI2APB_25", 0x80000 },
+ { "AXI2APB_26", 0x81000 },
+ { "AXI2APB_27", 0x82000 },
+ { "AXI2APB_28", 0x83000 },
+ { "AXI2APB_32", 0x87000 },
+ { "AXI2APB_33", 0x88000 },
+ { "AXI2APB_4", 0x8B000 },
+ { "AXI2APB_5", 0x8C000 },
+ { "AXI2APB_6", 0x93000 },
+ { "AXI2APB_9", 0x90000 },
+ { "AXI2APB_3", 0x91000 },
+};
+
+static const struct tegra234_fabric_lookup tegra238_cbb_fab_list[] = {
+ [T238_CBB_FABRIC_ID] = { "cbb-fabric", true,
+ tegra238_cbb_target_map,
+ ARRAY_SIZE(tegra238_cbb_target_map) },
+ [T238_AON_FABRIC_ID] = { "aon-fabric", true,
+ tegra234_aon_target_map,
+ ARRAY_SIZE(tegra234_aon_target_map) },
+ [T238_PSC_FABRIC_ID] = { "psc-fabric" },
+ [T238_BPMP_FABRIC_ID] = { "bpmp-fabric", true,
+ tegra234_bpmp_target_map,
+ ARRAY_SIZE(tegra234_bpmp_target_map) },
+ [T238_APE_FABRIC_ID] = { "ape-fabric", true,
+ tegra238_ape_target_map,
+ ARRAY_SIZE(tegra238_ape_target_map) },
+};
+
+static const struct tegra234_cbb_fabric tegra238_aon_fabric = {
+ .fab_id = T238_AON_FABRIC_ID,
+ .fab_list = tegra238_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 = 0x8f0,
+ .firewall_wr_ctl = 0x8e8,
+};
+
+static const struct tegra234_cbb_fabric tegra238_ape_fabric = {
+ .fab_id = T238_APE_FABRIC_ID,
+ .fab_list = tegra238_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 = 0x1E000,
+ .firewall_base = 0x30000,
+ .firewall_ctl = 0xad0,
+ .firewall_wr_ctl = 0xac8,
+};
+
+static const struct tegra234_cbb_fabric tegra238_bpmp_fabric = {
+ .fab_id = T238_BPMP_FABRIC_ID,
+ .fab_list = tegra238_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 tegra238_cbb_fabric = {
+ .fab_id = T238_CBB_FABRIC_ID,
+ .fab_list = tegra238_cbb_fab_list,
+ .initiator_id = tegra234_initiator_id,
+ .errors = tegra234_cbb_errors,
+ .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
+ .err_intr_enbl = 0x3f,
+ .err_status_clr = 0x3f,
+ .notifier_offset = 0x60000,
+ .off_mask_erd = 0x3d004,
+ .firewall_base = 0x10000,
+ .firewall_ctl = 0x2230,
+ .firewall_wr_ctl = 0x2228,
+};
+
static const char * const tegra241_initiator_id[] = {
[0x0] = "TZ",
[0x1] = "CCPLEX",
@@ -1160,7 +1315,7 @@ 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) },
+ tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_bpmp_target_map) },
};
static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
.fab_id = T234_CBB_FABRIC_ID,
@@ -1480,6 +1635,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,tegra238-aon-fabric", .data = &tegra238_aon_fabric },
+ { .compatible = "nvidia,tegra238-ape-fabric", .data = &tegra238_ape_fabric },
+ { .compatible = "nvidia,tegra238-bpmp-fabric", .data = &tegra238_bpmp_fabric },
+ { .compatible = "nvidia,tegra238-cbb-fabric", .data = &tegra238_cbb_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 },
@@ -1586,6 +1745,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev)
{
struct tegra234_cbb *cbb = dev_get_drvdata(dev);
+ /* set ERD bit to mask SError and generate interrupt to report error */
+ if (cbb->fabric->off_mask_erd)
+ tegra234_cbb_mask_serror(cbb);
+
tegra234_cbb_error_enable(&cbb->base);
dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name);
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
index d82b7670abb7..0864eb0185b4 100644
--- a/drivers/soc/tegra/common.c
+++ b/drivers/soc/tegra/common.c
@@ -118,7 +118,8 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev,
hw_version = BIT(tegra_sku_info.soc_process_id);
config.supported_hw = &hw_version;
config.supported_hw_count = 1;
- } else if (of_machine_is_compatible("nvidia,tegra30")) {
+ } else if (of_machine_is_compatible("nvidia,tegra30") ||
+ of_machine_is_compatible("nvidia,tegra114")) {
hw_version = BIT(tegra_sku_info.soc_speedo_id);
config.supported_hw = &hw_version;
config.supported_hw_count = 1;
@@ -131,7 +132,7 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev,
}
/*
- * Tegra114+ doesn't support OPP yet, return early for non tegra20/30
+ * Tegra124+ doesn't support OPP yet, return early for pre-Tegra124
* case.
*/
if (!config.supported_hw)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a1a2966512d1..2ee6539d796a 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -60,6 +60,7 @@
#include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/gpio/tegra194-gpio.h>
#include <dt-bindings/gpio/tegra234-gpio.h>
+#include <dt-bindings/gpio/nvidia,tegra264-gpio.h>
#include <dt-bindings/soc/tegra-pmc.h>
#define PMC_CNTRL 0x0
@@ -180,19 +181,18 @@
#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))
-#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2))
-#define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2))
-#define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2))
-#define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2))
-#define WAKE_AOWAKE_SW_STATUS_W_0 0x49c
-#define WAKE_AOWAKE_SW_STATUS(x) (0x4a0 + ((x) << 2))
-#define WAKE_LATCH_SW 0x498
-
-#define WAKE_AOWAKE_CTRL 0x4f4
-#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
+#define WAKE_AOWAKE_MASK_W(_pmc, x) \
+ ((_pmc)->soc->regs->aowake_mask_w + ((x) << 2))
+#define WAKE_AOWAKE_STATUS_W(_pmc, x) \
+ ((_pmc)->soc->regs->aowake_status_w + ((x) << 2))
+#define WAKE_AOWAKE_STATUS_R(_pmc, x) \
+ ((_pmc)->soc->regs->aowake_status_r + ((x) << 2))
+#define WAKE_AOWAKE_TIER2_ROUTING(_pmc, x) \
+ ((_pmc)->soc->regs->aowake_tier2_routing + ((x) << 2))
+#define WAKE_AOWAKE_SW_STATUS(_pmc, x) \
+ ((_pmc)->soc->regs->aowake_sw_status + ((x) << 2))
+
+#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
#define SW_WAKE_ID 83 /* wake83 */
@@ -201,6 +201,9 @@
#define TEGRA_SMC_PMC_READ 0xaa
#define TEGRA_SMC_PMC_WRITE 0xbb
+/* Tegra264 and later */
+#define PMC_IMPL_SDMMC1_HV_PADCTL_0 0x41004
+
struct pmc_clk {
struct clk_hw hw;
struct tegra_pmc *pmc;
@@ -294,10 +297,16 @@ struct tegra_io_pad_soc {
unsigned int dpd;
unsigned int request;
unsigned int status;
- unsigned int voltage;
const char *name;
};
+struct tegra_io_pad_vctrl {
+ enum tegra_io_pad id;
+ unsigned int offset;
+ unsigned int ena_3v3;
+ unsigned int ena_1v8;
+};
+
struct tegra_pmc_regs {
unsigned int scratch0;
unsigned int rst_status;
@@ -305,6 +314,14 @@ struct tegra_pmc_regs {
unsigned int rst_source_mask;
unsigned int rst_level_shift;
unsigned int rst_level_mask;
+ unsigned int aowake_mask_w;
+ unsigned int aowake_status_w;
+ unsigned int aowake_status_r;
+ unsigned int aowake_tier2_routing;
+ unsigned int aowake_sw_status_w;
+ unsigned int aowake_sw_status;
+ unsigned int aowake_latch_sw;
+ unsigned int aowake_ctrl;
};
struct tegra_wake_event {
@@ -359,11 +376,13 @@ struct tegra_pmc_soc {
bool has_tsense_reset;
bool has_gpu_clamps;
bool needs_mbist_war;
- bool has_impl_33v_pwr;
+ bool has_io_pad_wren;
bool maybe_tz_only;
const struct tegra_io_pad_soc *io_pads;
unsigned int num_io_pads;
+ const struct tegra_io_pad_vctrl *io_pad_vctrls;
+ unsigned int num_io_pad_vctrls;
const struct pinctrl_pin_desc *pin_descs;
unsigned int num_pin_descs;
@@ -437,7 +456,10 @@ struct tegra_pmc_soc {
* @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.
+ * @reboot_notifier: PMC reboot notifier handler
* @syscore: syscore suspend/resume callbacks
+ * @wake_work: IRQ work handler for processing wake-up events.
+ * @wake_status: Status of wake-up events.
*/
struct tegra_pmc {
struct device *dev;
@@ -1004,7 +1026,7 @@ static struct tegra_pmc *tegra_pmc_get(struct device *dev)
}
/**
- * tegra_pmc_get() - find the PMC for a given device
+ * devm_tegra_pmc_get() - find the PMC for a given device
* @dev: device for which to find the PMC
*
* Returns a pointer to the PMC on success or an ERR_PTR()-encoded error code
@@ -1688,6 +1710,18 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
return NULL;
}
+static const struct tegra_io_pad_vctrl *
+tegra_io_pad_vctrl_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
+{
+ unsigned int i;
+
+ for (i = 0; i < pmc->soc->num_io_pad_vctrls; i++)
+ if (pmc->soc->io_pad_vctrls[i].id == id)
+ return &pmc->soc->io_pad_vctrls[i];
+
+ return NULL;
+}
+
static int tegra_io_pad_prepare(struct tegra_pmc *pmc,
const struct tegra_io_pad_soc *pad,
unsigned long *request,
@@ -1746,7 +1780,7 @@ static void tegra_io_pad_unprepare(struct tegra_pmc *pmc)
}
/**
- * tegra_io_pad_power_enable() - enable power to I/O pad
+ * tegra_pmc_io_pad_power_enable() - enable power to I/O pad
* @pmc: power management controller
* @id: Tegra I/O pad ID for which to enable power
*
@@ -1883,44 +1917,38 @@ static int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id)
static int tegra_io_pad_set_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id,
int voltage)
{
- const struct tegra_io_pad_soc *pad;
+ const struct tegra_io_pad_vctrl *pad;
u32 value;
- pad = tegra_io_pad_find(pmc, id);
+ pad = tegra_io_pad_vctrl_find(pmc, id);
if (!pad)
return -ENOENT;
- if (pad->voltage == UINT_MAX)
- return -ENOTSUPP;
-
mutex_lock(&pmc->powergates_lock);
- if (pmc->soc->has_impl_33v_pwr) {
- value = tegra_pmc_readl(pmc, PMC_IMPL_E_33V_PWR);
-
- if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
- value &= ~BIT(pad->voltage);
- else
- value |= BIT(pad->voltage);
-
- tegra_pmc_writel(pmc, value, PMC_IMPL_E_33V_PWR);
- } else {
- /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
+ if (pmc->soc->has_io_pad_wren) {
+ /* write-enable PMC_PWR_DET_VALUE[pad->ena_3v3] */
value = tegra_pmc_readl(pmc, PMC_PWR_DET);
- value |= BIT(pad->voltage);
+ value |= BIT(pad->ena_3v3);
tegra_pmc_writel(pmc, value, PMC_PWR_DET);
+ }
- /* update I/O voltage */
- value = tegra_pmc_readl(pmc, PMC_PWR_DET_VALUE);
+ value = tegra_pmc_readl(pmc, pad->offset);
- if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
- value &= ~BIT(pad->voltage);
- else
- value |= BIT(pad->voltage);
+ if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8) {
+ value &= ~BIT(pad->ena_3v3);
- tegra_pmc_writel(pmc, value, PMC_PWR_DET_VALUE);
+ if (pad->ena_1v8)
+ value |= pad->ena_1v8;
+ } else {
+ value |= BIT(pad->ena_3v3);
+
+ if (pad->ena_1v8)
+ value &= ~pad->ena_1v8;
}
+ tegra_pmc_writel(pmc, value, pad->offset);
+
mutex_unlock(&pmc->powergates_lock);
usleep_range(100, 250);
@@ -1930,22 +1958,16 @@ static int tegra_io_pad_set_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id,
static int tegra_io_pad_get_voltage(struct tegra_pmc *pmc, enum tegra_io_pad id)
{
- const struct tegra_io_pad_soc *pad;
+ const struct tegra_io_pad_vctrl *pad;
u32 value;
- pad = tegra_io_pad_find(pmc, id);
+ pad = tegra_io_pad_vctrl_find(pmc, id);
if (!pad)
return -ENOENT;
- if (pad->voltage == UINT_MAX)
- return -ENOTSUPP;
-
- if (pmc->soc->has_impl_33v_pwr)
- value = tegra_pmc_readl(pmc, PMC_IMPL_E_33V_PWR);
- else
- value = tegra_pmc_readl(pmc, PMC_PWR_DET_VALUE);
+ value = tegra_pmc_readl(pmc, pad->offset);
- if ((value & BIT(pad->voltage)) == 0)
+ if ((value & BIT(pad->ena_3v3)) == 0)
return TEGRA_IO_PAD_VOLTAGE_1V8;
return TEGRA_IO_PAD_VOLTAGE_3V3;
@@ -2629,20 +2651,20 @@ static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
bit = data->hwirq % 32;
/* clear wake status */
- writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq));
+ writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(pmc, data->hwirq));
/* route wake to tier 2 */
- value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset));
+ value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(pmc, offset));
if (!on)
value &= ~(1 << bit);
else
value |= 1 << bit;
- writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset));
+ writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(pmc, offset));
/* enable wakeup event */
- writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq));
+ writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(pmc, data->hwirq));
return 0;
}
@@ -3309,7 +3331,7 @@ static void wke_write_wake_levels(struct tegra_pmc *pmc)
static void wke_clear_sw_wake_status(struct tegra_pmc *pmc)
{
- wke_32kwritel(pmc, 1, WAKE_AOWAKE_SW_STATUS_W_0);
+ wke_32kwritel(pmc, 1, pmc->soc->regs->aowake_sw_status_w);
}
static void wke_read_sw_wake_status(struct tegra_pmc *pmc)
@@ -3322,7 +3344,7 @@ static void wke_read_sw_wake_status(struct tegra_pmc *pmc)
wke_clear_sw_wake_status(pmc);
- wke_32kwritel(pmc, 1, WAKE_LATCH_SW);
+ wke_32kwritel(pmc, 1, pmc->soc->regs->aowake_latch_sw);
/*
* WAKE_AOWAKE_SW_STATUS is edge triggered, so in order to
@@ -3340,12 +3362,12 @@ static void wke_read_sw_wake_status(struct tegra_pmc *pmc)
*/
udelay(300);
- wke_32kwritel(pmc, 0, WAKE_LATCH_SW);
+ wke_32kwritel(pmc, 0, pmc->soc->regs->aowake_latch_sw);
bitmap_zero(pmc->wake_sw_status_map, pmc->soc->max_wake_events);
for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
- status = readl(pmc->wake + WAKE_AOWAKE_SW_STATUS(i));
+ status = readl(pmc->wake + WAKE_AOWAKE_SW_STATUS(pmc, i));
for_each_set_bit(wake, &status, 32)
set_bit(wake + (i * 32), pmc->wake_sw_status_map);
@@ -3359,11 +3381,12 @@ static void wke_clear_wake_status(struct tegra_pmc *pmc)
u32 mask;
for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
- mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
- status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
+ mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(pmc, i));
+ status = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(pmc, i)) & mask;
for_each_set_bit(wake, &status, 32)
- wke_32kwritel(pmc, 0x1, WAKE_AOWAKE_STATUS_W((i * 32) + wake));
+ wke_32kwritel(pmc, 0x1, WAKE_AOWAKE_STATUS_W(pmc,
+ (i * 32) + wake));
}
}
@@ -3374,8 +3397,9 @@ static void tegra186_pmc_wake_syscore_resume(void *data)
u32 mask;
for (i = 0; i < pmc->soc->max_wake_vectors; i++) {
- mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(i));
- pmc->wake_status[i] = readl(pmc->wake + WAKE_AOWAKE_STATUS_R(i)) & mask;
+ mask = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(pmc, i));
+ pmc->wake_status[i] = readl(pmc->wake +
+ WAKE_AOWAKE_STATUS_R(pmc, i)) & mask;
}
/* Schedule IRQ work to process wake IRQs (if any) */
@@ -3523,7 +3547,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.has_tsense_reset = false,
.has_gpu_clamps = false,
.needs_mbist_war = false,
- .has_impl_33v_pwr = false,
+ .has_io_pad_wren = true,
.maybe_tz_only = false,
.num_io_pads = 0,
.io_pads = NULL,
@@ -3585,7 +3609,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.has_tsense_reset = true,
.has_gpu_clamps = false,
.needs_mbist_war = false,
- .has_impl_33v_pwr = false,
+ .has_io_pad_wren = true,
.maybe_tz_only = false,
.num_io_pads = 0,
.io_pads = NULL,
@@ -3635,7 +3659,7 @@ static const u8 tegra114_cpu_powergates[] = {
};
static const struct tegra_pmc_soc tegra114_pmc_soc = {
- .supports_core_domain = false,
+ .supports_core_domain = true,
.num_powergates = ARRAY_SIZE(tegra114_powergates),
.powergates = tegra114_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
@@ -3643,7 +3667,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.has_tsense_reset = true,
.has_gpu_clamps = false,
.needs_mbist_war = false,
- .has_impl_33v_pwr = false,
+ .has_io_pad_wren = true,
.maybe_tz_only = false,
.num_io_pads = 0,
.io_pads = NULL,
@@ -3697,16 +3721,23 @@ static const u8 tegra124_cpu_powergates[] = {
TEGRA_POWERGATE_CPU3,
};
-#define TEGRA_IO_PAD(_id, _dpd, _request, _status, _voltage, _name) \
+#define TEGRA_IO_PAD(_id, _dpd, _request, _status, _name) \
((struct tegra_io_pad_soc) { \
.id = (_id), \
.dpd = (_dpd), \
.request = (_request), \
.status = (_status), \
- .voltage = (_voltage), \
.name = (_name), \
})
+#define TEGRA_IO_PAD_VCTRL(_id, _offset, _ena_3v3) \
+ ((struct tegra_io_pad_vctrl) { \
+ .id = (_id), \
+ .offset = (_offset), \
+ .ena_3v3 = (_ena_3v3), \
+ .ena_1v8 = 0, \
+ })
+
#define TEGRA_IO_PIN_DESC(_id, _name) \
((struct pinctrl_pin_desc) { \
.number = (_id), \
@@ -3714,36 +3745,36 @@ static const u8 tegra124_cpu_powergates[] = {
})
static const struct tegra_io_pad_soc tegra124_io_pads[] = {
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, UINT_MAX, "audio"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_BB, 15, 0x1b8, 0x1bc, UINT_MAX, "bb"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, UINT_MAX, "cam"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_COMP, 22, 0x1b8, 0x1bc, UINT_MAX, "comp"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HV, 6, 0x1c0, 0x1c4, UINT_MAX, "hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_NAND, 13, 0x1b8, 0x1bc, UINT_MAX, "nand"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x1c0, 0x1c4, UINT_MAX, "pex-cntrl"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, UINT_MAX, "sdmmc1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, UINT_MAX, "sdmmc3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 3, 0x1c0, 0x1c4, UINT_MAX, "sdmmc4"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SYS_DDC, 26, 0x1c0, 0x1c4, UINT_MAX, "sys_ddc"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, UINT_MAX, "uart"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb_bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_BB, 15, 0x1b8, 0x1bc, "bb"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_COMP, 22, 0x1b8, 0x1bc, "comp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, "dsi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, "dsib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, "dsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, "dsid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, "hdmi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, "hsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HV, 6, 0x1c0, 0x1c4, "hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, "lvds"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_NAND, 13, 0x1b8, 0x1bc, "nand"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, "pex-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x1c0, 0x1c4, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, "sdmmc1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, "sdmmc3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 3, 0x1c0, 0x1c4, "sdmmc4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SYS_DDC, 26, 0x1c0, 0x1c4, "sys_ddc"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, "usb0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, "usb1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, "usb2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, "usb_bias"),
};
static const struct pinctrl_pin_desc tegra124_pin_descs[] = {
@@ -3788,7 +3819,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.has_tsense_reset = true,
.has_gpu_clamps = true,
.needs_mbist_war = false,
- .has_impl_33v_pwr = false,
+ .has_io_pad_wren = true,
.maybe_tz_only = false,
.num_io_pads = ARRAY_SIZE(tegra124_io_pads),
.io_pads = tegra124_io_pads,
@@ -3844,46 +3875,60 @@ static const u8 tegra210_cpu_powergates[] = {
};
static const struct tegra_io_pad_soc tegra210_io_pads[] = {
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, 5, "audio"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x1c0, 0x1c4, 18, "audio-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, 10, "cam"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, UINT_MAX, "csia"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, UINT_MAX, "csib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 10, 0x1c0, 0x1c4, UINT_MAX, "csic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 11, 0x1c0, 0x1c4, UINT_MAX, "csid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, UINT_MAX, "csie"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 13, 0x1c0, 0x1c4, UINT_MAX, "csif"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x1b8, 0x1bc, 19, "dbg"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DEBUG_NONAO, 26, 0x1b8, 0x1bc, UINT_MAX, "debug-nonao"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC, 18, 0x1c0, 0x1c4, 20, "dmic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DP, 19, 0x1c0, 0x1c4, UINT_MAX, "dp"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, UINT_MAX, "dsi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, UINT_MAX, "dsib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, UINT_MAX, "dsic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, UINT_MAX, "dsid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC, 3, 0x1c0, 0x1c4, UINT_MAX, "emmc"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC2, 5, 0x1c0, 0x1c4, UINT_MAX, "emmc2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_GPIO, 27, 0x1b8, 0x1bc, 21, "gpio"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, UINT_MAX, "hdmi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, UINT_MAX, "hsic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, UINT_MAX, "lvds"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, UINT_MAX, "mipi-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, UINT_MAX, "pex-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, UINT_MAX, "pex-clk1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, UINT_MAX, "pex-clk2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, UINT_MAX, UINT_MAX, 11, "pex-cntrl"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, 12, "sdmmc1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, 13, "sdmmc3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 14, 0x1c0, 0x1c4, 22, "spi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SPI_HV, 15, 0x1c0, 0x1c4, 23, "spi-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, 2, "uart"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, UINT_MAX, "usb0"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, UINT_MAX, "usb1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, UINT_MAX, "usb2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB3, 18, 0x1b8, 0x1bc, UINT_MAX, "usb3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, UINT_MAX, "usb-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x1b8, 0x1bc, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x1c0, 0x1c4, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 4, 0x1c0, 0x1c4, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x1b8, 0x1bc, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x1b8, 0x1bc, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 10, 0x1c0, 0x1c4, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 11, 0x1c0, 0x1c4, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 12, 0x1c0, 0x1c4, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 13, 0x1c0, 0x1c4, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x1b8, 0x1bc, "dbg"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DEBUG_NONAO, 26, 0x1b8, 0x1bc, "debug-nonao"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC, 18, 0x1c0, 0x1c4, "dmic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DP, 19, 0x1c0, 0x1c4, "dp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x1b8, 0x1bc, "dsi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 7, 0x1c0, 0x1c4, "dsib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 8, 0x1c0, 0x1c4, "dsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 9, 0x1c0, 0x1c4, "dsid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC, 3, 0x1c0, 0x1c4, "emmc"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EMMC2, 5, 0x1c0, 0x1c4, "emmc2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_GPIO, 27, 0x1b8, 0x1bc, "gpio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI, 28, 0x1b8, 0x1bc, "hdmi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x1b8, 0x1bc, "hsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_LVDS, 25, 0x1c0, 0x1c4, "lvds"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x1b8, 0x1bc, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_BIAS, 4, 0x1b8, 0x1bc, "pex-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 5, 0x1b8, 0x1bc, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x1b8, 0x1bc, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, UINT_MAX, UINT_MAX, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 1, 0x1c0, 0x1c4, "sdmmc1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3, 2, 0x1c0, 0x1c4, "sdmmc3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 14, 0x1c0, 0x1c4, "spi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI_HV, 15, 0x1c0, 0x1c4, "spi-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x1b8, 0x1bc, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x1b8, 0x1bc, "usb0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x1b8, 0x1bc, "usb1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x1b8, 0x1bc, "usb2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB3, 18, 0x1b8, 0x1bc, "usb3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x1b8, 0x1bc, "usb-bias"),
};
+static const struct tegra_io_pad_vctrl tegra210_io_pad_vctrls[] = {
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO, PMC_PWR_DET_VALUE, 5),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO_HV, PMC_PWR_DET_VALUE, 18),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_CAM, PMC_PWR_DET_VALUE, 10),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_DBG, PMC_PWR_DET_VALUE, 19),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_DMIC, PMC_PWR_DET_VALUE, 20),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_GPIO, PMC_PWR_DET_VALUE, 21),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_PEX_CNTRL, PMC_PWR_DET_VALUE, 11),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1, PMC_PWR_DET_VALUE, 12),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC3, PMC_PWR_DET_VALUE, 13),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SPI, PMC_PWR_DET_VALUE, 22),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SPI_HV, PMC_PWR_DET_VALUE, 23),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_UART, PMC_PWR_DET_VALUE, 2),
+};
static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO, "audio"),
TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_AUDIO_HV, "audio-hv"),
@@ -3948,10 +3993,12 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.has_tsense_reset = true,
.has_gpu_clamps = true,
.needs_mbist_war = true,
- .has_impl_33v_pwr = false,
+ .has_io_pad_wren = true,
.maybe_tz_only = true,
.num_io_pads = ARRAY_SIZE(tegra210_io_pads),
.io_pads = tegra210_io_pads,
+ .num_io_pad_vctrls = ARRAY_SIZE(tegra210_io_pad_vctrls),
+ .io_pad_vctrls = tegra210_io_pad_vctrls,
.num_pin_descs = ARRAY_SIZE(tegra210_pin_descs),
.pin_descs = tegra210_pin_descs,
.regs = &tegra20_pmc_regs,
@@ -3974,44 +4021,53 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
};
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x74, 0x78, UINT_MAX, "dsi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x74, 0x78, UINT_MAX, "usb0"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x74, 0x78, UINT_MAX, "usb1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x74, 0x78, UINT_MAX, "usb2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x74, 0x78, UINT_MAX, "usb-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x74, 0x78, UINT_MAX, "hsic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC2_HV, 2, 0x7c, 0x80, 5, "sdmmc2-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 8, 0x7c, 0x80, UINT_MAX, "dsib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 9, 0x7c, 0x80, UINT_MAX, "dsic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 10, 0x7c, 0x80, UINT_MAX, "dsid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC_HV, 20, 0x7c, 0x80, 2, "dmic-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSI, 2, 0x74, 0x78, "dsi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, "pex-clk-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, "pex-clk3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB0, 9, 0x74, 0x78, "usb0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB1, 10, 0x74, 0x78, "usb1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB2, 11, 0x74, 0x78, "usb2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_USB_BIAS, 12, 0x74, 0x78, "usb-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HSIC, 19, 0x74, 0x78, "hsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, "dbg"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, "hdmi-dp1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC2_HV, 2, 0x7c, 0x80, "sdmmc2-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, "sdmmc4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIB, 8, 0x7c, 0x80, "dsib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSIC, 9, 0x7c, 0x80, "dsic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DSID, 10, 0x7c, 0x80, "dsid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, "spi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DMIC_HV, 20, 0x7c, 0x80, "dmic-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, "conn"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "ao-hv"),
+};
+
+static const struct tegra_io_pad_vctrl tegra186_io_pad_vctrls[] = {
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC2_HV, PMC_IMPL_E_33V_PWR, 5),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_DMIC_HV, PMC_IMPL_E_33V_PWR, 2),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1_HV, PMC_IMPL_E_33V_PWR, 4),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC3_HV, PMC_IMPL_E_33V_PWR, 6),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO_HV, PMC_IMPL_E_33V_PWR, 1),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AO_HV, PMC_IMPL_E_33V_PWR, 0),
};
static const struct pinctrl_pin_desc tegra186_pin_descs[] = {
@@ -4062,6 +4118,14 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
.rst_source_mask = 0x3c,
.rst_level_shift = 0x0,
.rst_level_mask = 0x3,
+ .aowake_mask_w = 0x180,
+ .aowake_status_w = 0x30c,
+ .aowake_status_r = 0x48c,
+ .aowake_tier2_routing = 0x4cc,
+ .aowake_sw_status_w = 0x49c,
+ .aowake_sw_status = 0x4a0,
+ .aowake_latch_sw = 0x498,
+ .aowake_ctrl = 0x4f4,
};
static void tegra186_pmc_init(struct tegra_pmc *pmc)
@@ -4094,14 +4158,14 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
return;
}
- value = readl(wake + WAKE_AOWAKE_CTRL);
+ value = readl(wake + pmc->soc->regs->aowake_ctrl);
if (invert)
value |= WAKE_AOWAKE_CTRL_INTR_POLARITY;
else
value &= ~WAKE_AOWAKE_CTRL_INTR_POLARITY;
- writel(value, wake + WAKE_AOWAKE_CTRL);
+ writel(value, wake + pmc->soc->regs->aowake_ctrl);
iounmap(wake);
}
@@ -4143,10 +4207,12 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
.has_tsense_reset = false,
.has_gpu_clamps = false,
.needs_mbist_war = false,
- .has_impl_33v_pwr = true,
+ .has_io_pad_wren = false,
.maybe_tz_only = false,
.num_io_pads = ARRAY_SIZE(tegra186_io_pads),
.io_pads = tegra186_io_pads,
+ .num_io_pad_vctrls = ARRAY_SIZE(tegra186_io_pad_vctrls),
+ .io_pad_vctrls = tegra186_io_pad_vctrls,
.num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
.pin_descs = tegra186_pin_descs,
.regs = &tegra186_pmc_regs,
@@ -4171,55 +4237,62 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
};
static const struct tegra_io_pad_soc tegra194_io_pads[] = {
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, UINT_MAX, "csia"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, UINT_MAX, "csib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, UINT_MAX, "mipi-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, UINT_MAX, "pex-clk-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, UINT_MAX, "pex-clk3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, UINT_MAX, "pex-clk2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, UINT_MAX, "pex-clk1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_EQOS, 8, 0x74, 0x78, UINT_MAX, "eqos"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, 0x74, 0x78, UINT_MAX, "pex-clk-2-bias"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2, 10, 0x74, 0x78, UINT_MAX, "pex-clk-2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DAP3, 11, 0x74, 0x78, UINT_MAX, "dap3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DAP5, 12, 0x74, 0x78, UINT_MAX, "dap5"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, UINT_MAX, "uart"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PWR_CTL, 15, 0x74, 0x78, UINT_MAX, "pwr-ctl"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO53, 16, 0x74, 0x78, UINT_MAX, "soc-gpio53"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, UINT_MAX, "audio"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM2, 18, 0x74, 0x78, UINT_MAX, "gp-pwm2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM3, 19, 0x74, 0x78, UINT_MAX, "gp-pwm3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO12, 20, 0x74, 0x78, UINT_MAX, "soc-gpio12"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO13, 21, 0x74, 0x78, UINT_MAX, "soc-gpio13"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO10, 22, 0x74, 0x78, UINT_MAX, "soc-gpio10"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UART4, 23, 0x74, 0x78, UINT_MAX, "uart4"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UART5, 24, 0x74, 0x78, UINT_MAX, "uart5"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, UINT_MAX, "dbg"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP3, 26, 0x74, 0x78, UINT_MAX, "hdmi-dp3"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP2, 27, 0x74, 0x78, UINT_MAX, "hdmi-dp2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, UINT_MAX, "hdmi-dp0"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, UINT_MAX, "hdmi-dp1"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, UINT_MAX, "pex-cntrl"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CTL2, 1, 0x7c, 0x80, UINT_MAX, "pex-ctl2"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L0_RST, 2, 0x7c, 0x80, UINT_MAX, "pex-l0-rst"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L1_RST, 3, 0x7c, 0x80, UINT_MAX, "pex-l1-rst"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, UINT_MAX, "sdmmc4"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L5_RST, 5, 0x7c, 0x80, UINT_MAX, "pex-l5-rst"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, UINT_MAX, "cam"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, UINT_MAX, "csic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, UINT_MAX, "csid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, UINT_MAX, "csie"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, UINT_MAX, "csif"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, UINT_MAX, "spi"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, UINT_MAX, "ufs"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 18, 0x7c, 0x80, UINT_MAX, "csig"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 19, 0x7c, 0x80, UINT_MAX, "csih"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, UINT_MAX, "edp"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, 4, "sdmmc1-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, 6, "sdmmc3-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, UINT_MAX, "conn"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, 1, "audio-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x74, 0x78, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x74, 0x78, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_MIPI_BIAS, 3, 0x74, 0x78, "mipi-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, 0x74, 0x78, "pex-clk-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK3, 5, 0x74, 0x78, "pex-clk3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK2, 6, 0x74, 0x78, "pex-clk2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK1, 7, 0x74, 0x78, "pex-clk1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EQOS, 8, 0x74, 0x78, "eqos"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2_BIAS, 9, 0x74, 0x78, "pex-clk-2-bias"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CLK_2, 10, 0x74, 0x78, "pex-clk-2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DAP3, 11, 0x74, 0x78, "dap3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DAP5, 12, 0x74, 0x78, "dap5"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART, 14, 0x74, 0x78, "uart"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PWR_CTL, 15, 0x74, 0x78, "pwr-ctl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO53, 16, 0x74, 0x78, "soc-gpio53"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO, 17, 0x74, 0x78, "audio"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM2, 18, 0x74, 0x78, "gp-pwm2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_GP_PWM3, 19, 0x74, 0x78, "gp-pwm3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO12, 20, 0x74, 0x78, "soc-gpio12"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO13, 21, 0x74, 0x78, "soc-gpio13"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SOC_GPIO10, 22, 0x74, 0x78, "soc-gpio10"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART4, 23, 0x74, 0x78, "uart4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UART5, 24, 0x74, 0x78, "uart5"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_DBG, 25, 0x74, 0x78, "dbg"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP3, 26, 0x74, 0x78, "hdmi-dp3"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP2, 27, 0x74, 0x78, "hdmi-dp2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 28, 0x74, 0x78, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP1, 29, 0x74, 0x78, "hdmi-dp1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CNTRL, 0, 0x7c, 0x80, "pex-cntrl"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_CTL2, 1, 0x7c, 0x80, "pex-ctl2"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L0_RST, 2, 0x7c, 0x80, "pex-l0-rst"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L1_RST, 3, 0x7c, 0x80, "pex-l1-rst"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC4, 4, 0x7c, 0x80, "sdmmc4"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_PEX_L5_RST, 5, 0x7c, 0x80, "pex-l5-rst"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CAM, 6, 0x7c, 0x80, "cam"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 11, 0x7c, 0x80, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 12, 0x7c, 0x80, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 13, 0x7c, 0x80, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 14, 0x7c, 0x80, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SPI, 15, 0x7c, 0x80, "spi"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 17, 0x7c, 0x80, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 18, 0x7c, 0x80, "csig"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 19, 0x7c, 0x80, "csih"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 21, 0x7c, 0x80, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 23, 0x7c, 0x80, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, 24, 0x7c, 0x80, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CONN, 28, 0x7c, 0x80, "conn"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, 29, 0x7c, 0x80, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "ao-hv"),
+};
+
+static const struct tegra_io_pad_vctrl tegra194_io_pad_vctrls[] = {
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1_HV, PMC_IMPL_E_33V_PWR, 4),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC3_HV, PMC_IMPL_E_33V_PWR, 6),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO_HV, PMC_IMPL_E_33V_PWR, 1),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AO_HV, PMC_IMPL_E_33V_PWR, 0),
};
static const struct pinctrl_pin_desc tegra194_pin_descs[] = {
@@ -4281,6 +4354,14 @@ static const struct tegra_pmc_regs tegra194_pmc_regs = {
.rst_source_mask = 0x7c,
.rst_level_shift = 0x0,
.rst_level_mask = 0x3,
+ .aowake_mask_w = 0x180,
+ .aowake_status_w = 0x30c,
+ .aowake_status_r = 0x48c,
+ .aowake_tier2_routing = 0x4cc,
+ .aowake_sw_status_w = 0x49c,
+ .aowake_sw_status = 0x4a0,
+ .aowake_latch_sw = 0x498,
+ .aowake_ctrl = 0x4f4,
};
static const char * const tegra194_reset_sources[] = {
@@ -4330,10 +4411,12 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
.has_tsense_reset = false,
.has_gpu_clamps = false,
.needs_mbist_war = false,
- .has_impl_33v_pwr = true,
+ .has_io_pad_wren = false,
.maybe_tz_only = false,
.num_io_pads = ARRAY_SIZE(tegra194_io_pads),
.io_pads = tegra194_io_pads,
+ .num_io_pad_vctrls = ARRAY_SIZE(tegra194_io_pad_vctrls),
+ .io_pad_vctrls = tegra194_io_pad_vctrls,
.num_pin_descs = ARRAY_SIZE(tegra194_pin_descs),
.pin_descs = tegra194_pin_descs,
.regs = &tegra194_pmc_regs,
@@ -4358,21 +4441,28 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = {
};
static const struct tegra_io_pad_soc tegra234_io_pads[] = {
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0xe0c0, 0xe0c4, UINT_MAX, "csia"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0xe0c0, 0xe0c4, UINT_MAX, "csib"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe0d0, 0xe0d4, UINT_MAX, "hdmi-dp0"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 2, 0xe0c0, 0xe0c4, UINT_MAX, "csic"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 3, 0xe0c0, 0xe0c4, UINT_MAX, "csid"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 4, 0xe0c0, 0xe0c4, UINT_MAX, "csie"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 5, 0xe0c0, 0xe0c4, UINT_MAX, "csif"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe064, 0xe068, UINT_MAX, "ufs"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 1, 0xe05c, 0xe060, UINT_MAX, "edp"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe054, 0xe058, 4, "sdmmc1-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, 6, "sdmmc3-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 1, "audio-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, 0, "ao-hv"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 6, 0xe0c0, 0xe0c4, UINT_MAX, "csig"),
- TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 7, 0xe0c0, 0xe0c4, UINT_MAX, "csih"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0xe0c0, 0xe0c4, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0xe0c0, 0xe0c4, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0xe0d0, 0xe0d4, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 2, 0xe0c0, 0xe0c4, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 3, 0xe0c0, 0xe0c4, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 4, 0xe0c0, 0xe0c4, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 5, 0xe0c0, 0xe0c4, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 0, 0xe064, 0xe068, "ufs"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 1, 0xe05c, 0xe060, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, 0, 0xe054, 0xe058, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC3_HV, UINT_MAX, UINT_MAX, UINT_MAX, "sdmmc3-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AUDIO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "audio-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_AO_HV, UINT_MAX, UINT_MAX, UINT_MAX, "ao-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 6, 0xe0c0, 0xe0c4, "csig"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 7, 0xe0c0, 0xe0c4, "csih"),
+};
+
+static const struct tegra_io_pad_vctrl tegra234_io_pad_vctrls[] = {
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1_HV, PMC_IMPL_E_33V_PWR, 4),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC3_HV, PMC_IMPL_E_33V_PWR, 6),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AUDIO_HV, PMC_IMPL_E_33V_PWR, 1),
+ TEGRA_IO_PAD_VCTRL(TEGRA_IO_PAD_AO_HV, PMC_IMPL_E_33V_PWR, 0),
};
static const struct pinctrl_pin_desc tegra234_pin_descs[] = {
@@ -4400,6 +4490,14 @@ static const struct tegra_pmc_regs tegra234_pmc_regs = {
.rst_source_mask = 0xfc,
.rst_level_shift = 0x0,
.rst_level_mask = 0x3,
+ .aowake_mask_w = 0x180,
+ .aowake_status_w = 0x30c,
+ .aowake_status_r = 0x48c,
+ .aowake_tier2_routing = 0x4cc,
+ .aowake_sw_status_w = 0x49c,
+ .aowake_sw_status = 0x4a0,
+ .aowake_latch_sw = 0x498,
+ .aowake_ctrl = 0x4f4,
};
static const char * const tegra234_reset_sources[] = {
@@ -4469,10 +4567,12 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.has_tsense_reset = false,
.has_gpu_clamps = false,
.needs_mbist_war = false,
- .has_impl_33v_pwr = true,
+ .has_io_pad_wren = false,
.maybe_tz_only = false,
.num_io_pads = ARRAY_SIZE(tegra234_io_pads),
.io_pads = tegra234_io_pads,
+ .num_io_pad_vctrls = ARRAY_SIZE(tegra234_io_pad_vctrls),
+ .io_pad_vctrls = tegra234_io_pad_vctrls,
.num_pin_descs = ARRAY_SIZE(tegra234_pin_descs),
.pin_descs = tegra234_pin_descs,
.regs = &tegra234_pmc_regs,
@@ -4495,6 +4595,50 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = {
.has_single_mmio_aperture = false,
};
+#define TEGRA264_IO_PAD_VCTRL(_id, _offset, _ena_3v3, _ena_1v8) \
+ ((struct tegra_io_pad_vctrl) { \
+ .id = (_id), \
+ .offset = (_offset), \
+ .ena_3v3 = (_ena_3v3), \
+ .ena_1v8 = (_ena_1v8), \
+ })
+
+static const struct tegra_io_pad_soc tegra264_io_pads[] = {
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIA, 0, 0x41020, 0x41024, "csia"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIB, 1, 0x41020, 0x41024, "csib"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_HDMI_DP0, 0, 0x41050, 0x41054, "hdmi-dp0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIC, 2, 0x41020, 0x41024, "csic"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSID, 3, 0x41020, 0x41024, "csid"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIE, 4, 0x41020, 0x41024, "csie"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIF, 5, 0x41020, 0x41024, "csif"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_UFS, 4, 0x41040, 0x41044, "ufs0"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_EDP, 0, 0x41028, 0x4102c, "edp"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1, 0, 0x41090, 0x41094, "sdmmc1"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_SDMMC1_HV, UINT_MAX, UINT_MAX, UINT_MAX, "sdmmc1-hv"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIG, 6, 0x41020, 0x41024, "csig"),
+ TEGRA_IO_PAD(TEGRA_IO_PAD_CSIH, 7, 0x41020, 0x41024, "csih"),
+};
+
+static const struct tegra_io_pad_vctrl tegra264_io_pad_vctrls[] = {
+ TEGRA264_IO_PAD_VCTRL(TEGRA_IO_PAD_SDMMC1_HV, PMC_IMPL_SDMMC1_HV_PADCTL_0, 0, 0x6),
+};
+
+static const struct pinctrl_pin_desc tegra264_pin_descs[] = {
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIA, "csia"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIB, "csib"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_HDMI_DP0, "hdmi-dp0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIC, "csic"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSID, "csid"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIE, "csie"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIF, "csif"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_UFS, "ufs0"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_EDP, "edp"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1, "sdmmc1"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_SDMMC1_HV, "sdmmc1-hv"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIG, "csig"),
+ TEGRA_IO_PIN_DESC(TEGRA_IO_PAD_CSIH, "csih"),
+};
+
static const struct tegra_pmc_regs tegra264_pmc_regs = {
.scratch0 = 0x684,
.rst_status = 0x4,
@@ -4502,6 +4646,14 @@ static const struct tegra_pmc_regs tegra264_pmc_regs = {
.rst_source_mask = 0x1fc,
.rst_level_shift = 0x0,
.rst_level_mask = 0x3,
+ .aowake_mask_w = 0x200,
+ .aowake_status_w = 0x410,
+ .aowake_status_r = 0x610,
+ .aowake_tier2_routing = 0x660,
+ .aowake_sw_status_w = 0x624,
+ .aowake_sw_status = 0x628,
+ .aowake_latch_sw = 0x620,
+ .aowake_ctrl = 0x68c,
};
static const char * const tegra264_reset_sources[] = {
@@ -4595,10 +4747,26 @@ static const char * const tegra264_reset_sources[] = {
};
static const struct tegra_wake_event tegra264_wake_events[] = {
+ TEGRA_WAKE_IRQ("pmu", 0, 727),
+ TEGRA_WAKE_GPIO("power", 5, 1, TEGRA264_AON_GPIO(AA, 5)),
+ TEGRA_WAKE_IRQ("rtc", 65, 548),
+ TEGRA_WAKE_IRQ("usb3-port-0", 79, 965),
+ TEGRA_WAKE_IRQ("usb3-port-1", 80, 965),
+ TEGRA_WAKE_IRQ("usb3-port-3", 82, 965),
+ TEGRA_WAKE_IRQ("usb2-port-0", 83, 965),
+ TEGRA_WAKE_IRQ("usb2-port-1", 84, 965),
+ TEGRA_WAKE_IRQ("usb2-port-2", 85, 965),
+ TEGRA_WAKE_IRQ("usb2-port-3", 86, 965),
};
static const struct tegra_pmc_soc tegra264_pmc_soc = {
- .has_impl_33v_pwr = true,
+ .has_io_pad_wren = false,
+ .num_io_pads = ARRAY_SIZE(tegra264_io_pads),
+ .io_pads = tegra264_io_pads,
+ .num_io_pad_vctrls = ARRAY_SIZE(tegra264_io_pad_vctrls),
+ .io_pad_vctrls = tegra264_io_pad_vctrls,
+ .num_pin_descs = ARRAY_SIZE(tegra264_pin_descs),
+ .pin_descs = tegra264_pin_descs,
.regs = &tegra264_pmc_regs,
.init = tegra186_pmc_init,
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c
index bae954e79fdc..f751d743a120 100644
--- a/drivers/tee/optee/device.c
+++ b/drivers/tee/optee/device.c
@@ -13,10 +13,7 @@
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
{
- if (ver->impl_id == TEE_IMPL_ID_OPTEE)
- return 1;
- else
- return 0;
+ return (ver->impl_id == TEE_IMPL_ID_OPTEE);
}
static int get_devices(struct tee_context *ctx, u32 session,