diff options
Diffstat (limited to 'drivers/reset')
-rw-r--r-- | drivers/reset/Kconfig | 36 | ||||
-rw-r--r-- | drivers/reset/Makefile | 4 | ||||
-rw-r--r-- | drivers/reset/core.c | 196 | ||||
-rw-r--r-- | drivers/reset/reset-imx7.c | 21 | ||||
-rw-r--r-- | drivers/reset/reset-scmi.c | 130 | ||||
-rw-r--r-- | drivers/reset/reset-simple.c | 191 | ||||
-rw-r--r-- | drivers/reset/reset-socfpga.c | 18 | ||||
-rw-r--r-- | drivers/reset/reset-starfive-vic.c | 9 | ||||
-rw-r--r-- | drivers/reset/reset-stm32.c | 214 |
9 files changed, 546 insertions, 273 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 9429f107bb..16c05d50f0 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config ARCH_HAS_RESET_CONTROLLER bool @@ -14,6 +15,23 @@ menuconfig RESET_CONTROLLER if RESET_CONTROLLER +config RESET_SIMPLE + bool "Simple Reset Controller Driver" if COMPILE_TEST + help + This enables a simple reset controller driver for reset lines that + that can be asserted and deasserted by toggling bits in a contiguous, + exclusive register space. + + Currently this driver supports: + - Altera 64-Bit SoCFPGAs + - ASPEED BMC SoCs + - Bitmain BM1880 SoC + - Realtek SoCs + - RCC reset controller in STM32 MCUs + - Allwinner SoCs + - SiFive FU740 SoCs + + config RESET_IMX7 bool "i.MX7 Reset Driver" default ARCH_IMX7 @@ -21,16 +39,22 @@ config RESET_IMX7 help This enables the reset controller driver for i.MX7 SoCs. -config RESET_STM32 - bool "STM32 Reset Driver" - depends on ARCH_STM32MP || COMPILE_TEST - help - This enables the reset controller driver for STM32MP and STM32 MCUs. - config RESET_STARFIVE bool "StarFive Controller Driver" if COMPILE_TEST + depends on COMMON_CLK default SOC_STARFIVE help This enables the reset controller driver for the StarFive JH7100. +config RESET_SCMI + tristate "Reset driver controlled via ARM SCMI interface" + depends on ARM_SCMI_PROTOCOL || COMPILE_TEST + default ARM_SCMI_PROTOCOL + help + This driver provides support for reset signal/domains that are + controlled by firmware that implements the SCMI interface. + + This driver uses SCMI Message Protocol to interact with the + firmware controlling all the reset signals. + endif diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index ce494baae5..b1668433d7 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,5 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_RESET_CONTROLLER) += core.o +obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o -obj-$(CONFIG_RESET_STM32) += reset-stm32.o obj-$(CONFIG_RESET_STARFIVE) += reset-starfive-vic.o +obj-$(CONFIG_RESET_SCMI) += reset-scmi.o diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 9f5a642539..94bfad2067 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Reset Controller framework * * Copyright 2013 Philipp Zabel, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ + #include <common.h> #include <gpio.h> #include <malloc.h> @@ -32,8 +29,21 @@ struct reset_control { int gpio; int gpio_active_high; - struct device_d *dev; + struct device *dev; unsigned int id; + bool array; +}; + +/** + * struct reset_control_array - an array of reset controls + * @base: reset control for compatibility with reset control API functions + * @num_rstcs: number of reset controls + * @rstc: array of reset controls + */ +struct reset_control_array { + struct reset_control base; + unsigned int num_rstcs; + struct reset_control *rstc[]; }; /** @@ -85,6 +95,86 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev) EXPORT_SYMBOL_GPL(reset_controller_unregister); /** + * reset_control_status - returns a negative errno if not supported, a + * positive value if the reset line is asserted, or zero if the reset + * line is not asserted or if the desc is NULL (optional reset). + * @rstc: reset controller + */ +int reset_control_status(struct reset_control *rstc) +{ + if (!rstc) + return 0; + + if (WARN_ON(IS_ERR(rstc))) + return -EINVAL; + + if (rstc->rcdev->ops->status) + return rstc->rcdev->ops->status(rstc->rcdev, rstc->id); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(reset_control_status); + +static inline struct reset_control_array * +rstc_to_array(struct reset_control *rstc) { + return container_of(rstc, struct reset_control_array, base); +} + +static int reset_control_array_reset(struct reset_control_array *resets) +{ + int ret, i; + + for (i = 0; i < resets->num_rstcs; i++) { + ret = reset_control_reset(resets->rstc[i]); + if (ret) + return ret; + } + + return 0; +} + +static int reset_control_array_assert(struct reset_control_array *resets) +{ + int ret, i; + + for (i = 0; i < resets->num_rstcs; i++) { + ret = reset_control_assert(resets->rstc[i]); + if (ret) + goto err; + } + + return 0; + +err: + while (i--) + reset_control_deassert(resets->rstc[i]); + return ret; +} + +static int reset_control_array_deassert(struct reset_control_array *resets) +{ + int ret, i; + + for (i = 0; i < resets->num_rstcs; i++) { + ret = reset_control_deassert(resets->rstc[i]); + if (ret) + goto err; + } + + return 0; + +err: + while (i--) + reset_control_assert(resets->rstc[i]); + return ret; +} + +static inline bool reset_control_is_array(struct reset_control *rstc) +{ + return rstc->array; +} + +/** * reset_control_reset - reset the controlled device * @rstc: reset controller */ @@ -93,6 +183,9 @@ int reset_control_reset(struct reset_control *rstc) if (!rstc) return 0; + if (reset_control_is_array(rstc)) + return reset_control_array_reset(rstc_to_array(rstc)); + if (rstc->rcdev->ops->reset) return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); @@ -109,6 +202,9 @@ int reset_control_assert(struct reset_control *rstc) if (!rstc) return 0; + if (reset_control_is_array(rstc)) + return reset_control_array_assert(rstc_to_array(rstc)); + if (rstc->gpio >= 0) return gpio_direction_output(rstc->gpio, rstc->gpio_active_high); @@ -128,6 +224,9 @@ int reset_control_deassert(struct reset_control *rstc) if (!rstc) return 0; + if (reset_control_is_array(rstc)) + return reset_control_array_deassert(rstc_to_array(rstc)); + if (rstc->gpio >= 0) return gpio_direction_output(rstc->gpio, !rstc->gpio_active_high); @@ -139,14 +238,15 @@ int reset_control_deassert(struct reset_control *rstc) EXPORT_SYMBOL_GPL(reset_control_deassert); /** - * of_reset_control_count - Count reset lines - * @node: device node + * reset_control_get_count - Count reset lines + * @dev: device * * Returns number of resets, 0 if none specified */ -static int of_reset_control_count(struct device_node *node) +int reset_control_get_count(struct device *dev) { - return of_count_phandle_with_args(node, "resets", "#reset-cells"); + return of_count_phandle_with_args(dev->of_node, "resets", + "#reset-cells"); } /** @@ -173,9 +273,8 @@ static struct reset_control *of_reset_control_get_by_index(struct device_node *n if (ret) return ERR_PTR(ret); - ret = of_device_ensure_probed(args.np); - if (ret) - return ERR_PTR(ret); + /* Ignore error, as CLK_OF_DECLARE resets have no proper driver. */ + of_device_ensure_probed(args.np); rcdev = NULL; list_for_each_entry(r, &reset_controller_list, list) { @@ -218,14 +317,17 @@ struct reset_control *of_reset_control_get(struct device_node *node, { int index = 0; - if (id) + if (id) { index = of_property_match_string(node, "reset-names", id); + if (index < 0) + return ERR_PTR(-ENOENT); + } return of_reset_control_get_by_index(node, index); } static struct reset_control * -gpio_reset_control_get(struct device_d *dev, const char *id) +gpio_reset_control_get(struct device *dev, const char *id) { struct reset_control *rc; int gpio; @@ -234,10 +336,10 @@ gpio_reset_control_get(struct device_d *dev, const char *id) if (id) return ERR_PTR(-EINVAL); - if (!of_get_property(dev->device_node, "reset-gpios", NULL)) + if (!of_get_property(dev->of_node, "reset-gpios", NULL)) return NULL; - gpio = of_get_named_gpio_flags(dev->device_node, "reset-gpios", 0, &flags); + gpio = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0, &flags); if (gpio < 0) return ERR_PTR(gpio); @@ -257,14 +359,14 @@ gpio_reset_control_get(struct device_d *dev, const char *id) * * Use of id names is optional. */ -struct reset_control *reset_control_get(struct device_d *dev, const char *id) +struct reset_control *reset_control_get(struct device *dev, const char *id) { struct reset_control *rstc; if (!dev) return ERR_PTR(-EINVAL); - rstc = of_reset_control_get(dev->device_node, id); + rstc = of_reset_control_get(dev->of_node, id); if (IS_ERR(rstc)) return ERR_CAST(rstc); @@ -310,7 +412,7 @@ EXPORT_SYMBOL_GPL(reset_control_put); * This is useful for the common case of devices with single, dedicated reset * lines. */ -int device_reset(struct device_d *dev) +int device_reset(struct device *dev) { struct reset_control *rstc; int ret; @@ -331,15 +433,61 @@ int device_reset(struct device_d *dev) } EXPORT_SYMBOL_GPL(device_reset); -int device_reset_all(struct device_d *dev) +/* + * APIs to manage an array of reset controls. + */ + +/** + * reset_control_array_get - Get a list of reset controls + * + * @dev: device that requests the reset controls array + * + * Returns pointer to allocated reset_control on success or error on failure + */ +struct reset_control *reset_control_array_get(struct device *dev) +{ + struct reset_control_array *resets; + struct reset_control *rstc; + struct device_node *np = dev->of_node; + int num, i; + + num = reset_control_get_count(dev); + if (num < 0) + return ERR_PTR(num); + + resets = kzalloc(struct_size(resets, rstc, num), GFP_KERNEL); + if (!resets) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < num; i++) { + rstc = of_reset_control_get_by_index(np, i); + if (IS_ERR(rstc)) + goto err_rst; + resets->rstc[i] = rstc; + } + resets->num_rstcs = num; + resets->base.array = true; + + return &resets->base; + +err_rst: + while (--i >= 0) + reset_control_put(resets->rstc[i]); + + kfree(resets); + + return rstc; +} + +int device_reset_all(struct device *dev) { struct reset_control *rstc; int ret, i; - for (i = 0; i < of_reset_control_count(dev->device_node); i++) { + for (i = 0; i < reset_control_get_count(dev); i++) { int ret; - rstc = of_reset_control_get_by_index(dev->device_node, i); + rstc = of_reset_control_get_by_index(dev->of_node, i); if (IS_ERR(rstc)) return PTR_ERR(rstc); @@ -364,7 +512,7 @@ int device_reset_all(struct device_d *dev) } EXPORT_SYMBOL_GPL(device_reset_all); -int device_reset_us(struct device_d *dev, int us) +int device_reset_us(struct device *dev, int us) { struct reset_control *rstc; int ret; diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index c8c8fa98e0..c6c38f48a8 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017, Impinj, Inc. * * i.MX7 System Reset Controller (SRC) driver * * Author: Andrey Smirnov <andrew.smirnov@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <common.h> @@ -22,7 +14,7 @@ #include <linux/err.h> #include <linux/reset-controller.h> #include <mfd/syscon.h> -#include <regmap.h> +#include <linux/regmap.h> #include <of_device.h> struct imx7_src_signal { @@ -261,14 +253,14 @@ static const struct imx7_src_variant variant_imx8mq = { }, }; -static int imx7_reset_probe(struct device_d *dev) +static int imx7_reset_probe(struct device *dev) { struct imx7_src *imx7src; const struct imx7_src_variant *variant = of_device_get_match_data(dev); imx7src = xzalloc(sizeof(*imx7src)); imx7src->signals = variant->signals; - imx7src->regmap = syscon_node_to_regmap(dev->device_node); + imx7src->regmap = syscon_node_to_regmap(dev->of_node); if (IS_ERR(imx7src->regmap)) { dev_err(dev, "Unable to get imx7-src regmap"); return PTR_ERR(imx7src->regmap); @@ -276,7 +268,7 @@ static int imx7_reset_probe(struct device_d *dev) imx7src->rcdev.nr_resets = variant->signals_num; imx7src->rcdev.ops = &variant->ops; - imx7src->rcdev.of_node = dev->device_node; + imx7src->rcdev.of_node = dev->of_node; return reset_controller_register(&imx7src->rcdev); } @@ -286,8 +278,9 @@ static const struct of_device_id imx7_reset_dt_ids[] = { { .compatible = "fsl,imx8mq-src", .data = &variant_imx8mq }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, imx7_reset_dt_ids); -static struct driver_d imx7_reset_driver = { +static struct driver imx7_reset_driver = { .name = "imx7d-src", .probe = imx7_reset_probe, .of_compatible = DRV_OF_COMPAT(imx7_reset_dt_ids), diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c new file mode 100644 index 0000000000..d8c4734f1b --- /dev/null +++ b/drivers/reset/reset-scmi.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM System Control and Management Interface (ARM SCMI) reset driver + * + * Copyright (C) 2019-2021 ARM Ltd. + */ + +#include <common.h> +#include <of.h> +#include <driver.h> +#include <linux/reset-controller.h> +#include <linux/scmi_protocol.h> + +static const struct scmi_reset_proto_ops *reset_ops; + +/** + * struct scmi_reset_data - reset controller information structure + * @rcdev: reset controller entity + * @ph: ARM SCMI protocol handle used for communication with system controller + */ +struct scmi_reset_data { + struct reset_controller_dev rcdev; + const struct scmi_protocol_handle *ph; +}; + +#define to_scmi_reset_data(p) container_of((p), struct scmi_reset_data, rcdev) +#define to_scmi_handle(p) (to_scmi_reset_data(p)->ph) + +/** + * scmi_reset_assert() - assert device reset + * @rcdev: reset controller entity + * @id: ID of the reset to be asserted + * + * This function implements the reset driver op to assert a device's reset + * using the ARM SCMI protocol. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int +scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev); + + return reset_ops->assert(ph, id); +} + +/** + * scmi_reset_deassert() - deassert device reset + * @rcdev: reset controller entity + * @id: ID of the reset to be deasserted + * + * This function implements the reset driver op to deassert a device's reset + * using the ARM SCMI protocol. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int +scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev); + + return reset_ops->deassert(ph, id); +} + +/** + * scmi_reset_reset() - reset the device + * @rcdev: reset controller entity + * @id: ID of the reset signal to be reset(assert + deassert) + * + * This function implements the reset driver op to trigger a device's + * reset signal using the ARM SCMI protocol. + * + * Return: 0 for successful request, else a corresponding error value + */ +static int +scmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + const struct scmi_protocol_handle *ph = to_scmi_handle(rcdev); + + return reset_ops->reset(ph, id); +} + +static const struct reset_control_ops scmi_reset_ops = { + .assert = scmi_reset_assert, + .deassert = scmi_reset_deassert, + .reset = scmi_reset_reset, +}; + +static int scmi_reset_probe(struct scmi_device *sdev) +{ + struct scmi_reset_data *data; + struct device *dev = &sdev->dev; + struct device_node *np = dev->of_node; + const struct scmi_handle *handle = sdev->handle; + struct scmi_protocol_handle *ph; + + if (!handle) + return -ENODEV; + + reset_ops = handle->dev_protocol_get(sdev, SCMI_PROTOCOL_RESET, &ph); + if (IS_ERR(reset_ops)) + return PTR_ERR(reset_ops); + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->rcdev.ops = &scmi_reset_ops; + data->rcdev.of_node = np; + data->rcdev.nr_resets = reset_ops->num_domains_get(ph); + data->ph = ph; + + return reset_controller_register(&data->rcdev); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_RESET, "reset" }, + { }, +}; + +static struct scmi_driver scmi_reset_driver = { + .name = "scmi-reset", + .probe = scmi_reset_probe, + .id_table = scmi_id_table, +}; +core_scmi_driver(scmi_reset_driver); + +MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); +MODULE_DESCRIPTION("ARM SCMI reset controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c new file mode 100644 index 0000000000..20f3df18f4 --- /dev/null +++ b/drivers/reset/reset-simple.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Simple Reset Controller Driver + * + * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> + * + * Based on Allwinner SoCs Reset Controller driver + * + * Copyright 2013 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + */ + +#include <common.h> +#include <init.h> +#include <linux/err.h> +#include <linux/reset-controller.h> +#include <linux/reset/reset-simple.h> +#include <restart.h> +#include <reset_source.h> +#include <asm/io.h> + +static inline struct reset_simple_data * +to_reset_simple_data(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct reset_simple_data, rcdev); +} + +static int reset_simple_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct reset_simple_data *data = to_reset_simple_data(rcdev); + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); + u32 reg; + + reg = readl(data->membase + (bank * reg_width)); + if (assert ^ data->active_low) + reg |= BIT(offset); + else + reg &= ~BIT(offset); + writel(reg, data->membase + (bank * reg_width)); + + return 0; +} + +static int reset_simple_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return reset_simple_update(rcdev, id, true); +} + +static int reset_simple_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return reset_simple_update(rcdev, id, false); +} + +static int reset_simple_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_simple_data *data = to_reset_simple_data(rcdev); + int ret; + + if (!data->reset_us) + return -ENOTSUPP; + + ret = reset_simple_assert(rcdev, id); + if (ret) + return ret; + + udelay(data->reset_us); + + return reset_simple_deassert(rcdev, id); +} + +static int reset_simple_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct reset_simple_data *data = to_reset_simple_data(rcdev); + int reg_width = sizeof(u32); + int bank = id / (reg_width * BITS_PER_BYTE); + int offset = id % (reg_width * BITS_PER_BYTE); + u32 reg; + + reg = readl(data->membase + (bank * reg_width)); + + return !(reg & BIT(offset)) ^ !data->status_active_low; +} + +const struct reset_control_ops reset_simple_ops = { + .assert = reset_simple_assert, + .deassert = reset_simple_deassert, + .reset = reset_simple_reset, + .status = reset_simple_status, +}; +EXPORT_SYMBOL_GPL(reset_simple_ops); + +/** + * struct reset_simple_devdata - simple reset controller properties + * @reg_offset: offset between base address and first reset register. + * @nr_resets: number of resets. If not set, default to resource size in bits. + * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits + * are set to assert the reset. + * @status_active_low: if true, bits read back as cleared while the reset is + * asserted. Otherwise, bits read back as set while the + * reset is asserted. + */ +struct reset_simple_devdata { + u32 reg_offset; + u32 nr_resets; + bool active_low; + bool status_active_low; +}; + +#define SOCFPGA_NR_BANKS 8 + +static const struct reset_simple_devdata reset_simple_socfpga = { + .reg_offset = 0x20, + .nr_resets = SOCFPGA_NR_BANKS * 32, + .status_active_low = true, +}; + +static const struct reset_simple_devdata reset_simple_active_low = { + .active_low = true, + .status_active_low = true, +}; + +static const struct of_device_id reset_simple_dt_ids[] = { + { .compatible = "altr,stratix10-rst-mgr", + .data = &reset_simple_socfpga }, + { .compatible = "st,stm32-rcc", }, + { .compatible = "allwinner,sun6i-a31-clock-reset", + .data = &reset_simple_active_low }, + { .compatible = "zte,zx296718-reset", + .data = &reset_simple_active_low }, + { .compatible = "aspeed,ast2400-lpc-reset" }, + { .compatible = "aspeed,ast2500-lpc-reset" }, + { .compatible = "bitmain,bm1880-reset", + .data = &reset_simple_active_low }, + { .compatible = "brcm,bcm4908-misc-pcie-reset", + .data = &reset_simple_active_low }, + { .compatible = "snps,dw-high-reset" }, + { .compatible = "snps,dw-low-reset", + .data = &reset_simple_active_low }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, reset_simple_dt_ids); + +static int reset_simple_probe(struct device *dev) +{ + const struct reset_simple_devdata *devdata; + struct reset_simple_data *data; + struct resource *res; + u32 reg_offset = 0; + + devdata = device_get_match_data(dev); + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + data->membase = IOMEM(res->start); + data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; + data->rcdev.ops = &reset_simple_ops; + data->rcdev.of_node = dev->of_node; + + if (devdata) { + reg_offset = devdata->reg_offset; + if (devdata->nr_resets) + data->rcdev.nr_resets = devdata->nr_resets; + data->active_low = devdata->active_low; + data->status_active_low = devdata->status_active_low; + } + + data->membase += reg_offset; + + return reset_controller_register(&data->rcdev); +} + +static struct driver reset_simple_driver = { + .probe = reset_simple_probe, + .name = "simple-reset", + .of_compatible = reset_simple_dt_ids, +}; +postcore_platform_driver(reset_simple_driver); diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index 073f8faea8..d214ce503e 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright 2014 Steffen Trumtrar <s.trumtrar@pengutronix.de> * @@ -7,11 +8,6 @@ * Copyright 2013 Maxime Ripard * * Maxime Ripard <maxime.ripard@free-electrons.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <common.h> @@ -78,19 +74,20 @@ static const struct reset_control_ops socfpga_reset_ops = { .deassert = socfpga_reset_deassert, }; -static int socfpga_reset_probe(struct device_d *dev) +static int socfpga_reset_probe(struct device *dev) { struct socfpga_reset_data *data; struct resource *res; - struct device_node *np = dev->device_node; + struct device_node *np = dev->of_node; u32 modrst_offset; data = xzalloc(sizeof(*data)); res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + data->membase = IOMEM(res->start); - if (IS_ERR(data->membase)) - return PTR_ERR(data->membase); if (of_property_read_u32(np, "altr,modrst-offset", &modrst_offset)) { dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n"); @@ -111,8 +108,9 @@ static const struct of_device_id socfpga_reset_dt_ids[] = { { .compatible = "altr,rst-mgr", }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, socfpga_reset_dt_ids); -static struct driver_d socfpga_reset_driver = { +static struct driver socfpga_reset_driver = { .name = "socfpga_reset", .probe = socfpga_reset_probe, .of_compatible = DRV_OF_COMPAT(socfpga_reset_dt_ids), diff --git a/drivers/reset/reset-starfive-vic.c b/drivers/reset/reset-starfive-vic.c index bcf615da0a..3e9e367215 100644 --- a/drivers/reset/reset-starfive-vic.c +++ b/drivers/reset/reset-starfive-vic.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2021 Ahmad Fatoum, Pengutronix * @@ -196,7 +196,7 @@ static const struct reset_control_ops starfive_rstgen_ops = { .reset = starfive_reset, }; -static int starfive_rstgen_probe(struct device_d *dev) +static int starfive_rstgen_probe(struct device *dev) { struct starfive_rstgen *priv; struct resource *iores; @@ -216,7 +216,7 @@ static int starfive_rstgen_probe(struct device_d *dev) priv->base = IOMEM(iores->start); priv->rcdev.nr_resets = RSTN_END; priv->rcdev.ops = &starfive_rstgen_ops; - priv->rcdev.of_node = dev->device_node; + priv->rcdev.of_node = dev->of_node; return reset_controller_register(&priv->rcdev); } @@ -225,8 +225,9 @@ static const struct of_device_id starfive_rstgen_reset_dt_ids[] = { { .compatible = "starfive,jh7100-rstgen", .data = jh7110_rstgen_sync_resets }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, starfive_rstgen_reset_dt_ids); -static struct driver_d starfive_rstgen_reset_driver = { +static struct driver starfive_rstgen_reset_driver = { .name = "starfive_rstgen", .probe = starfive_rstgen_probe, .of_compatible = starfive_rstgen_reset_dt_ids, diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c deleted file mode 100644 index 2ef00859c4..0000000000 --- a/drivers/reset/reset-stm32.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Copyright (C) 2019, Ahmad Fatoum, Pengutronix - * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics. - */ - -#include <common.h> -#include <init.h> -#include <linux/err.h> -#include <linux/reset-controller.h> -#include <restart.h> -#include <reset_source.h> -#include <asm/io.h> - -#define RCC_CL 0x4 - -#define RCC_MP_GRSTCSETR 0x404 -#define RCC_MP_RSTSCLRR 0x408 - -#define STM32MP_RCC_RSTF_POR BIT(0) -#define STM32MP_RCC_RSTF_BOR BIT(1) -#define STM32MP_RCC_RSTF_PAD BIT(2) -#define STM32MP_RCC_RSTF_HCSS BIT(3) -#define STM32MP_RCC_RSTF_VCORE BIT(4) - -#define STM32MP_RCC_RSTF_MPSYS BIT(6) -#define STM32MP_RCC_RSTF_MCSYS BIT(7) -#define STM32MP_RCC_RSTF_IWDG1 BIT(8) -#define STM32MP_RCC_RSTF_IWDG2 BIT(9) - -#define STM32MP_RCC_RSTF_STDBY BIT(11) -#define STM32MP_RCC_RSTF_CSTDBY BIT(12) -#define STM32MP_RCC_RSTF_MPUP0 BIT(13) -#define STM32MP_RCC_RSTF_MPUP1 BIT(14) - -struct stm32_reset_reason { - uint32_t mask; - enum reset_src_type type; - int instance; -}; - -struct stm32_reset { - void __iomem *base; - struct reset_controller_dev rcdev; - struct restart_handler restart; - const struct stm32_reset_ops *ops; -}; - -struct stm32_reset_ops { - void (*reset)(void __iomem *reg, unsigned offset, bool assert); - void __noreturn (*sys_reset)(struct restart_handler *rst); - const struct stm32_reset_reason *reset_reasons; -}; - -static struct stm32_reset *to_stm32_reset(struct reset_controller_dev *rcdev) -{ - return container_of(rcdev, struct stm32_reset, rcdev); -} - -static void stm32mp_reset(void __iomem *reg, unsigned offset, bool assert) -{ - if (!assert) - reg += RCC_CL; - - writel(BIT(offset), reg); -} - -static void stm32mcu_reset(void __iomem *reg, unsigned offset, bool assert) -{ - if (assert) - setbits_le32(reg, BIT(offset)); - else - clrbits_le32(reg, BIT(offset)); -} - -static u32 stm32_reset_status(struct stm32_reset *priv, unsigned long bank) -{ - return readl(priv->base + bank); -} - -static void stm32_reset(struct stm32_reset *priv, unsigned long id, bool assert) -{ - int bank = (id / 32) * 4; - int offset = id % 32; - - priv->ops->reset(priv->base + bank, offset, assert); -} - -static void stm32_set_reset_reason(struct stm32_reset *priv, - const struct stm32_reset_reason *reasons) -{ - enum reset_src_type type = RESET_UKWN; - u32 reg; - int i, instance = 0; - - reg = stm32_reset_status(priv, RCC_MP_RSTSCLRR); - - for (i = 0; reasons[i].mask; i++) { - if (reg & reasons[i].mask) { - type = reasons[i].type; - instance = reasons[i].instance; - break; - } - } - - reset_source_set_prinst(type, RESET_SOURCE_DEFAULT_PRIORITY, instance); - - pr_info("STM32 RCC reset reason %s (MP_RSTSR: 0x%08x)\n", - reset_source_to_string(type), reg); -} - -static int stm32_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - stm32_reset(to_stm32_reset(rcdev), id, true); - return 0; -} - -static int stm32_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - stm32_reset(to_stm32_reset(rcdev), id, false); - return 0; -} - -static const struct reset_control_ops stm32_reset_ops = { - .assert = stm32_reset_assert, - .deassert = stm32_reset_deassert, -}; - -static int stm32_reset_probe(struct device_d *dev) -{ - struct stm32_reset *priv; - struct resource *iores; - int ret; - - priv = xzalloc(sizeof(*priv)); - ret = dev_get_drvdata(dev, (const void **)&priv->ops); - if (ret) - return ret; - - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - - priv->base = IOMEM(iores->start); - priv->rcdev.nr_resets = (iores->end - iores->start) * BITS_PER_BYTE; - priv->rcdev.ops = &stm32_reset_ops; - priv->rcdev.of_node = dev->device_node; - - if (priv->ops->sys_reset) { - priv->restart.name = "stm32-rcc"; - priv->restart.restart = priv->ops->sys_reset; - priv->restart.priority = 200; - - ret = restart_handler_register(&priv->restart); - if (ret) - dev_warn(dev, "Cannot register restart handler\n"); - } - - if (priv->ops->reset_reasons) - stm32_set_reset_reason(priv, priv->ops->reset_reasons); - - return reset_controller_register(&priv->rcdev); -} - -static void __noreturn stm32mp_rcc_restart_handler(struct restart_handler *rst) -{ - struct stm32_reset *priv = container_of(rst, struct stm32_reset, restart); - - stm32_reset(priv, RCC_MP_GRSTCSETR * BITS_PER_BYTE, true); - - mdelay(1000); - hang(); -} - -static const struct stm32_reset_reason stm32mp_reset_reasons[] = { - { STM32MP_RCC_RSTF_POR, RESET_POR, 0 }, - { STM32MP_RCC_RSTF_BOR, RESET_BROWNOUT, 0 }, - { STM32MP_RCC_RSTF_STDBY, RESET_WKE, 0 }, - { STM32MP_RCC_RSTF_CSTDBY, RESET_WKE, 1 }, - { STM32MP_RCC_RSTF_MPSYS, RESET_RST, 2 }, - { STM32MP_RCC_RSTF_MPUP0, RESET_RST, 0 }, - { STM32MP_RCC_RSTF_MPUP1, RESET_RST, 1 }, - { STM32MP_RCC_RSTF_IWDG1, RESET_WDG, 0 }, - { STM32MP_RCC_RSTF_IWDG2, RESET_WDG, 1 }, - { STM32MP_RCC_RSTF_PAD, RESET_EXT, 1 }, - { /* sentinel */ } -}; - -static const struct stm32_reset_ops stm32mp1_reset_ops = { - .reset = stm32mp_reset, - .sys_reset = stm32mp_rcc_restart_handler, - .reset_reasons = stm32mp_reset_reasons, -}; - -static const struct stm32_reset_ops stm32mcu_reset_ops = { - .reset = stm32mcu_reset, -}; - -static const struct of_device_id stm32_rcc_reset_dt_ids[] = { - { .compatible = "st,stm32mp1-rcc", .data = &stm32mp1_reset_ops }, - { .compatible = "st,stm32-rcc", .data = &stm32mcu_reset_ops }, - { /* sentinel */ }, -}; - -static struct driver_d stm32_rcc_reset_driver = { - .name = "stm32_rcc_reset", - .probe = stm32_reset_probe, - .of_compatible = DRV_OF_COMPAT(stm32_rcc_reset_dt_ids), -}; - -postcore_platform_driver(stm32_rcc_reset_driver); |