summaryrefslogtreecommitdiff
path: root/drivers/reset
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/reset')
-rw-r--r--drivers/reset/Kconfig7
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-imx-scu.c101
-rw-r--r--drivers/reset/reset-imx8mp-audiomix.c78
-rw-r--r--drivers/reset/reset-microchip-sparx5.c19
5 files changed, 179 insertions, 27 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 5b3abb6db248..99f6f9784e68 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -96,6 +96,13 @@ config RESET_HSDK
help
This enables the reset controller driver for HSDK board.
+config RESET_IMX_SCU
+ tristate "i.MX8Q Reset Driver"
+ depends on IMX_SCU && HAVE_ARM_SMCCC
+ depends on (ARM64 && ARCH_MXC) || COMPILE_TEST
+ help
+ This enables the reset controller driver for i.MX8QM/i.MX8QXP
+
config RESET_IMX7
tristate "i.MX7/8 Reset Driver"
depends on HAS_IOMEM
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 677c4d1e2632..31f9904d13f9 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
obj-$(CONFIG_RESET_EYEQ) += reset-eyeq.o
obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
+obj-$(CONFIG_RESET_IMX_SCU) += reset-imx-scu.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_IMX8MP_AUDIOMIX) += reset-imx8mp-audiomix.o
obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o
diff --git a/drivers/reset/reset-imx-scu.c b/drivers/reset/reset-imx-scu.c
new file mode 100644
index 000000000000..919fc29f944c
--- /dev/null
+++ b/drivers/reset/reset-imx-scu.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ * Frank Li <Frank.Li@nxp.com>
+ */
+#include <linux/firmware/imx/svc/misc.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+struct imx_scu_reset {
+ struct reset_controller_dev rc;
+ struct imx_sc_ipc *ipc_handle;
+};
+
+static struct imx_scu_reset *to_imx_scu(struct reset_controller_dev *rc)
+{
+ return container_of(rc, struct imx_scu_reset, rc);
+}
+
+struct imx_scu_id_map {
+ u32 resource_id;
+ u32 command_id;
+};
+
+static const struct imx_scu_id_map imx_scu_id_map[] = {
+ { IMX_SC_R_CSI_0, IMX_SC_C_MIPI_RESET },
+ { IMX_SC_R_CSI_1, IMX_SC_C_MIPI_RESET },
+};
+
+static int imx_scu_reset_assert(struct reset_controller_dev *rc, unsigned long id)
+{
+ struct imx_scu_reset *priv = to_imx_scu(rc);
+
+ return imx_sc_misc_set_control(priv->ipc_handle, imx_scu_id_map[id].resource_id,
+ imx_scu_id_map[id].command_id, true);
+}
+
+static const struct reset_control_ops imx_scu_reset_ops = {
+ .assert = imx_scu_reset_assert,
+};
+
+static int imx_scu_xlate(struct reset_controller_dev *rc, const struct of_phandle_args *reset_spec)
+{
+ int i;
+
+ for (i = 0; i < rc->nr_resets; i++)
+ if (reset_spec->args[0] == imx_scu_id_map[i].resource_id)
+ return i;
+
+ return -EINVAL;
+}
+
+static int imx_scu_reset_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct imx_scu_reset *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, &priv->rc);
+
+ ret = imx_scu_get_handle(&priv->ipc_handle);
+ if (ret)
+ return dev_err_probe(dev, ret, "sc_misc_MIPI get ipc handle failed!\n");
+
+ priv->rc.ops = &imx_scu_reset_ops;
+ priv->rc.owner = THIS_MODULE;
+ priv->rc.of_node = dev->of_node;
+ priv->rc.of_reset_n_cells = 1;
+ priv->rc.of_xlate = imx_scu_xlate;
+ priv->rc.nr_resets = ARRAY_SIZE(imx_scu_id_map);
+
+ return devm_reset_controller_register(dev, &priv->rc);
+}
+
+static const struct of_device_id imx_scu_reset_ids[] = {
+ { .compatible = "fsl,imx-scu-reset", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, imx_scu_reset_ids);
+
+static struct platform_driver imx_scu_reset_driver = {
+ .probe = imx_scu_reset_probe,
+ .driver = {
+ .name = "scu-reset",
+ .of_match_table = imx_scu_reset_ids,
+ },
+};
+module_platform_driver(imx_scu_reset_driver);
+
+MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>");
+MODULE_DESCRIPTION("i.MX scu reset driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/reset/reset-imx8mp-audiomix.c b/drivers/reset/reset-imx8mp-audiomix.c
index 6e3f3069f727..6b357adfe646 100644
--- a/drivers/reset/reset-imx8mp-audiomix.c
+++ b/drivers/reset/reset-imx8mp-audiomix.c
@@ -3,6 +3,8 @@
* Copyright 2024 NXP
*/
+#include <dt-bindings/reset/imx8mp-reset-audiomix.h>
+
#include <linux/auxiliary_bus.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -11,8 +13,36 @@
#include <linux/of_address.h>
#include <linux/reset-controller.h>
-#define EARC 0x200
-#define EARC_RESET_MASK 0x3
+#define IMX8MP_AUDIOMIX_EARC_RESET_OFFSET 0x200
+#define IMX8MP_AUDIOMIX_EARC_RESET_MASK BIT(1)
+#define IMX8MP_AUDIOMIX_EARC_PHY_RESET_MASK BIT(2)
+
+#define IMX8MP_AUDIOMIX_DSP_RUNSTALL_OFFSET 0x108
+#define IMX8MP_AUDIOMIX_DSP_RUNSTALL_MASK BIT(5)
+
+struct imx8mp_reset_map {
+ unsigned int offset;
+ unsigned int mask;
+ bool active_low;
+};
+
+static const struct imx8mp_reset_map reset_map[] = {
+ [IMX8MP_AUDIOMIX_EARC_RESET] = {
+ .offset = IMX8MP_AUDIOMIX_EARC_RESET_OFFSET,
+ .mask = IMX8MP_AUDIOMIX_EARC_RESET_MASK,
+ .active_low = true,
+ },
+ [IMX8MP_AUDIOMIX_EARC_PHY_RESET] = {
+ .offset = IMX8MP_AUDIOMIX_EARC_RESET_OFFSET,
+ .mask = IMX8MP_AUDIOMIX_EARC_PHY_RESET_MASK,
+ .active_low = true,
+ },
+ [IMX8MP_AUDIOMIX_DSP_RUNSTALL] = {
+ .offset = IMX8MP_AUDIOMIX_DSP_RUNSTALL_OFFSET,
+ .mask = IMX8MP_AUDIOMIX_DSP_RUNSTALL_MASK,
+ .active_low = false,
+ },
+};
struct imx8mp_audiomix_reset {
struct reset_controller_dev rcdev;
@@ -25,38 +55,42 @@ static struct imx8mp_audiomix_reset *to_imx8mp_audiomix_reset(struct reset_contr
return container_of(rcdev, struct imx8mp_audiomix_reset, rcdev);
}
-static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev,
- unsigned long id)
+static int imx8mp_audiomix_update(struct reset_controller_dev *rcdev,
+ unsigned long id, bool assert)
{
struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev);
void __iomem *reg_addr = priv->base;
- unsigned int mask, reg;
- unsigned long flags;
+ unsigned int mask, offset, active_low;
+ unsigned long reg, flags;
+
+ mask = reset_map[id].mask;
+ offset = reset_map[id].offset;
+ active_low = reset_map[id].active_low;
- mask = BIT(id);
spin_lock_irqsave(&priv->lock, flags);
- reg = readl(reg_addr + EARC);
- writel(reg & ~mask, reg_addr + EARC);
+
+ reg = readl(reg_addr + offset);
+ if (active_low ^ assert)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ writel(reg, reg_addr + offset);
+
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
+static int imx8mp_audiomix_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ return imx8mp_audiomix_update(rcdev, id, true);
+}
+
static int imx8mp_audiomix_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
- struct imx8mp_audiomix_reset *priv = to_imx8mp_audiomix_reset(rcdev);
- void __iomem *reg_addr = priv->base;
- unsigned int mask, reg;
- unsigned long flags;
-
- mask = BIT(id);
- spin_lock_irqsave(&priv->lock, flags);
- reg = readl(reg_addr + EARC);
- writel(reg | mask, reg_addr + EARC);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return imx8mp_audiomix_update(rcdev, id, false);
}
static const struct reset_control_ops imx8mp_audiomix_reset_ops = {
@@ -78,7 +112,7 @@ static int imx8mp_audiomix_reset_probe(struct auxiliary_device *adev,
spin_lock_init(&priv->lock);
priv->rcdev.owner = THIS_MODULE;
- priv->rcdev.nr_resets = fls(EARC_RESET_MASK);
+ priv->rcdev.nr_resets = ARRAY_SIZE(reset_map);
priv->rcdev.ops = &imx8mp_audiomix_reset_ops;
priv->rcdev.of_node = dev->parent->of_node;
priv->rcdev.dev = dev;
diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c
index aa5464be7053..6d3e75b33260 100644
--- a/drivers/reset/reset-microchip-sparx5.c
+++ b/drivers/reset/reset-microchip-sparx5.c
@@ -8,6 +8,7 @@
*/
#include <linux/mfd/syscon.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -72,14 +73,22 @@ static struct regmap *mchp_lan966x_syscon_to_regmap(struct device *dev,
struct device_node *syscon_np)
{
struct regmap_config regmap_config = mchp_lan966x_syscon_regmap_config;
- resource_size_t size;
+ struct resource res;
void __iomem *base;
+ int err;
+
+ err = of_address_to_resource(syscon_np, 0, &res);
+ if (err)
+ return ERR_PTR(err);
- base = devm_of_iomap(dev, syscon_np, 0, &size);
- if (IS_ERR(base))
- return ERR_CAST(base);
+ /* It is not possible to use devm_of_iomap because this resource is
+ * shared with other drivers.
+ */
+ base = devm_ioremap(dev, res.start, resource_size(&res));
+ if (!base)
+ return ERR_PTR(-ENOMEM);
- regmap_config.max_register = size - 4;
+ regmap_config.max_register = resource_size(&res) - 4;
return devm_regmap_init_mmio(dev, base, &regmap_config);
}