summaryrefslogtreecommitdiffstats
path: root/drivers/reset
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/reset')
-rw-r--r--drivers/reset/Kconfig39
-rw-r--r--drivers/reset/Makefile5
-rw-r--r--drivers/reset/core.c258
-rw-r--r--drivers/reset/reset-imx7.c33
-rw-r--r--drivers/reset/reset-scmi.c130
-rw-r--r--drivers/reset/reset-simple.c191
-rw-r--r--drivers/reset/reset-socfpga.c24
-rw-r--r--drivers/reset/reset-starfive-vic.c235
-rw-r--r--drivers/reset/reset-stm32.c109
9 files changed, 851 insertions, 173 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 048f2081f8..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,16 +15,46 @@ 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 SOC_IMX7D
+ default ARCH_IMX7
select MFD_SYSCON
help
This enables the reset controller driver for i.MX7 SoCs.
-config RESET_STM32
- bool "STM32 Reset Driver"
+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 STM32MP and STM32 MCUs.
+ 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 8460c4b154..b1668433d7 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,4 +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 99b9c80655..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,35 +238,44 @@ int reset_control_deassert(struct reset_control *rstc)
EXPORT_SYMBOL_GPL(reset_control_deassert);
/**
- * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * reset_control_get_count - Count reset lines
+ * @dev: device
+ *
+ * Returns number of resets, 0 if none specified
+ */
+int reset_control_get_count(struct device *dev)
+{
+ return of_count_phandle_with_args(dev->of_node, "resets",
+ "#reset-cells");
+}
+
+/**
+ * of_reset_control_get_by_index - Lookup and obtain a reference to a reset controller.
* @node: device to be reset by the controller
- * @id: reset line name
+ * @index: reset line index
*
* Returns a struct reset_control or IS_ERR() condition containing errno.
- *
- * Use of id names is optional.
*/
-static struct reset_control *of_reset_control_get(struct device_node *node,
- const char *id)
+static struct reset_control *of_reset_control_get_by_index(struct device_node *node,
+ int index)
{
- struct reset_control *rstc = ERR_PTR(-ENODEV);
+ struct reset_control *rstc;
struct reset_controller_dev *r, *rcdev;
struct of_phandle_args args;
- int index = 0;
int rstc_id;
int ret;
if (!of_get_property(node, "resets", NULL))
return NULL;
- if (id)
- index = of_property_match_string(node,
- "reset-names", id);
ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
index, &args);
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) {
if (args.np == r->of_node) {
@@ -195,8 +303,31 @@ static struct reset_control *of_reset_control_get(struct device_node *node,
return rstc;
}
+/**
+ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+struct reset_control *of_reset_control_get(struct device_node *node,
+ const char *id)
+{
+ int index = 0;
+
+ 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;
@@ -205,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);
@@ -228,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);
@@ -281,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;
@@ -302,7 +433,86 @@ int device_reset(struct device_d *dev)
}
EXPORT_SYMBOL_GPL(device_reset);
-int device_reset_us(struct device_d *dev, int us)
+/*
+ * 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 < reset_control_get_count(dev); i++) {
+ int ret;
+
+ rstc = of_reset_control_get_by_index(dev->of_node, i);
+ if (IS_ERR(rstc))
+ return PTR_ERR(rstc);
+
+ ret = reset_control_reset(rstc);
+ if (ret)
+ return ret;
+
+ reset_control_put(rstc);
+ }
+
+ if (i == 0) {
+ rstc = gpio_reset_control_get(dev, NULL);
+
+ ret = reset_control_reset(rstc);
+ if (ret)
+ return ret;
+
+ reset_control_put(rstc);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(device_reset_all);
+
+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 9d4344a94c..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 {
@@ -177,9 +169,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
[IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) },
[IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) },
[IMX8MQ_RESET_MIPI_DSI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(2) },
- [IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
- [IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
- [IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
+ [IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N] = { SRC_MIPIPHY_RCR, BIT(3) },
+ [IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N] = { SRC_MIPIPHY_RCR, BIT(4) },
+ [IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N] = { SRC_MIPIPHY_RCR, BIT(5) },
[IMX8MQ_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR,
BIT(2) | BIT(1) },
[IMX8MQ_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) },
@@ -228,9 +220,9 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN: /* fallthrough */
- case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N: /* fallthrough */
- case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N: /* fallthrough */
- case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
+ case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
case IMX8MQ_RESET_MIPI_DSI_RESET_N: /* fallthrough */
case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: /* fallthrough */
value = assert ? 0 : bit;
@@ -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 9b499f23c5..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,15 +108,12 @@ 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),
};
-static int socfpga_reset_init(void)
-{
- return platform_driver_register(&socfpga_reset_driver);
-}
-postcore_initcall(socfpga_reset_init);
+postcore_platform_driver(socfpga_reset_driver);
diff --git a/drivers/reset/reset-starfive-vic.c b/drivers/reset/reset-starfive-vic.c
new file mode 100644
index 0000000000..3e9e367215
--- /dev/null
+++ b/drivers/reset/reset-starfive-vic.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021 Ahmad Fatoum, Pengutronix
+ *
+ * StarFive Reset Controller driver
+ */
+#define pr_fmt(fmt) "reset-starfive: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/reset-controller.h>
+#include <soc/starfive/rstgen.h>
+#include <dt-bindings/reset-controller/starfive-jh7100.h>
+#include <dt-bindings/clock/starfive-jh7100.h>
+
+struct starfive_rstgen {
+ void __iomem *base;
+ struct reset_controller_dev rcdev;
+ const struct starfive_rstgen_ops *ops;
+ struct device_node *clknp;
+ const int *sync_resets;
+};
+
+static struct starfive_rstgen *to_starfive_rstgen(struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct starfive_rstgen, rcdev);
+}
+
+static const int jh7110_rstgen_sync_resets[RSTN_END] = {
+ [RSTN_SGDMA2P_AHB] = CLK_SGDMA2P_AHB,
+ [RSTN_SGDMA2P_AXI] = CLK_SGDMA2P_AXI,
+ [RSTN_DMA2PNOC_AXI] = CLK_DMA2PNOC_AXI,
+ [RSTN_DLA_AXI] = CLK_DLA_AXI,
+ [RSTN_DLANOC_AXI] = CLK_DLANOC_AXI,
+ [RSTN_DLA_APB] = CLK_DLA_APB,
+ [RSTN_VDECBRG_MAIN] = CLK_VDECBRG_MAIN,
+ [RSTN_VDEC_AXI] = CLK_VDEC_AXI,
+ [RSTN_VDEC_BCLK] = CLK_VDEC_BCLK,
+ [RSTN_VDEC_CCLK] = CLK_VDEC_CCLK,
+ [RSTN_VDEC_APB] = CLK_VDEC_APB,
+ [RSTN_JPEG_AXI] = CLK_JPEG_AXI,
+ [RSTN_JPEG_CCLK] = CLK_JPEG_CCLK,
+ [RSTN_JPEG_APB] = CLK_JPEG_APB,
+ [RSTN_JPCGC300_MAIN] = CLK_JPCGC300_MAIN,
+ [RSTN_GC300_2X] = CLK_GC300_2X,
+ [RSTN_GC300_AXI] = CLK_GC300_AXI,
+ [RSTN_GC300_AHB] = CLK_GC300_AHB,
+ [RSTN_VENC_AXI] = CLK_VENC_AXI,
+ [RSTN_VENCBRG_MAIN] = CLK_VENCBRG_MAIN,
+ [RSTN_VENC_BCLK] = CLK_VENC_BCLK,
+ [RSTN_VENC_CCLK] = CLK_VENC_CCLK,
+ [RSTN_VENC_APB] = CLK_VENC_APB,
+ [RSTN_DDRPHY_APB] = CLK_DDRPHY_APB,
+ [RSTN_USB_AXI] = CLK_USB_AXI,
+ [RSTN_SGDMA1P_AXI] = CLK_SGDMA1P_AXI,
+ [RSTN_DMA1P_AXI] = CLK_DMA1P_AXI,
+ [RSTN_NNE_AHB] = CLK_NNE_AHB,
+ [RSTN_NNE_AXI] = CLK_NNE_AXI,
+ [RSTN_NNENOC_AXI] = CLK_NNENOC_AXI,
+ [RSTN_DLASLV_AXI] = CLK_DLASLV_AXI,
+ [RSTN_VOUT_SRC] = CLK_VOUT_SRC,
+ [RSTN_DISP_AXI] = CLK_DISP_AXI,
+ [RSTN_DISPNOC_AXI] = CLK_DISPNOC_AXI,
+ [RSTN_SDIO0_AHB] = CLK_SDIO0_AHB,
+ [RSTN_SDIO1_AHB] = CLK_SDIO1_AHB,
+ [RSTN_GMAC_AHB] = CLK_GMAC_AHB,
+ [RSTN_SPI2AHB_AHB] = CLK_SPI2AHB_AHB,
+ [RSTN_SPI2AHB_CORE] = CLK_SPI2AHB_CORE,
+ [RSTN_EZMASTER_AHB] = CLK_EZMASTER_AHB,
+ [RSTN_SEC_AHB] = CLK_SEC_AHB,
+ [RSTN_AES] = CLK_AES,
+ [RSTN_PKA] = CLK_PKA,
+ [RSTN_SHA] = CLK_SHA,
+ [RSTN_TRNG_APB] = CLK_TRNG_APB,
+ [RSTN_OTP_APB] = CLK_OTP_APB,
+ [RSTN_UART0_APB] = CLK_UART0_APB,
+ [RSTN_UART0_CORE] = CLK_UART0_CORE,
+ [RSTN_UART1_APB] = CLK_UART1_APB,
+ [RSTN_UART1_CORE] = CLK_UART1_CORE,
+ [RSTN_SPI0_APB] = CLK_SPI0_APB,
+ [RSTN_SPI0_CORE] = CLK_SPI0_CORE,
+ [RSTN_SPI1_APB] = CLK_SPI1_APB,
+ [RSTN_SPI1_CORE] = CLK_SPI1_CORE,
+ [RSTN_I2C0_APB] = CLK_I2C0_APB,
+ [RSTN_I2C0_CORE] = CLK_I2C0_CORE,
+ [RSTN_I2C1_APB] = CLK_I2C1_APB,
+ [RSTN_I2C1_CORE] = CLK_I2C1_CORE,
+ [RSTN_GPIO_APB] = CLK_GPIO_APB,
+ [RSTN_UART2_APB] = CLK_UART2_APB,
+ [RSTN_UART2_CORE] = CLK_UART2_CORE,
+ [RSTN_UART3_APB] = CLK_UART3_APB,
+ [RSTN_UART3_CORE] = CLK_UART3_CORE,
+ [RSTN_SPI2_APB] = CLK_SPI2_APB,
+ [RSTN_SPI2_CORE] = CLK_SPI2_CORE,
+ [RSTN_SPI3_APB] = CLK_SPI3_APB,
+ [RSTN_SPI3_CORE] = CLK_SPI3_CORE,
+ [RSTN_I2C2_APB] = CLK_I2C2_APB,
+ [RSTN_I2C2_CORE] = CLK_I2C2_CORE,
+ [RSTN_I2C3_APB] = CLK_I2C3_APB,
+ [RSTN_I2C3_CORE] = CLK_I2C3_CORE,
+ [RSTN_WDTIMER_APB] = CLK_WDTIMER_APB,
+ [RSTN_WDT] = CLK_WDT_CORE,
+ [RSTN_VP6INTC_APB] = CLK_VP6INTC_APB,
+ [RSTN_TEMP_APB] = CLK_TEMP_APB,
+ [RSTN_TEMP_SENSE] = CLK_TEMP_SENSE,
+};
+
+static struct clk *starfive_reset_clk_get(struct starfive_rstgen *priv, unsigned id)
+{
+ struct of_phandle_args clkspec = {
+ .np = priv->clknp,
+ .args_count = 1,
+ };
+
+ if (!priv->sync_resets || !priv->sync_resets[id])
+ return 0;
+
+ clkspec.args[0] = priv->sync_resets[id];
+
+ pr_debug("synchronous reset=%u clk=%u\n", id, priv->sync_resets[id]);
+
+ return of_clk_get_from_provider(&clkspec);
+}
+
+static int starfive_reset_clk_enable(struct starfive_rstgen *priv, unsigned id)
+{
+ return clk_enable(starfive_reset_clk_get(priv, id));
+}
+
+static void starfive_reset_clk_disable(struct starfive_rstgen *priv, unsigned id)
+{
+ clk_disable(starfive_reset_clk_get(priv, id));
+}
+
+static int starfive_rstgen(struct starfive_rstgen *priv, unsigned id, bool assert)
+{
+ void __iomem *base = priv->base;
+
+ __starfive_rstgen(base, id, assert);
+
+ return wait_on_timeout(NSEC_PER_MSEC, __starfive_rstgen_asserted(base, id) == assert);
+}
+
+static int starfive_rstgen_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct starfive_rstgen *priv = to_starfive_rstgen(rcdev);
+ int ret;
+
+ starfive_reset_clk_enable(priv, id);
+ ret = starfive_rstgen(priv, id, true);
+ starfive_reset_clk_disable(priv, id);
+
+ return ret;
+}
+
+static int starfive_rstgen_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct starfive_rstgen *priv = to_starfive_rstgen(rcdev);
+ int ret;
+
+ starfive_reset_clk_enable(priv, id);
+ ret = starfive_rstgen(priv, id, false);
+ starfive_reset_clk_disable(priv, id);
+
+ return ret;
+}
+
+static int starfive_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct starfive_rstgen *priv = to_starfive_rstgen(rcdev);
+ int ret;
+
+ starfive_reset_clk_enable(priv, id);
+
+ ret = starfive_rstgen(priv, id, true);
+ if (ret)
+ goto out;
+
+ udelay(2);
+
+ ret = starfive_rstgen(priv, id, false);
+
+out:
+ starfive_reset_clk_disable(priv, id);
+
+ return ret;
+}
+
+static const struct reset_control_ops starfive_rstgen_ops = {
+ .assert = starfive_rstgen_assert,
+ .deassert = starfive_rstgen_deassert,
+ .reset = starfive_reset,
+};
+
+static int starfive_rstgen_probe(struct device *dev)
+{
+ struct starfive_rstgen *priv;
+ struct resource *iores;
+
+ priv = xzalloc(sizeof(*priv));
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ if ((priv->sync_resets = device_get_match_data(dev))) {
+ priv->clknp = of_find_compatible_node(NULL, NULL, "starfive,jh7100-clkgen");
+ if (!priv->clknp)
+ return -ENODEV;
+ }
+
+ priv->base = IOMEM(iores->start);
+ priv->rcdev.nr_resets = RSTN_END;
+ priv->rcdev.ops = &starfive_rstgen_ops;
+ priv->rcdev.of_node = dev->of_node;
+
+ return reset_controller_register(&priv->rcdev);
+}
+
+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 starfive_rstgen_reset_driver = {
+ .name = "starfive_rstgen",
+ .probe = starfive_rstgen_probe,
+ .of_compatible = starfive_rstgen_reset_dt_ids,
+};
+core_platform_driver(starfive_rstgen_reset_driver);
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
deleted file mode 100644
index 5689dfd488..0000000000
--- a/drivers/reset/reset-stm32.c
+++ /dev/null
@@ -1,109 +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 <asm/io.h>
-
-#define RCC_CL 0x4
-
-struct stm32_reset {
- void __iomem *base;
- struct reset_controller_dev rcdev;
- void (*reset)(void __iomem *reg, unsigned offset, bool assert);
-};
-
-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 void stm32_reset(struct stm32_reset *priv, unsigned long id, bool assert)
-{
- int bank = (id / BITS_PER_LONG) * 4;
- int offset = id % BITS_PER_LONG;
-
- priv->reset(priv->base + bank, offset, assert);
-}
-
-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->reset);
- 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;
-
- return reset_controller_register(&priv->rcdev);
-}
-
-static const struct of_device_id stm32_rcc_reset_dt_ids[] = {
- { .compatible = "st,stm32mp1-rcc", .data = stm32mp_reset },
- { .compatible = "st,stm32-rcc", .data = stm32mcu_reset },
- { /* 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),
-};
-
-static int stm32_rcc_reset_init(void)
-{
- return platform_driver_register(&stm32_rcc_reset_driver);
-}
-postcore_initcall(stm32_rcc_reset_init);