diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-16 20:34:34 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-16 20:34:34 -0700 |
| commit | 31b43c079f9aa55754c20404a42bca9a49e01f60 (patch) | |
| tree | 5c05933f3546f52ff9adab5c10a65599e6b62293 /drivers | |
| parent | e65f4718a577fcc84d40431f022985898b6dbf2e (diff) | |
| parent | 33a20cdaf41d08a66581cc01a60c1a3d596ba9cd (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')
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, ®); 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, |
