aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/device-tree-bindings/reset/ti,sci-reset.txt54
-rw-r--r--drivers/reset/Kconfig8
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-ti-sci.c206
4 files changed, 269 insertions, 0 deletions
diff --git a/doc/device-tree-bindings/reset/ti,sci-reset.txt b/doc/device-tree-bindings/reset/ti,sci-reset.txt
new file mode 100644
index 0000000..e7e2d13
--- /dev/null
+++ b/doc/device-tree-bindings/reset/ti,sci-reset.txt
@@ -0,0 +1,54 @@
+Texas Instruments TI SCI Reset Controller
+=========================================
+
+Some TI SoCs contain a system controller (like the SYSFW, etc...) that is
+responsible for controlling the state of the IPs that are present.
+Communication between the host processor running an OS and the system
+controller happens through a protocol known as TI SCI [1].
+
+[1] http://processors.wiki.ti.com/index.php/TISCI
+
+Reset Controller Node
+=====================
+The reset controller node represents the resets of various hardware modules
+present on the SoC managed by the SYSFW. Because this relies on the TI SCI
+protocol to communicate with the SYSFW it must be a child of the sysfw node.
+
+Required Properties:
+--------------------
+ - compatible: Must be "ti,sci-reset"
+ - #reset-cells: Must be 2. Please see the reset consumer node below for
+ usage details.
+
+Example (AM65x):
+----------------
+ sysfw: sysfw {
+ compatible = "ti,am654-system-controller";
+ ...
+ k3_reset: reset-controller {
+ compatible = "ti,sci-reset";
+ #reset-cells = <2>;
+ };
+ };
+
+Reset Consumers
+===============
+Each of the reset consumer nodes should have the following properties,
+in addition to their own properties.
+
+Required Properties:
+--------------------
+ - resets: A phandle and reset specifier pair, one pair for each reset signal
+ that affects the device, or that the device manages. The phandle
+ should point to the TI SCI reset controller node, and the reset
+ specifier should have 2 cell-values. The first cell should contain
+ the device ID. The second cell should contain the reset mask value
+ used by system controller.
+
+Example (AM65x):
+----------------
+ uart2: serial@02800000 {
+ compatible = "ti,omap4-uart";
+ ...
+ resets = <&k3_reset 5 1>;
+ };
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 33c39b7..9c5208b 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -49,6 +49,14 @@ config TEGRA186_RESET
Enable support for manipulating Tegra's on-SoC reset signals via IPC
requests to the BPMP (Boot and Power Management Processor).
+config RESET_TI_SCI
+ bool "TI System Control Interface (TI SCI) reset driver"
+ depends on DM_RESET && TI_SCI_PROTOCOL
+ help
+ This enables the reset driver support over TI System Control Interface
+ available on some new TI's SoCs. If you wish to use reset resources
+ managed by the TI System Controller, say Y here. Otherwise, say N.
+
config RESET_BCM6345
bool "Reset controller driver for BCM6345"
depends on DM_RESET && ARCH_BMIPS
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index ad08be4..abdfa0c 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_STI_RESET) += sti-reset.o
obj-$(CONFIG_STM32_RESET) += stm32-reset.o
obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o
obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
+obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o
diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c
new file mode 100644
index 0000000..c8a76df
--- /dev/null
+++ b/drivers/reset/reset-ti-sci.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments System Control Interface (TI SCI) reset driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Andreas Dannenberg <dannenberg@ti.com>
+ *
+ * Loosely based on Linux kernel reset-ti-sci.c...
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset-uclass.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+/**
+ * struct ti_sci_reset_data - reset controller information structure
+ * @sci: TI SCI handle used for communication with system controller
+ */
+struct ti_sci_reset_data {
+ const struct ti_sci_handle *sci;
+};
+
+static int ti_sci_reset_probe(struct udevice *dev)
+{
+ struct ti_sci_reset_data *data = dev_get_priv(dev);
+
+ debug("%s(dev=%p)\n", __func__, dev);
+
+ if (!data)
+ return -ENOMEM;
+
+ /* Store handle for communication with the system controller */
+ data->sci = ti_sci_get_handle(dev);
+ if (IS_ERR(data->sci))
+ return PTR_ERR(data->sci);
+
+ return 0;
+}
+
+static int ti_sci_reset_of_xlate(struct reset_ctl *rst,
+ struct ofnode_phandle_args *args)
+{
+ debug("%s(rst=%p, args_count=%d)\n", __func__, rst, args->args_count);
+
+ if (args->args_count != 2) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ /*
+ * On TI SCI-based devices, the reset provider id field is used as a
+ * device ID, and the data field is used as the associated reset mask.
+ */
+ rst->id = args->args[0];
+ rst->data = args->args[1];
+
+ return 0;
+}
+
+static int ti_sci_reset_request(struct reset_ctl *rst)
+{
+ debug("%s(rst=%p)\n", __func__, rst);
+ return 0;
+}
+
+static int ti_sci_reset_free(struct reset_ctl *rst)
+{
+ debug("%s(rst=%p)\n", __func__, rst);
+ return 0;
+}
+
+/**
+ * ti_sci_reset_set() - program a device's reset
+ * @rst: Handle to a single reset signal
+ * @assert: boolean flag to indicate assert or deassert
+ *
+ * This is a common internal function used to assert or deassert a device's
+ * reset using the TI SCI protocol. The device's reset is asserted if the
+ * @assert argument is true, or deasserted if @assert argument is false.
+ * The mechanism itself is a read-modify-write procedure, the current device
+ * reset register is read using a TI SCI device operation, the new value is
+ * set or un-set using the reset's mask, and the new reset value written by
+ * using another TI SCI device operation.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int ti_sci_reset_set(struct reset_ctl *rst, bool assert)
+{
+ struct ti_sci_reset_data *data = dev_get_priv(rst->dev);
+ const struct ti_sci_handle *sci = data->sci;
+ const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
+ u32 reset_state;
+ int ret;
+
+ ret = dops->get_device_resets(sci, rst->id, &reset_state);
+ if (ret) {
+ dev_err(rst->dev, "%s: get_device_resets failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (assert)
+ reset_state |= rst->data;
+ else
+ reset_state &= ~rst->data;
+
+ ret = dops->set_device_resets(sci, rst->id, reset_state);
+ if (ret) {
+ dev_err(rst->dev, "%s: set_device_resets failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * ti_sci_reset_assert() - assert device reset
+ * @rst: Handle to a single reset signal
+ *
+ * This function implements the reset driver op to assert a device's reset
+ * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
+ * with the corresponding parameters as passed in, but with the @assert
+ * argument set to true for asserting the reset.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int ti_sci_reset_assert(struct reset_ctl *rst)
+{
+ debug("%s(rst=%p)\n", __func__, rst);
+ return ti_sci_reset_set(rst, true);
+}
+
+/**
+ * ti_sci_reset_deassert() - deassert device reset
+ * @rst: Handle to a single reset signal
+ *
+ * This function implements the reset driver op to deassert a device's reset
+ * using the TI SCI protocol. This invokes the function ti_sci_reset_set()
+ * with the corresponding parameters as passed in, but with the @assert
+ * argument set to false for deasserting the reset.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int ti_sci_reset_deassert(struct reset_ctl *rst)
+{
+ debug("%s(rst=%p)\n", __func__, rst);
+ return ti_sci_reset_set(rst, false);
+}
+
+/**
+ * ti_sci_reset_status() - check device reset status
+ * @rst: Handle to a single reset signal
+ *
+ * This function implements the reset driver op to return the status of a
+ * device's reset using the TI SCI protocol. The reset register value is read
+ * by invoking the TI SCI device operation .get_device_resets(), and the
+ * status of the specific reset is extracted and returned using this reset's
+ * reset mask.
+ *
+ * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted
+ */
+static int ti_sci_reset_status(struct reset_ctl *rst)
+{
+ struct ti_sci_reset_data *data = dev_get_priv(rst->dev);
+ const struct ti_sci_handle *sci = data->sci;
+ const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
+ u32 reset_state;
+ int ret;
+
+ debug("%s(rst=%p)\n", __func__, rst);
+
+ ret = dops->get_device_resets(sci, rst->id, &reset_state);
+ if (ret) {
+ dev_err(rst->dev, "%s: get_device_resets failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return reset_state & rst->data;
+}
+
+static const struct udevice_id ti_sci_reset_of_match[] = {
+ { .compatible = "ti,sci-reset", },
+ { /* sentinel */ },
+};
+
+static struct reset_ops ti_sci_reset_ops = {
+ .of_xlate = ti_sci_reset_of_xlate,
+ .request = ti_sci_reset_request,
+ .free = ti_sci_reset_free,
+ .rst_assert = ti_sci_reset_assert,
+ .rst_deassert = ti_sci_reset_deassert,
+ .rst_status = ti_sci_reset_status,
+};
+
+U_BOOT_DRIVER(ti_sci_reset) = {
+ .name = "ti-sci-reset",
+ .id = UCLASS_RESET,
+ .of_match = ti_sci_reset_of_match,
+ .probe = ti_sci_reset_probe,
+ .priv_auto_alloc_size = sizeof(struct ti_sci_reset_data),
+ .ops = &ti_sci_reset_ops,
+};