diff options
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Kconfig | 7 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/amlogic/reset-meson-aux.c | 97 | ||||
-rw-r--r-- | drivers/reset/reset-imx-scu.c | 101 | ||||
-rw-r--r-- | drivers/reset/reset-imx8mp-audiomix.c | 78 | ||||
-rw-r--r-- | drivers/reset/reset-microchip-sparx5.c | 19 |
6 files changed, 200 insertions, 103 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/amlogic/reset-meson-aux.c b/drivers/reset/amlogic/reset-meson-aux.c index 61ce515d92a2..33c06013439e 100644 --- a/drivers/reset/amlogic/reset-meson-aux.c +++ b/drivers/reset/amlogic/reset-meson-aux.c @@ -11,20 +11,20 @@ #include <linux/auxiliary_bus.h> #include <linux/regmap.h> #include <linux/reset-controller.h> -#include <linux/slab.h> #include "reset-meson.h" -#include <soc/amlogic/reset-meson-aux.h> -static DEFINE_IDA(meson_rst_aux_ida); - -struct meson_reset_adev { - struct auxiliary_device adev; - struct regmap *map; +static const struct meson_reset_param meson_a1_audio_param = { + .reset_ops = &meson_reset_toggle_ops, + .reset_num = 32, + .level_offset = 0x28, }; -#define to_meson_reset_adev(_adev) \ - container_of((_adev), struct meson_reset_adev, adev) +static const struct meson_reset_param meson_a1_audio_vad_param = { + .reset_ops = &meson_reset_toggle_ops, + .reset_num = 6, + .level_offset = 0x8, +}; static const struct meson_reset_param meson_g12a_audio_param = { .reset_ops = &meson_reset_toggle_ops, @@ -40,6 +40,12 @@ static const struct meson_reset_param meson_sm1_audio_param = { static const struct auxiliary_device_id meson_reset_aux_ids[] = { { + .name = "a1-audio-clkc.rst-a1", + .driver_data = (kernel_ulong_t)&meson_a1_audio_param, + }, { + .name = "a1-audio-clkc.rst-a1-vad", + .driver_data = (kernel_ulong_t)&meson_a1_audio_vad_param, + }, { .name = "axg-audio-clkc.rst-g12a", .driver_data = (kernel_ulong_t)&meson_g12a_audio_param, }, { @@ -54,10 +60,13 @@ static int meson_reset_aux_probe(struct auxiliary_device *adev, { const struct meson_reset_param *param = (const struct meson_reset_param *)(id->driver_data); - struct meson_reset_adev *raux = - to_meson_reset_adev(adev); + struct regmap *map; + + map = dev_get_regmap(adev->dev.parent, NULL); + if (!map) + return -EINVAL; - return meson_reset_controller_register(&adev->dev, raux->map, param); + return meson_reset_controller_register(&adev->dev, map, param); } static struct auxiliary_driver meson_reset_aux_driver = { @@ -66,70 +75,6 @@ static struct auxiliary_driver meson_reset_aux_driver = { }; module_auxiliary_driver(meson_reset_aux_driver); -static void meson_rst_aux_release(struct device *dev) -{ - struct auxiliary_device *adev = to_auxiliary_dev(dev); - struct meson_reset_adev *raux = - to_meson_reset_adev(adev); - - ida_free(&meson_rst_aux_ida, adev->id); - kfree(raux); -} - -static void meson_rst_aux_unregister_adev(void *_adev) -{ - struct auxiliary_device *adev = _adev; - - auxiliary_device_delete(adev); - auxiliary_device_uninit(adev); -} - -int devm_meson_rst_aux_register(struct device *dev, - struct regmap *map, - const char *adev_name) -{ - struct meson_reset_adev *raux; - struct auxiliary_device *adev; - int ret; - - raux = kzalloc(sizeof(*raux), GFP_KERNEL); - if (!raux) - return -ENOMEM; - - ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL); - if (ret < 0) - goto raux_free; - - raux->map = map; - - adev = &raux->adev; - adev->id = ret; - adev->name = adev_name; - adev->dev.parent = dev; - adev->dev.release = meson_rst_aux_release; - device_set_of_node_from_dev(&adev->dev, dev); - - ret = auxiliary_device_init(adev); - if (ret) - goto ida_free; - - ret = __auxiliary_device_add(adev, dev->driver->name); - if (ret) { - auxiliary_device_uninit(adev); - return ret; - } - - return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev, - adev); - -ida_free: - ida_free(&meson_rst_aux_ida, adev->id); -raux_free: - kfree(raux); - return ret; -} -EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register); - MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver"); MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); MODULE_LICENSE("Dual BSD/GPL"); 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, ®map_config); } |